Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 链接具有依赖项的动态库_Gcc_Dll_Dependencies_G++ - Fatal编程技术网

Gcc 链接具有依赖项的动态库

Gcc 链接具有依赖项的动态库,gcc,dll,dependencies,g++,Gcc,Dll,Dependencies,G++,考虑以下场景: 共享库libA.so,没有依赖项 共享库libB.so,其依赖项为libA.so 我想编译一个与libB链接的二进制文件。 我应该只使用libB链接二进制文件还是使用libA链接二进制文件 有没有办法只与直接依赖项链接,让运行时从依赖项中解析未解析的符号 我担心库libB实现将来可能会改变,引入其他依赖项(例如libC、libD、libE)。我会有问题吗 换言之: libA文件:a.cpp a.h libB文件:b.cpp b.h 主要程序文件:main.cpp 当然,b

考虑以下场景:

  • 共享库libA.so,没有依赖项
  • 共享库libB.so,其依赖项为libA.so
我想编译一个与libB链接的二进制文件。 我应该只使用libB链接二进制文件还是使用libA链接二进制文件

有没有办法只与直接依赖项链接,让运行时从依赖项中解析未解析的符号

我担心库libB实现将来可能会改变,引入其他依赖项(例如libC、libD、libE)。我会有问题吗

换言之:

  • libA文件:a.cpp a.h
  • libB文件:b.cpp b.h
  • 主要程序文件:main.cpp
当然,b.cpp包括a.h,main.cpp包括b.h

编译命令:

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

我不能使用第一个选项。链接器抱怨库libA中未解析的符号。但我觉得有点奇怪

非常感谢

--更新评论:

当我链接二进制文件时,链接器将尝试解析main和libB中的所有符号。但是,libB具有来自libA的未定义符号。这就是链接器对此抱怨的原因

这就是为什么我也需要和libA联系。 然而,我找到了一种忽略共享库中未解析符号的方法。 看起来我应该使用以下命令行来执行此操作:

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
不应用于此目的。强制在给定目录中找到库是很有用的。
-未解析符号
方法看起来更好


再次感谢。

看来你已经完成了大部分工作。你的调查做得很好。让我们看看我能不能帮你弄清楚背后的原因

下面是链接器正在做的事情。当你链接你的可执行文件('main'在上面)时,它有一些未解析的符号(函数和其他东西)。它将查找下面的库列表,试图解析未解析的符号。在此过程中,它发现一些符号是由libB.so提供的,因此它注意到它们现在由这个库解析

但是,它还发现其中一些符号使用了在可执行文件中尚未解析的其他符号,因此它现在也需要解析这些符号。如果不链接libA.so,您的应用程序将不完整。一旦它链接到libA.so,所有符号都被解析,链接就完成了

如您所见,在共享lib中使用
-未解析符号并不能解决问题。它只是将其延迟,以便在运行时解析这些符号。这就是
-rpath
的作用:指定要在运行时搜索的库。如果这些符号无法解析,那么您的应用程序将无法启动

弄清楚库依赖关系不是一件容易的事,因为一个符号可以由多个库提供,并且可以通过与其中任何一个库进行链接而得到满足


这里还有对该过程的另一种描述:

对于仅具有直接依赖关系的动态链接,您可以根据需要使用
-Wl,--as-needed
并在
-Wl,--as-needed
之后添加libs

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)
set(CMAKE_EXE_LINKER_FLAGS    "-Wl,--as-needed ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}")
如果使用cmake,则可以添加以下行以仅包含直接依赖项:

$ 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)
set(CMAKE_EXE_LINKER_FLAGS    "-Wl,--as-needed ${CMAKE_EXE_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}")
另一个选择是使用


如果您将
g++
调用更改为
libtool--mode=compile g++
以编译源代码,然后
libtool--mode=link g++
以在
libB
上创建应用程序,那么
libA
将自动链接。

这是一篇有趣的帖子-我也用它来敲我的头,但我认为你在这里漏掉了一点

想法如下,对吗

main.cpp =(depends)=> libB.so =(depends)=> libA.so
我们进一步考虑…

  • 在a.cpp中(仅在那里)定义一个类/变量,我们称之为“symA”
  • 在b.cpp中(仅在这里)定义了一个类/变量,我们称之为“symB”
  • symB使用symA
  • main.cpp使用符号
现在,libB.so和libA.so已按照上述方式编译。在这之后,您的第一个选项应该有效,即:

g++ main.cpp -o main -I. -L. -lB
我想你的问题源于这样一个事实

在main.cpp中,您还可以参考symA

我说得对吗

如果在代码中使用符号,则必须在.so文件中找到该符号

交互引用共享库(即创建API)的整体思想是,深层中的符号是隐藏的(想想剥皮的洋葱),不使用。
.. i、 e.不要在main.cpp中引用symA,而只引用symB(让symB只引用symA)。

我知道这是很久以前的事了,我忘了将其标记为已解决。非常感谢你们的回答。]谢谢你们提出的令人惊讶的问题,以及一个合适的答案!我有几乎完全相同的情景。我正在尝试将openCV共享对象包装到自定义共享对象中。假设C.so是我的自定义so,CV.so是一些openCV so。我已经成功地将C.so链接到了CV.so,我想将main.cpp(你明白了!)链接到C.so,但是除了使用C.so中的对象之外,main.cpp还使用了一个在CV.so中定义的对象“CV::Mat”。。在这种情况下,要运行main.cpp,是否需要链接aga