如何在GCC为C++03的CentOS 6上部署C++11程序(带依赖)?

How can I deploy a C++11 program (with dependencies) on CentOS 6, whose GCC is C++03?

只要您使用相同的 C++ 标准,GCC 的 ABI 兼容性就很好 [1]。

但令我震惊的是,如果 GCC 4.3 在 C++03 模式下编译的共享库公开了一个 std::string,这将是一个不同于理解的 std::string通过 GCC 4.8 在 C++11 模式下编译的可执行文件。

我问的原因是我打算在CentOS 6上部署一个GCC 4.8编译的C++11模式的程序,最大打包的GCC是4.3...和一些共享库(是他们第三方 C++ 库或更多系统级的东西)可能因此都是 C++03。但如果真是这样,我们将永远无法在较旧的 Linux 发行版上部署任何 C++11 程序,这似乎不太可能。

我是不是天真地认为这里可能有问题?而且,如果有,我该如何解决?

关于这件事有一个精彩的页面:https://gcc.gnu.org/wiki/Cxx11AbiCompatibility

简而言之,gcc 中的 C++11 大部分 ABI 与 c++98 兼容,但也有一些不匹配之处。上面的页面列出了所有这些。

为了缓解这个问题,我建议采用以下方法:

  • 清楚地识别所有依赖项,它们是 C++ 库。你通常不会有太多 - 首先想到的是提升,你还有什么吗?
  • 比你检查你的应用程序需要的符号是否在损坏的 ABI 列表中(见上文)。如果他们不是,那你就没事了。
  • 如果是,则重新编译该库,并将其作为共享库与您的应用程序一起分发(使用 Rpath 标志以确保您的应用程序加载您的版本)或link静态地反对它。

以防万一,你也可以link静态地反对libstdc++。

实际上,您可以在 vanilla CentOS 6 平台上分发使用较新的 g++ 编译器编译的程序。有几种方法可以做到这一点:最简单的方法是使用 DevToolset 3, which will give you g++ 4.9.2 (the dev toolset 2 will give you gcc 4.8.2). Then, just compile your application with this g++. When distributing your software, you need to make sure to also ship the libstdc++.so that is being shipped with g++ 4.9. Either set the LD_LIBRARY_PATH so it gets picked up on startup, or set the RPATH 告诉您的可执行文件首先在哪里查找库。

基本上,您也可以使用较新的编译器来执行此操作,但是您首先需要编译编译器本身。如果您不想先编译编译器,请使用相应的开发工具集,您应该没问题。

是的,你也可以试试statically link libstdc++.a。搜索选项 -static-libstdc++:

When the g++ program is used to link a C++ program, it normally automatically links against libstdc++. If libstdc++ is available as a shared library, and the -static option is not used, then this links against the shared version of libstdc++. That is normally fine. However, it is sometimes useful to freeze the version of libstdc++ used by the program without going all the way to a fully static link. The -static-libstdc++ option directs the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.

但是如果你静态 link,你将不会获得任何安全更新等。当然,如果你自己发布 libstdc++.so,你将不会获得更新,但增量更新可能更容易.

关于 运行 您的应用程序:经验法则是:在您需要支持的最旧平台上编译,然后您的二进制文件(带有自发布的 libstdc++ 和其他所需的库)可能会工作也在较新的版本上。也就是说,如果您在 CentOS 6 上编译并且它可以运行,那么您可以期望它也可以在 CentOS 7 上运行。在相关主题上,这正是 AppImage 和相关解决方案建议构建的原因在旧系统上。

如果您使用定义 _GLIBCXX_USE_CXX11_ABI=0 构建 C++11 程序(参见 this) and the option --abi-version=2 (see this),您应该与使用 GCC 4.3 构建的任何库兼容,包括 libstdc++。

默认的 ABI 版本是 2 到 4.9,CentOS 使用默认的 ABI 似乎是一个安全的假设。

_GLIBCXX_USE_CXX11_ABI 宏会影响标准库的类型,使用与 C++11 之前版本相同的布局。这将引入一些 C++11 一致性问题(首先更改它们的原因),例如 std::list<>::size().

的复杂性

--abi-version= 命令行选项影响编译器的 ABI、调用约定、名称修改等。从 3.4 到 4.9,默认 ABI 为 2。

在我的公司,我们使用 gcc 5.1.0,在 CentOS 5.5 上编译和使用(板载旧 gcc)。

当我们部署我们的应用程序时,我们还重新分发了 libstdc++.solibgcc_s.so,它们是从 gcc 5.1.0 源代码编译的。

例如:

/opt/ourapp/lib/libstdc++.so
/opt/ourapp/lib/libgcc_s.so
/opt/ourapp/bin/myapp

为了正确启动二进制文件,我们执行:

LD_LIBRARY_PATH=/opt/ourapp/lib/ myapp.

希望对您有所帮助。

缺点: 至少你不能在这样的环境中使用原生 gdb,因为 DWARF 格式不兼容。