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

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

Don’t be surprised if one executable has no RPATH value set.

Below screenshot provides an example of readelf output with RUNPATH and $ORIGIN:

“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 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.

OpenSource & Automation make me excited. Release engineering @MongoDB