LD_LIBRARY_PATH 对 LibXML.so 无效

LD_LIBRARY_PATH doesn't take effect for LibXML.so

XML::LibXML 是一个 Perl 库。 LibXML.so 是图书馆的一部分。我正在尝试让 XML::LibXML 使用自定义 libxml2。但是提供 LD_LIBRARY_PATH 没有任何区别:

$ ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
    libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f66af5e9000)

$ LD_LIBRARY_PATH=/home/yuri/_/libxml2/.libs ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
    libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f2d26ae3000)

$ ldd /usr/lib/python3.7/site-packages/libxml2mod.so | grep libxml2
    libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f878cbc8000)

$ LD_LIBRARY_PATH=/home/yuri/_/libxml2/.libs ldd /usr/lib/python3.7/site-packages/libxml2mod.so | grep libxml2
    libxml2.so.2 => /home/yuri/_/libxml2/.libs/libxml2.so.2 (0x00007f6f8f5d8000)

我做错了什么?有办法处理吗?目标是让 Perl 脚本使用自定义构建 libxml2(调查一些问题)。

UPD

$ find /usr/lib -name libxml2.so.2
/usr/lib/libxml2.so.2
/usr/lib/vmware-installer/2.1.0/lib/lib/libxml2.so.2
/usr/lib/vmware-installer/2.1.0/lib/lib/libxml2.so.2/libxml2.so.2
/usr/lib/vmware-vmrc/5.5/lib/libxml2.so.2
/usr/lib/vmware-vmrc/5.5/lib/libxml2.so.2/libxml2.so.2

$ find /usr/local/lib -name libxml2.so.2

如果您在 /usr/local/lib 中安装自定义版本的 libxml,我认为 XML::LibXML 模块应该加载自定义版本而不是 /usr/lib 中的版本(假设您有 sudoers或 root 权限来安装它)。

我不确定为什么 Python 似乎使用与 Perl 不同的库查找路径。也许 libxml 库的完整路径被硬编码在 XML::LibXML 的 LibXML.so 中?如果 XML::LibXML 模块与 -l/usr/lib/libxml2.so 而不是 -lxml2 链接,那将是问题所在。

tl;博士

ExtUtils::MakeMaker 通过 .dynamic 部分中的 RPATH 条目硬编码二进制文件中共享库的路径。但是你可以预加载需要的库,

$ LD_PRELOAD=path/to/custom/libxml2/.libs/libxml2.so.2 ldd ./blib/arch/auto/XML/LibXML/LibXML.so

或者让加载程序忽略 RPATH 项,

$ LD_LIBRARY_PATH=path/to/custom/libxml2/.libs /usr/lib/ld-linux-x86-64.so.2 --inhibit-rpath /abs/path/to/LibXML.so /abs/path/to/perl ./1.pl

或将RPATH条目转换为RUNPATH一个,

$ chrpath --convert blib/arch/auto/XML/LibXML/LibXML.so

或删除 RPATH 个条目,

$ chrpath --delete blib/arch/auto/XML/LibXML/LibXML.so

或指定XMLPREFIX变量,

$ perl Makefile.PL XMLPREFIX=path/to/custom/libxml2/build

引擎盖下

ExtUtils::Liblist::ext() 获取要链接的库列表,例如 -lxml2 -lz -llzma -licui18n -licuuc -licudata -lm -ldl,并将它们转换为 four or five variables,从而进入生成的 Makefile .其中之一是 LD_RUN_PATH。它包含找到库的所有路径。

$is_dyna 如果库是动态的(不是 ends with .a). $is_perl is true if Perl was not built with it%ld_run_path_seen 是为了不重复 LD_RUN_PATH 中的值。

calculates LD_RUN_PATH, that generates part of the Makefile with the variable, and the part that passes it to the linker.

的部分

后果

LD_RUN_PATH 和二进制文件中的 RPATH 条目使加载程序在找到它们的目录中(在编译时)搜索库(在 运行 时间) .

-rpath=dir Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF executable, the contents of the environment variable "LD_RUN_PATH" will be used if it is defined.

https://jlk.fjfi.cvut.cz/arch/manpages/man/core/binutils/ld.1.en

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.

https://jlk.fjfi.cvut.cz/arch/manpages/man/core/man-pages/ld.so.8.en

$ perl Makefile.PL
$ make

结果,

$ readelf --dynamic ./blib/arch/auto/XML/LibXML/LibXML.so | grep RPATH
 0x000000000000000f (RPATH)              Library rpath: [/usr/lib]

$ objdump -x ./blib/arch/auto/XML/LibXML/LibXML.so | egrep RPATH
  RPATH                /usr/lib

$ LD_LIBRARY_PATH=path/to/custom/libxml2/.libs ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
    libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f6cfabb2000)

--dynamic - 显示 .dynamic 部分的内容,-x - 显示所有 headers.

解决方案

解决此问题的一种方法是预加载 libxml2

所需的实例
$ LD_PRELOAD=path/to/custom/libxml2/.libs/libxml2.so.2 ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
    path/to/custom/libxml2/build/lib/libxml2.so.2 (0x00007fe183aeb000)

另一种是告诉Makefile.PL在所需位置(编译时)搜索libxml2

$ perl Makefile.PL XMLPREFIX=path/to/custom/libxml2/build
$ make

结果,

$ readelf --dynamic ./blib/arch/auto/XML/LibXML/LibXML.so | grep RPATH
 0x000000000000000f (RPATH)              Library rpath: [path/to/custom/libxml2/build/lib:/usr/lib]

$ objdump -x ./blib/arch/auto/XML/LibXML/LibXML.so | egrep RPATH
  RPATH                path/to/custom/libxml2/build/lib:/usr/lib

$ ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
    libxml2.so.2 => path/to/custom/libxml2/build/lib/libxml2.so.2 (0x00007fe183aeb000)

边注

如果你想调试 XML::LibXML,你可以 运行 使用 OPTIMIZE 变量进行构建(添加 -B 以进行重建,以防库已经被建成),

$ make OPTIMIZE='-g3 -O0'

还有 -O2LDDLFLAGS 中没有 -g,但不确定这是否重要。

或者,WriteMakeFile 采用 OPTIMIZE 参数,因此您可以添加一行 here

'OPTIMIZE' => '-g3 -O0'

或者你可以添加变量here,然后传递给Makefile.PL

$ perl Makefile.PL OPTIMIZE='-g3 -O0'