Note that this is not a duplicate of Multiple instances of singleton across shared libraries on Linux since adding -rdynamic
flag doesn't change what is described in the question.
I have a static c++ library which has some static initialization code (for variables requiring a constructor call in an unnammed namespace). I then have 2 (or more) shared library using that static library internally.
Any executable using both shared libraries will call the initialization code of the static library twice, making things like folly::Singleton
or gflags global variables misbehave.
Is that the intended behavior? Is that a bug/weakness of dynamic linkers?
edit: Note that on macos it only initialize once.
Example:
static.h
int get();
static.cpp
static int y = 0;
struct C { C() : x(y++) {}; int x; };
namespace { C c; }
int get() { return c.x; }
shared.h
int shared_get();
shared.cpp
#include "static.h"
int shared_get() { return get(); }
shared2.h
int shared2_get();
shared2.cpp
#include "static.h"
int shared2_get() { return get(); }
main.cpp
#include "shared.h"
#include "shared2.h"
#include <iostream>
int main() {
std::cout << shared_get() << " " << shared2_get() << std::endl;
return 0;
}
Compile:
g++ -fPIC -g -c -o static.o static.cpp
ar rcs libstatic.a static.o
g++ -g -fPIC -shared -o libshared.so shared.cpp ./libstatic.a
g++ -g -fPIC -shared -o libshared2.so shared2.cpp ./libstatic.a
g++ main.cpp ./libshared.so ./libshared2.so
Run :
LD_LIBRARY_PATH=. ./a.out
The result is "1 1" when I would expect it to be "0 0".
Looking at the symbols with nm
, libshared.so
and libshared2.so
do both contain:
t _GLOBAL__sub_I_static.cpp
Linking the static library only to the executable solves the behaviour but doesn't explain how two shared libraries can use a static library internally without interfering. For completion here is how to get "0 0":
Compile:
g++ -fPIC -g -c -o static.o static.cpp
ar rcs libstatic.a static.o
g++ -g -fPIC -shared -o libshared.so shared.cpp
g++ -g -fPIC -shared -o libshared2.so shared2.cpp
g++ main.cpp ./libshared.so ./libshared2.so ./libstatic.a