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,-rpath,\'$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,-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)。您可以通过将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,-rpath,\'$ORIGIN/../lib/dir/sub\' -Llib/dir/sub -l:bar.so
    
首先,$符号扩展存在问题,可能会引起问题。我正在从源代码构建Python,我这样做:
export LDFLAGS=\'-Wl,-rpath,\\$${ORIGIN}/../lib -Wl,-rpath,\\$${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,-rpath-link,/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,-rpath-link,/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日志...     

要回复问题请先登录注册