【问题标题】:G++ Dynamic Library Linking IssuesG++ 动态库链接问题
【发布时间】:2014-04-18 13:04:31
【问题描述】:

我正在尝试将多个动态库链接到一个应用程序中,但遇到了 g++ 问题。

考虑:

  • libA.so
  • libB.so 依赖于 libA.so
  • libC.so 依赖于 libB.so
  • 应用程序 D 直接依赖于 libC.so

如果我尝试将应用程序 D 仅链接到 libC.so,我会得到 A 和 B 中符号的未解析符号。我觉得编译器应该能够弄清楚,当我使用 intel 编译器时,确实如此。然而,G++ 无法找出链接。我希望我的库和可执行文件只需要链接到他们直接需要的东西,而不是试图预测他们使用的库需要什么。

当 libA.so 链接到静态库时,我也遇到了问题,当我尝试编译可执行文件时,我从 libA.so 应该使用的静态库中得到未解析的符号。

我看到很多其他人问过这个问题和类似问题并得到了各种各样的答案 (Linking with dynamic library with dependencies),但答案都相当模糊,经常相互矛盾,而且非常类似于“继续卡车运输”和 RTFM”。

我觉得链接顺序很重要。怎么会,我怎么知道链接的顺序?

更新

我相信正在发生的事情类似于 libA.so 包含两个函数(AA 和 AB)。 libB.so 需要 AA,libC.so 需要 AB。当 libB.so 被链接时,g++ 得到 libA.so,看到只使用了 AA,并删除了 AB。然后当 libC.so 被链接进来时,g++ 看到 libA.so 已经被链接并且不会重新访问它,导致 AB 未定义。我已经看到文档表明静态库以这种方式工作,但是编译器会以同样的方式处理动态库吗?如果是这样,有没有办法解决它?

【问题讨论】:

  • 如果 libC 直接从 libA 引用一个符号,那么 libC 可能应该直接链接到 libA。
  • “但是,G++ 无法识别链接。”您的意思是链接器,而不是 G++
  • "g++得到libA.so,看到只用了AA,就丢掉AB" 再次,G++和它无关,链接器做,但是没有,它不适用于动态库
  • 您使用的是什么版本的 binutils?你得到的错误到底是什么?有没有提到-rpath-link
  • 我的链接器错误类似于“libX.so: undefined reference/symbol fooBar”,其中“fooBar”来自 libX.so 链接到的库之一。这是标准的“您没有使用您正在使用的功能链接到库”链接错误。 libX.so 链接正确,ldd 显示它引用了所需的库,但我从 libX.so 构建的可执行文件会生成链接错误。是的,可执行文件直接链接到它使用的所有内容。问题是当可执行文件链接到 B 和 B 使用 A,但可执行文件不使用 A 所以不直接链接到它。

标签: c++ g++ dynamic-linking


【解决方案1】:

(您没有显示实际的链接器错误,也没有提供关于该问题的足够信息,所以接下来的部分是猜测......)

如果我尝试将应用程序 D 仅链接到 libC.so,我会得到 A 和 B 中符号的未解析符号。

当链接可执行文件时,GNU 链接器会检查所有符号是否可用。您可以使用 --allow-shlib-undefined 将其关闭(告诉 GCC 将其传递给链接器使用 -Wl,--allow-shlib-undefined

最好不要使用该选项,但在这种情况下,链接器需要知道在哪里可以找到libA.solibB.so,以便它可以检查是否可以找到libC.so 所需的符号。您可以使用 -rpath-link 链接器选项来做到这一点

使用 ELF 或 SunOS 时,一个共享库可能需要另一个共享库。当“ld -shared”链接包含一个共享库作为输入文件之一时,就会发生这种情况。

当链接器在做一个非共享的、不可重定位的链接时遇到这样的依赖,它会自动尝试定位需要的共享库并将其包含在链接中,如果没有包含明确的。

因此,您应该能够通过使用 -Wl,-rpath-link,. 告诉链接器在当前目录 (.) 中查找 libC.so 所依赖的库来解决问题。

我觉得链接顺序很重要。怎么会,我怎么知道链接的顺序是什么?

是的,链接顺序很重要。您应该按照明显的顺序链接 ;-) 如果文件 foo.cc 依赖于库,则将该库稍后放在链接器行中,因此将在处理 foo.cc 之后 找到它,如果该库依赖于稍后放置的另一个库,因此它将在需要它的早期库之后处理。如果您将库放在链接行的开头,则链接器没有任何未解析的符号可供查找,因此不需要链接到该库。

【讨论】:

  • 你能澄清一下 -rpath 和 -rpath-link 之间的区别吗?此外,看起来它们都只是指定了动态库的运行时搜索路径。这与设置 LD_LIBRARY_PATH 有何不同?
  • @mjr: -rpath 在可执行文件中记录一个路径,因此会影响 runtime 链接器路径(与 LD_LIBRARY_PATH 相关),而 -rpath-link 不会,它只是告诉链接器(链接时链接器,而不是运行时链接器)在哪里查找库,并且不会更改可执行文件,它对运行时搜索路径没有任何影响..
【解决方案2】:

您需要明确指定您直接使用的所有库。

在静态链接期间,不使用加载的.so的依赖;链接主程序时,所有符号都必须在主程序本身、命令行指定的静态库或命令行指定的共享库中找到。

这是你得到错误的地方。

程序执行时,会加载动态库的依赖关系,以便解析来自其他共享库的引用。 到程序运行时,它实际上可能(动态地)链接到不同版本的共享库。此不同版本可能具有不同的依赖项,因此主程序不得依赖作为依赖项加载的附加库集。

这就是静态链接器提前阻止您的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-24
    • 2012-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多