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

时间:2019-01-10 10:27:59

标签: c++ linux gcc

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

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

我的理解是,由于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 个答案:

答案 0 :(得分:1)

请参见here 了解与静态库的链接,尤其是默认情况下,只有链接器需要时,静态库中的目标文件libx.a(p.o)才会被提取并链接到程序中。

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

因此,如果您在编译的源文件g_register_derive中定义p.cppp.o并存档为libx.a(p.o),并且您的应用程序需要链接 libx.a(p.o) 出于任何原因,默认情况下, 1 g_register_derive变为 在程序中定义。

如果将g_register_derive的定义移至 q.cpp(已编译并存档为libx.a(q.o))和您的应用程序 出于某种原因不需要需要链接libx.a(q.o),然后g_register_derive 在您的程序中未定义。


[1]使用非默认编译和链接选项,您可以删除定义 程序中的未使用符号。请参阅the Stackoverflow tag wiki about static-libraries和接受的答案。