如何强制 gcc 链接未使用的静态库

Posted

技术标签:

【中文标题】如何强制 gcc 链接未使用的静态库【英文标题】:How to force gcc to link an unused static library 【发布时间】:2012-12-16 11:42:30 【问题描述】:

我有一个程序和一个静态库:

// main.cpp
int main() 

// mylib.cpp
#include <iostream>
struct S 
    S()  std::cout << "Hello World\n";
;
S s;

我想将静态库(libmylib.a)链接到程序对象(main.o),虽然后者不直接使用前者的任何符号。

以下命令似乎不适用于g++ 4.7。它们将运行而不会出现任何错误或警告,但显然libmylib.a 不会被链接:

g++ -o program main.o -Wl,--no-as-needed /path/to/libmylib.a

g++ -o program main.o -L/path/to/ -Wl,--no-as-needed -lmylib

你有更好的想法吗?

【问题讨论】:

@chris 我已经把问题说得更清楚了 -lmylib 不会改变情况 静态 s 可以在 main 之前的任何地方初始化,直到第一次调用该翻译单元中的函数......这意味着根据标准,从不实例化 s 是有效的,因为没有函数来自该翻译单元曾经被调用过。 +1,几周前我遇到了完全相同的情况。我有一些小型库和一个使用所有较小库的较大库(嗯,不一定通过调用它们的方法;它将它们“捆绑”在一起)。最终的应用程序应该使用更大的库以及与之“捆绑”的较小的库,但它们不存在,因为较大的库没有使用它们。我通过在小型库中引入一个虚拟方法并在更大的库中使用它们来解决问题......肮脏的黑客! :\我期待看到这个问题的好答案:) @K-ballo 但构造函数 S::S() 从定义 S 的翻译单元调用的。还是我在您的评论中遗漏了什么? 您错过了这样一个事实,即完全符合的实现可以在调用该翻译单元的第一个函数之前实例化其全局变量,在您的情况下永远不会...... 【参考方案1】:

使用--whole-archive 链接器选项。

在命令行中之后的库不会丢弃未引用的符号。您可以通过在这些库之后添加 --no-whole-archive 来恢复正常的链接行为。

在您的示例中,命令将是:

g++ -o program main.o -Wl,--whole-archive /path/to/libmylib.a

一般来说是:

g++ -o program main.o \
    -Wl,--whole-archive -lmylib \
    -Wl,--no-whole-archive -llib1 -llib2

【讨论】:

有谁知道是否有更好的控制,比如使用 DSO 可见性?我正在考虑标记一些要强制执行的功能。请参阅gcc.gnu.org/wiki/Visibility 用户无论如何都应该在末尾添加-Wl,-no-whole-archive。正如man ld 所说:“第二,不要忘记在你的档案列表之后使用-Wl,-no-whole-archive,因为 gcc 会将它自己的档案列表添加到你的链接中,你可能不希望这个标志影响那些好吧。”【参考方案2】:

最初的建议是“关闭”:

How to force gcc to link unreferenced, static C++ objects from a library

试试这个:-Wl,--whole-archive -lyourlib

【讨论】:

【参考方案3】:

我更喜欢其他答案,但这是另一个“解决方案”。

    使用 ar 命令从存档中提取所有 .o 文件。

    cd mylib ; ar x /path/to/libmylib.a
    

    然后将所有这些 .o 文件添加到链接器命令中

    g++ -o program main.o mylib/*.o
    

【讨论】:

【参考方案4】:

如果静态库中有特定函数被链接器剥离为未使用,但您确实需要它(一个常见示例是 JNI_OnLoad() 函数),则可以强制链接器保留它(当然,所有从此函数调用的代码)。将-u JNI_OnLoad 添加到您的链接命令中。

【讨论】:

Alex,我一直在尝试将 whole-archiveandroid 的 NDK 和 CMake 一起使用,但没有成功,我认为使用链接器的 -u 标志是我唯一的选择。你会如何在 NDK 上这样做?在您知道的 Android 上,还有其他替代方法可以做到这一点吗? (我不能使用LOCAL_WHOLE_STATIC_LIBRARIES ,因为我使用的是CMake而不是android.mk

以上是关于如何强制 gcc 链接未使用的静态库的主要内容,如果未能解决你的问题,请参考以下文章

GCC强制静态库链接未使用的函数变量

强制链接到未使用的共享库

gcc系强制链接静态库(同时有.so和.a)

Android NDK编译如何强制使用libc++.a的静态链接库

如何静态链接到 libstdc++.喜欢升级的GCC的朋友快来看看

未定义弱函数的引用(静态库+ GCC)