C++ – When looking for symbols, the program does not search from the correct library

When looking for symbols, the program does not search from the correct library… here is a solution to the problem.

When looking for symbols, the program does not search from the correct library

I’m adding two classes and libraries to the system, parent.so and child.so derive from it.

The problem is that when the program loads child.so, it cannot find the virtual function definition of parent from parent.so.

What happened,

nm -D child.so would give something similar (I just changed the name).

U _ZN12PARENT15virtualFunctionEv


The program crashes

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

It gives an error LD_DEBUG = libs

symbol lookup error: undefined symbol: _ZN12PARENT15virtualFunctionEv (fatal)

What I can’t explain is that I tried using GDB LD_DEBUG=symbols, and when running dlopen, the logs show that it’s basically trying to find the system in all libraries except parent.so, where symbols are defined. But from libs log parent.so is already loaded and the code is running, and it is in the same path as 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 does a program or system manage libraries that look up symbol definitions?

I’m new to Linux, can anyone point me to some direction of work?

Thank you.

Edit

The command to generate parent.so file is

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

Similar to child.so. Is there any information missing from the link here? It looks like child only includes parent header files.

EDIT2

After testing again, call

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

Fixing the issue before crashing the line, I think means initially parent.so didn’t load. But the specific reason is not very clear to me.

Solution

You need to tell the linker that your library libchild.so use the features in libparent.so. Do this when you create a sublibrary:

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

Note that the order is important. Specify -lparent after all your target files. You may also need to pass additional options to the linker via -Wl. G++ options.

This may not be good enough. You may need to add a library containing libparent.so to LD_LIBRARY_PATH environment variables.

Some pitfalls: If you don’t name these library prefixes with lib, you’ll confuse the linker a lot of the time. If you do not compile the source files with –fPIC or -fpic, you will have no relocatable objects.

Appendix
Dependent inventory of other libraries is a big potential problem. Suppose you use version 1.5 of the parent package when compiling sublibrary source files. You managed to resolve all library dependencies. You have specified your libchild.so depends on libparent.so Your stuff works. Until version 2.0 of the parent package came out. Now your stuff breaks wherever it’s used, and you haven’t changed a single line of code.

The solution to this problem is to specify that the resulting shared library depends specifically on version 1.5 of libparent.so’ when building the sublibrary.

To do this, you need to pass the options from g++/gcc to the linker via -Wl. Options. Use -wl, <linker_option>, <linker_option>,... If these linker options require spaces, you need to backslash them in the g++ command. For example, –rpath=/path/to/lib,-soname=libparent.so.1.5

Please note: You need the option when building libparent.so with -soname=libparent.so.1.5. That’s why the system says 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. libparent.so about ? This needs to be present, but it should be a symbolic link to some numbered version of libparent.so (preferably the latest version).

Now suppose that a non-backwards compatible parent version 2.0 is compiled and built into a new libparent.so.2.0 of Shiny, and a symbolic link is libparent.so to this new version of Shiny. Applications that use clunky old libchild.so (version 1.0) will happily use the clunky old version libparent.so instead of the new Shiny version that breaks everything.

Related Problems and Solutions