【问题标题】:how do I always include symbols from a static library?如何始终包含静态库中的符号?
【发布时间】:2009-11-19 12:43:03
【问题描述】:

假设我有一个静态库 libx.a。如何让这个库中的一些符号(不是全部)始终出现在我与我的库链接的任何二进制文件中?原因是我需要这些符号通过 dlopen+dlsym 可用。我知道 --whole-archive 链接器开关,但它强制库存档中的所有目标文件链接到生成的二进制文件中,这不是我想要的......

到目前为止的观察(CentOS 5.4,32 位)(upd:这一段是错误的;我无法重现这种行为)

ld main.o libx.a

会愉快地去除所有未引用的符号,而

ld main.o -L. -lx

将链接整个库。我想这取决于使用的 binutils 版本,但是,较新的链接器将能够从静态库中挑选单个对象。

另一个问题是如何在Windows下达到同样的效果?

提前致谢。任何提示将不胜感激。

【问题讨论】:

    标签: c windows linux


    【解决方案1】:

    假设你有一个项目,它在同一个文件夹中包含以下三个 C 文件;

    // ---- jam.h
     int jam_badger(int);
    
    // ---- jam.c
     #include "jam.h"
     int jam_badger(int a)
     {
       return a + 1;
     }
    
     // ---- main.c
     #include "jam.h"
     int main()
     {
       return jam_badger(2);
     }
    

    然后你用像这样的 boost-build bjam 文件来构建它;

    lib jam : jam.c <link>static ;
    
    lib jam_badger : jam ;
    
    exe demo : jam_badger main.c ;
    

    你会得到这样的错误。

    undefined reference to `jam_badger'
    

    (我在这里使用了 bjam,因为文件更容易阅读,但你可以使用任何你想要的东西)

    删除“静态”会生成一个工作二进制文件,就像将静态添加到另一个库一样,或者只使用一个库(而不是在另一个库中进行愚蠢的包装)

    发生这种情况的原因是因为 ld 足够聪明,可以只选择存档中实际使用的部分,在这种情况下,它们都没有。

    解决方案是用 -Wl,--whole-archive 和 -Wl,--no-whole-archive 包围静态存档,就像这样;

    g++ -o "libjam_candle_badger.so" -Wl,--whole-archive libjam_badger.a Wl,--no-whole-archive
    

    不太确定如何让 boost-build 为您执行此操作,但您明白了。

    【讨论】:

    • 您是否偶然知道如何通过 Apple Xcode 构建设置执行此操作? Xcode 为自己构建命令行。使用它的“构建设置”表单,您可以修改它的工作方式,从而间接引入链接器标志,另外您可以添加自己的“其他链接器标志”,但我认为它们不会“环绕”特定输入文件/静态库。
    【解决方案2】:

    第一件事:ld main.o libx.a 没有构建有效的可执行文件。一般来说,您应该永远使用ld 直接链接任何内容; 总是使用正确的编译器驱动程序(在这种情况下为gcc)。

    另外,"ld main.o libx.a""ld main.o -L. -lx" 应该完全等价。我很怀疑你实际上从这两个命令中得到了不同的结果。

    现在回答您的问题:如果您希望从您的a.out 导出foobarbaz,请执行以下操作:

    gcc -Wl,-u,foo,-u,bar,-u,baz main.o -L. -lx -rdynamic
    

    更新:
    您的陈述:“我想包含的符号仅在库内部使用”没有多大意义:如果符号在库内部,为什么要导出它们?如果有其他东西使用它们(通过 dlsym),那么它们不是库内部的——它们是库公共 API 的一部分。

    您应该澄清您的问题并解释您真正想要达到的目标。提供示例代码也不会受到伤害。

    【讨论】:

    • 1.确实,我现在无法直接重现 -l 和指定库之间的区别。也许我当时做错了什么...... 2.虽然 -u 看起来像一个解决方案,但要使用它,我需要在构建二进制文件时知道“额外”符号列表。我想“隐藏”这些依赖项(我想包含的符号仅供库内部使用)。
    【解决方案3】:

    我会先将那些你总是需要的符号拆分到一个单独的库中,只保留libx.a 中的可选符号。

    【讨论】:

    • 似乎是最简单、最实用的实现目标的方法,但我相信 OP 想要一个更优雅的解决方案 :)
    • @MottiShneor:简单实用就是优雅。 ;-) 天哪,这一定是我最古老的 SO帖子之一... :-D
    • 我认为应该有一个链接器标志,比如 -whole-archive 或类似的东西。我来这个问题和答案是因为我现在遇到了相反的问题。我的静态库的符号不会“通过”我的 Xcode 框架(这是一种 dylib),我不明白为什么。
    【解决方案4】:

    获取您需要包含的符号的地址。

    如果 gcc 的优化器无论如何都会消除它,请使用此地址做一些事情 - 应该足够了。

    【讨论】:

    • 谢谢,但我已经想到了这个技巧;我想知道是否有干净的方法可以做到这一点。
    • @kolubsa:我不认为这是一种黑客行为......您需要以某种方式引用这些符号以使链接器将它们拉入。
    • @qrld 是的,但是这样我将不得不让符号在它们当前不可见的某些地方可见(它们只是位于单独的目标文件中......)。
    • @kolbusa 我没明白。如果这些符号不可见,dlsym() 找不到它们,因此它们必须可见。
    • @qrld 我的意思是我需要将这些地址操作放入一个函数中,该函数a)公开可见并且b)总是被调用。我确实有这样的功能,但我的意思是从代码模块化的角度来看,把这样的代码放在那里没有多大意义......
    猜你喜欢
    • 2018-12-16
    • 2021-07-29
    • 1970-01-01
    • 2012-07-16
    • 2023-03-21
    • 2011-11-07
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多