【问题标题】:Separate instance of static variable in static library for shared library共享库的静态库中静态变量的单独实例
【发布时间】:2015-12-20 13:38:15
【问题描述】:

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

static.cpp

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

static.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();

ma​​in.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 库按预期工作
  • msvc 下的行为是相反的,我试图获得你得到的结果(在所有 dll 和 exe 中使用相同的静态函数调用相同的函数)。现在运气不好,你能指点一下如何得到它吗?

标签: c++ linux shared-libraries clang static-libraries


【解决方案1】:

显然,尽管在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

那么你能做些什么来“解决”这个问题呢?

  1. 您可以使用-Bsymbolic 链接libsharedb.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

命令行matters上的源/目标文件和库的顺序,库应遵循引用它们的目标文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2016-06-23
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多