如何解决ld:在共享库中使用-rpath,$ ORIGIN递归
| 我只是在此处使用ld \的-rpath
选项和$ORIGIN
做了一个基本示例(有关工作版本,请参见第二个响应)。我正在尝试创建一个示例,其中main.run
链接到foo.so
,然后依次链接到bar.so
,都使用rpath
和$ORIGIN
。
运行时文件结构为:
项目/
lib /
目录/
子/
栏
foo.so
跑/
main.run(无法构建)
我正在使用以下命令构建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,\'$ORIGIN/../lib/dir\' -Llib/dir -l:foo.so
如果使用的是其他版本的foo.so
,而该版本没有递归链接,则效果很好。 (在下面的项目中的make.sh中取消注释行以进行测试)。
但是,使用普通的foo.so
在构建main.run
时出现此错误:
/ usr / bin / ld:警告:找不到lib / dir / foo.so所需的bar.so(尝试使用-rpath或-rpath-link)
所以我的问题是:
foo.so中的$ORIGIN
解析为project/lib/dir
(where3是)或project/run
(where2ѭ(链接它的可执行文件))?
ldd似乎表明它是project/lib/dir
,这似乎是最好的方法(尽管我尝试同时假设两者)。
我如何使它们链接(同时保持可重定位性)-最好不使用-rpath-link
。
您可以在此处下载项目。这就是我所能做到的。 4个简短的资源和一个脚本。
提取后,只需在project/
之内运行./make.sh
。
注意:我使用的是-l:
。除了将库命名为foo.so
(而不是ѭ28)以及用-l:foo.so
(而不是ѭ30)来命名外,这没有什么改变。
解决方法
好吧,我有东西在工作。但是我真的不明白为什么会起作用。对我来说,这感觉就像是一个小虫。
我为main.run编译跑了31英镑。静态链接器实际上正在尝试打开其文字名称看起来像\“ $ 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,.
。
[附录]
好吧,我想我知道发生了什么事。首先,静态链接器(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,lib/dir/sub
来使main.run链接正常工作,就像您知道静态链接器根本不遵守$ ORIGIN一样,这是您所期望的。
顺便说一下,我在GNU ld手册的任何地方都没有看到-l:bar.so
语法。出于好奇,您是怎么想出来的?
假设它是受支持的功能,则看起来有点像个错误(-l:bar.so创建了对lib / dir / sub / bar.so的依赖,而不仅仅是bar.so)。您可以通过将main.run的rpath-link设置为\'。\'来解决此错误,也可以按通常的方式(libxxx.so)重命名内容。
, 从ld-linux(8)联机帮助页:
$ ORIGIN和rpath
ld.so在一个字符串中理解字符串$ ORIGIN(或等效的$ {ORIGIN})
rpath规范(DT_RPATH或DT_RUNPATH)表示目录
包含应用程序可执行文件。因此,位于
somedir / app可以用gcc -Wl,-rpath,\'$ ORIGIN /../ lib \'编译,所以
它无论在somedir / lib中都找到关联的共享库
somedir在目录层次结构中的位置。这有利于
创建“交钥匙”应用程序,不需要
安装到特殊目录中,但可以解压缩到
任何目录,仍然找到自己的共享库。
因此,对于第一个问题,,1ѭ只有一个值:project/run
。
因此,第二个问题的答案应该是使用以下命令链接foo.so
:
g++ -shared -o lib/dir/foo.so obj/foo.o -Wl,-soname,foo.so -Wl,\'$ORIGIN/../lib/dir/sub\' -Llib/dir/sub -l:bar.so
,首先,$符号扩展存在问题,可能会引起问题。我正在从源代码构建Python,我这样做:
export LDFLAGS=\'-Wl,\\$${ORIGIN}/../lib -Wl,\\$${ORIGIN}/../usr/lib -Wl,--enable-new-dtags\'
在运行make
之前。效果很好,并且找到了第一级依赖项。处理此类宏扩展问题时,请小心单引号和双引号。
其次,如果您在二进制文件或库上运行“ 49”,则可以看到它实际包含的RPATH标头。当我运行objdump -x path/to/python |grep RPATH
时,它显示了此信息。
RPATH$ {ORIGIN} /../ lib:$ {ORIGIN} /../ usr / lib`
我建议您检查二进制文件以查看RPATH标头中的实际内容。不幸的是,我认为这不会解决您的问题。这是我在运行ldd path/to/python
时看到的内容:
libpython2.7.so.1.0 => /data1/python27/bin/../lib/libpython2.7.so.1.0 (0x00002ad369d4f000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00002ad36a12f000)
libdl.so.2 => /lib/libdl.so.2 (0x00002ad36a34d000)
libutil.so.1 => /lib/libutil.so.1 (0x00002ad36a551000)
libm.so.6 => /lib/libm.so.6 (0x00002ad36a754000)
libc.so.6 => /lib/libc.so.6 (0x00002ad36a9d8000)
/lib64/ld-linux-x86-64.so.2 (0x00002ad369b2d000)
如您所见,第一级依赖关系由ѭ5正确处理,但是第二级依赖关系(即libpython的依赖关系)恢复为系统库。是的,libpython在其二进制文件中具有完全相同的RPATH标头。我在搜寻rpath recursive
时发现了您的问题,以尝试解决制作发行独立软件包的问题。
以后添加
rpath
标头仅更改搜索库的第一条路径。如果未在此处找到它们,则加载程序会继续在正常位置搜索。 ldd
仅列出通过搜索找到的库的实际路径。当我将这些库复制到rpath
目录时,一切正常。基本上,没有一种整洁的方法来找到所有依赖项并复制它们,只有ldd -v path/to/python
和对该输出的一些解析。
, 我也一直在研究这个问题,最好的是,我可以告诉您在使用ORIGIN扩展的任何路径上都需要使用-rpath-link
。例如:
CC -shared (other flags) -R\'$ORIGIN/../lib/\' -o /buildpath/lib/libmylib1.so
CC -shared (other flags) -R\'$ORIGIN/../lib/\' -lmylib1 -o /buildpath/lib/libmylib2.so
# This fails to link \'somebinary\'
CC (various flags) -R\'$ORIGIN/../lib/\' -lmylib2 -o /buildpath/bin/somebinary
# This works correctly
CC (various flags) -R\'$ORIGIN/../lib/\' -Wl,/buildpath/lib/mylib1 -lmylib2 -o /buildpath/bin/somebinary
# The text above the carets to the right is a typo: ------------------^^^^^^
# I\'m fairly sure it should read like this (though it has been awhile since I wrote this):
# (...) -Wl,/buildpath/lib -lmylib1 (...)
ld
不会在使用-rpath-link
指定的路径或从子依赖项的RPATH检索的路径内扩展$ORIGIN
。在上面的示例中,mylib2
取决于mylib1
;在链接somebinary
时,ld
会尝试使用libmylib2.so中嵌入的文字/未扩展字符串$ORIGIN/../lib/
查找mylib1
。 ld.so
在运行时会显示,但ld
在运行时不会显示。
它还不会使用用with73指定的路径来找到子依赖库librar(y | ies)。
, 检查我的make脚本的修改版本。基本上,应该使用没有$ORIGIN
的附加-rpath-link
,因为ld
根本不理解$ORIGIN
。
至于你的问题。
$ORIGIN
仅在运行时有效,并且每个图书馆。因此,不同的共享库具有不同的“ 1”。
恐怕最好的方法是添加rpath-link
,这不会影响您的可移植性,因为它们是相对的,并且不会出现在最终的可执行文件中,正如我在make.sh
版本中所展示的那样。
另外,这是我对整个链接内容的理解。希望对您有所帮助。
, 据我了解,这是ld(即binutils)中的问题,以及它如何解决“次要依赖项”
AFAIK始于binutils >= 2.30
。依赖项中的rpath将添加到搜索中。
即ld ... main.exe
找到foo.so
,然后读取foo.so
中的RPATH,从而找到bar.so
这是我的堆栈溢出问题:
Binutils次要依赖关系变更
这是我对各种发行版(在Docker容器内部)的调查,以测试各种binutils版本
https://github.com/Mizux/SecondaryDependency
注意:看看travis-CI日志...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。