我有一个Linux C++程序,它构建和链接(使用-Wl,--no-undefined
,不少(,但是当我尝试运行它时无法加载其所有库。 我一直在尝试检查它与ldd
的依赖关系,但我无法弄清楚为什么它会在失败的库上绊倒:
$ ldd standalone_test
... lots of libraries that are found ...
libPythia6.so => not found
现在,这个库位于应该根据可执行文件中嵌入的RUNPATH
找到它的地方:
$ readelf -d ./standalone_test | grep "RUNPATH"
0x000000000000001d (RUNPATH) Library runpath: [/home/jeremy/code/NOvARwgt/cmake-build-debug/src:/home/jeremy/code/genie-2.12.2/lib:/opt/genie/GENIESupport/pythia6/v6_424/lib:/opt/root/lib:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug]
$ ls /opt/genie/GENIESupport/pythia6/v6_424/lib
liblund.a libPythia6.so pydata.o
(可执行文件standalone_test
和库libPythia6.so
都是ELF64,所以我不认为这是处理器架构不匹配或类似的东西。
我尝试进一步深入研究库加载期间发生的事情,我注意到在同一可执行文件下加载不同库时报告了不同的RUNPATH
(其中一些是"链"加载,它们是由可执行文件请求的库请求的(:
$ LD_DEBUG=libs,files ./standalone_test 2>&1 | ack RUNPATH
# this one is the 'correct' RUNPATH (the one from the executable)
19553: search path=/opt/root/lib/tls/haswell/x86_64:/opt/root/lib/tls/haswell:/opt/root/lib/tls/x86_64:/opt/root/lib/tls:/opt/root/lib/haswell/x86_64:/opt/root/lib/haswell:/opt/root/lib/x86_64:/opt/root/lib (RUNPATH from file ./standalone_test)
# next one has been 'augmented' with processor architecture subdirs
19553: search path=/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls/haswell/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls/haswell:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/tls:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/haswell/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/haswell:/home/jeremy/code/NOvARwgt/cmake-build-debug/src/x86_64:/home/jeremy/code/NOvARwgt/cmake-build-debug/src:/home/jeremy/code/genie-2.12.2/lib/tls/haswell/x86_64:/home/jeremy/code/genie-2.12.2/lib/tls/haswell:/home/jeremy/code/genie-2.12.2/lib/tls/x86_64:/home/jeremy/code/genie-2.12.2/lib/tls:/home/jeremy/code/genie-2.12.2/lib/haswell/x86_64:/home/jeremy/code/genie-2.12.2/lib/haswell:/home/jeremy/code/genie-2.12.2/lib/x86_64:/home/jeremy/code/genie-2.12.2/lib:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls/haswell/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls/haswell:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib/tls:/opt/genie/GENIESupport/pythia6/v6_424/lib/haswell/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib/haswell:/opt/genie/GENIESupport/pythia6/v6_424/lib/x86_64:/opt/genie/GENIESupport/pythia6/v6_424/lib:/opt/root/lib:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls/haswell/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls/haswell:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/tls:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/haswell/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/haswell:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug/x86_64:/cvmfs/nova-development.opensciencegrid.org/novasoft/releases/development/lib/Linux2.6-GCC-debug (RUNPATH from file ./standalone_test)
... more variants of these two ...
# this one contains only a single entry from the real runpath??
19553: search path=/opt/root/lib (RUNPATH from file ./standalone_test)
在最后一种情况下,库未找到并且可执行文件失败并出现cannot open shared object file: No such file or directory
错误,它也会继续查找系统搜索路径。
我的问题是:这些变体是如何炮制RUNPATH
的?我收集到它们被以某种方式请求它们的各种库修改了,但我似乎在谷歌网络上找不到任何解释。 (也许我搜索错了东西? 似乎如果我了解这里发生了什么,我就可以向后工作,以理解为什么首先找不到该库。
我的问题是:RUNPATH 上的这些变体是如何炮制的?
与旧RPATH
不同,该RUNPATH
只适用于搜索二进制文件的直接依赖关系。
也就是说,如果a.out
有/foo
的RUNPATH
,libfoo.so
的NEEDED
(位于/foo
(,那么就会找到libfoo.so
。但是如果libfoo.so
本身取决于libbar.so
(也位于/foo
(,如果libfoo.so
没有RUNPATH
,那么libbar.so
将找不到。
这种行为提倡"每个 ELF 二进制都应该是自给自足的"。在上面的情况下,libfoo.so
不是自给自足的(需要libbar.so
但没有说明在哪里可以找到它(。
如果改用RPATH
,则那里的路径将应用于每个搜索,并且将找到libbar.so
。您可以在链接a.out
时使用-Wl,--disable-new-dtags
来实现此目的。