我刚刚做了一个使用 ld 的 -rpath
的基本示例带有 $ORIGIN
的选项here (有关工作版本,请参阅第二个响应)。我正在尝试创建一个示例,其中 main.run
链接到 foo.so
,它又链接到 bar.so
, 全部使用 rpath
和 $ORIGIN
.
运行时文件结构是:
- project/
- lib/
- dir/
- sub/
- bar.so
- foo.so
- run/
- main.run (failing to build)
我正在构建 foo.so 使用:
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
.
但是,当我尝试链接 main.run
时至 foo.so
, foo.so
找不到 bar.so。
我正在构建 main.so 使用:
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 中的行以进行测试)。
但是,使用正常的 foo.so
构建 main.run
时出现此错误:
/usr/bin/ld: warning: bar.so, needed by lib/dir/foo.so, not found (try using -rpath or -rpath-link)
所以我的问题是:
- 是否
$ORIGIN
在 foo.so 中解析为project/lib/dir
(其中foo.so
是)或project/run
(main.run
(链接它的可执行文件)在哪里)?
ldd 似乎表明它是project/lib/dir
,这似乎是最好的方法(尽管我尝试假设两者都假设)。 - 如何让这些链接(同时保留可重定位性)- 最好不使用
-rpath-link
.
您可以下载项目here .这很简单,我可以做到。 4 个短资源和一个脚本。
解压后,运行./make.sh
来自内部 project/
.
注意:我正在使用 -l:
.这不应该改变任何东西,除了库被命名为 foo.so
而不是 libfoo.so
, 和 lunk -l:foo.so
而不是 -lfoo
.
最佳答案
嗯,我有一些工作。但我真的不明白为什么会这样。这对我来说就像是 ld 中的错误。
我为 main.run 编译运行了 strace -f -o/var/tmp/strace.out -- g++ ...
。静态链接器实际上试图打开字面名称类似于“$ORIGIN/lib/dir/sub/bar.so”的文件,以及其他 20-30 个文件。 (换句话说,它正在寻找名为 $ORIGIN
的实际目录。说真的。)
它似乎还在 -rpath-link 路径中搜索名称“lib/dir/sub/bar.so”,而不仅仅是“bar.so”。我不知道为什么。
无论如何,这是为我工作的 main.run 的链接:
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Wl,-rpath-link,. -Llib/dir -l:foo.so
它与您的相同,但插入了 -Wl,-rpath-link,.
。
[附录]
好的,我想我知道发生了什么。首先,静态链接器 (GNU ld) 根本不支持它链接的库中的 $ORIGIN。
其次,使用 -lbar
与 -l:bar.so
时的行为非常不同。
在 foo.so
上运行 readelf -a
。在您的构建中,它显示了对“lib/dir/sub/bar.so”的依赖。这就是将 rpath-link 设置为“.”的原因。修复 main.run 的构建;它会导致静态链接器搜索“。”对于它找到的“lib/dir/sub/bar.so”。
如果将 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。
顺便说一下,我没有在 GNU ld 手册中的任何地方看到 -l:bar.so
语法。出于好奇,你是怎么想出来的?
假设它是受支持的功能,这看起来有点像错误(-l:bar.so 创建对 lib/dir/sub/bar.so 的依赖,而不仅仅是 bar.so)。您可以通过将 rpath-link 设置为“.”来处理此错误。对于 main.run,或者您可以按照通常的方式重命名内容 (libxxx.so)。
关于linux - ld : Using -rpath, $ORIGIN 在共享库中(递归),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6323603/