为什么我不能用LD_LIBRARY_PATH覆盖动态库的搜索路径?

18

编辑:我已解决此问题,解决方案如下。

我正在构建一个用于科学计算的共享计算集群中的代码,因此我只能控制我的主目录中的文件。尽管我使用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_LIBRARY_PATH更优先?为什么另一台计算机上情况不是这样?
我正在使用intel编译器13.1.2、mkl 11.0.4.183和openmpi 1.6.2,如果有关系的话。
编辑:感谢所有答案。在这些帮助下,我们能够将问题隔离到RPATH,并从那里,群集支持能够找出问题所在。我接受了第一个答案,但两个答案都很好。
之所以这么难以解决,是因为我们并不知道编译器实际上是包装脚本,会向编译器命令行添加内容。这里是支持回复的一部分:
[The] compilation goes through our compiler wrapper. We do RPATH-ing by default as it helps most users in correctly running their jobs without loading LD-LIBRARY_PATH etc. However we exclude certain library paths from default RPATH which includes /lib, /lib64 /proj /home etc. Earlier the /usr/lib64 was not excluded by mistake (mostly). Now we have added that path in the exclusion list.
2个回答

22

来自 http://man7.org/linux/man-pages/man8/ld.so.8.html

在解决共享对象依赖关系时,动态链接器首先检查每个依赖字符串是否包含斜杠(如果在链接时指定了包含斜杠的共享对象路径名,则可能会出现这种情况)。 如果找到斜杠,则将依赖字符串解释为(相对或绝对)路径名,并使用该路径名加载共享对象。 如果共享对象依赖性不包含斜杠,则按以下顺序搜索: o(仅限ELF)如果存在二进制DT_RPATH动态部分属性并且DT_RUNPATH属性不存在,则使用其中指定的目录。 使用DT_RPATH已被弃用。 o使用环境变量LD_LIBRARY_PATH。 但是,如果可执行文件是设置用户ID /设置组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]` - Mikael Kuisma
编译时会添加rpath。我不知道fftw库,但也许有一个--disable-rpath配置标志。要更改rpath,可以使用chrpath -r<new_path> <executable>来更改库中的rpath。 - Martin Bonetti
嘿@MartinBonetti,感谢您的回答,我在这里学到了很多,并且能够使用您的建议LD_DEBUG解决我的问题! - David Zorychta

5

我看到这有两个可能的原因。

首先,libfftw3_mpi.so 可能与 /usr/lib64/ 链接为 RPATH。在这种情况下,提供 LD_LIBRARY_PATH 将不起作用。要检查是否是这种情况,请运行 readelf -d libfftw3_mpi.so | grep RPATH 并查看是否将 /usr/lib64/ 作为库路径。如果是这样,请使用 chrpath 实用程序来更改或删除它。

另外,您可能正在运行一个完全不支持 LD_LIBRARY_PATH 的系统(例如 HP-UX)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接