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

C++ C++;链接器在运行时缺少库(SONAME行为),c++,linker,g++,shared,C++,Linker,G++,Shared,我制作了一个使用两个共享库(我编译过)的程序,其放置方式如下: /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 g++ .

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

/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
g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so
编译程序时,我会将这些库的相对位置传递给链接器,如下所示:

/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
g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so
它编译得很好,但是在运行程序时找不到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++参数来修改它

最好的

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

/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
g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so
无论如何它都失败了;它不仅失败了,还因为找不到“libre2.so.0”而失败了

为什么

*更新#2*

expndtw-1\u program.o的
readelf-d输出

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一起工作……所以不能与libre2.so.0一起工作。(libjson…..因此没有SONAME的条目)

我终于找到了我要找的确切问题:


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

当您针对共享库(.so)进行链接时,在您执行程序时,库加载路径中必须存在这些条目。链接时提供的位置在可执行文件中不被“记住”

替代解决方案:

  • 将.so文件与可执行文件放在同一目录中
  • 使用
    LD\u LIBRARY\u PATH=lib./程序运行
  • 在运行程序之前,将.so文件安装到库路径中的某个位置,例如
    /usr/local/lib
  • 静态链接

正确的编译器命令行应该是:

g++ ...... stuff ........ my_program.cc -Llib -ljson_linux-gcc-4.4.6_libmt -lre2

您应该将共享对象放在标准目录(如/usr/lib)中,或者将它们的路径添加到
LD_LIBRARY\u path
,以便能够运行可执行文件。

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

运行可执行文件时,传递给链接器的文件名与此无关(除非在构建库时未能提供
-soname
,请参见下面的第二次编辑)。依赖项取自所谓的“soname”。如果在库上运行
readelf
命令,则可以确定其soname eg

readelf -d libre2.so.0 | grep SONAME
是否重命名该文件并不重要。上述命令的结果仍然会给您相同的soname,因此程序仍然无法找到“libre2.so.0”

至于问题的原始部分,这完全取决于库是否内置了
RPATH
RUNPATH
,和/或
LD\u LIBRARY\u PATH
环境变量的内容。这些是运行时链接器(ld.so)用来查找共享库的东西。试一试

man ld.so
了解更多信息

由于您自己构建了这些库,您将知道它们是否在最终链接阶段使用了
-rpath
-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\u LIBRARY\u路径
为空。真奇怪

也许您在soname上为libjson添加了前缀“lib/?i、 e.
readelf
命令是否用于SONAME返回

lib/libjson_linux-gcc-4.4.6_libmt.so
而不仅仅是

libjson_linux-gcc-4.4.6_libmt.so
另外,通过运行

readelf -d my_progam | grep NEEDED
可能是因为您将其传递给gcc的方式,“lib/”前缀在这里。如果是这样的话,那么如果您使用@enobayram给出的gcc命令,那么它将公平竞争,也就是说,它将无法找到libjson

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

编辑

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

编辑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免费 软件Fou