alm*_*now 7 c++ linker shared g++
我已经制作了一个程序,它使用了两个共享库(我编译过)并且放置如下:
/home_directory_where_I_compile_and_run_everything
-->/lib/libjson_linux-gcc-4.4.6_libmt.so
-->/lib/libre2.so.0
Run Code Online (Sandbox Code Playgroud)
当我编译我的程序时,我将这些库的相对位置传递给链接器,如下所示:
g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/libre2.so.0
Run Code Online (Sandbox Code Playgroud)
并且它编译得很好,但是在运行程序时它无法找到libre2.so,如果我用ldd检查它,这是发生了什么:
....
lib/libjson_linux-gcc-4.4.6_libmt.so (0x00007f62906bc000)
libre2.so.0 => not found
....
Run Code Online (Sandbox Code Playgroud)
显然,它确实承认libjson上的路径是相对的,但它在libre2.so.0上没有这样做(它修剪了所有路径,只留下了libre2.so.0)
有人能告诉我为什么会这样吗?
另外,有没有办法通过g ++参数修改它?
最好.
*更新*哇看看这个!我已经将libre2.so.0的名称更改为stuff.so,然后尝试编译基本相同,如下所示:
g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so
Run Code Online (Sandbox Code Playgroud)
它无论如何都会失败; 不仅它失败了,它失败了,因为它找不到"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]
Run Code Online (Sandbox Code Playgroud)
现在,如果我可以将[libre2.so.0]改为[lib/libre2.so.0],那就没关系了.
*更新#3*
正如@troubadour发现:
当可执行文件与具有DT_SONAME字段的共享对象链接时,则在运行可执行文件时,动态链接器将尝试加载由DT_SONAME字段指定的共享对象,而不是使用为链接器指定的文件名.
这就是为什么它适用于libjson .....所以而不是libre2.so.0.(libjson .....所以没有SONAME的条目).
我终于找到了我正在寻找的确切问题:
有没有办法告诉gcc链接器忽略共享库文件上的SONAME条目,而是链接到特定的文件路径?
Tro*_*our 11
我将首先回答您问题的第二部分,即为什么重命名libre2.so.0没有达到预期效果.
运行可执行文件时传递给链接器的文件名无关紧要(除非-soname在构建库时未能提供- 请参见下面的第二个编辑).依赖性来自所谓的"soname".如果您readelf在库上运行该命令,则可以确定其名称,例如.
readelf -d libre2.so.0 | grep SONAME
Run Code Online (Sandbox Code Playgroud)
重命名文件无关紧要.上面命令的结果仍然会给你相同的soname,因此程序仍然无法找到"libre2.so.0".
至于问题的原始部分,这一切都取决于图书馆是否拥有RPATH或RUNPATH内置了它们和/或LD_LIBRARY_PATH环境变量的内容是什么.这些是运行时链接程序(ld.so)将用于查找共享库的内容.尝试
man ld.so
Run Code Online (Sandbox Code Playgroud)
欲获得更多信息.
由于您自己构建了库,因此您将知道它们是否在最终链接阶段使用了-rpath或-runpath选项.或者,readelf再次使用,例如.
readelf -d libre2.so.0 | grep RPATH
readelf -d libre2.so.0 | grep RUNPATH
Run Code Online (Sandbox Code Playgroud)
我怀疑上面两个命令都不会返回任何内容.
我的猜测是你的当前目录中LD_LIBRARY_PATH允许运行时链接器找到lib/libjson_linux-gcc-4.4.6_libmt.so而不是libre2.so.0.我注意到你回复了我对你的问题的评论,说你LD_LIBRARY_PATH是空的.那很奇怪.
也许你已经以某种方式在libjson的soname上获得了前缀"lib /"?即readelf,SONAME 的命令返回
lib/libjson_linux-gcc-4.4.6_libmt.so
Run Code Online (Sandbox Code Playgroud)
而不仅仅是
libjson_linux-gcc-4.4.6_libmt.so
Run Code Online (Sandbox Code Playgroud)
此外,通过运行检查程序在soname方面需要什么
readelf -d my_progam | grep NEEDED
Run Code Online (Sandbox Code Playgroud)
也许"lib /"前缀在那里,因为你将它传递给gcc的方式.如果是这样,那么如果你使用@enobayram给出的gcc命令,那么它将调整游戏区域,即它也将无法找到libjson.
建立的第一件事是不是它为什么没有发现libre2.so.0但它是如何被管理找到libjson.如果你尝试从不同的目录运行你的可执行文件它仍然可以工作,或者它现在也失败了libjson?或者,如果您将libre2.so.0复制到可执行文件旁边,那会改变什么吗?
编辑
一个在Fedora的论坛发帖建议ld.so的Fedora的版本有当前目录作为一个内置的搜索路径.虽然我无法对此进行验证,但它可以解释为什么你在选择任何库时,因为你的案例中没有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 Free Software Foundation,Inc.
根据GNU自由文档许可证1.3版或自由软件基金会发布的任何更新版本的条款,允许复制,分发和/或修改本文档; 没有不变的部分,没有封面文本,没有封底文本.许可证的副本包含在标题为"GNU自由文档许可证"的部分中.
所以,你评论中的理论是正确的.如果没有-soname当库建立在明确指定则不存在SONAME在共享对象和可执行文件所需要的领域简单地给到,在你的情况下,包含领先"的lib /"链接的文件名.