【问题标题】:object file from .a not included in .so.a 中的目标文件未包含在 .so 中
【发布时间】:2010-08-11 15:09:03
【问题描述】:

我创建了一个 .c 文件,该文件与大约 300 个其他 .c 文件一起转换为 .o 文件,并包含在 .a 静态库中。该库与许多其他库一起用于创建.so 动态库。在使用nm 分析.a.so 文件时,我发现由于某种原因,.c 文件中定义的符号出现在.a 文件中,但不在.so 文件中。我想不出为什么会发生这种情况。有人可以帮我吗?用于创建这两个二进制文件的步骤是:

gcc -fvisibility=hidden -c foo.c -o foo.c.o
ar cr libbar.a foo.c.o ...
gcc -fvisibility=hidden -fPIC -o libfinal.so libbar.a x.o y.a ... 

我在这里指定可见性隐藏的原因是我只想公开几个选定的符号。为了从foo.c 中公开符号,我指定了可见性属性,以便标头foo.h 中的函数签名看起来像:

extern int _____attribute_____ ((visibility ("default"))) func();

编辑:命令nm libbar.a | grep Ctx 给出:

000023c5 T CtxAcquireBitmap
000026e9 T CtxAcquireArray
00001e77 T CtxCallMethod

但是,nm libfinal.so | grep Ctx 没有显示任何内容。

更新:找到另一个post,它讨论了--whole-archive 选项的用法。此外,偶然发现了--export-dynamicoption,它显然告诉链接器保留未引用的符号。进一步调查。

【问题讨论】:

  • 能否请您向我们展示一些nm 的输出,以明确区别?而且我们可以看到这些符号的“类型”消失了。
  • -fPIC 选项仅在编译时生效,在链接时不生效。因此,除非您在编译时使用-fPIC,否则您最终会得到一个非PIC 共享库。这意味着每个实例将使用更多内存(大多数页面无法共享),甚至在某些系统(如 x86_64)上也无法运行。
  • 用信息更新了问题。
  • @sylvainulg 给出的answer 告诉你出了什么问题。如果您没有在任何地方使用任何可见性属性,您仍然会遇到同样的问题。
  • 那么我如何包含那些打算被导出以供另一个.so 或可执行文件使用但在.so 中未引​​用的符号?不能使用导出文件。

标签: c linux gcc shared-libraries


【解决方案1】:

尝试使用--whole-archive链接器选项在链接时将所有对象包含到您的共享库中

gcc -o libfinal.so -Wl,--whole-archive libbar.a x.o y.a -Wl,--no-whole-archive

来自man ld

--整体存档
对于命令行中在 --whole-archive 选项之后提到的每个存档,将存档中的每个目标文件包含在 链接,而不是在存档中搜索所需的目标文件。这通常用于将存档文件转换为共享文件 库,强制每个对象都包含在生成的共享库中。此选项可以多次使用。

在 gcc 中使用此选项时的两个注意事项:首先,gcc 不知道此选项,因此您必须使用 -Wl,-whole-archive。 其次,不要忘记在你的档案列表之后使用 -Wl,-no-whole-archive,因为 gcc 会将它自己的档案列表添加到你的 链接,您可能不希望此标志也影响这些。

【讨论】:

  • 嗯。好点子。尽管我的项目使用CMake,但在两个标签中包含这个.a 会很复杂。必须想办法在项目限制范围内做到这一点。谢谢。
  • 我个人会谨慎使用 --whole-archive(也就是说,使用 objdump 和 nm 仔细检查输出),因为我不确定如果链接到“标准”,链接器会做什么库已尝试。
  • 在 --whole-archive 和 --no-whole-archive 之间只包含这个静态库应该是安全的,不需要包含标准库
【解决方案2】:

据我所知,在针对 .a 进行编译时,gcc 只会提取其他模块引用的对象。如果您的意图是将 .a 的全部内容包含在 .so 中,那么简单的“使用 libbar.a 中的内容将 x.c 编译/链接到 libfinal.so”不是您想要的。

【讨论】:

  • 是的,就是这样。来自我系统上的 gcc 4.3.2 手册页-“链接器通过扫描归档文件来处理归档文件,这些成员定义了迄今为止已被引用但未定义的符号。但如果找到的文件是普通的目标文件, 它以通常的方式链接。”
  • 我很想说生成 .a 和 .so 的最常见方法是从一组 .o 文件中构建它们,而不是从另一个中构建一个一。
【解决方案3】:

在我的主文件中为所需符号创建虚拟引用并没有解决问题。引用的符号出现在带有U(=未定义)标记的二进制转储(使用nm 获得)中。我设法通过在创建.so 文件时直接链接目标文件而不是首先将其包含在.a 库中来解决问题。由于这些函数被标记为extern,它们被包含在.so 中,即使它们没有在库中被引用。如果他们没有被标记为extern,他们就不会像 sylvainulg 所说的那样被包括在内。

感谢 Dmitry 指出 --whole-archive 选项。我不知道存在这样的选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多