С ++ отличаются между связыванием с.o и с.a файлом: другое поведение, почему?
Я ожидал, что:
связь с файлом.o и связь с файлом.a, заархивированным из файла.o, не должны иметь различий.
Но на самом деле это не так. У меня есть 2 исходных файла, каждый из которых объявляет 1class+1 статический объект + 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) Результат выполнения MylinkSta не создает первый объект, но MyDirect делает.
(2) В то время как "Второй" объект всегда создается.
Я действительно не вижу никакой разницы между связыванием с двумя файлами '.o' и связыванием с файлом '.a', который заархивирован из этих двух файлов '.o'.
Почему они ведут себя по-разному? Я экспериментировал с gcc/clang на rhel/ubuntu, все показывают один и тот же результат. Интересно, есть ли какой-либо стандарт C++ ABI, который говорит, когда должен быть действительно вызван созданный статический / глобальный объект, с помощью любого варианта связывания?
Откуда эта разница?
1 ответ
Это связано с семантикой статических библиотек. Линкер будет включать файлы из статической библиотеки только в том случае, если он содержит символ, на который ссылается некоторый объектный файл, который предшествует ему в командной строке (например, main.cpp ссылается на f2 из Second, поэтому он включен). Вы можете изменить это поведение, окружив свою библиотеку
-Wl,--whole-archive -lmystatic -Wl,--no-whole-archive
но это не стандартно