6

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

因此,我编写了一个小程序来向我展示库间依赖关系并生成要链接的库的顺序。它从nm中读取已定义的('T'、'B' 等)和未定义的符号('U')并从'未定义的符号列表'。现在它为每个未定义的符号确定解析它的库。

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

如果它们真的存在,我根本无法链接......那么在分析 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
4

2 回答 2

6

链接具有循环依赖关系的库的另一个选项是为此使用特殊的链接器选项。男人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.

不过,消除循环依赖总是更干净。

于 2011-01-24T12:29:17.270 回答
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 作为普通目标文件简单地引用。

请注意,这样做可能会干扰链接器丢弃静态库中未引用部分的能力(我相信,通常这是在 .a 中的 .o 文件级别完成的)。如果您使用所有或大部分这些库,这可能不是问题。但是,如果代码内存是一个问题,您可能需要考虑在函数级别自动丢弃未使用的代码。如果这样做,请仅在最后的链接阶段通过--gc-sections-s如果需要调试,请避免这样做!)。此外,现代 gcc 似乎不需要与系统库进行静态链接。

于 2011-01-24T08:27:00.560 回答