Toy project to show how rpath, $ORIGIN and LD_DEBUG work.
Usage:
mkdir bin
mkdir -p lib/sublib
g++ -shared -fPIC src/func2.cpp -o lib/sublib/libfunc2.so
g++ -shared -fPIC src/func1.cpp -o lib/libfunc1.so -Llib/sublib/ -lfunc2 -Wl,-rpath,'$ORIGIN/sublib'
g++ src/main.cpp -o ./bin/a.out -L./lib/ -lfunc1 -Wl,-rpath,'$ORIGIN/../lib'
Note that libfunc1 sees func2 relative to itself, and that main only needs to know about func1.
a.out now works from anywhere, without needing LD_LIBRARY_PATH:
./bin/a.out
Several ways to check what happened:
readelf -d ./bin/a.out |head -n 10
readelf -d ./lib64/libfunc1.so |head -n 10
On multi-arch, it is sometimes desirable to use lib, lib64 or lib/x86_64-linux-gnu.
rpath uses $LIB for that purpose:
libdir=lib64 # or lib/x86_64-linux-gnu
mkdir bin
mkdir -p $libdir/sublib
g++ -shared -fPIC src/func2.cpp -o $libdir/sublib/libfunc2.so
g++ -shared -fPIC src/func1.cpp -o $libdir/libfunc1.so -L$libdir/sublib/ -lfunc2 -Wl,-rpath,'$ORIGIN/sublib'
g++ src/main.cpp -o ./bin/a.out -L./$libdir/ -lfunc1 -Wl,-rpath,'$ORIGIN/../$LIB'
$LIB is specific to every distro:
- on RHEL-8 is is
lib64, - on Ubuntu-20 it is
lib/x86_64-linux-gnu.
In case of doubt, double check with:
LD_DEBUG=libs ./bin/a.out
LD_DEBUG=help ./bin/a.out shows other interesting options.
To play with R[UN]PATH, without recompiling:
patchelf --set-rpath '$ORIGIN/sublib' my_lib.so
You may like realpath -s --relative-to=path/to/my/program path/to/my/library in the previous command.