Creating relocatable Linux executables by setting RPATH with $ORIGIN
Lots of modern C/C++ projects leverage Autotools to create GNU building system e.g. generate make files based on the platform. Executable files (binaries) are generated during the make/compile process, and can be executed locally on the machine where the compilation is performed. However, if the same executable were moved onto a different machine, or simply a different folder on the same machine, the “library not found” error might be encountered while running the executable.
What is RPATH and $ORIGIN
RPATH stands for run-time search path. According to Wikipedia, “rpath designates the run-time search path hard-coded in an executable file or library. Dynamic linking loaders use the rpath to find required libraries.” Dynamic linking is a sort of “lazy” linking of required shared libraries not during the stage of compiling but the later stage of running one executable. A path to the shared libraries will be encoded into the header of the executable if rpath is set, overriding or supplementing the system default shared library searching paths, similar as one extends the chain of PATH system variable.
$ORIGIN is a special variable that indicate actual executable filename. It is resolved to where the executable is at run-time, and can be quite useful when setting RPATH.
How to check the value of RPATH/RUNPATH
There are various ways of checking the RPATH value for an executable or library. objdump, readelf and chrpath are 3 of the frequently used utilities.
$ objdump -x path/to/executable | grep RPATH
or
$ readelf -d path/to/executable | head -20
or
$ chrpath -l path/to/executable
RUNPATH, introduced after RPATH to make it easier to testing libraries (without needing to rebuild them every time), is gaining wider adoptions these days and making the latter obsolete. There’s another post covering more details on this topic. So don’t be surprised if an executable has RUNPATH instead of RPATH set.
Below screenshot provides an example of readelf output with RUNPATH and $ORIGIN:
Why and How to set RPATH
The aim of RPATH setting is to change the library search path so that one executable or library is able to link the desired dependent libraries during run-time.
There are 2 different stages RPATH could be set:
During compilation time
$ ./configure LDFLAGS=-Wl,-rpath=$ORIGIN/path/to/library
will tell the linker to build and run the executable under the specified library path, usually used to override the default library paths.
After compilation before execution
$ chrpath -r “\$\ORIGIN/path/to/library” <executable>
Above command could fail if no rpath was set previously for the executable.
Try below command with patchelf utility, which won’t complain about an unset rpath, and will get RUNPATH set to achieve similar target.
$ patchelf — set-rpath ‘$ORIGIN/path/to/library’ <executable>
Conclusion
After setting RPATH/RUNPATH to the directory where dependent libraries locate, with the help of $ORIGIN, an Linux executable could be run successfully either in place, or be moved around to different directories or even hosts, achieving the desired properties of relocatability and flexibility.