C++ 在链接 .o 和链接 .a 文件之间存在差异:不同的行为,为什么?

C++ differ between Linking with .o and with .a file: different behavior, why?

我预计:

linking with .o file, and linking with .a file archived from the .o file, should have no difference.

但事实并非如此。我有 2 个源文件,每个都声明 1class+1 static object+1 函数,还有一个 main.cpp 调用其中一个函数

$cat First.cpp
#include<stdio.h>
struct First{
  First(){printf("First\n");}
};
void f1(){printf("f1\n");}//Not called in main
static First f_obj;

$cat Second.cpp
#include<stdio.h>
struct Second{
  Second(){printf("Second\n");}
};
void f2(){printf("f2\n");}//Not called in main
static Second s_obj;

$cat main.cpp
void f2();
int main()
{
    f2();
    return 0;
}

$g++ -c First.cpp  -fPIC
$g++ -c Second.cpp -fPIC
$ar -rvs libmystatic.a  First.o Second.o
$g++ main.cpp -o MylinkSta -lmystatic -L.
$g++ main.cpp -o MyDirect First.o Second.o

$./MylinkSta
Second
f2

$./MyDirect
Second
First
f2

所以你可以看到

(1) The running result of MylinkSta doesn't construct 'First' object, but MyDirect does.

(2) While the 'Second' object is always constructed.

我真的看不出链接 2 个“.o”文件和链接从这 2 个“.o”文件归档的“.a”文件有什么区别。

为什么他们的行为不同?我在 rhel/ubuntu 上用 gcc/clang 进行了实验,结果都是一样的。我想知道是否有任何 C++ ABI 标准规定何时应该通过任何链接选项真正调用创建的 static/global 对象?

这种差异是怎么来的?

这是由于静态库的语义。如果链接器包含由命令行中它前面的某个目标文件引用的符号,则链接器将仅包含静态库中的文件(例如,main.cpp 引用来自 Second 的 f2,因此它被包含在内)。您可以使用

围绕您的库来覆盖此行为
-Wl,--whole-archive -lmystatic -Wl,--no-whole-archive

但这不是标准。