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

C++ 共享库的静态库中静态变量的单独实例,c++,linux,shared-libraries,clang,static-libraries,C++,Linux,Shared Libraries,Clang,Static Libraries,考虑以下由两个共享库组成的设置,它们都使用静态库: 静态.cpp #include "static.h" static int a = 0; int getA() { return a++; } #include <iostream> #include "shareda.h" #include "static.h" void printA() { std::cout << getA() << std::endl; } #include &l

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

静态.cpp

#include "static.h"
static int a = 0;
int getA()
{
    return a++;
}
#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
    std::cout << getA() << std::endl;
}
#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
    std::cout << getA() << std::endl;
}
#include "shareda.h"
#include "sharedb.h"
int main()
{
    printA();
    printA();
    printB();
    printA();
    printB();
    return 0;
}
静态.h

#pragma once
int getA();
#pragma once
void printA();
#pragma once
void printB();
shareda.cpp

#include "static.h"
static int a = 0;
int getA()
{
    return a++;
}
#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
    std::cout << getA() << std::endl;
}
#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
    std::cout << getA() << std::endl;
}
#include "shareda.h"
#include "sharedb.h"
int main()
{
    printA();
    printA();
    printB();
    printA();
    printB();
    return 0;
}
sharedb.cpp

#include "static.h"
static int a = 0;
int getA()
{
    return a++;
}
#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
    std::cout << getA() << std::endl;
}
#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
    std::cout << getA() << std::endl;
}
#include "shareda.h"
#include "sharedb.h"
int main()
{
    printA();
    printA();
    printB();
    printA();
    printB();
    return 0;
}
main.cpp

#include "static.h"
static int a = 0;
int getA()
{
    return a++;
}
#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
    std::cout << getA() << std::endl;
}
#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
    std::cout << getA() << std::endl;
}
#include "shareda.h"
#include "sharedb.h"
int main()
{
    printA();
    printA();
    printB();
    printA();
    printB();
    return 0;
}
我使用以下命令编译并运行了这些文件(使用clang3.8.0,从源代码编译,以及使用gnuld2.25的64位Debian):

令我惊讶的是,结果如下:

0
1
2
3
4
我的期望是:

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

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

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

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

clang++  -L. -o main main.cpp shareda.o sharedb.o libstatic.a
那么你能做些什么来“修复”这个问题呢

  • 您可以使用
    -Bsymbolic
    链接
    libsharedb.so
    以更喜欢它自己的
    getA
  • 您可以将
    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

  • 使用链接器版本脚本可以获得类似的结果
  • 请注意,您的链接命令:

    clang++  -L. -lshareda -lsharedb -o main main.cpp
    
    这完全是倒退。应该是:

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

    源/对象文件和库在命令行上的顺序,库应遵循引用它们的对象文件

    对于静态库,我会像预期的那样工作。msvc下的行为正好相反,我正在尝试获得您得到的结果(使用相同的静态访问对所有DLL和exe进行相同的函数调用)。现在运气不好,你能告诉我怎么得到它吗?