考虑以下情形:
- 共享库libA.so,无依赖性。
- 共享库libB.so,与libA.so作为其依赖。
我想编译与libB链接的二进制文件。 我应该libB链接二进制单独或与力霸要么?
有没有什么办法只能与直接依赖关系链接,让悬而未决的符号从依赖运行系统的分辨率?
我担心的是,该库libB实现可能在将来改变,引入其他依赖(libC中,LIBD,libE例如)。 我是不是要和的问题?
换一种说法:
- 力霸文件:a.cpp啊
- libB文件:b.cpp BH
- 主程序文件:main.cpp中
当然,b.cpp包括啊和main.cpp中包括BH
编译命令:
g++ -fPIC a.cpp -c
g++ -shared -o libA.so a.o
g++ -fPIC b.cpp -c -I.
g++ -shared -o libB.so b.o -L. -lA
我应该使用哪波纹管的选择?
g++ main.cpp -o main -I. -L. -lB
要么
g++ main.cpp -o main -I. -L. -lB -lA
我不能使用第一个选项。 链接器抱怨从库力霸未解决的符号。 但它听起来有点怪我。
非常感谢。
-更新评论:
当我链接的二进制文件,链接器将尝试解决从主和libB所有符号。 然而,libB是未定义从利巴符号。 这就是为什么链接器抱怨说。
这就是为什么我需要太多与力霸链接。 但是我发现了一个办法忽略从共享库解析的符号。 看起来我应该使用以下命令行来做到这一点:
g++ main.cpp -o main -I. -L. -lB -Wl,-unresolved-symbols=ignore-in-shared-libs
看起来它仍然可以使用-rpath
选项。 不过,我需要一点点更好地理解它。
是否使用时,任何人都知道任何可能存在的缺陷-Wl,-unresolved-symbols=ignore-in-shared-libs
的选择吗?
-更新注释2:
-rpath
不应该被用于此目的。 它是有用的,迫使库在给定的目录中找到。 该-unresolved-symbol
的方法看起来好多了。
再次感谢。
它看起来像你最的方式存在了。 与你的调查做得很好。 让我们来看看,如果我能帮助清理“为什么”背后。
下面是该接头用做。 当您将可执行文件(“主”以上)它有一个尚未解决的一些符号(函数和其他东西)。 它会看不起遵循库的列表,试图解决悬而未决的符号。 一路上,它发现一些符号是由libB.so提供,因此它指出,他们现在通过此库解决。
然而,它也发现一些这些符号的使用尚未解决您的可执行其他符号,所以现在需要解决那些为好。 如果没有对libA.so链接,你的应用程序将是不完整的。 一旦链接对libA.so,所有符号都解决了并且完成了链接。
正如你所看到的,使用-unresolved-symbols-in-shared-libs
,不解决问题。 它只是推迟它,以便这些符号在运行时解决。 这就是-rpath
是:到指定的库文件在运行时进行搜索。 如果这些符号不能再解决,您的应用程序将无法启动。
这不是找出库的依赖,因为符号可以由多个库来提供,并通过对他们中的任何一个连接来满足一件容易的事情。
这里有这个过程的另一种描述: 在GCC为什么的顺序库有时与造成的错误?
对于动态链接只能用直接的依赖,你可以使用-Wl,--as-needed
使用后加入库-Wl,--as-needed
:
gcc main.c -o main -I. -L. -Wl,--as-needed -lB -lA
为了检查有直接的依赖,你应该使用readelf LDD因为LDD也显示了间接的依赖关系。
$ readelf -d main | grep library
0x0000000000000001 (NEEDED) Shared library: [libB.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
LDD也显示了间接的依赖关系:
$ LD_LIBRARY_PATH=. ldd ./main
linux-vdso.so.1 (0x00007fff13717000)
libB.so => ./libB.so (0x00007fb6738ed000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb6734ea000)
libA.so => ./libA.so (0x00007fb6732e8000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb673af0000)
如果你使用的cmake,您可以添加以下行只包括直接依赖关系:
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}")
另一种选择是使用libtool
如果更改g++
调用libtool --mode=compile g++
编译源代码,然后libtool --mode=link g++
来创建应用程序关闭的libB
,然后libA
将被自动链接。
这是一个有趣的帖子 - 我敲我的头,这为好,但我觉得你错过这里的一个点..
这个想法是如下,对不对?
main.cpp =(depends)=> libB.so =(depends)=> libA.so
让我们进一步考虑..
- 在a.cpp(只有那里)你定义一个类/变量,我们称之为“司马”
- 在b.cpp(只有那里)你定义一个类/变量,我们称之为“SYMB”。
- SYMB使用西马
- main.cpp中使用SYMB
现在,如果上述libB.so和libA.so已经编译。 在这之后,你的第一选择应该工作,即:
g++ main.cpp -o main -I. -L. -lB
我猜你的问题的事实,起源
在main.cpp中还指司马
我对么?
如果您在代码中使用符号,那么该符号必须在.so文件发现
回参考间共享库(即创建的API)的整体思想是,在更深的层被隐藏符号(认为剥洋葱的),而不是使用。 ..即不是指司马在main.cpp中,但只SYMB来代替(让SYMB仅指司马)。