LD_LIBRARY_PATH Is Not The Answer


When an executable is run that relies on shared libraries not defined in the global search path, an error similar to the following is displayed:

$ curl

ld.so.1: curl: fatal: libgcc_s.so.1: open failed: No such file or directory
Killed

Typically this problem is fixed by running ldd(1) on the executable, locating the missing shared libraries, and adding one or more directories to the LD_LIBRARY_PATH environment variable:

$ ldd curl

        libcurl.so.3 =>  /tmp/curl1/lib/libcurl.so.3
        libdl.so.1 =>    /usr/lib/libdl.so.1
        libsocket.so.1 =>        /usr/lib/libsocket.so.1
        libnsl.so.1 =>   /usr/lib/libnsl.so.1
        libz.so.1 =>     /usr/lib/libz.so.1
        libc.so.1 =>     /usr/lib/libc.so.1
        <b>libgcc_s.so.1 =>         (file not found)</b>
        libmp.so.2 =>    /usr/lib/libmp.so.2
        /usr/platform/SUNW,Ultra-5_10/lib/libc_psr.so.1

$ export LD_LIBRARY_PATH=/usr/local/lib

$ curl

curl: try 'curl --help' or 'curl --manual' for more information

Using LD_LIBRARY_PATH for this purpose is a complete hack, and according to the linker gurus, this variable should be avoided. This is easy to do, since the vast majority of executable formats allow a runtime search path to be added to the executable. For Solaris ELF executables, the native linker’s “-R” (record path) option can be used to record a runtime search path:

$ export LDFLAGS="-R/usr/local/lib"

$ ./configure --prefix=/tmp/curl2

$ make

$ make install

To view the runtime search path in a Solaris ELF executable, the dump utility can be run with the “-L” (dump dynamic linking information) and “-v” (print verbose information) options, and an executable to query:

$ dump -Lv curl | egrep '(RPATH|RUNPATH)'

[9]     RUNPATH         /usr/local/lib
[10]    RPATH           /usr/local/lib

$ curl

curl: try 'curl --help' or 'curl --manual' for more information

If a binary is already built, the setrpath utility can often be used to update the search path in an ELF executable:

$ curl

ld.so.1: curl: fatal: libgcc_s.so.1: open failed: No such file or directory
Killed

$ gcc -o setrpath setrpath.c -lelf

$ setrpath curl "/usr/local/lib"

Old RPATH: /tmp/curl1/lib:/tmp/curl:/tmp:/curl:/tmp/curl:/tmp/curl
New RPATH set to: /usr/local/lib

$ setrpath libcurl.so.3.0.0 "/usr/local/lib"

Old RPATH: /tmp/curl:/tmp:/curl:/tmp/curl:/tmp/curl
New RPATH set to: /usr/local/lib

$ curl

curl: try 'curl --help' or 'curl --manual' for more information

To use setrpath, you need to ensure that enough space exists to accomodate the new seach path. For binaries that need to move within a file system, the Solaris $ORIGIN variable should be used instead of absolute paths. If you haven’t already, I highly recommend sitting down with the Solaris linkers and libraries guide. This document contains an awesome introduction to the Solaris linker, and provides a detailed overview of the dynamic linking process.

References

The following references were used while writing this article: