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

Why I cannot override search path of dynamic libraries with LD_LIBRARY_PATH?

编辑:我解决了这个问题,解决方案如下。

我正在专用于科学计算的共享计算集群中构建代码,因此我只能控制我的主文件夹中的文件。虽然我以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] 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.

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

When resolving shared object dependencies, the dynamic linker first inspects each dependency string to see if it contains a slash (this can occur if a shared object pathname containing slashes was specified at link time). If a slash is found, then the dependency string is interpreted as a (relative or absolute) pathname, and the shared object is loaded using that pathname.

If a shared object dependency does not contain a slash, then it is searched for in the following order:

o (ELF only) 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. Except if the executable is a set-user-ID/set-group-ID binary, in which case it is ignored.

o (ELF only) Using the directories specified in the DT_RUNPATH dynamic section attribute of the binary if present.

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 archiectures, 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.

  • with readelf readelf -d libfftw3_mpi.so 你可以检查你的库是否在动态部分包含这样的属性。

  • export LD_DEBUG=libs 您可以调试用于查找库的搜索路径

  • with chrpath -r<new_path> <executable> rpath可以改变

我认为这有两个可能的原因。

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

或者,您可能 运行 正在使用一个根本不支持 LD_LIBRARY_PATH 的系统(例如 HP-UX)。