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

45

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

// 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并没有改变情况。 - Martin
2
静态变量s可以在main函数之前的任何地方初始化,直到该翻译单元中的某个函数被调用为止...这意味着根据标准,从未实例化s是有效的,只要该翻译单元中没有调用任何函数。 - K-ballo
@K-ballo 但是构造函数S::S()确实是从定义S的翻译单元中调用的。或者你在评论中漏掉了什么? - Martin
2
你忽略了一个事实,即一个完全符合规范的实现可以在调用该翻译单元中的第一个函数之前实例化其全局变量,在你的情况下从未调用... - K-ballo
你可以在Bash上创建一个脚本来选择你想要使用的库。 - Mihai8
显示剩余2条评论
4个回答

60

使用 --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可见性?我在考虑标记一些函数以强制执行。请参阅https://gcc.gnu.org/wiki/Visibility - csl
6
用户应该在末尾添加-Wl,-no-whole-archive。正如man ld所说:“其次,在归档文件列表之后不要忘记使用-Wl,-no-whole-archive,因为gcc会将它自己的归档文件列表添加到链接中,而您可能不希望这个标志也影响那些归档文件。” - Sasha

8

6
我更喜欢其他答案,但这里有另一个“解决方案”。
  1. Use the ar command to extract all the .o files from the archive.

    cd mylib ; ar x /path/to/libmylib.a
    
  2. Then add all those .o files to the linker command

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

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

Alex,我一直在尝试在Android的NDK和CMake中使用whole-archive,但一直没有成功。我认为使用链接器的-u标志是我的唯一选择。你会如何在NDK上实现这个呢?还有其他在Android上实现这个的替代方法吗?(我不能使用LOCAL_WHOLE_STATIC_LIBRARIES,因为我正在使用CMake而不是android.mk - Jaime Ivan Cervantes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接