C ++:使用dlopen()加载共享库时未定义的符号

时间:2012-10-06 19:04:27

标签: c++ shared-libraries dlopen undefined-symbol

当我尝试使用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; }

plugin.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

1 个答案:

答案 0 :(得分: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)

另一种可能性是在加载main-library时添加RTLD_GLOBAL

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

相关联