我最近在升级系统后遇到了这个问题:使用GCC -Wl,-rpath=
选项的工作方式与以前不同。
我用它来设置一些共享库的搜索路径,这些库是在我项目的子模块中构建的。当时我认为它比在系统范围内设置LD_LIBRARY_PATH
更好(我不想每次打开电脑时都设置它)。一切都很好,这两种方法似乎相同。
现在它接近-rpath
的行为发生了变化。它仍适用于直接依赖库,但不适用于通过-rpath=
链接同一目录集中的其他库的库。出口LD_LIBRARY_PATH
仍然像以前一样工作。
我使用readelf
检查了编译的输出,并且存在差异。在升级之前(Linux Mint 18.2 with GCC 5.4),Dynamic部分有这一行:
0x000000000000000f (RPATH) Library rpath: [submod/lib]
升级后(Linux Mint 19 with GCC 7.3),该行改为:
0x000000000000001d (RUNPATH) Library runpath: [submod/lib]
在 use RPATH but not RUNPATH?中,建议将RPATH替换为RUNPATH(或者它至少服务器具有不同的目的,因为它具有较低的优先级),但它没有给出为什么这会影响间接链接的答案。库本身在readelf
输出中既没有RPATH,也没有RUNPATH。
所以我的问题是:为什么链接器突然开始以不同的方式解释-rpath=
选项,有没有办法强制旧的行为? (或者做一些不同的事情,产生相同的结果。)
另一个问题是:是否有可能告诉旧版本的链接器产生新的输出(即RUNPATH而不是RPATH)?
编辑
这不是How to set RunPath of a binary?的重复 - 我的问题恰恰相反:我想要RPATH的行为。我想通了(感谢评论中的提示),我将在这里回答我的问题。
有没有办法强迫旧的行为?
是。您可以使用此选项-Wl,--disable-new-dtags
告诉新链接器使用旧行为,即RPATH。
是否有可能告诉旧版本的链接器产生新输出(即RUNPATH而不是RPATH)?
是。使用-Wl,--enable-new-dtags
告诉旧链接器使用新行为,即RUNPATH。
我用readelf
验证了可执行文件,这两个选项似乎控制了将在ELF Dynamic部分中编写的内容。我认为这个问题是由新版本默认值的变化引起的,尽管有趣的是,ld
的手册页表明它应该仍然是相同的:
--enable-新的DTAG - 禁用新的DTAG 此链接器可以在ELF中创建新的动态标记。但旧的ELF系统可能无法理解它们。如果指定--enable-new-dtags,将根据需要创建新的动态标记,并省略旧的动态标记。如果指定--disable-new-dtags,则不会创建新的动态标记。默认情况下,不会创建新的动态标记。请注意,这些选项仅适用于ELF系统。
项目GNU Binutils(包含GNU链接器(ld))不是这种行为变化的起源,而是Debian(2016)1和Gentoo(2013!)2。
根据Mike Frysinger在2013年1月的gentoo提交:
“新的”dtags选项已经存在了14年多,所以对于Linux和GNU目标,默认情况下启用它们。“
这种变化不太受欢迎3,4,5,因为RUNPATH和RPATH具有“无证件行为差异”......令人惊讶的是,这种变化现在应用于Debian稳定版。
问题是使用RUNPATH会导致不可预测的问题...但主要是起作用。来自维基百科:
与DT_RPATH不同,ld动态链接器不会在DT_RUNPATH位置搜索传递依赖性。