When troubleshooting shared library dependencies with ldd
, understanding its search path mechanism is crucial. The tool follows the same search rules as the dynamic linker (ld.so), which is configured through several mechanisms:
1. DT_RPATH in the ELF binary (deprecated but still used)
2. DT_RUNPATH in the ELF binary
3. LD_LIBRARY_PATH environment variable
4. /etc/ld.so.cache (built from /etc/ld.so.conf)
5. Default paths: /lib and /usr/lib (plus architecture-specific variants)
To view the effective search paths, use these commands:
# Display the linker's default configuration
ldconfig -v 2>/dev/null | grep -v ^$'\t'
# Alternative method showing registered directories
cat /etc/ld.so.conf.d/*.conf
# For runtime inspection of a specific binary:
readelf -d /path/to/binary | grep -E 'RPATH|RUNPATH'
When you encounter output like:
libstdc++.so.5 => not found
Here's how to resolve it:
# Locate the library manually
find / -name libstdc++.so.5 2>/dev/null
# Once found, add its directory to the search path temporarily
export LD_LIBRARY_PATH=/path/to/library:$LD_LIBRARY_PATH
# Or permanently by creating a new config file
echo "/path/to/library" | sudo tee /etc/ld.so.conf.d/custom.conf
sudo ldconfig
For developers building packages, you can embed search paths directly in the binary:
# During compilation with GCC:
gcc -Wl,-rpath=/custom/library/path -o output input.c
# To verify the embedded path:
readelf -d output | grep RPATH
When dealing with multi-arch systems (x86_64 vs. i386):
# For 32-bit libraries on 64-bit systems:
dpkg -L libc6-i386 | grep .so
# Or on RPM systems:
rpm -ql glibc.i686 | grep .so
# Cross-arch linking example:
gcc -m32 -Wl,-rpath=/usr/lib32 -o output32 input.c
Remember that system-wide changes should be made through /etc/ld.so.conf
or its included files rather than modifying LD_LIBRARY_PATH
globally.
When examining shared library dependencies with ldd
, it's crucial to understand how the dynamic linker locates libraries. The search paths shown in your example (/lib64
, etc.) are determined by several configuration mechanisms:
$ ldd /path/to/your/binary
linux-vdso.so.1 => (0x00007ffd45bf9000)
libexample.so.1 => /usr/local/lib/libexample.so.1
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
The search path is primarily controlled by:
/etc/ld.so.conf
- Main configuration file- Files in
/etc/ld.so.conf.d/
- Additional configuration snippets - Environment variables (
LD_LIBRARY_PATH
, etc.)
To inspect the current library search paths:
$ ldconfig -v 2>/dev/null | grep -v ^$'\t'
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
/usr/local/lib
Alternatively, check the config files directly:
$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
$ ls /etc/ld.so.conf.d/
fakeroot-x86_64-linux-gnu.conf libc.conf x86_64-linux-gnu.conf
To add a new library path (e.g., /opt/myapp/lib
):
# Create new config file
echo '/opt/myapp/lib' | sudo tee /etc/ld.so.conf.d/myapp.conf
# Update cache
sudo ldconfig
For temporary changes (current session only):
export LD_LIBRARY_PATH=/custom/path:$LD_LIBRARY_PATH
ldd /path/to/binary
For detailed debugging of library resolution:
$ LD_DEBUG=libs ldd /path/to/binary
31533: find library=libexample.so.1 [0]; searching
31533: search path=/opt/myapp/lib/tls/x86_64:/opt/myapp/lib/tls:/opt/myapp/lib/x86_64
31533: trying file=/opt/myapp/lib/tls/x86_64/libexample.so.1
31533: trying file=/opt/myapp/lib/tls/libexample.so.1
31533: trying file=/opt/myapp/lib/x86_64/libexample.so.1
Remember that ldd
itself uses the dynamic linker (ld.so
) to resolve dependencies, following the same path resolution rules as executed programs.