ld:在共享库中使用-rpath,$ ORIGIN(递归) [英] ld: Using -rpath,$ORIGIN inside a shared library (recursive)
问题描述
我刚刚举了一个使用ld的-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
.
运行时文件结构为:
- 项目/
- lib/
- dir/
- sub/
- bar.so
- project/
- lib/
- dir/
- sub/
- 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 find bar.so
.
但是,当我尝试将main.run
链接到foo.so
时,foo.so
找不到bar.so.
However, when I try to link main.run
to foo.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 building main.run
:
/usr/bin/ld:警告:lib.dir/foo.so所需的bar.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 within project/
.
注意:我正在使用-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 like foo.so
instead of libfoo.so
, and lunk with -l:foo.so
instead of -lfoo
.
推荐答案
好,我有一些工作要做.但是我真的不明白为什么会起作用.对我来说,这感觉就像是一个小虫.
Well, I have something working. But I do not really understand why it works. This feels like a bug in ld to me.
我运行strace -f -o /var/tmp/strace.out -- g++ ...
进行main.run编译.静态链接器实际上正在尝试打开其文字名称看起来像"$ 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
on foo.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屋!