I have a libA.so that depends on libB.so and having trouble finding it even though it's in the same directory.
ldd libA.so
linux-vdso.so.1 (0x00007fff50bdb000)
libB.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4aeb902000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4aebadb000)
I'm wondering if there is a way to make libA.so always look for libB.so in the same directory as this will be the case for my application? I know updating LD_LIBRARY_PATH
is an option as well but wanted to reduce the amount of work required.
CodePudding user response:
From 'man 8 ld.so':
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.
The key here is to use the DT_RUNPATH, which can be embedded into the binary you are creating. You can link it so that it points to the same directory, as you wanted.
See this post about how to do this: https://stackoverflow.com/a/67131878
CodePudding user response:
The .dynamic
section of an ELF file (.so
libraries on Linux use ELF format) contains information to help the library find its dependencies. .dynamic
entries with type DT_NEEDED
contain the names of other .so
files for the dynamic linker to find, but they do not contain any information on where to find those files. For that, as you mentioned, you can use LD_LIBRARY_PATH
, but the ELF format also provides a way to specify it in the file itself.
A .dynamic
entry with type DT_RUNPATH
gives the dynamic linker a path to a directory where the dynamic linker should look for DT_NEEDED
files. DT_RUNPATH
allows a special variable, $ORIGIN
, which refers to the file's current directory. This allows you to use relative paths, without requiring the user to invoke an executable from a specific working directory.
You use the -rpath
linker flag to specify a DT_RUNPATH
entry. In order to pass the literal string $ORIGIN
, however, you must wrap it in single quotes to prevent your shell from interpreting it as an environment variable.
Assuming you are using gcc
, you should use add this argument to the link step:
-Wl,-rpath,'$ORIGIN'