C++ 链接器运行时缺少库(SONAME 行为)

2023-11-24

我制作了一个使用两个共享库(我编译的)的程序,并且放置如下:

/home_directory_where_I_compile_and_run_everything
-->/lib/libjson_linux-gcc-4.4.6_libmt.so
-->/lib/libre2.so.0

当我编译程序时,我将这些库的相对位置传递给链接器,如下所示:

g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/libre2.so.0

它编译得很好,但是运行程序时它找不到 libre2.so,如果我用 ldd 检查它,会发生以下情况:

....
lib/libjson_linux-gcc-4.4.6_libmt.so (0x00007f62906bc000)
libre2.so.0 => not found
....

显然,它确实承认 libjson 上的路径是相对的,但它在 libre2.so.0 上却没有这样做(它会修剪所有路径,只留下 libre2.so.0)

有人能告诉我为什么会发生这种情况吗?

另外,有没有办法通过 g++ 参数来修改它?

Best.

* 更新 *哇看看这个! 我已将 libre2.so.0 的名称更改为 stuff.so,然后尝试编译基本相同的内容,如下所示:

g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so

无论如何它都会失败;它不仅失败了,而且失败了,因为它找不到“libre2.so.0”。

Whyyy?

* 更新#2 *

输出为readelf -d the_program.o

0x0000000000000001 (NEEDED)             Shared library: [lib/libjson_linux-gcc-4.4.6_libmt.so]
0x0000000000000001 (NEEDED)             Shared library: [libre2.so.0]

现在,如果我可以将 [libre2.so.0] 改为 [lib/libre2.so.0] 就可以了。

* 更新#3 *

正如@troubadour 发现的那样:

当可执行文件与具有 DT_SONAME 字段的共享对象链接时,当可执行文件运行时,动态链接器将尝试加载由 DT_SONAME 字段指定的共享对象,而不是使用为链接器提供的文件名。

这就是为什么它适用于 libjson.....so 而不是 libre2.so.0。 (libjson.....so 没有 SONAME 条目)。

我终于找到了我正在寻找的确切问题:

有没有办法告诉 gcc 链接器忽略共享库文件上的 SONAME 条目并链接到特定的文件路径?


我将首先回答您问题的第二部分,即为什么重命名 libre2.so.0 没有达到您的预期。

当您运行可执行文件时,传递给链接器的文件名是无关紧要的(除非您无法提供-soname构建库时 - 请参阅下面的第二次编辑)。依赖关系取自所谓的“soname”。如果您运行readelf在你的库上命令你可以确定它的soname,例如。

readelf -d libre2.so.0 | grep SONAME

即使您重命名该文件也没关系。上述命令的结果仍然会给你相同的soname,因此程序仍然无法找到“libre2.so.0”。

至于你问题的原始部分,这完全取决于图书馆是否有RPATH or RUNPATH内置于它们和/或您的内容LD_LIBRARY_PATH环境变量是。这些是运行时链接器 (ld.so) 将用来查找共享库的内容。尝试

man ld.so

了解更多信息。

由于您自己构建了这些库,因此您会知道它们是否使用了-rpath or -runpath最后链接阶段的选项。或者,使用readelf再次例如。

readelf -d libre2.so.0 | grep RPATH
readelf -d libre2.so.0 | grep RUNPATH

我怀疑上面两个命令不会返回任何内容。

我的猜测是你的当前目录在LD_LIBRARY_PATH这将允许运行时链接器找到 lib/libjson_linux-gcc-4.4.6_libmt.so 但找不到 libre2.so.0。我注意到您回复了我对您的问题的评论,表示您的LD_LIBRARY_PATH是空的。这很奇怪。

也许您以某种方式在 libjson 的 soname 上添加了前缀“lib/”?即做了readelfSONAME 返回命令

lib/libjson_linux-gcc-4.4.6_libmt.so

而不仅仅是

libjson_linux-gcc-4.4.6_libmt.so

另外,通过运行检查程序在 soname 方面需要什么

readelf -d my_progam | grep NEEDED

也许“lib/”前缀在那里是因为你将它传递给 gcc 的方式。如果是这样,那么如果您使用 @enobayram 给出的 gcc 命令,那么它将平衡竞争环境,即它也将无法找到 libjson。

首先要确定的不是为什么not找到 libre2.so.0 但它是如何实现的is设法找到 libjson。如果您尝试从不同的目录运行可执行文件,它仍然有效还是现在对于 libjson 也失败了?或者,如果您将 libre2.so.0 复制到可执行文件旁边,这会改变什么吗?

Edit

A 在 Fedora 论坛上发帖建议 Fedora 版本的 ld.so 将当前目录作为内置搜索路径。虽然我无法验证这一点,但它可以解释为什么你要选择任何库,因为你的案例中不存在 ld.so 使用的所有其他东西。

Edit 2

从我系统上的 ld 手册页

-soname=名称

创建ELF共享对象时,设置内部DT_SONAME字段 到指定的名称。当可执行文件与共享文件链接时 具有 DT_SONAME 字段的对象,然后当可执行文件运行时 动态链接器将尝试加载指定的共享对象 DT_SONAME 字段而不是使用给定的文件名 链接器。

版权所有 (c) 1991、1992、1993、1994、1995、1996、1997、1998、1999、 2000、2001、2002、2003、2004、2005、2006、2007、2008、2009 免费 软件基金会公司

授予复制、分发和/或修改本文档的许可 根据 GNU 自由文档许可证 1.3 版的条款或 自由软件基金会发布的任何更高版本;没有 不变部分,没有封面文本,也没有封底 文本。许可证副本包含在标题为“GNU 免费文档许可证”。

所以,你评论中的理论是正确的。如果不-soname在构建库时显式指定,则共享对象中不存在 SONAME,并且可执行文件中的 NEEDED 字段仅具有提供给链接器的文件名,在您的情况下,该文件名包含前导“lib/”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 链接器运行时缺少库(SONAME 行为) 的相关文章

随机推荐