ld:在共享库中使用 -rpath,$ORIGIN(递归) [英] ld: Using -rpath,$ORIGIN inside a shared library (recursive)
问题描述
我刚刚做了一个基本示例,将 ld 的 -rpath
选项与 $ORIGIN
here(有关工作版本,请参阅第二个响应).我正在尝试创建一个示例,其中 main.run
链接到 foo.so
,而 foo.so
又链接到 bar.so
,全部使用rpath
和 $ORIGIN
.
I just made a basic example of using ld's -rpath
option with $ORIGIN
here (see 2nd response for a working version). I'm trying to create an example where main.run
links to foo.so
, which in turn links to bar.so
, all using rpath
and $ORIGIN
.
运行时文件结构为:
- 项目/
- 库/
- 目录/
- 子/
- bar.so
- main.run(构建失败)
- main.run (failing to build)
我正在构建 foo.so 使用:
I'm building foo.so using:
g++ -c -o obj/foo.o src/foo.cpp -fPIC g++ -shared -o lib/dir/foo.so obj/foo.o -Wl,-soname,foo.so -Wl,-rpath,'$ORIGIN/sub' -Llib/dir/sub -l:bar.so
构建良好.
ldd lib/dir/foo.so
甚至可以找到bar.so
.Which builds fine.
ldd lib/dir/foo.so
can even findbar.so
.但是,当我尝试将
main.run
链接到foo.so
时,foo.so
找不到 bar.so.However, when I try to link
main.run
tofoo.so
,foo.so
can't find bar.so.我正在构建 main.so 使用:
I'm building main.so using:
g++ -c -o obj/main.o src/main.cpp g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Llib/dir -l:foo.so
如果使用不递归链接的另一个版本的
foo.so
,这会正常工作.(在 make.sh 中取消注释行,在下面的项目中进行测试).This works fine if another version of
foo.so
is used that doesn't recursively link. (Uncomment lines in make.sh, in project below, to test).但是,使用普通
foo.so
我在构建main.run
时遇到此错误:However, using the normal
foo.so
I'm getting this error when buildingmain.run
:/usr/bin/ld: 警告:bar.so,lib/dir/foo.so 需要,未找到(尝试使用 -rpath 或 -rpath-link)
/usr/bin/ld: warning: bar.so, needed by lib/dir/foo.so, not found (try using -rpath or -rpath-link)
所以我的问题是:
- foo.so 中的
$ORIGIN
是否解析为project/lib/dir
(foo.so
所在的位置)或project/run
(main.run
(链接它的可执行文件)在哪里)?
ldd 似乎表明它是project/lib/dir
,这似乎是最好的方法(尽管我尝试同时假设两者). - 如何让这些链接(同时保持可重定位性) - 最好不使用
-rpath-link
.
- Does
$ORIGIN
within foo.so resolve toproject/lib/dir
(wherefoo.so
is) orproject/run
(wheremain.run
(the executable linking it) is)?
ldd would seem to indicate that it'sproject/lib/dir
, which would seem to be the best way (although I tried assuming both). - How do I get these to link (while preserving relocatability) - preferably without using
-rpath-link
.
您可以在此处下载项目.这就像我能做到的一样简单.4 个短资源和一个脚本.
解压后,只需在project/
中运行./make.sh
.You can download the project here. It's as simple as I can make it. 4 short sources and a script.
After extracting, just run./make.sh
from withinproject/
.注意:我使用的是
-l:
.这不应该改变任何东西,除了库被命名为foo.so
而不是libfoo.so
,并且与-l:foo.so
而不是-lfoo
.Note: I'm using
-l:
. This shouldn't change anything except that the libraries are named likefoo.so
instead oflibfoo.so
, and lunk with-l:foo.so
instead of-lfoo
.推荐答案
好吧,我有一些工作.但我真的不明白为什么它会起作用.这对我来说就像 ld 中的一个错误.
Well, I have something working. But I do not really understand why it works. This feels like a bug in ld to me.
我为 main.run 编译运行了
strace -f -o/var/tmp/strace.out -- g++ ...
.静态链接器实际上是在尝试打开文字名称类似于$ORIGIN/lib/dir/sub/bar.so"的文件,以及其他 20-30 个文件.(换句话说,它正在寻找一个名为$ORIGIN
的实际目录.说真的.)I ran
strace -f -o /var/tmp/strace.out -- g++ ...
for the main.run compilation. The static linker is actually trying to open files whose literal name looks like "$ORIGIN/lib/dir/sub/bar.so", among 20-30 other things. (In other words, it is looking for an actual directory named$ORIGIN
. Seriously.)它似乎还在 -rpath-link 路径中搜索名称lib/dir/sub/bar.so",而不仅仅是bar.so".我不知道为什么.
It also appears to be searching the -rpath-link path for the name "lib/dir/sub/bar.so", not just "bar.so". I have no clue why.
无论如何,这是对我有用的 main.run 链接:
Anyway, this is the link for main.run that is working for me:
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Wl,-rpath-link,. -Llib/dir -l:foo.so
它与你的相同,但插入了
-Wl,-rpath-link,.
.It is identical to yours but with
-Wl,-rpath-link,.
inserted.[附录]
好的,我想我明白发生了什么.首先,静态链接器 (GNU ld) 根本不支持它链接的库中的 $ORIGIN.
OK I think I see what is going on. First, the static linker (GNU ld) simply does not honor $ORIGIN in the libraries it links against.
其次,使用
-lbar
与-l:bar.so
时的行为非常不同.Second, the behavior when you use
-lbar
versus-l:bar.so
is very different.在
foo.so
上运行readelf -a
.在您的构建中,它显示了对lib/dir/sub/bar.so"的依赖.这就是为什么将 rpath-link 设置为."的原因.修复 main.run 的构建;它会导致静态链接器搜索."对于它找到的lib/dir/sub/bar.so".Run
readelf -a
onfoo.so
. In your build, it shows a dependency on "lib/dir/sub/bar.so". This is why setting the rpath-link to "." fixes the build of main.run; it causes the static linker to search "." for "lib/dir/sub/bar.so", which it finds.如果将 bar.so 重命名为 libbar.so,并将 foo.so 链接为使用
-lbar
而不是-l:bar.so
,同样的 readelf 会显示foo.so 现在依赖于libbar.so"(没有路径组件).使用 foo.so,您可以使用-Wl,-rpath-link,lib/dir/sub
使 main.run 链接正常工作,正如您所期望的那样,如果您知道静态链接器只是简单的不尊重 $ORIGIN.If you rename bar.so to libbar.so, and link foo.so to use
-lbar
instead of-l:bar.so
, the same readelf shows that foo.so now depends on "libbar.so" (with no path component). With that foo.so, you can get the main.run link to work using-Wl,-rpath-link,lib/dir/sub
, as you would expect if you knew that the static linker simply does not honor $ORIGIN.顺便说一句,我在 GNU ld 手册的任何地方都没有看到
-l:bar.so
语法.出于好奇,你是怎么想到的?By the way, I do not see the
-l:bar.so
syntax documented anywhere in the GNU ld manual. Out of curiosity, how did you come up with it?假设它是一个受支持的功能,这看起来有点像一个错误(-l:bar.so 创建对 lib/dir/sub/bar.so 的依赖,而不仅仅是 bar.so).您可以通过将 rpath-link 设置为 '.' 来处理此错误.对于 main.run,或者您可以以通常的方式重命名 (libxxx.so).
Assuming it is a supported feature, this looks a bit like a bug (-l:bar.so creating a dependency on lib/dir/sub/bar.so instead of just bar.so). You can either deal with this bug by setting rpath-link to '.' for main.run, or you can rename stuff in the usual way (libxxx.so).
这篇关于ld:在共享库中使用 -rpath,$ORIGIN(递归)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- 子/
- 目录/
- 库/