【发布时间】:2018-12-15 11:55:18
【问题描述】:
请注意,这不是 Multiple instances of singleton across shared libraries on Linux 的重复项,因为添加 -rdynamic 标志不会改变问题中的描述。
我有一个静态 c++ 库,其中包含一些静态初始化代码(对于需要在未命名的命名空间中调用构造函数的变量)。 然后我有 2 个(或更多)共享库在内部使用该静态库。
使用这两个共享库的任何可执行文件都将调用静态库的初始化代码两次,从而使 folly::Singleton 或 gflags 全局变量等行为异常。
这是预期的行为吗?这是动态链接器的错误/弱点吗?
编辑:请注意,在 macOS 上它只初始化一次。
示例:
静态.h
int get();
静态.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;
}
编译:
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
运行:
LD_LIBRARY_PATH=. ./a.out
结果是“1 1”,而我认为它是“0 0”。
看看nm、libshared.so和libshared2.so的符号都包含:
t _GLOBAL__sub_I_static.cpp
仅将静态库链接到可执行文件可以解决问题,但没有解释两个共享库如何在内部使用静态库而不会相互干扰。为了完成这里是如何获得“0 0”:
编译:
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
【问题讨论】:
-
每个共享库都有自己的静态库副本。他们彼此不了解。
-
@PeteBecker 即使有两个副本,它们不应该都有自己的
y和c,而且c.x不应该都等于0吗? -
@Leonard:请发一个minimal reproducible example(也就是main的代码)。
-
@Aconcagua — 是的;我没有仔细阅读这个问题。
-
@PeteBecker 在同时加载之前,他们并不知道彼此:例如
get的符号不会被加载两次,只会使用第一个加载的符号,正确的?所以我有点疑惑为什么对初始化的调用也被调用了两次。
标签: c++ compilation linker shared-libraries static-initialization