3

当我尝试使用 dlopen() 将共享库加载到另一个共享库时遇到问题。我检查了所有关于如何正确使用 dlopen() 的教程。所以这里是简化的代码:

主共享库包含一个具有纯虚函数的类,子共享库(又名插件)必须实现该类。此外,它还有一些其他功能,这些功能是通过默认行为实现的。我创建了一个宏,它被添加到每个插件中,以便有一个符号来加载和创建类。

主共享库

插件.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

子共享库只实现纯虚拟功能。另一个函数可以被覆盖,尽管它是可选的。

子共享库

插件-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,现在,现在 | 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 回答