在链接静态库时初始化静态对象

时间:2011-09-07 00:42:14

标签: c++ static-libraries ld

在另一个共享库中声明的静态对象的初始化有哪些规则?例如,请考虑以下事项:

文件X.hpp:

struct X {
   X ();
   static X const s_x;
};

struct Y {
   Y (X const &) {}
};

文件X.cpp:

#include "X.hpp"
#include <iostream>

X::X ()
{
   std::cout << "side effect";
}

X const X::s_x;

我在静态库libX.a中编译了X.cpp,并尝试将以下可执行文件链接到它(文件main.cpp):

#include "X.hpp"

int main ()
{
     (void)X::s_x;  // (1)
     X x = s_x;     // (2)
     Y y = s_x;     // (3)
 }

只有(1)或(2),没有任何反应。但是如果我添加(3),则初始化静态对象(即打印“副作用”)。 (我使用gcc 4.6.1)。

有没有办法预测会发生什么?

我不明白指令(2)如何不强制X::s_x对象是默认构造的,而(3)则不行。

编辑:构建命令:

g++ -c X.cpp
g++ -c main.cpp
ar rcs libX.a X.o
g++ -o test main.o -L. -lX

1 个答案:

答案 0 :(得分:5)

默认情况下,在许多平台上,如果您的程序没有引用静态库中给定目标文件的任何符号,则将删除整个目标文件(包括静态初始化程序)。所以链接器忽略了libX.a中的X.o,因为它看起来像是未使用过。

这里有一些解决方案:

  1. 不要依赖静态初始化器的副作用。这是最便携/最简单的解决方案。
  2. 通过以编译器无法看到的方式引用虚拟符号(例如将地址存储到外部可见的全局中),对每个文件引入一些假依赖。
  3. 使用某些特定于平台的技巧来保留有问题的对象。例如,在Linux上,您可以使用-Wl,-whole-archive a.o b.a -Wl,-no-whole-archive