当我尝试使用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
。
答案 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
。