Reputation: 63
I have the following problem:
I am trying to build software on an Ubuntu18 by using the default gnu compiler (gcc-7) and linker versions available.
Now we have the case, that an executable may link a shared library, which again links another shared libraries. Thus the executable has a secondary dependency. But secondary dependencies are only picked up from rpath and not from runpath. So even if the secondary dependency is placed in the runpath folder of the executable it will not be found.
The problem was identified when using googletest in combination with cmake. There the tests cannot be compiled, because of not found secondary dependencies. So setting LD_LIBRARY_PATH
might not be an option or at least complicates everything a lot.
Here is an example for what is going wrong with gcc-7 on an Ubuntu18 system (but works fine with gcc-5 on Ubuntu16):
secondary.hpp
#include <string>
class World{
public:
std::string world();
};
secondary.cpp
#include "secondary.hpp"
std::string World::world(){
return "world";
}
primary.hpp
#include <string>
class Hello{
public:
std::string helloWorld();
};
primary.cpp
#include "primary.hpp"
#include "secondary.hpp"
#include <sstream>
std::string Hello::helloWorld(){
std::stringstream strm;
World world;
strm << "hello ";
strm << world.world();
strm << "!";
return strm.str();
}
and compile the both libraries like this
mkdir build
cd build
gcc -shared -o libsecondary.so -fPIC ../secondary.cpp
gcc -shared -o libprimary.so -fPIC ../primary.cpp -lsecondary -L$(pwd)
If I now build an executable from the following files
main.cpp
#include "primary.hpp"
#include <iostream>
int main(int argc, char** argv){
Hello hello;
std::cout << hello.helloWorld() << std::endl;
}
by doing the following in a new build directory (parallel to the previous one)
cd ..
mkdir build_app
cd build_app
gcc -o app ../main.cpp -L../build -lstdc++ -lsecondary -lprimary -Wl,-rpath=$(pwd)/../build
If I now do ldd app
I see, that libsecondary.so
is not found
linux-vdso.so.1 (0x00007fff0cf8c000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9e86fe7000)
libprimary.so => <some_path>/libprimary.so (0x00007f9e86de5000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9e86bcd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9e867dc000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9e8643e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9e87573000)
libsecondary.so => not found
and the runpath of app is (by running readelf -d app
)
Dynamic section at offset 0x1d40 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libprimary.so]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath:[<some_path>/build]
The question is, why ld
is not taking libsecondary.so
from the runpath of app
? Both libprimary.so
and libsecondary.so
are placed in the same folder, but only libprimary.so
is found.
One solution to the problem is to compile with --disable-new-dtags
which will use rpath instead of runpath and is the default for gcc-5 on Ubuntu16. However, the usage of rpath seems to be deprecated from ld.
So what is a proper way to use runpath together with secondary dependencies?
Upvotes: 3
Views: 1757
Reputation: 31010
libprimary
is responsible for loading libsecondary
, not app
. That means that the DT_RUNPATH entry for app
does not apply.
Since you have control over all libraries, you could add a -Wl,-rpath=...
to the compile statements for libprimary
and libsecondary
as well.
Upvotes: 3