Before we start
When talking about “dynamic linking”, people could refer to any of the following two processes: one is a step of program’s construction, where (relocatable) object files are dynamically linked by the linker – a toolchain’s component; the other is a pre-processing stage of program’s execution, performed by the dynamic linker , which is usually provided by the operating system. Obviously it could easily lead to confusion due to their similar names. Therefore, personally I prefer dynamic loading, its another commonly recognizable name, to refer to the latter one, and correspondingly dynamic loader to its performer.
Search paths are different for dynamic linking and loading. The simple answer to the question “why does this difference ever exist” is that the two operations are done by not a single but different entries. But the more fundamental reason for this, I think, is that we can’t always align the environment of producers with the one of consumers, although most of the time they are on the same site (i.e. we build our own program and run it on our own machine) and we therefore simply overlook this potential difference.
The search paths of dynamic linking can be obtained by querying ld
, the linker:
1ld --verbose | grep SEARCH_DIR
2gcc -print-search-dirs
As for search paths of dynamic loading, system manual of ld.so is the right place to check:
1o Using the directories specified in the DT_RPATH dynamic 2 section attribute of the binary if present and DT_RUNPATH 3 attribute does not exist. Use of DT_RPATH is deprecated. 4 5o Using the environment variable LD_LIBRARY_PATH, unless the 6 executable is being run in secure-execution mode (see below), 7 in which case this variable is ignored. 8 9o Using the directories specified in the DT_RUNPATH dynamic 10 section attribute of the binary if present. Such directories 11 are searched only to find those objects required by DT_NEEDED 12 (direct dependencies) entries and do not apply to those 13 objects' children, which must themselves have their own 14 DT_RUNPATH entries. This is unlike DT_RPATH, which is applied 15 to searches for all children in the dependency tree. 16 17o From the cache file /etc/ld.so.cache, which contains a 18 compiled list of candidate shared objects previously found in 19 the augmented library path. If, however, the binary was 20 linked with the -z nodeflib linker option, shared objects in 21 the default paths are skipped. Shared objects installed in 22 hardware capability directories (see below) are preferred to 23 other shared objects. 24 25o In the default path /lib, and then /usr/lib. (On some 64-bit 26 architectures, the default paths for 64-bit shared objects are 27 /lib64, and then /usr/lib64.) If the binary was linked with 28 the -z nodeflib linker option, this step is skipped.
Program Library HOWTO
by David A. Wheeler is a great material explaining how all kinds of libraries are created and used on Linux, and I recommend you to read it through. However, take a look at section 3.2
and 3.3
if you only care about how dynamic loading is done and relevant environment variables like LD_LIBRARY_PATH
.
P.s. Append LD_LIBRARY_PATH
when it’s unset
LD_LIBRARY_PATH
is often unset, and when we set it by the usual way: LD_LIBRARY_PATH=/my/path:$LD_LIBRARY_PATH
, sometimes Bash complains:
1bash: LD_LIBRARY_PATH: unbound variable
It’s related to the following shell option:
1set -u # or `set -o nounset`
2
3# check shell options of the current shell
4echo $-
5
6# unset the shell option
7set +u
Smartly create/append LD_LIBRARY_PATH
via shell parameter expansion
:
1export LD_LIBRARY_PATH=/mypath${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}