【问题标题】:How to determine inter-library dependencies?如何确定库间依赖关系?
【发布时间】:2011-06-14 08:46:19
【问题描述】:

我的项目由几个静态库组成,它们在最后一步中链接在一起。现在我遇到了问题,link order of the library is important(否则我得到一个未定义的符号链接器错误)。有时我会遇到问题,我必须重新排序链接库(-lcommon -lsetup -lcontrol 等)。目前这是一个愚蠢的试验和错误:重新排序、编译、检查错误、重新排序、编译等等。

所以我编写了一个小程序来显示库间依赖关系并生成要链接的库的顺序。它从nm 中读取已定义的('T'、'B' 等)和未定义的符号('U')并删除 weak symbols('w'、'W'、'v' 和 'V' ) 来自“未定义的符号列表”。现在它为每个未定义符号确定解析它的库。

但是我的程序显示了循环依赖...我的错误是什么?

如果它们真的存在,我根本无法链接...所以在分析 nm 输出时我错过了什么?还是分析 nm 输出不是获取这些依赖项的方法?

libcommon.a:
         U _ZN15HardwareUnit23GetHardwareSerialNumberEv
libhardware.a:
00000484 T _ZN15HardwareUnit23GetHardwareSerialNumberEv
libsecurityaccess.a:
         U _ZN15HardwareUnit23GetHardwareSerialNumberEv
---
libhardware.a:
         U _ZN21ApplicationProfile26GetApplicationSettingsPathERK7QString
libsecurityaccess.a:
00004020 T _ZN21ApplicationProfile26GetApplicationSettingsPathERK7QString
         U _ZN21ApplicationProfile26GetApplicationSettingsPathERK7QString

【问题讨论】:

    标签: c++ gcc ld undefined-symbol nm


    【解决方案1】:

    链接具有循环依赖关系的库的另一个选项是为此使用特殊的链接器选项。男人ld:

       -( archives -)
       --start-group archives --end-group
           The archives should be a list of archive files.  They may be either
           explicit file names, or -l options.
    
           The specified archives are searched repeatedly until no new
           undefined references are created.  Normally, an archive is searched
           only once in the order that it is specified on the command line.
           If a symbol in that archive is needed to resolve an undefined
           symbol referred to by an object in an archive that appears later on
           the command line, the linker would not be able to resolve that
           reference.  By grouping the archives, they all be searched
           repeatedly until all possible references are resolved.
    
           Using this option has a significant performance cost.  It is best
           to use it only when there are unavoidable circular references
           between two or more archives.
    

    但消除循环依赖总是更干净。

    【讨论】:

    • 有没有办法确定哪些“循环依赖”会破坏编译,哪些不会?
    • 链接器会告诉您它无法解析的符号名称。
    • 是的,这就是我现在的做法(当不使用“组选项”时——效果很好,谢谢!!)。我编译,重新排序库列表并遇到下一个链接器错误。如果我能够提前计算依赖关系,我会在编译之前创建库顺序,而不必通过反复试验来完成。 (目前大约有 20 个库,每个库都依赖于其他模块)
    • 不确定是否有自动化工具。脚本可以为每个 .a nm 执行其未解析符号列表,然后找到提供符号定义的 .a 并注意该依赖关系。然后,您可以从依赖项注释中绘制图表。
    • 我在我的问题中描述了一个类似的脚本/程序,但 'nm' 的输出在可以由链接器解决的循环依赖项和其他会产生链接器错误的循环依赖项之间没有区别。因此这个输出是无用的 - 我在哪里可以获得更详细的信息?
    【解决方案2】:

    如果你真的有一个静态库的循环依赖链(这在你的粘贴中并不清楚;你只显示了一个非循环依赖),有两种选择:

    1. 以某种方式移除循环依赖;例如,您可以确保 libcommon 不引用 libpthardware 中的符号。
    2. 从 .a 库中提取单个 .o 文件,然后直接链接它们。那么链接顺序就不再重要了。

    在 2. 的情况下,您可能会发现使用部分链接比创建静态库更有帮助。在使用 GNU bintools 的系统上,这可以通过调用类似的东西来完成:

    ld -r -o libfoo.o foo.o bar.o
    

    这样做的效果是将 foo.o 和 bar.o 合并到一个 .o 文件中。顺序无关紧要。然后,您可以在最后的链接步骤中将 libfoo.o 作为普通对象文件简单地引用。

    请注意,这样做可能是interfere with the linker's ability to discard unreferenced portions of the static library(我相信,通常这是在 .a 中的 .o 文件级别完成的)。如果您使用所有或大部分这些库,这可能不是问题。但是,如果代码内存是一个问题,您可能需要查看automatically discarding unused code at the function level。如果这样做,请仅在 final 链接阶段传递 --gc-sections-s(如果需要调试,请避免这样做!)。此外,现代 gcc 似乎不需要与系统库进行静态链接。

    【讨论】:

    • 非常感谢。这可以解决症状 - 但最后我会对库之间的依赖关系感兴趣。为什么 nm 输出显示循环依赖 - 但链接成功??
    • 不确定 - 在我的实验中,我发现具有循环依赖关系的库的某些排序确实成功链接,但我不确定为什么。我将您的问题读为询问如何处理这种情况,但如果您更想知道它为什么成功,我建议您构建一个最小的测试用例(应该相当简单)并明确提交一个问题,询问它为什么成功.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    • 2018-05-17
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多