C++编译静态变量和共享对象

标签 c++ static compilation shared-libraries

描述:

一个。 X类包含静态私有(private)数据成员ptr和静态公共(public)函数成员getptr()/setptr()。
在 X.cpp 中,ptr 设置为 NULL。

libXYZ.so(共享对象)包含类 X 的对象(即 libXYZ.so 包含 X.o)。

libVWX.so(共享对象)包含类 X 的对象(即 libVWX.so 包含 X.o)。

可执行文件 a.exe 包含 X.cpp 作为翻译单元的一部分,最后链接到 libXYZ.so、libVWX.so

附言:
1. 任何类都没有涉及用户命名空间。
2.库和可执行文件还包含许多其他类。
3. 没有执行 dlopen()。所有库都在编译期间使用 -L 和 -l 标志进行链接。

问题陈述:

  1. 当编译 a.exe 并将其与其他库(即 libXYZ.so 和 libVWX.so)链接时,我预计会出现链接器错误(多次出现相同符号的冲突/出现),但并没有出现。

  2. 程序执行时 - 在 SUSE 10 Linux 和 HP-UX 11 IA64 中行为异常。
    在 Linux 中,当执行流被推送到不同库中的所有对象时,效果仅在 X 的一个拷贝中注册。
    在 HPUX 中,当执行流被推送到不同库中的所有对象时,效果在 X 的 3 个不同拷贝中注册(2 个属于每个库,1 个用于可执行文件)

PS:我的意思是在运行程序期间,流程确实通过了属于 a.exe、libXYZ.so 和 libVWX.so 的多个对象,这些对象与属于 X 的静态指针交互。

问题:

  • Expecting linker error 是否不正确?由于两个编译器默默地通过了编译,所以在这种情况下可能有一个标准规则,我错过了。如果是这样,请让我知道。
  • 编译器(Linux 中的 gcc 和 HPUX 中的 aCC)如何决定在最终可执行文件中保留多少 X 拷贝并在这种情况下引用它们。
  • 在这种情况下,gcc 和 aCC 是否支持向用户发出警告/停止编译的标志?

提前感谢您的帮助。

最佳答案

我不太确定我是否完全理解了这个场景。然而, 在 Linux 下加载动态对象的默认行为(和其他 Unices) 是为了使库中的所有符号都可用,并且只使用 第一次遇到。因此,如果您同时使用 libXYZ.solibVWX.so 包含符号 X::ourData,这不是错误;如果你加载它们 该顺序,libVWX.so 将使用 libXYZ.so 中的 X::ourData, 而不是它自己的。从逻辑上讲,这很像模板定义 在 header 中:编译器或多或少随机选择一个,如果 任何定义都与其他定义不同,它是 未定义的行为。这种行为可以是 通过将标志 RTLD_LOCAL 传递给 dlopen 来覆盖。

关于您的问题:

  • 链接器只是实现了 dlopen 的默认行为(系统隐式加载库时得到的行为)。因此,没有错误(但如果任何定义不相同,则逻辑上等同于未定义行为)。

  • 编译器不做决定。该决定是在加载 .so 时做出的,具体取决于您在调用 dlopen 时指定的是 RTLD_GLOBAL 还是 RTLD_LOCAL .当运行时隐式调用 dlopen 来解决依赖关系时,如果在加载主可执行文件时发生这种情况,它将使用 RTLD_GLOBAL,以及在加载主可执行文件时用于加载库的内容依赖来自库。 (当然,这意味着 RTLD_GLOBAL 将传播,直到您显式调用 dlopen。)

关于C++编译静态变量和共享对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7792235/

相关文章:

linux - 使用mkfile编译linux内核模块

android - 构建特定的 Android 平台?

c++ - 使用 unordered_set 防止不同哈希值的键落入同一个桶

c++ - 在 TRACE 调用后中断调试

c++ - 删除 max 并添加新元素时的单个 'Heapify' 调用 c++ std::make_heap

c++ - 在 C++ 头文件中声明和定义静态变量?

c - 为什么我们需要解决 `make` 和 `make install` 之后的依赖关系?

c++ - 为什么隐式类型转换在模板推导中不起作用?

c++ - 模板函数内的静态变量

c - 如何在翻译单元之间共享一组内部功能而不需要外部链接?