tez
tez

Reputation: 5300

undefined symbols when linking one .so with other

a.so defines function A(), b.so defines function B() and calls A() that is defined in a.so. b.so is linked to a.so as below

gcc -fPIC -shared B.c -o libb.so -la

Now I created a binary which is calling B() that is defined in b.so

gcc mybin.c -o mybin -lb

gcc is checking for every symbol in b.so and throws error saying A() is not defined.

gcc mybin.c -o mybin -lb -la

The above works but I had to link mybin with a.so even though it is not directly related to a.so. My requirement is that if b.so is properly linked with a.so, linking mybin with just b.so should work.

Is this possible ??

Upvotes: 2

Views: 2065

Answers (3)

Jonathan Wakely
Jonathan Wakely

Reputation: 171453

When linking the executable the linker wants to know that the libraries needed by libb.so exist so it can check they resolve any undefined references in libb.so

The linker looks for the required libraries in the usual places, so if that wouldn't find liba.so then you can tell the linker where to look by using LD_LIBRARY_PATH as shown by another answer, or by using the linker option that exists specifically for this purpose, -rpath-link

gcc mybin.c -o mybin -lb -Wl,-rpath-link=.

(The -Wl, prefix is how you tell GCC to pass an option to the linker, which is needed for linker options that GCC doesn't know about directly.)

Alternatively, you can tell the linker to allow undefined symbols in libb.so in which case it doesn't try to find liba.so to resolve the reference to A(), and trusts that you'll link correctly and ensure the library is available at run-time. That is done with the --allow-shlib-undefined option:

gcc mybin.c -o mybin -lb -Wl,--allow-shlib-undefined

However, it's generally better to let the linker check that all symbols are defined, and tell it how to find the required libraries, as it finds real problems sooner.

The -rpath-link option only tells the linker where to look for additional shared libraries, it has no visible effect on the linked executable (i.e. it doesn't record the path to the library in the executable anywhere). Another alternative is to create libb.so so that it contains the knowledge of how to find liba.so embedded within it. That is done with the -rpath linker option, e.g. if liba.so is in /some/path you could do:

gcc -fPIC -shared B.c -o libb.so -la -Wl,-rpath=/some/path

This puts a DT_RPATH tag in libb.so and the linker will use that to find its dependencies:

readelf -d libb.so  | fgrep RPATH
 0x000000000000000f (RPATH)              Library rpath: [/some/path]

Now you can link the executable without needing any knowledge of liba.so, the linker will see that libb.so needs liba.so and will use the RPATH to find it:

gcc mybin.c -o mybin -lb

This works fine if the path /some/path/liba.so is fixed, but it might not be true that the library is found in the same location during development and after your executable is deployed. In that case you can still use -rpath-link for the executable to tell the linker where to look for it during linking, and rely on the RPATH to find it at run-time. Or you can use the special string $ORIGIN in the RPATH which the dynamic linker expands to the location of the object containing the RPATH, e.g. if liba.so and libb.so are always in the same directory, you can link libb.so like this (note the quotes to prevent the shell expanding $ORIGIN):

gcc -fPIC -shared B.c -o libb.so -la '-Wl,-rpath=$ORIGIN'

readelf -d libb.so  | fgrep RPATH
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN]

Upvotes: 3

ysdx
ysdx

Reputation: 9335

The missing bit was the LD_LIBRARY_PATH:

export LD_LIBRARY_PATH=.
gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so -la
gcc mybin.c -o mybin -lb -L.

The reason -L does not work seems it that this flag it used to « Add directory dir to the list of directories to be searched for -l » , see the GCC doc. And libba.so is not specified in a -l.

Upvotes: 2

Romaan
Romaan

Reputation: 2757

Here are the steps:

gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so
gcc mybin.c -o mybin -lb -la -L.    # -L to look for the directory to load .so files

Then make sure you do:
export LD_LIBRARY_PATH=<your_directory>

You need to have liba.so and libb.so mentioned in gcc mybin.c -o mybin -lb -la -L. as the function A() needs to be loaded at runtime. b.so IS NOT LINKED with a.so. Linking happens that runtime in shared library. They are compiled and any reference to functions or extern variables are not resolved.

If you want to include b.so but not a.so then compile the b as static library thereby it loads a into its binary. And then when you compile mybin you will only need b.lib

Upvotes: 0

Related Questions