为啥我不能用 LD_LIBRARY_PATH 覆盖动态库的搜索路径?
Posted
技术标签:
【中文标题】为啥我不能用 LD_LIBRARY_PATH 覆盖动态库的搜索路径?【英文标题】:Why I cannot override search path of dynamic libraries with LD_LIBRARY_PATH?为什么我不能用 LD_LIBRARY_PATH 覆盖动态库的搜索路径? 【发布时间】:2016-02-04 19:36:12 【问题描述】:编辑:我解决了这个问题,解决方案如下。
我正在一个专用于科学计算的共享计算集群中构建代码,因此我只能控制我的主文件夹中的文件。虽然我以 fftw 为例,但我想了解具体原因,为什么我尝试设置 LD_LIBRARY_PATH 不起作用。
我像这样在我的主文件夹中构建 fftw 和 fftw_mpi 库
./configure --prefix=$HOME/install/fftw --enable-mpi --enable-shared
make install
它构建得很好,但是在 install/fftw/lib 中,我发现新构建的 libfftw3_mpi.so 链接到错误版本的 fftw 库。
$ ldd libfftw3_mpi.so |grep fftw
libfftw3.so.3 => /usr/lib64/libfftw3.so.3 (0x00007f7df0979000)
如果我现在尝试将 LD_LIBRARY_PATH 正确设置为指向该目录,它仍然偏爱错误的库:
$ export LD_LIBRARY_PATH=$HOME/install/fftw/lib
$ ldd libfftw3_mpi.so |grep fftw
libfftw3.so.3 => /usr/lib64/libfftw3.so.3 (0x00007f32b4794000)
只有当我明确使用 LD_PRELOAD 时,我才能覆盖此行为。我不认为 LD_PRELOAD 是一个合适的解决方案。
$ export LD_PRELOAD=$HOME/install/fftw/lib/libfftw3.so.3
$ ldd libfftw3_mpi.so |grep fftw
$HOME/install/fftw/lib/libfftw3.so.3 (0x00007f5ca3d14000)
这是我所期望的,在 Ubuntu 桌面上完成的一个小测试,我首先将 fftw 安装到 /usr/lib,然后用 LD_LIBRARY_PATH 覆盖这个搜索路径。
$ export LD_LIBRARY_PATH=
$ ldd q0test_mpi |grep fftw3
libfftw3.so.3 => /usr/lib/x86_64-linux-gnu/libfftw3.so.3
$ export LD_LIBRARY_PATH=$HOME/install/fftw-3.3.4/lib
$ ldd q0test_mpi |grep fftw3
libfftw3.so.3 => $HOME/install/fftw-3.3.4/lib/libfftw3.so.3
简而言之:为什么 libfft3_mpi 库仍然会找到错误的动态 fftw3 库?这个搜索路径在哪里以优先于 LD_LIBARY_PATH 的方式硬编码?为什么在另一台计算机上不是这样?
如果这很重要,我正在使用英特尔编译器 13.1.2、mkl 11.0.4.183 和 openmpi 1.6.2。
编辑:感谢所有答案。在这些帮助下,我们能够将问题隔离到 RPATH,并且从那里,集群支持能够找出问题所在。我接受了第一个答案,但两个答案都很好。
之所以如此难以弄清楚,是因为我们不知道编译器实际上是包装脚本,将东西添加到编译器命令行。以下是支持人员的部分回复:
[The] 编译通过我们的编译器包装器进行。我们做 RPATH-ing 默认情况下,因为它可以帮助大多数用户正确运行他们的工作 不加载 LD-LIBRARY_PATH 等。但是我们排除某些 来自默认 RPATH 的库路径,包括 /lib、/lib64 /proj /home 等。之前 /usr/lib64 没有被错误排除 (大多)。现在我们已将该路径添加到排除列表中。
【问题讨论】:
【参考方案1】:来自http://man7.org/linux/man-pages/man8/ld.so.8.html
解析共享对象依赖时,动态链接器首先 检查每个依赖字符串以查看它是否包含斜杠(这 如果包含斜杠的共享对象路径名是 在链接时指定)。如果找到斜线,则依赖项 string 被解释为(相对或绝对)路径名,并且 使用该路径名加载共享对象。
如果共享对象依赖项不包含斜线,则它是 按以下顺序搜索:
o(仅限 ELF)使用 DT_RPATH 动态中指定的目录 二进制文件的部分属性(如果存在)和 DT_RUNPATH 属性不存在。不推荐使用 DT_RPATH。
o 使用环境变量 LD_LIBRARY_PATH。除非 可执行文件是一个 set-user-ID/set-group-ID 二进制文件,在这种情况下它 被忽略。
o(仅限 ELF)使用 DT_RUNPATH 中指定的目录 二进制文件的动态部分属性(如果存在)。
o 来自缓存文件 /etc/ld.so.cache,其中包含一个已编译的 先前在增强中找到的候选共享对象列表 库路径。但是,如果二进制文件与 -z nodeflib 链接器选项,默认路径中的共享对象是 跳过。安装在硬件能力中的共享对象 目录(见下文)优先于其他共享对象。
o 在默认路径 /lib 中,然后是 /usr/lib。 (在某些 64 位 架构中,64 位共享对象的默认路径是 /lib64,然后是 /usr/lib64。)如果二进制文件与 -z nodeflib 链接器选项,跳过此步骤。
使用 readelf readelf -d libfftw3_mpi.so
你可以检查你的库是否在动态部分包含这样的属性。
使用export LD_DEBUG=libs
,您可以调试用于查找库的搜索路径
chrpath -r<new_path> <executable>
可以更改 rpath
【讨论】:
确实,对于 readelf,似乎 /usr/lib64 确实在名为 RPATH 的变量中的 /home/USER/install/fftw/lib 之前。现在问题仍然存在,/usr/lib64 是如何在 /fftw/lib 之前到达那里的。$ readelf -d libfftw3_mpi.so | grep RPATH 0x000000000000000f (RPATH) Library rpath: [/software/intel/composer_xe_2013.4.183/compiler/lib/intel64:/usr/lib:/usr/lib/gcc/x86_64-redhat-linux/4.4.4:/usr/lib64:/home/USER/install/fftw/lib]
rpath 是在编译时添加的。我不知道 fftw 库,但也许有一个 --disable-rpath
配置标志。要更改 rpath,您可以使用 chrpath -r<new_path> <executable>
更改库中的 rpath【参考方案2】:
我认为这有两个可能的原因。
首先,libfftw3_mpi.so
可以与/usr/lib64/
链接为RPATH
。在这种情况下,提供LD_LIBRARY_PATH
将无效。要检查是否是您的情况,请运行 readelf -d libfftw3_mpi.so | grep RPATH
并查看它是否将 /usr/lib64/
作为库路径。如果是,请使用chrpath
实用程序更改或删除它。
或者,您可能正在运行一个根本不支持LD_LIBRARY_PATH
的系统(如HP-UX)。
【讨论】:
以上是关于为啥我不能用 LD_LIBRARY_PATH 覆盖动态库的搜索路径?的主要内容,如果未能解决你的问题,请参考以下文章