I'm dynamically loading (whith dlopen()
) a shared object (named libprofile1.so
) from main
.
In libprofile1.so
I have defined factory function CreateProfile
and class Profile
. CreateProfile
function creates an instance of Profile
class and returns a pointer to it. Class Profile
has a method pMethod
.
In main, after loading libprofile1.so
, I'm calling CreateProfile
method which returns the pointer to the object of Profile
class (call it p
).
Afterwards, I'm calling pMethod
method against object p
(p->pMethod
). In this method I'm dynamically loading other shared object (libdatasources.so
).
In this shared object I have a factory function CreateDataSource
and class DataSource
.CreateDataSource
function creates an instance of DataSource
class and returns a pointer to it. DataSource
class has method dsMethod
.
As you can notice, structures of both shared objects are similar.
From pMethod
after loading libdatasources.so
I'm calling CreateDataSource
method, which returns me a pointer to an instance of DataSource
class, call it ds
.
Then I'm calling dsMethod
of ds
object
(ds->dsMethod
).
Now, the problem is following.
When I try to call dsMethod
of ds
object, shared object that I'm first loading (libprofile1.so
) doesn't load. Actually dlopen()
returns NULL
. When I read dlerror
after dlopen
I get:
./libprofile1.so: undefined symbol: _ZN18DataSource13dsMethod
So if I have a call ds->Method
, than first shared object doesn't load!
If I comment out call ds->dsMethod
from the source, then my libprofile1.so
and libdatasources.so
are loaded without any problems.
I don't see the connection between the call of a method from the second SO, with loading first SO???
Maybe I don't know, but are there any constraints when dynamically loading a shared object, from a shared object that's also been dynamically loaded?
Btw, dlopen
is used with RTLD_NOW|RTLD_GLOBAL
. I tried with RTLD_LAZY
, but still the same problem.
UPDATE:
Libraries are built in Eclipse. Options for G++ compiler and linker are the same for both libraries.
Here are G++ compiler:
-O0 -g3 -Wall -c -fmessage-length=0
and G++ linker:
-shared
options, pasted from Project Properties -> Settings -> Tool Settings
Thanks in advance.
As Martin York pointed out, that's the way it works in Linux. When linking against a library, you have to link to all dependencies, too. That's different in Windows, DLLs take care of their dependencies themselves. When dynamically loading a library that has another library as a dependency, you need to load that library first with the RTLD_GLOBAL flag. This is pretty awkard, imho, since you may not be able to know which dependencies another shared objects requires, or the dependencies can change with a newer version that's otherwise binary compatible. From what I know (and from reading the g++ and ld manpages), it is not possible to create a behaviour similar to Windows' DLLs. Here's a little testcase:
two.cpp:
#include <iostream>
extern "C"
{
void bar()
{
std::cout << "bar()\n";
}
}
one.cpp:
#include <iostream>
extern "C"
{
void bar();
void foo()
{
std::cout << "foo()\n";
bar ();
}
}
test.cpp:
#include <dlfcn.h>
#include <iostream>
int main (int argc, char *argv[])
{
using namespace std;
// void *libtwo = dlopen("./libtwo.so", RTLD_NOW | RTLD_GLOBAL);
void *libone = dlopen("./libone.so", RTLD_NOW);
if (!libone)
{
cout << "dlopen(libone.so) failed: " << dlerror() << "\n";
return 1;
}
typedef void (*foo_t)();
foo_t foo = reinterpret_cast<foo_t>(dlsym(libone, "foo"));
if (!foo)
{
cout << "dlsym(libone.so, foo) failed\n";
return 2;
}
}
one.cpp is compiled into libone.so
and two.cpp in libtwo.so
, test.cpp is compiled into the test
binary.
This will fail and only succeed when the commented line is uncommented.
If you dynamically load a DLL you must make sure that it has no unresolved symbols.
The easiest way to do this is to link it against the other DLLs that it needs so that they load automatically rather than you having to load and resolve all dependencies manually.
So if libprofile1
always uses libdatasources
make sure they are linked with each other.
If you must do it manually then reverse the order that you load the libraries. So that when you load libprofile1
the functions that it needs have already been loaded.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With