如何强制 .so 依赖项与库位于同一目录中

How to force .so dependency to be in same directory as library

我有一个 libA.so 依赖于 libB.so,即使它在同一目录中也找不到它。

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)

我想知道是否有办法让 libA.so 始终在同一目录中查找 libB.so,因为我的应用程序就是这种情况?我知道更新 LD_LIBRARY_PATH 也是一个选项,但我想减少所需的工作量。

来自'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.

这里的关键是使用 DT_RUNPATH,它可以嵌入到您正在创建的二进制文件中。您可以 link 它指向同一目录,如您所愿。

查看此post了解如何执行此操作:

ELF 文件的 .dynamic 部分(Linux 上的 .so 库使用 ELF 格式)包含帮助库找到其依赖项的信息。 .dynamic 类型为 DT_NEEDED 的条目包含供动态 link 用户查找的其他 .so 文件的名称,但它们不包含有关在哪里可以找到这些文件的任何信息。为此,正如您提到的,您可以使用 LD_LIBRARY_PATH,但 ELF 格式还提供了一种在文件本身中指定它的方法。

类型为 DT_RUNPATH.dynamic 条目为动态 linker 提供了动态 linker 应该查找 DT_NEEDED 的目录路径文件。 DT_RUNPATH 允许一个特殊变量,$ORIGIN,它指的是文件的当前目录。这允许您使用相对路径,而不需要用户从特定工作目录调用可执行文件。

您使用 -rpath linker 标志来指定 DT_RUNPATH 条目。但是,为了传递文字字符串 $ORIGIN,您必须将其用单引号括起来,以防止您的 shell 将其解释为环境变量。

假设您使用的是 gcc,您应该将此参数添加到 link 步骤:

-Wl,-rpath,'$ORIGIN'