如何用 GCC/LD 设置 RPATH 和 RUNPATH?

How to set RPATH and RUNPATH with GCC/LD?

我最近在升级系统后遇到了这个问题:使用 GCC -Wl,-rpath= 选项的工作方式与以前不同。

我用它来设置一些共享库的搜索路径,这些共享库是在我的项目的子模块中构建的。当时我认为它比在系统范围内设置 LD_LIBRARY_PATH 更好(我不想每次打开计算机都设置它)。一切正常,这两种方法似乎是等价的。

现在看来 -rpath 的行为已经改变了。它仍然适用于直接依赖的库,但不适用于通过 -rpath= 设置的来自同一目录的 link 其他库。导出 LD_LIBRARY_PATH 仍然像以前一样工作。

我使用 readelf 检查了编译的输出,发现有区别。在升级之前(Linux Mint 18.2 with GCC 5.4)动态部分有这一行:

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(或者它至少服务于不同的目的,因为它具有较低的优先级),但它没有给出为什么会这样的答案影响间接 linking。库本身在 readelf 输出中既没有 RPATH,也没有 RUNPATH。

所以我的问题是:为什么 linker 突然开始以不同的方式解释 -rpath= 选项,有没有办法强制执行旧行为?(或者做一些不同的事情会产生相同的结果。)

另一个问题是:是否可以告诉旧版本的 linker 产生新的输出(即 RUNPATH 而不是 RPATH)?


编辑

这不是 How to set RunPath of a binary? 的副本——我的问题恰恰相反:我想要 RPATH 的行为。我弄明白了(感谢评论中的提示),我会在这里回答我的问题。

Is there a way to force the old behavior?

是的。您可以使用此选项 -Wl,--disable-new-dtags 告诉 new 链接器使用 old 行为,即 RPATH。

Is it possible to tell the old version of linker to produce the new output (i.e. RUNPATH instead of RPATH)?

是的。使用 -Wl,--enable-new-dtags 告诉 old 链接器使用 new 行为,即 RUNPATH。

我用 readelf 验证了可执行文件,这两个选项似乎控制了将写入 ELF 动态部分的内容。我认为问题是由新版本的默认值更改引起的,尽管有趣的是,ld 的手册页建议它应该仍然相同:

--enable-new-dtags
--disable-new-dtags
This linker can create the new dynamic tags in ELF. But the older ELF systems may not understand them. If you specify --enable-new-dtags, the new dynamic tags will be created as needed and older dynamic tags will be omitted. If you specify --disable-new-dtags, no new dynamic tags will be created. By default, the new dynamic tags are not created. Note that those options are only available for ELF systems.

GNU Binutils 项目(包含 GNU 链接器 (ld))不是这种行为变化的起源,而是 Debian (2016)1, and Gentoo (2013!)2.

根据 Mike Frysinger 在 2013 年 1 月提交的 gentoo:

"The "new" dtags options have been around for 14+ years now, so for Linux and GNU targets, enable them by default."

此更改未被广泛接受 3, 4, 5,因为 RUNPATH 和 RPATH "undocumented behaviour difference"... 令人惊讶的是,此更改现在已应用于 Debian 稳定版。

问题是使用 RUNPATH 会导致不可预知的问题... 但主要只是工作。来自维基百科:

The ld dynamic linker does not search DT_RUNPATH locations for transitive dependencies, unlike DT_RPATH.