管理共享库的二级依赖

Managing secondary dependencies of shared libraries

我对共享库的二次依赖有疑问。 假设我们有如下依赖树:

libA.so
├─libB.so
└─libC.so
  └─libD.so

也就是说,共享库A依赖于共享库B和C,共享库C依赖于共享库D。libC的一个很好的例子是GSL shared library,它依赖于CBLAS .

为了制作一个自给自足且易于使用的包并避免安装共享库的不同版本出现问题,我打包了库 libBlibClibD使用 libA,并如解释的那样,例如,在 Drepper 的 article,“如何编写共享库”(2011 年)中,我添加了 link 标志 -Wl,-rpath,$ORIGIN --enable-new-dtags 来设置 RUN_PATH of libA.so, 这样动态加载器就可以在对应的目录中找到 libA 的依赖,而不需要设置 LD_LIBRARY_PATH (这有它的缺点).

问题是在 libA 中设置 RUN_PATH 对辅助依赖项没有帮助,例如 libD.so。 打开动态加载程序调试消息(通过设置 LD_DEBUG)显示加载程序仅在 standard 库位置尝试查找 libD.so,而不是在该位置libA 的(与查找 libBlibC 的做法相反)。

有没有办法解决这个问题?

确实,如果我有源代码或正确编译的静态库,我可以 link 静态库 C 和 D。
但是有没有更好的方法呢?


解决方法:
正如 Employed Russian 所解释的那样,解决方案是设置 RPATH 而不是 RUNPATH。 对于最新版本的 GCC,应该使用以下 link 标志:

-Wl,--disable-new-dtags,-rpath,$ORIGIN

RPATH 搜索 transitive 依赖;也就是说,RPATH 中的路径将被考虑用于动态加载的所有内容,甚至是依赖项的依赖项。

相比之下,ld 动态 linker 搜索传递依赖项的 RUNPATH 位置(不同于 RPATH ).

另请参阅:

通过设置 DT_RUNPATH,您告诉加载程序 每个 二进制文件 link 都包含其所有依赖项。

但是对于libC.so来说是不正确的——它(显然)没有自己的DT_RUNPATH

I can link the libraries C and D statically, ... But is there a better way?

是:link libC.so 正确 DT_RUNPATH (如果 libC.solibD.so 在同一个目录,那么 -Wl,-rpath,$ORIGIN 将也为 libC.so 工作。

更新:

The problem is that I may not have the source or the properly compiled object files of libC

因此您应该使用 RPATH 而不是 RUNPATH。与后者不同,前者适用于对象本身以及该对象的所有 依赖项。

换句话说,在这种情况下使用 --enable-new-dtags 是错误的——您想要相反的结果。

In this case, there is no solution (besides static linking); correct?

另一个解决方案(除了使用RPATH)是在环境中设置LD_LIBRARY_PATH

更新二:

Difference between RPATH and RUNPATH

区别在 ld.so man page:

中解释
       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 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.