Question

Consider we have the following situation:

  • a program named program which depends dynamically on libfoo.so
  • libfoo.so that depends on nothing (well, it depends on libstdc++ and stuff but I guess we can omit that)

program runs perfectly.

Suddenly, libfoo codes changes, and some function now uses internally func_bar() a function that is provided by another library libbar.so.

libfoo.so is recompiled and now depends on libbar.so. program remains unchanged, it still depends only on libfoo.so.

Now when I execute program it complains that he can't find func_bar().

Here are my questions:

  • libfoo.so interface didn't change, only its implementation. Why does program have to explicitely link with libbar.so ?
  • Isn't the dependency tree recursive ? I would have think that since libfoo.so depends on libbar.so, libbar.so would have been automatically added to the dependency list of program, without recompilation. However, ldd program shows that it is not the case.

It seems weird that one has to recompile (relink) every binary that depends on some library everytime that library's dependencies change. What solutions do I have here to prevent this ?

Was it helpful?

Solution

The problem arises when you have not linked libfoo.so against libbar. When you are compiling an executable, by default the linker will not let you leave undefined references. However, when you're compiling a shared library, it will - and it will expect them to be satisfied at link time. This is so that libfoo can use functions exported by program itself - when you try to run it, the dynamic linker is expecting func_bar() to be supplied by program. The problem is illustrated like so:

(foo.c is selfcontained)

export LD_RUN_PATH=`pwd`
gcc -Wall -shared foo.c -o libfoo.so
gcc -Wall -L. p.c -lfoo -o p

At this point, ./p runs correctly, as you would expect. We then create libbar.so and modify foo.c to use it:

gcc -Wall -shared bar.c -o libbar.so
gcc -Wall -shared foo.c -o libfoo.so

At this point, ./p gives the error you describe. If we check ldd libfoo.so, we notice that it does not have a dependency on libbar.so - this is the error. To correct the error, we must link libfoo.so correctly:

gcc -Wall -L. -lbar -shared foo.c -o libfoo.so

At this point, ./p again runs correctly, and ldd libfoo.so shows a dependency on libbar.so.

OTHER TIPS

On Fedora dynamic linking is performed by ld-linux.so.2. The dynamic linker use /etc/ld.so.cache and /etc/ld.so.preload to find library files.

Run ldconfig to tell the system where libfoo should look for libbar.

ldconfig looks in /lib, /usr/lib and any directory listed in /etc/ld.so.conf. You can check which libraries a program uses with ldd.

More details are available on the manual pages for each command.

Here is an example of an application using shared libraries.
Program.cc

#include "foo.h"
#include <iostream>

int main(int argc, char *argv[])
{
    for (int i = 0; i < argc; ++i) {
        std::cout << func_foo(argv[i]) << std::endl;
    }
}

foo.h

#ifndef FOO_H
#define FOO_H
#include <string>
std::string func_foo(std::string const &);
#endif

foo.cc

#include "foo.h"

std::string func_foo(std::string const &arg)
{
    return arg + "|" + __func__;
}

bar.h

#ifndef BAR_H
#define BAR_H
#include <string>
std::string func_bar();
#endif

bar.cc

#include "bar.h"

std::string func_bar()
{
    return __func__;
}

Build with libfoo.so as a shared library.
g++ -Wall -Wextra -fPIC -shared foo.cc -o libfoo.so
g++ -lfoo -L./ -Wall -Wextra program.cc foo.h -o program
ldd program
...
libfoo.so => not found

Update /etc/ld.so.cache
sudo ldconfig /home/tobias/projects/stubs/so/

ldd shows that the dynamic linker finds libfoo.so
ldd program
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f0bb9f15000)

Add a call to libbar.so in libfoo.so
New foo.cc

#include "foo.h"
#include "bar.h"

std::string func_foo(std::string const &arg)
{
    return arg + "|" + __func__ + "|" + func_bar();
}

Build libbar.so and rebuild libfoo.so
g++ -Wall -Wextra -fPIC -shared bar.cc -o libbar.so
g++ -Wall -Wextra -fPIC -shared libbar.so foo.cc -o libfoo.so
ldd libfoo.so
...
libbar.so => not found

ldd program
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f49236c7000)
libbar.so => not found
This shows that the dynamic linker still finds libfoo.so but not libbar.so
Again update /etc/ld.so.cache and recheck.
sudo ldconfig /home/tobias/projects/stubs/so/
ldd libfoo.so
...
libbar.so => /home/tobias/projects/stubs/so/libbar.so (0x00007f935e0bd000)

ldd program
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f2be4f11000)
libbar.so => /home/tobias/projects/stubs/so/libbar.so (0x00007f2be4d0e000)

Both libfoo.so and libbar.so are found.

Note this last step have no effect on the application program. If you are really strict running ldconfig is kind of relinking. Weird or not the linker need to know the dependencies of the libraries it links. There are a lot of other ways to implement this but this was chosen.

You did not give any system information, are you using glibc? If yes what is the output of this command:

LD_DEBUG=files program

Also check "How to write shared (ELF) libraries"(pdf) (whether you are using glibc or not)

Your program doesn't have to link with libbar.so.

I think that the problem is caused by failing to specify libbar.so as a dependency of libfoo.so when building the later. I am not sure what build system are you using but in CMake it can be done as follows:

add_library(bar SHARED bar.c)

add_library(foo SHARED foo.c)
target_link_libraries(foo bar)

add_executable(program program.c)
target_link_libraries(program foo)

As you can see program is linked only with foo (libfoo.so) and foo only with bar (libbar.so).

Or it may be that libbar.so can't be found. Try to specify the path to its directory in LD_LIBRARY_PATH environment variable.

This should not be the case unless something about the bar_func symbol changed. Use the "nm" command to get a dump of the symbols in both your program, and the shared object - see if there is a mismatch and why.

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