C++ libstdc&x2B+;动态库中的静态链接

C++ libstdc&x2B+;动态库中的静态链接,c++,linux,c++11,gcc,C++,Linux,C++11,Gcc,为了理解这个问题,我应该告诉你们更多关于加载动态库的程序的信息。它是半衰期专用服务器。它使用位于可执行文件旁边的旧libstdc++。 为了避免出现问题,在使用新标准库的功能时,我通常将我的项目静态链接到libstdc++ 我的朋友告诉我,libstdc++静态链接可能会产生问题,如果加载了使用不同编译器编译的2个库,或者当我从服务器调用函数时(这是用旧libstdc在内部实现的)​++). 这是真的吗?如何解决此问题?是的,这是真的。最简单的示例是,如果您在库中使用new创建对象,然后在另一

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

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


这是真的吗?如何解决此问题?

是的,这是真的。最简单的示例是,如果您在库中使用
new
创建对象,然后在另一个不使用相同STL的库中删除它

您有两种解决方案:

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

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

如果有代码>在STI中暴露的STD::/Cuth:Type,它会抛出C++异常,那么这意味着共享库必须使用相同的标准库头和宏定义编译。在这种情况下,您可以动态地与宿主应用程序一起出现的<>代码> LIbSTDC++/<代码>。 如果API中没有公开的

std::
类型,并且没有从共享库抛出异常,则可以静态链接到
libstdc++
。但是,所有外部符号仍将从共享库中公开,因此在加载时调用
dlopen
而不使用
RTLD\u 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=
编译器链接器选项(
LDFLAGS
)一起使用。除了
-static libstdc++
选项外,还需要
-static libgcc
链接器选项

还有,通读一遍


更详细。

此示例适用于MSVC运行时,而不是Linux和G++.@ MaximEgorushkin。它适用于Linux和G++。它确实适用于任何C++平台和编译器。在Linux上,一般情况下,由于系统安装了STL,所有二进制文件都是编译的,但仍然不能混合LIbSTDC++和LBC+++也不能混合2个不兼容的版本,LIGB++。STL是C++标准库的一部分,而<代码>新< /Calp> <代码> Dele> <代码>不是STL。@ MaximEgorushkin <代码>新< /COD>和 Dele> <代码>运算符不是STL,它们是C++核心语言特性,但是当你调用它们时,你调用的函数是在
libstdc++.so.6
。这才是这里最重要的。非常感谢你花时间写下这个答案。你解释了我无法理解的一切。我会等一等,接受你的答案。@Inline我可能错过了一些东西。
ldd
nm
是你在这里最好的朋友:确保你的共享库不链接任何意外的内容,请查看它实际导出的符号。