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

Nic*_*lle 7 c++ ld static-libraries

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

文件X.hpp:

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

struct Y {
   Y (X const &) {}
};
Run Code Online (Sandbox Code Playgroud)

文件X.cpp:

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

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

X const X::s_x;
Run Code Online (Sandbox Code Playgroud)

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

#include "X.hpp"

int main ()
{
     (void)X::s_x;  // (1)
     X x = s_x;     // (2)
     Y y = s_x;     // (3)
 }
Run Code Online (Sandbox Code Playgroud)

只有(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
Run Code Online (Sandbox Code Playgroud)

ser*_*rvn 5

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

这里有一些解决方案:

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