共享库的静态库中静态变量的单独实例

Separate instance of static variable in static library for shared library

本文关键字:静态 实例 单独 共享 变量      更新时间:2023-10-16

考虑以下由两个共享库组成的设置,这两个库都使用静态库:

静态.cpp

#include "static.h"
static int a = 0;
int getA()
{
    return a++;
}

静态.h

#pragma once
int getA();

shareda.cpp

#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
    std::cout << getA() << std::endl;
}

shareda.h

#pragma once
void printA();

sharedb.cpp

#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
    std::cout << getA() << std::endl;
}

sharedb.h

#pragma once
void printB();

main.cpp

#include "shareda.h"
#include "sharedb.h"
int main()
{
    printA();
    printA();
    printB();
    printA();
    printB();
    return 0;
}

我用以下命令编译并运行了这些文件(使用Clang 3.8.0,从源代码编译,使用GNU ld 2.25的64位Debian):

clang++ -c static.cpp -o static.o -fPIC
ar rcs libstatic.a static.o
clang++ -c shareda.cpp -o shareda.o -fPIC
clang++ -shared -o libshareda.so shareda.o libstatic.a
clang++ -c sharedb.cpp -o sharedb.o -fPIC
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
clang++  -L. -lshareda -lsharedb -o main main.cpp
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main

令我惊讶的是,输出如下:

0
1
2
3
4

我的期望是:

0
1
0
2
1

显然,尽管static.cpp中a前面有static关键字,但a只存在一个实例。有没有办法拥有两个a实例,每个共享库一个?

显然,尽管static.cpp中的前面有static关键字,但只有一个实例存在。

这是不正确的:存在两个a实例,但实际只使用了一个。

发生是因为(与您的预期相反)printB调用第一个可用的getA(来自libshareda.so的,而不是来自libsharedb.so的)。这是UNIX共享库和Windows DLL之间的一个主要区别。UNIX共享库模拟了如果您的链接是时会发生的情况

clang++  -L. -o main main.cpp shareda.o sharedb.o libstatic.a

那么,你能做些什么来"修复"这个问题呢?

  1. 您可以使用-Bsymboliclibsharedb.so链接为自己的getA
  2. 您可以将getA完全隐藏在libsharedb.so中(就好像它是一个私有的实现细节一样):

    clang++ -c -fvisibility=hidden -fPIC static.cpp ar rcs libstatic.a static.o clang++ -shared -o libsharedb.so sharedb.o libstatic.a

  3. 使用链接器版本脚本可以获得类似的结果

附言:你的链接命令:

clang++  -L. -lshareda -lsharedb -o main main.cpp

完全倒退了。应该是:

clang++  -L. -o main main.cpp -lshareda -lsharedb

命令行中源/对象文件和库的顺序很重要,库应该遵循引用它们的对象文件。