3

dlopen() を使用して共有ライブラリを別の共有ライブラリにロードしようとすると、問題が発生します。dlopen() を正しく使用する方法に関するすべてのチュートリアルを確認しました。したがって、簡略化されたコードは次のとおりです。

メイン共有ライブラリには、サブ共有ライブラリ (別名プラグイン) が実装する必要がある純粋仮想関数を持つクラスが含まれています。さらに、デフォルトの動作で実装されている他の機能がいくつかあります。クラスをロードして作成するシンボルを持つために、すべてのプラグインに追加されるマクロを作成しました。

主な共有ライブラリ

plugin.h:

Class A {
public:
  virtual int func1() = 0;
  virtual bool func2() const;
}

#define CREATE_CLASS(cls) extern "C" void *CreateClass(void) { return new cls; }

プラグイン.cpp:

bool A::func2() const {   return true; }

main.so をビルドしてリンクする

g++ -g -Wall -Woverloaded-virtual -Wno-parentheses -O2 -fPIC -c -o plugin.o plugin.cpp
g++ -g -Wall -Woverloaded-virtual -Wno-parentheses -O2 -fPIC  -rdynamic -shared plugin.o -ldl -o main-plugin.so

サブ共有ライブラリは、純粋仮想関数のみを実装します。他の関数はオプションですが、オーバーライドできます。

サブ共有ライブラリ

plugin-impl.cpp

Class B : public A {
public:
  virtual int func1() { return 0; }
}

CREATE_CLASS(B)

これらは、サブ共有ライブラリを構築およびリンクするための行です。

sub.so をビルドしてリンクする

g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC -c -o subPlugin.o subPlugin.cpp
g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC  -shared subPlugin.o  -o subPlugin.so

これは、サブ共有ライブラリを開くための行です。LAZY、NOW、NOW | を試してみました。GLOBAL など、影響はありません。

メイン共有ライブラリのどこかで dlopen() を呼び出します。

  handle = dlopen(file.c_str(), RTLD_LAZY);

これのほとんどは非常にうまく機能しています。ただし、サブ共有ライブラリをメイン共有ライブラリにロードしようとすると、dlopen は の未定義シンボルについて不平を言いbool A::func2() constます。関数はメインの共有ライブラリにしか存在しないため、とにかくエクスポートする必要があると思います。私を助けてください!私は非常に混乱しています!

解決

実行可能ファイルを変更できないため、次のオプションを g++ に追加して、メイン共有ライブラリをサブ共有ライブラリとリンクする必要があります。

-L$(PLUGINDIR) -Wl,-R$(PLUGINDIR) -lmain-shared

このセットでは、 を設定する必要はありませんLD_LIBRARY_PATH

4

1 に答える 1

3

サブライブラリにはメインライブラリのシンボルが必要なので、サブライブラリとリンクしてほしいと思います。次のようにリンクしてみてください。

g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC  -shared 
    -lmain-plugin subPlugin.o  -o subPlugin.so

おそらくあなた-Lも遊ぶ必要があるでしょう。

これは私が試したものです:

jirka@debian:/tmp$ cat executable.cpp 
#include <dlfcn.h>
#include <stdio.h>
int main()
{
  dlopen("./main-library.so", RTLD_NOW);
  void* handle=dlopen("./sub-library.so", RTLD_LAZY);
  printf("%x %s", dlsym(handle, "CreateClass"), dlerror());
}
jirka@debian:/tmp$ cat main-library.cpp 
class A {
public:
  virtual int func1() = 0;
  virtual bool func2() const;
};

#define CREATE_CLASS(cls) extern "C" void *CreateClass(void) { return new cls; }

bool A::func2() const {   return true; }
jirka@debian:/tmp$ cat sub-library.cpp 
class A {
public:
  virtual int func1() = 0;
  virtual bool func2() const;
};

#define CREATE_CLASS(cls) extern "C" void *CreateClass(void) { return new cls; }

class B : public A {
public:
  virtual int func1() { return 0; }
};

CREATE_CLASS(B)

jirka@debian:/tmp$ g++ -g -Wall -Woverloaded-virtual -Wno-parentheses -O2 -fPIC  -rdynamic -shared main-library.cpp -ldl -o main-library.so
jirka@debian:/tmp$ g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC  -shared -l:main-library.so sub-library.cpp  -o sub-library.so
jirka@debian:/tmp$  g++ -ldl executable.cpp -o executable
jirka@debian:/tmp$ LD_LIBRARY_PATH=. ./executable 
b7713740 (null)

RTLD_GLOBAL別の可能性は、ロード時に追加することmain-libraryです:

jirka@debian:/tmp$ cat executable.cpp 
#include <dlfcn.h>
#include <stdio.h>
int main()
{
  dlopen("./main-library.so", RTLD_LAZY | RTLD_GLOBAL);
  void* handle=dlopen("./sub-library.so", RTLD_LAZY);
  printf("%x %s", dlsym(handle, "CreateClass"), dlerror());
}

そうすれば、何もリンクする必要はありませんmain-library.so

于 2012-10-06T19:14:10.147 に答える