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

symbols in static library sometimes got linked into executable, sometimes not

本文关键字:可执行文件 链接 符号 静态      更新时间:2023-10-16

我有一个静态库,它是使用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);
}
}

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

FactoryRegister<Derive> g_register_derive("derive");

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

我的理解是,由于gregister_drive没有被任何代码引用,所以除非提供完整的归档选项,否则不应该将其链接到可执行文件中。

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

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

当然,如果我提供了完整的归档选项,g_register_drive将始终链接到可执行文件中。

请参阅关于静态库的Stackoverflow标记wiki理解与静态库的链接,特别是默认情况下,只有当链接器需要时,静态库中的对象文件libx.a(p.o)才会被提取并链接到程序中。

如果链接器需要链接存档成员libx.a(p.o)以便解析对在该对象文件中定义的符号CCD_ 4的一些先前引用,则也在CCD_ 6中定义的任何其它符号CCD_也链接到程序中-因为它是对象文件的一部分-是否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]使用非默认编译和链接选项,可以删除定义程序中的个未使用的符号。请参阅如何使用GCC和ld删除未使用的C/C++符号?以及被接受的答案。