【问题标题】:libstdc++ static linking in dynamic library动态库中的 libstdc++ 静态链接
【发布时间】:2017-11-30 16:53:59
【问题描述】:

为了理解问题,我应该告诉你更多关于加载动态库的程序。这是半条命专用服务器。它使用位于可执行文件旁边的旧 libstdc++。 为避免出现问题,在使用新标准库中的功能时,我通常将我的项目静态链接到 libstdc++。

我的朋友告诉我,如果加载了 2 个使用不同编译器编译的库或当我从服务器调用函数时(根据旧的 libstdc​++ 在内部实现),libstdc++ 静态链接会产生问题。

这是真的吗?我该如何解决这个问题?

【问题讨论】:

    标签: c++ linux c++11 gcc


    【解决方案1】:

    您的共享库公开的 API 必须使用宿主应用程序期望的相同 ABI,即所涉及的类型必须具有相同的布局、大小和对齐方式。

    如果 API 中暴露了 std:: 类型或它引发 C++ 异常,则意味着必须使用定义的相同标准库头文件和宏来编译共享库。在这种情况下,您可以动态链接到主机应用程序附带的 libstdc++

    如果 API 中没有公开 std:: 类型并且共享库中没有抛出异常,则可以静态链接到 libstdc++。但是,所有外部符号仍会从共享库中公开,因此当它通过调用 dlopen 而没有 RTLD_DEEPBIND 标志时,它将使用主机应用程序中具有相同名称的符号,如果它们可用而不是您希望静态链接的那些,这可能会导致您的朋友可能提到的未定义行为。为避免这种情况,需要链接器版本脚本来使共享库中的所有符号都成为本地符号,并且仅将 API 符号公开为全局符号。比如:

    MYHALFLIFEPLUGIN_0.0 {
      global: half_life_foo,half_life_bar; # Explicitly list symbols to be exported.
      local: *; # Hide everything else.
    };
    

    并通过-Wl,--version-script=<filename> 编译器链接器选项(LDFLAGS)指示链接器使用此脚本。除了-static-libstdc++ 选项,您还需要-static-libgcc 链接器选项。

    另外,请仔细阅读

    了解更多详情。

    【讨论】:

    • 非常感谢您花时间写这个答案。你解释了我无法理解的一切。我会稍等一下并接受你的回答。
    • @Inline 我可能错过了一些东西。 lddnm 是你最好的朋友:确保你的共享库没有链接任何意外的东西,看看它实际导出了哪些符号。
    【解决方案2】:

    是的,这是真的。最简单的例子是,如果您在一个库中使用new 创建一个对象,而在另一个不使用相同 STL 的库中使用delete 创建一个对象。

    您有 2 个解决方案:

    • 为 STL 使用动态链接
    • 确保不兼容性不会跨越二进制文件(库、exe)的边界。要做到这一点,最困难的方法是让你的库只公开一个 C API(没有 C++)。

    【讨论】:

    • 此示例适用于 MSVC 运行时,不适用于 Linux 和 g++。
    • @MaximEgorushkin 它确实适用于 Linux 和 g++。它确实适用于任何 C++ 平台和编译器。在 Linux 上,它通常更简单,因为您在系统上安装了 STL,并且您的所有二进制文件都是针对它编译的。但是你仍然不能混合使用 libstdc++ 和 libc++,也不能混合使用 2 个不兼容的 libc++ 版本。
    • 学究气,STL 是 C++ 标准库的一部分,new/delete 不是来自 STL。
    • @MaximEgorushkin newdelete 运算符不是 STL,它们是 C++ 核心语言功能,但是当您调用它们时,您确实调用了在 libstdc++.so.6 中实现的函数。这就是这里的重点。
    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多