I've been reading for a while about how the dynamic linker/loader works, RPATH vs RUNPATH, direct vs transitive dependencies, etc. My understanding so far is that if a binary has RPATH (not RUNPATH), then its RPATH is what the dynamic loader uses to find all dependencies, including transitive dependencies.
However it does not work in the following situation:
binary(RPATH) -> libB(RUNPATH) -> libA
Toy example:
g++ a.cpp -shared -fPIC -o liba.so
g++ b.cpp -shared -fPIC -o libb.so -L. -la -Wl,-rpath=/foo
g++ main.cpp -L. -lb -la -Wl,-rpath=\$ORIGIN -Wl,--disable-new-dtags
Under this setup, the RPATH of the binary is not enough to find libA transitively:
$ ldd a.out
linux-vdso.so.1 (0x00007ffd2dd81000)
libb.so => /tmp/test/./libb.so (0x00007ff0d8217000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff0d800f000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff0d8223000)
liba.so => not found
However if the RUNPATH from libB
is removed, then libA
can be found via the RPATH of the binary.
Is this expected? The docs only say:
Using the directories specified in the DT_RPATH dynamic section attribute of the binary if present and DT_RUNPATH attribute does not exist
DT_RUNPATH does not exist in the binary.
In my actual case libA
and libB
are third-party libs out of my control. Given that I need to have my binary and libraries in a non-standard location and I'd rather not patchelf
third-party libs, is LD_LIBRARY_PATH
really the only solution to have my binary find the libraries it needs?
To clarify, I'm running Ubuntu 20.04 with default GCC toolchain.
Thanks!