Where shared object is located in Linux
I want to know, where .so file information got stored in linux? I am looking for libruby.so.2.6 . When I searched in internet, ld.so first starts the search with LD_LIBRARY_PATH and then it will look for ld.so.conf file and cache files and then the default paths like /lib and /usr/local/lib . In my case ruby got installed in /opt/puppetlabs/puppet/root/bin location and when I executed ldd /opt/puppetlabs/puppet/root/bin , got the location of the libruby.so as /opt/puppetlabs/puppet/lib/libruby.so.2.6 . Now I am able to get the location of the shared object, but I would like to know from where it got the details? I have checked the ld_library_path and ld.so.conf file, I could find that entry. Could someone please help me to get this detail?
1 Answer 1
The man page for ldd says:
In the usual case, ldd invokes the standard dynamic linker (see ld.so(8)) with the LD_TRACE_LOADED_OBJECTS environment variable set to 1. This causes the dynamic linker to inspect the program's dynamic dependencies, and find (according to the rules described in ld.so(8)) and load the objects that satisfy those dependencies.
The man page for ld gives the explanation of the rules:
When resolving shared object dependencies, the dynamic linker first inspects each dependency string to see if it contains a slash (this can occur if a shared object pathname containing slashes was specified at link time). If a slash is found, then the dependency string is interpreted as a (relative or absolute) pathname, and the shared object is loaded using that pathname. If a shared object dependency does not contain a slash, then it is searched for in the following order: o Using the directories specified in the DT_RPATH dynamic section attribute of the binary if present and DT_RUNPATH attribute does not exist. Use of DT_RPATH is deprecated. o Using the environment variable LD_LIBRARY_PATH, unless the executable is being run in secure-execution mode (see below), in which case this variable is ignored. o Using the directories specified in the DT_RUNPATH dynamic section attribute of the binary if present. Such directories are searched only to find those objects required by DT_NEEDED (direct dependencies) entries and do not apply to those objects' children, which must themselves have their own DT_RUNPATH entries. This is unlike DT_RPATH, which is applied to searches for all children in the dependency tree. o From the cache file /etc/ld.so.cache, which contains a compiled list of candidate shared objects previously found in the augmented library path. If, however, the binary was linked with the -z nodeflib linker option, shared objects in the default paths are skipped. Shared objects installed in hardware capability directories (see below) are preferred to other shared objects. o In the default path /lib, and then /usr/lib. (On some 64-bit architectures, the default paths for 64-bit shared objects are /lib64, and then /usr/lib64.) If the binary was linked with the -z nodeflib linker option, this step is skipped.
.so search paths
I am a Linux novice (coming from a Windows background). I’d like to understand the details of how shared objects (.so files) are loaded at runtime. According to http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html the file /etc/ld.so.conf configures the directories to search for .so files at runtime. However an experiment shown below seems to indicate that isn’t the case. /usr/local/lib is in one of the .conf files in /etc/ld.so.conf.d, but when my .so is in /usr/local/lib it is not found at run-time. Conversely /usr/lib is not configured by /etc/ld.so.conf, but when my .so is in /usr/lib it is found at runtime. What am I missing? Thanks, Dave
davids@ds-ub64-7:/$ # Display the .so search path configured in /etc/ld.so.conf davids@ds-ub64-7:/$ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf davids@ds-ub64-7:/$ cat /etc/ld.so.conf.d/*.conf /usr/lib/mesa /usr/lib32/mesa /usr/lib32/alsa-lib /usr/lib/alsa-lib # libc default configuration /usr/local/lib # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu davids@ds-ub64-7:/$ # libsotest.so.1 is in /usr/local/lib davids@ds-ub64-7:/$ ls -la /usr/local/lib/libsotest* lrwxrwxrwx 1 root root 14 2012-07-19 08:24 /usr/local/lib/libsotest.so -> libsotest.so.1 lrwxrwxrwx 1 root root 18 2012-07-19 08:24 /usr/local/lib/libsotest.so.1 -> libsotest.so.1.0.1 -rwxr-xr-x 1 davids davids 7952 2012-07-19 08:13 /usr/local/lib/libsotest.so.1.0.1 davids@ds-ub64-7:/$ # But when I run an executable that refrs to libsotest.so.1, the loader doesn't find it. davids@ds-ub64-7:/$ /projects/sotest/exe/sotestexe /projects/sotest/exe/sotestexe: error while loading shared libraries: libsotest.so.1: cannot open shared object file: No such file or directory davids@ds-ub64-7:/$ # Configure loader to display the paths it's searching. it's searching /usr/lib but not /usr/local/lib davids@ds-ub64-7:/$ export LD_DEBUG=lib davids@ds-ub64-7:/$ /projects/sotest/exe/sotestexe warning: debug option `lib' unknown; try LD_DEBUG=help /projects/sotest/exe/sotestexe: error while loading shared libraries: libsotest.so.1: cannot open shared object file: No such file or directory davids@ds-ub64-7:/$ export LD_DEBUG=libs davids@ds-ub64-7:/$ /projects/sotest/exe/sotestexe 6691: find library=libsotest.so.1 [0]; searching 6691: search cache=/etc/ld.so.cache 6691: search path=/lib/tls/x86_64:/lib/tls:/lib/x86_64:/lib:/usr/lib/tls/x86_64:/usr/lib/tls:/usr/lib/x86_64:/usr/ lib:/lib/x86_64-linux-gnu/tls/x86_64:/lib/x86_64-linux-gnu/tls:/lib/x86_64-linux- gnu/x86_64:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/tls/x86_64:/usr/lib/x86_64-linux- gnu/tls:/usr/lib/x86_64-linux-gnu/x86_64:/usr/lib/x86_64-linux-gnu (system search path) 6691: trying file=/lib/tls/x86_64/libsotest.so.1 6691: trying file=/lib/tls/libsotest.so.1 6691: trying file=/lib/x86_64/libsotest.so.1 6691: trying file=/lib/libsotest.so.1 6691: trying file=/usr/lib/tls/x86_64/libsotest.so.1 6691: trying file=/usr/lib/tls/libsotest.so.1 6691: trying file=/usr/lib/x86_64/libsotest.so.1 6691: trying file=/usr/lib/libsotest.so.1 6691: trying file=/lib/x86_64-linux-gnu/tls/x86_64/libsotest.so.1 6691: trying file=/lib/x86_64-linux-gnu/tls/libsotest.so.1 6691: trying file=/lib/x86_64-linux-gnu/x86_64/libsotest.so.1 6691: trying file=/lib/x86_64-linux-gnu/libsotest.so.1 6691: trying file=/usr/lib/x86_64-linux-gnu/tls/x86_64/libsotest.so.1 6691: trying file=/usr/lib/x86_64-linux-gnu/tls/libsotest.so.1 6691: trying file=/usr/lib/x86_64-linux-gnu/x86_64/libsotest.so.1 6691: trying file=/usr/lib/x86_64-linux-gnu/libsotest.so.1 6691: /projects/sotest/exe/sotestexe: error while loading shared libraries: libsotest.so.1: cannot open shared object file: No such file or directory davids@ds-ub64-7:/$
LD_LIBRARY_PATH, the shared lib path in linux
I wrote a shared object, say libsd.so , and I put libsd.so and its header file sd.h in ~/lib . Here is another program using libsd.so , say test.c , then compile it like this:
$ gcc -o test test.c -I~/lib -L~/lib -lsd
$ ./test ./test_sd: error while loading shared libraries: libsd.so: cannot open shared object file: No such file or directory
So I set export LD_LIBRARY_PATH=. , then it works. But if I unset LD_LIBRARY_PATH and put LD_LIBRARY_PATH=~/lib in my ~/.bashrc , then source ~/.bashrc , again it doesn’t work for ./test , WHY? export LD_LIBRARY_PATH=~/lib is difference from putting LD_LIBRARY_PATH=~/lib in ~/.bashrc ?
2 Answers 2
Without the export your declared LD_LIBRARY_PATH is only valid in the script (.bashrc). With the export it should work, but it is usually not a good idea to set your LD_LIBRARY_PATH like this.
If you don’t want to install your library in the system path (e.g. /usr/lib) you should probably use a script that sets LD_LIBARAY_PATH locally and starts your application.
You can see here, why it is not a good idea: linuxmafia.com/faq/Admin/ld-lib-path.html However, it seems, that you shouldn’t even use it in a script, but rather use the -R option
On Fedora there should be -rpath, that should do pretty much the same thing, even though I actually do not know for sure.
Try $HOME/lib instead of ~/lib — it should be the same but I’ve seen cases where ~ wasn’t expanded properly when used in an variable assignment.
To check, try echo $LD_LIBRARY_PATH which gives you the current value.
Re export : If you omit the export , then the variable is only known to the current shell process and will not be exported to child processes. So if you omit it, echo $LD_LIBRARY_PATH will get the value because the variable is expanded by the shell before the echo command/builtin has a chance to do anything. But ./test won’t see it because it’s not exported to the new subprocess.