I have an issue when I try to use dlopen() to load a shared library into another shared library. I checked all tutorials on how to use dlopen() correctly. So here is the simplified code:
The main shared library contains a class with pure virtual functions which the sub-shared library (aka plug-in) must implement. Additionally, it has some other functions which are implemented with a default behavior. I created a macro which is added to every plug-in to have a symbol to load and create the class.
Main shared library
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; }
Build and link 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
The sub-shared library does only implement the pure-virtual functions. The other function can be overridden though it is optional.
Sub shared library
plugin-impl.cpp
Class B : public A {
public:
virtual int func1() { return 0; }
}
CREATE_CLASS(B)
These are the lines to build and link the sub-shared library.
Build and link 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
This is the line to open the sub-shared library. I tried LAZY, NOW, NOW | GLOBAL and so on, without any effects.
dlopen() call somewhere in the main-shared library:
handle = dlopen(file.c_str(), RTLD_LAZY);
Most of this is working very well. However, when I try to load the sub-shared library into the main shared library, dlopen complains about the undefined symbol of bool A::func2() const
. The function does only exists in the main shared library, so I guess it must be exported anyway. Please help me out! I am very confused!
Because I cannot change the executable, I have to link the main-shared library with the sub-shared librarys by adding the following options to g++:
-L$(PLUGINDIR) -Wl,-R$(PLUGINDIR) -lmain-shared
With this set, it is not required to set the LD_LIBRARY_PATH
.
Since your sub-library needs symbols from the main library, I think it you want it to be linked with it. Try linking it like this:
g++ -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC -shared
-lmain-plugin subPlugin.o -o subPlugin.so
Probably you'll need to play with -L
as well.
This is what I tried:
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)
Another possibility is adding RTLD_GLOBAL
when loading 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());
}
That way, you needn't link anything with main-library.so
.