GNU/Linux >> Belajar Linux >  >> Linux

C++ Dynamic Shared Library di Linux

kelasku.h

#ifndef __MYCLASS_H__
#define __MYCLASS_H__

class MyClass
{
public:
  MyClass();

  /* use virtual otherwise linker will try to perform static linkage */
  virtual void DoSomething();

private:
  int x;
};

#endif

kelasku.cc

#include "myclass.h"
#include <iostream>

using namespace std;

extern "C" MyClass* create_object()
{
  return new MyClass;
}

extern "C" void destroy_object( MyClass* object )
{
  delete object;
}

MyClass::MyClass()
{
  x = 20;
}

void MyClass::DoSomething()
{
  cout<<x<<endl;
}

pengguna_kelas.cc

#include <dlfcn.h>
#include <iostream>
#include "myclass.h"

using namespace std;

int main(int argc, char **argv)
{
  /* on Linux, use "./myclass.so" */
  void* handle = dlopen("myclass.so", RTLD_LAZY);

  MyClass* (*create)();
  void (*destroy)(MyClass*);

  create = (MyClass* (*)())dlsym(handle, "create_object");
  destroy = (void (*)(MyClass*))dlsym(handle, "destroy_object");

  MyClass* myClass = (MyClass*)create();
  myClass->DoSomething();
  destroy( myClass );
}

Di Mac OS X, kompilasi dengan:

g++ -dynamiclib -flat_namespace myclass.cc -o myclass.so
g++ class_user.cc -o class_user

Di Linux, kompilasi dengan:

g++ -fPIC -shared myclass.cc -o myclass.so
g++ class_user.cc -ldl -o class_user

Jika ini untuk sistem plugin, Anda akan menggunakan MyClass sebagai kelas dasar dan mendefinisikan semua fungsi yang diperlukan secara virtual. Penulis plugin kemudian akan mengambil dari MyClass, menimpa virtual dan mengimplementasikan create_object dan destroy_object . Aplikasi utama Anda tidak perlu diubah dengan cara apa pun.


Berikut ini adalah contoh shared class library shared.[h,cpp] dan modul main.cpp yang menggunakan library tersebut. Ini adalah contoh yang sangat sederhana dan makefile dapat dibuat jauh lebih baik. Tapi itu berhasil dan dapat membantu Anda:

shared.h mendefinisikan kelas:

class myclass {
   int myx;

  public:

    myclass() { myx=0; }
    void setx(int newx);
    int  getx();
};

shared.cpp mendefinisikan fungsi getx/setx:

#include "shared.h"

void myclass::setx(int newx) { myx = newx; }
int  myclass::getx() { return myx; }

main.cpp menggunakan kelas,

#include <iostream>
#include "shared.h"

using namespace std;

int main(int argc, char *argv[])
{
  myclass m;

  cout << m.getx() << endl;
  m.setx(10);
  cout << m.getx() << endl;
}

dan makefile yang menghasilkan libshared.so dan menautkan main dengan pustaka bersama:

main: libshared.so main.o
    $(CXX) -o main  main.o -L. -lshared

libshared.so: shared.cpp
    $(CXX) -fPIC -c shared.cpp -o shared.o
    $(CXX) -shared  -Wl,-soname,libshared.so -o libshared.so shared.o

clean:
    $rm *.o *.so

Untuk benar-benar menjalankan 'main' dan menautkan dengan libshared.so Anda mungkin perlu menentukan jalur pemuatan (atau meletakkannya di /usr/local/lib atau yang serupa).

Berikut ini menentukan direktori saat ini sebagai jalur pencarian untuk perpustakaan dan menjalankan main (sintaks bash):

export LD_LIBRARY_PATH=.
./main

Untuk melihat bahwa program tersebut ditautkan dengan libshared.so Anda dapat mencoba ldd:

LD_LIBRARY_PATH=. ldd main

Cetakan di mesin saya:

  ~/prj/test/shared$ LD_LIBRARY_PATH=. ldd main
    linux-gate.so.1 =>  (0xb7f88000)
    libshared.so => ./libshared.so (0xb7f85000)
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e74000)
    libm.so.6 => /lib/libm.so.6 (0xb7e4e000)
    libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xb7e41000)
    libc.so.6 => /lib/libc.so.6 (0xb7cfa000)
    /lib/ld-linux.so.2 (0xb7f89000)

Di atas jawaban sebelumnya, saya ingin meningkatkan kesadaran tentang fakta bahwa Anda harus menggunakan idiom RAII (Resource Acquisition Is Initialisation) agar aman dari penghancuran penangan.

Berikut adalah contoh lengkap yang berfungsi:

Deklarasi antarmuka:Interface.hpp :

class Base {
public:
    virtual ~Base() {}
    virtual void foo() const = 0;
};

using Base_creator_t = Base *(*)();

Konten pustaka bersama:

#include "Interface.hpp"

class Derived: public Base {
public:
    void foo() const override {}
};

extern "C" {
Base * create() {
    return new Derived;
}
}

Penangan perpustakaan bersama dinamis:Derived_factory.hpp :

#include "Interface.hpp"
#include <dlfcn.h>

class Derived_factory {
public:
    Derived_factory() {
        handler = dlopen("libderived.so", RTLD_NOW);
        if (! handler) {
            throw std::runtime_error(dlerror());
        }
        Reset_dlerror();
        creator = reinterpret_cast<Base_creator_t>(dlsym(handler, "create"));
        Check_dlerror();
    }

    std::unique_ptr<Base> create() const {
        return std::unique_ptr<Base>(creator());
    }

    ~Derived_factory() {
        if (handler) {
            dlclose(handler);
        }
    }

private:
    void * handler = nullptr;
    Base_creator_t creator = nullptr;

    static void Reset_dlerror() {
        dlerror();
    }

    static void Check_dlerror() {
        const char * dlsym_error = dlerror();
        if (dlsym_error) {
            throw std::runtime_error(dlsym_error);
        }
    }
};

Kode klien:

#include "Derived_factory.hpp"

{
    Derived_factory factory;
    std::unique_ptr<Base> base = factory.create();
    base->foo();
}

Catatan:

  • Saya meletakkan semuanya di file header untuk keringkasan. Dalam kehidupan nyata, Anda tentu saja harus membagi kode Anda antara .hpp dan .cpp file.
  • Untuk mempermudah, saya mengabaikan kasus di mana Anda ingin menangani new /delete kelebihan muatan.

Dua artikel yang jelas untuk mendapatkan detail lebih lanjut:

  • C++ buka mini how-to
  • Pemuatan Dinamis C++ dari Objek Bersama saat Waktu Proses

Linux
  1. Pengantar Pustaka Bersama Linux (Cara Membuat Pustaka Bersama)

  2. Kompilasi Pustaka Bersama Dinamis dengan g++

  3. Mengonversi Perpustakaan Statis menjadi Perpustakaan Bersama?

  1. Penemuan ketergantungan pustaka Dinamis pada Mac OS &Linux

  2. Cara menginisialisasi perpustakaan bersama di Linux

  3. Mengupas perpustakaan bersama linux

  1. Bagaimana cara mengkompilasi pustaka dinamis untuk aplikasi JNI di linux?

  2. Bagaimana cara melihat daftar fungsi yang diekspor oleh perpustakaan bersama Linux?

  3. Mendeteksi Windows atau Linux di C, C++