Question

I'm adding two classes and libraries to a system, parent.so and child.so deriving from it.

The problem is when the program is loading child.so it cannot find parent's virtual function's definition from parent.so.

What happens,

nm -D child.so will gives something like (I just changed the names)

U _ZN12PARENT15virtualFunctionEv


The program will crash running

_handle = dlopen(filename, RTLD_NOW|RTLD_GLOBAL); //filename is child.so

it'll give an error with LD_DEBUG = libs

symbol lookup error: undefined symbol: _ZN12PARENT15virtualFunctionEv (fatal)

The thing I cannot explain is, I tried LD_DEBUG = symbols using GDB, when running dlopen, the log shows it tried to look up basically in all libaries in the system except parent.so, where the symbol is defined. But from libs log parent.so is already loaded and code is run, and it is at the same path of all other libraries.

 ......
 27510:     symbol=_ZN12PARENT15virtualFunctionEv;  lookup in file=/lib/tls/libm.so.6
 27510:     symbol=_ZN12PARENT15virtualFunctionEv;  lookup in file=/lib/tls/libc.so.6
 27510:     symbol=_ZN12PARENT15virtualFunctionEv;  lookup in file=/lib/ld-linux.so.2
 27510:     child.so: error: symbol lookup error: undefined symbol: _ZN12PARENT15virtualFunctionEv(fatal)

How the program or system is managing which library to look for a symbol's definition?

I'm new to Linux, can anybody point me some directions to work on?

Thanks.

EDIT

The command used to generate parent.so file is

c++  -shared  -o parent.so parent.o

Similar for child.so. Is any information missing for linking here? Looks like child is only including parent's header file.

EDIT2

After another test, calling

_handle = dlopen("parent.so", RTLD_NOW|RTLD_GLOBAL);

before the crashing line will solve the problem, which I think means originally parent.so was not loaded. But I'm still not very clear about the cause.

Was it helpful?

Solution

You need to tell the linker that your library libchild.so uses functionality in libparent.so. You do this when you are creating the child library:

g++ -shared -o libchild.so child_file1.o child_file2.o -Lparent_directory -lparent

Note that order is important. Specify the -lparent after all of your object files. You might also need to pass additional options to the linker via the -Wl option to g++.

That still might not be good enough. You might need to add the library that contains libparent.so to the LD_LIBRARY_PATH environment variable.

A couple of gotchas: If you aren't naming those libraries with a lib prefix you will confuse the linker big time. If you aren't compiling your source files with either -fPIC or -fpic you will not have relocatable objects.

Addendum
There's a big potential problem with libraries that depend on other libraries. Suppose you use version 1.5 of the parent package when your compile your child library source files. You manage to get past all of the library dependencies problems. You've specified that your libchild.so depends on libparent.so. Your stuff just works. That is until version 2.0 of the parent package comes out. Now your stuff breaks everywhere it's used, and you haven't changed one line of code.

The way to overcome this problem is to specify at the time you build your child library that the resultant shared library depends specifically on version 1.5 of libparent.so`.

To do this you will need to pass options from g++/gcc to the linker via the -Wl option. Use -Wl,<linker_option>,<linker_option>,... If those linker options need spaces you'll need to backslash-escape them in the command to g++. A couple of key options are -rpath and -soname. For example, -rpath=/path/to/lib,-soname=libparent.so.1.5.

Note very well: You need to use the -soname=libparent.so.1.5 option when you are building libparent.so. This is what lets the system denote that your libchild.so (version 1.0) depends on libparent.so (version 1.5). And you don't build libparent.so. You build libparent.so.1.5. What about libparent.so? That needs to exist to, but it should be a symbolic link to some numbered numbered version (preferably the most recent version) of libparent.so.

Now suppose non-backward compatible parent version 2.0 is compiled and built into a shiny new libparent.so.2.0 and libparent.so is symbolically linked to this shiny new version. An application that uses your clunky old libchild.so (version 1.0) will happily use the clunky old version of libparent.so instead of the shiny new one that breaks everything.

OTHER TIPS

It looks like you're not telling the linker that child.so needs parent.so, use something like the following:

g++ -shared -o libparent.so parent.o
g++ -shared -o libchild.so -lparent child.o

When you build your main program, you have to tell the compiler that it links with those libraries; that way, when it starts, linux will load them for it.

Change their names to libparent.so and libchild.so.

Then compile with something like this:

g++ <your files and flags> -L<folder where the .so's are> -lparent -lchild

EDIT:

Maybe it would be a smaller change to try loading parent.so before child.so. Did you try that already?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top