これは、 g ++を使用した動的共有ライブラリのコンパイル のフォローアップです。
LinuxのC++で共有クラスライブラリを作成しようとしています。ライブラリをコンパイルすることができ、 here および here を見つけたチュートリアルを使用して(クラスではない)関数を呼び出すことができます。ライブラリで定義されているクラスを使用しようとすると、問題が発生します。リンクした2番目のチュートリアルは、ライブラリで定義されたクラスのオブジェクトを作成するためのシンボルを読み込む方法を示していますが、using作業を完了します。
共有C++クラスライブラリを作成するためのより完全なチュートリアルを知っていますか?別の実行可能ファイルでそれらのクラスをuseする方法も示していますか?オブジェクトの作成、使用(単純なgetterおよびsetterは問題ありません)、および削除を示す非常に簡単なチュートリアルです。共有クラスライブラリの使用方法を示すオープンソースコードへのリンクまたは参照も同様に適切です。
codelogic および nimrodm からの回答は機能しますが、この質問を尋ねてから Beginning Linux Programming のコピーを選択したことを追加したいだけです。 、最初の章にはサンプルCコードがあり、静的ライブラリと共有ライブラリの両方を作成および使用するための適切な説明があります。これらの例は、Googleブック検索で その書籍の古い版 から入手できます。
myclass.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
myclass.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;
}
class_user.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 );
}
Mac OS Xでは、次を使用してコンパイルします。
g++ -dynamiclib -flat_namespace myclass.cc -o myclass.so
g++ class_user.cc -o class_user
Linuxでは、次を使用してコンパイルします。
g++ -fPIC -shared myclass.cc -o myclass.so
g++ class_user.cc -ldl -o class_user
これがプラグインシステムの場合、MyClassを基本クラスとして使用し、必要なすべての関数を仮想で定義します。プラグインの作成者は、MyClassから派生し、virtualsをオーバーライドし、create_object
およびdestroy_object
を実装します。メインアプリケーションを変更する必要はありません。
以下に、共有クラスライブラリshared。[h、cpp]と、ライブラリを使用するmain.cppモジュールの例を示します。これは非常に単純な例であり、メイクファイルをさらに改善することができます。しかし、それは機能し、あなたを助けるかもしれません:
shared.hはクラスを定義します:
class myclass {
int myx;
public:
myclass() { myx=0; }
void setx(int newx);
int getx();
};
shared.cppは、getx/setx関数を定義します。
#include "shared.h"
void myclass::setx(int newx) { myx = newx; }
int myclass::getx() { return myx; }
main.cppはクラスを使用し、
#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;
}
また、libshared.soを生成し、mainを共有ライブラリにリンクするメイクファイル:
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
実際に 'main'を実行してlibshared.soにリンクするには、おそらくロードパスを指定する(または/ usr/local/libなどに配置する)必要があります。
以下は、ライブラリの検索パスとして現在のディレクトリを指定し、mainを実行します(bash構文):
export LD_LIBRARY_PATH=.
./main
プログラムがlibshared.soにリンクされていることを確認するには、lddを試してください。
LD_LIBRARY_PATH=. ldd main
私のマシンで印刷:
~/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)
基本的に、共有ライブラリでクラスを使用するコードにクラスのヘッダーファイルを含める必要があります。次に、リンクするときに '-l'フラグを使用 を使用して、コードを共有ライブラリにリンクします。もちろん、これには.soがOSが見つけられる場所である必要があります。 .5。共有ライブラリのインストールと使用 を参照してください
Dlsymの使用は、コンパイル時に使用するライブラリがわからない場合に使用します。それはここの場合のように聞こえません。たぶん混乱は、コンパイルまたは実行時にリンクを実行するかどうかに関係なく、Windowsが動的にロードされたライブラリを呼び出すことです(同様の方法で)?その場合、dlsymはLoadLibraryに相当すると考えることができます。
ライブラリを動的にロードする必要がある場合(つまり、プラグイン)、 このFAQ が役立ちます。
以前の回答に加えて、ハンドラーの破壊について安全にするために RAII(Resource Acquisition Is Initialisation)イディオム を使用する必要があるという事実について認識を高めたいと思います。
完全な作業例は次のとおりです。
インターフェイス宣言:Interface.hpp
:
class Base {
public:
virtual ~Base() {}
virtual void foo() const = 0;
};
using Base_creator_t = Base *(*)();
共有ライブラリのコンテンツ:
#include "Interface.hpp"
class Derived: public Base {
public:
void foo() const override {}
};
extern "C" {
Base * create() {
return new Derived;
}
}
動的共有ライブラリハンドラ: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);
}
}
};
クライアントコード:
#include "Derived_factory.hpp"
{
Derived_factory factory;
std::unique_ptr<Base> base = factory.create();
base->foo();
}
注意:
.hpp
ファイルと.cpp
ファイルに分割する必要があります。new
/delete
オーバーロードを処理する場合は無視しました。詳細を取得するための2つの明確な記事: