I've encountered recently on a problem with static initialization fiasco in the code that I was developing. It made me realize my lack of knowledge about linking process and global variables initialization so I've found this this very interesting talks at cppcon about globals, linking and possible issue with having static library embedded in shared and linking both at the same time (with globals defined). What was basically said there is that when having following structure:
//static.hpp
#pragma once
#include <string>
extern std::string globalString;
//static.cpp
#include "static.hpp"
std::string globalString;
//shared.hpp
#pragma once
#include "static.hpp"
#include <string>
std::string& getGlobalString();
//shared.cpp
#include "shared.hpp"
#include "static.hpp"
std::string& getGlobalString(){
return globalString;
}
//main.cpp
#include "static.hpp"
#include "shared.hpp"
#include <iostream>
int main(){
std::cout << "Global variable: " << globalString << std::endl;
std::cout << "Global var acccesed through shared lib: " << getGlobalString() << std::endl;
return 0;
}
All compiled with:
clang++ -c -std=c++14 -fpic static.cpp
clang++ -c -std=c++14 -fpic shared.cpp
clang++ -c -std=c++14 main.cpp
ar rsc libstatic.a static.o
clang++ -shared -o libshared.so shared.o -L./ -lstatic
clang++ -L./ -Wl,-rpath=./ main.o -lstatic -lshared
My lead to segmentation fault due to calling multiple times constructor and destructor of the same object. This is surprising as I took this as invariant that every object constructor will be called exactly once!
- What standard says about calling constructor/destructor multiple times?
- If in that case the global of static i embedded in both main.o and libshared.so the does it mean that rule of having one definition is broken? Why linker does not complain about having second definition available while linking main?
- One of suggested ways to establish construction and destruction order when having at least two global in separate translation unit would be to Initialize when first use. This is however ensures only construction order as far as I understand. What about destruction order? How to control?