静态库中的符号有时会链接到可执行文件,有时不会

Posted

技术标签:

【中文标题】静态库中的符号有时会链接到可执行文件,有时不会【英文标题】:symbols in static library sometimes got linked into executable, sometimes not 【发布时间】:2019-01-10 10:27:59 【问题描述】:

我有一个静态库,它是使用 g++ 从 linux 上的许多 cpp 文件生成的。一个头文件包含一个实现工厂模式的类

头文件中的伪代码如下

class Factory

public:
    static Factory& instance();
    Base * create(const std::string& name);
    template<class T>
      void register_class(const std::string& name);


template <class T>
class FactoryRegister

public:
    FactoryRegister(const std::string& name)
    
       Factory::instance().register_class<T>(name);
    

工厂的 cpp 文件有实现。在另一个 cpp 文件 Derive.cpp 中,有一个我想注册到工厂的类。我定义了一个全局变量来做到这一点。代码如下

FactoryRegister<Derive> g_register_derive("derive");

所有这些文件都编译成一个静态库并链接到一个可执行文件。

我的理解是,由于任何代码都没有引用 g_register_derive,因此除非提供了整体存档选项,否则不应将其链接到可执行文件中。

奇怪的是,如果我把 g_register_derive 放在 Derive.cpp 中,这个符号确实没有链接到可执行文件中。但是如果我将 g_register_derive 放在 Factory.cpp 中,它就会链接到可执行文件中。

我用nm验证结果,还有一行代码调用Factory::instance().create("Derive")也可以用来检查g_register_derive是否链接。

当然,如果我提供了整体存档选项,g_register_derive 将始终链接到可执行文件中。

【问题讨论】:

【参考方案1】:

见the *** tag wiki about static-libraries 了解与静态库的链接,尤其是默认情况下,仅当链接器需要时,才会提取静态库中的目标文件libx.a(p.o) 并将其链接到程序中。

如果链接器需要链接存档成员 libx.a(p.o) 以便 解决对该目标文件中定义的符号foo 的某些先前引用, 然后定义在libx.a(p.o) 中定义的任何其他符号bar 也链接到程序中 - 因为它是该目标文件的一部分 - 是否 bar是否被程序引用。

所以,如果你在编译的源文件p.cpp 中定义g_register_derivep.o并归档为libx.a(p.o),您的应用程序需要链接 libx.a(p.o) 出于任何原因,那么默认情况下1g_register_derive 变为 在你的程序中定义。

如果您将g_register_derive 的定义移动到 q.cpp,编译归档为libx.a(q.o),你的应用 不需要出于任何原因需要链接libx.a(q.o),然后g_register_derive 没有在你的程序中定义。


[1] 使用非默认编译和链接选项,您可以删除定义 未使用 符号从您的程序。请参阅How to remove unused C/C++ symbols with GCC and ld? 和接受的答案。

【讨论】:

谢谢,这个问题困扰我好几天了。

以上是关于静态库中的符号有时会链接到可执行文件,有时不会的主要内容,如果未能解决你的问题,请参考以下文章

如何检测二进制/库中的未定义符号?

如何防止静态库中的所有符号加载以及为什么在链接静态库时导出相同.o文件中的其他符号进行测试

避免从 Linux 上的可执行文件中导出符号

Linux学习——动态链接库和静态链接库

使用objdump objcopy查看与修改符号表

程序的编译过程