混合 libstdc++ 版本
Mixing libstdc++ versions
有 2 个软件团队为同一个 OS(科学 Linux 6.5)开发 C++ 应用程序:
Team_A 使用 OS 提供的编译器和库(GCC 4.4.7、GLIBC_2.12、GLIBCXX_3 .4.13),构建其 C++98 应用程序和各种共享库。
Team_B 使用从源代码构建的较新 GCC 版本 (4.8.3)。它是一个本地编译器,它链接到 OS libc,并使用 OS 标准头文件,但有自己的 stdc++ 版本 (GLIBCXX_3.4.19)。 Team_B 在 C++11 模式下使用此编译器构建其应用程序 (AppB),并随它一起部署 libstdc++ 和 libgcc_s。
Team_A 以共享库(.so、.hpp)的形式向 Team_B 提供服务:LibA。库的API是一组C++类(在header中声明,.so中实现),methods以std::string等stdc++类为参数。
此时我们遇到了问题:AppB 构造 GLIBCXX_3.4.19 C++11 风格的 std::whatever 对象并将它们传递给 LibA,后者将它们解释为 GLIBCXX_3.4.13 C++98 样式对象,这可能不向前兼容。
这是个问题吗?它会导致应用程序崩溃吗? std::whatever 实现是否在版本之间兼容(相同的内存布局)? C++98 与 C++11 相比如何?
一些让我比较迷惑的情节曲折:
- AFAICT,当 AppB 运行时,只有一个 libstdc++ 加载,较新的
一。即使 LibA 链接到旧的,它也不会被加载。
- 但是 libstdc++ 中的符号是版本化的。所以,如果 LibA 显式使用
一个符号的旧版本,它将被链接到那个。这表示
AppB 将使用相同功能的 2 个不同实现
和 LibA。
- std::string 和容器是模板 类,这意味着
它们的一部分实现最终在它生成的地方结束,一部分
在 libstdc++.so 中。即使加载了较新的 libstdc++,生成的
LibA 中的模板代码来自旧版本。
我想了解在这种情况下到底发生了什么,是否存在风险和无效问题。让团队处于相同的开发环境中不是一种选择。从 API 中删除 std:: 类 也很难做到。
欢迎指点! :)
与 C 不同,C++ 没有定义的 ABI。这意味着....
- C++ 重整可能会改变 wikipedia : name mangling。请注意 Alpha 名称修改是如何更改的。
- class 的结构可能不同。布局结构的
protected:
、private:
和 public:
部分可能会有不同的决定。 vtable 的位置和含义可以在编译器之间移动。不同的编译器版本之间可能存在不同的预定义函数,例如 vtable 中的 typeinfo。
- STL 中结构的实现可能因 C++ 版本而异(例如,字符串共享在早期的 Visual studio 实现中完成,但在 C++11 中已被禁止)。
- 在Windows中,不同的运行时可能会以不同的方式管理它们的内存(绑定到不同的malloc/free)。传递完整的对象或指针时,这可能会导致调用不正确的自由实现。
你能做些什么来缓解这些问题?
资源分享
不提供编译库,而是将服务作为源代码交付,以便在同一环境中编译。
标准化 libstdc++
源编译器,可以用旧的 stdC++ 重新编译。这将限制第 3) 点的影响。
创建外观
两个团队之间有一个接口,需要说共同语言。这个语言应该是C.
团队 A => C++ facade/stub => C 接口 => C++ facade/proxy => 团队 B.
立面应建在将要使用的环境中。
有 2 个软件团队为同一个 OS(科学 Linux 6.5)开发 C++ 应用程序:
Team_A 使用 OS 提供的编译器和库(GCC 4.4.7、GLIBC_2.12、GLIBCXX_3 .4.13),构建其 C++98 应用程序和各种共享库。
Team_B 使用从源代码构建的较新 GCC 版本 (4.8.3)。它是一个本地编译器,它链接到 OS libc,并使用 OS 标准头文件,但有自己的 stdc++ 版本 (GLIBCXX_3.4.19)。 Team_B 在 C++11 模式下使用此编译器构建其应用程序 (AppB),并随它一起部署 libstdc++ 和 libgcc_s。
Team_A 以共享库(.so、.hpp)的形式向 Team_B 提供服务:LibA。库的API是一组C++类(在header中声明,.so中实现),methods以std::string等stdc++类为参数。
此时我们遇到了问题:AppB 构造 GLIBCXX_3.4.19 C++11 风格的 std::whatever 对象并将它们传递给 LibA,后者将它们解释为 GLIBCXX_3.4.13 C++98 样式对象,这可能不向前兼容。
这是个问题吗?它会导致应用程序崩溃吗? std::whatever 实现是否在版本之间兼容(相同的内存布局)? C++98 与 C++11 相比如何?
一些让我比较迷惑的情节曲折:
- AFAICT,当 AppB 运行时,只有一个 libstdc++ 加载,较新的 一。即使 LibA 链接到旧的,它也不会被加载。
- 但是 libstdc++ 中的符号是版本化的。所以,如果 LibA 显式使用 一个符号的旧版本,它将被链接到那个。这表示 AppB 将使用相同功能的 2 个不同实现 和 LibA。
- std::string 和容器是模板 类,这意味着 它们的一部分实现最终在它生成的地方结束,一部分 在 libstdc++.so 中。即使加载了较新的 libstdc++,生成的 LibA 中的模板代码来自旧版本。
我想了解在这种情况下到底发生了什么,是否存在风险和无效问题。让团队处于相同的开发环境中不是一种选择。从 API 中删除 std:: 类 也很难做到。
欢迎指点! :)
与 C 不同,C++ 没有定义的 ABI。这意味着....
- C++ 重整可能会改变 wikipedia : name mangling。请注意 Alpha 名称修改是如何更改的。
- class 的结构可能不同。布局结构的
protected:
、private:
和public:
部分可能会有不同的决定。 vtable 的位置和含义可以在编译器之间移动。不同的编译器版本之间可能存在不同的预定义函数,例如 vtable 中的 typeinfo。 - STL 中结构的实现可能因 C++ 版本而异(例如,字符串共享在早期的 Visual studio 实现中完成,但在 C++11 中已被禁止)。
- 在Windows中,不同的运行时可能会以不同的方式管理它们的内存(绑定到不同的malloc/free)。传递完整的对象或指针时,这可能会导致调用不正确的自由实现。
你能做些什么来缓解这些问题?
资源分享
不提供编译库,而是将服务作为源代码交付,以便在同一环境中编译。
标准化 libstdc++
源编译器,可以用旧的 stdC++ 重新编译。这将限制第 3) 点的影响。
创建外观
两个团队之间有一个接口,需要说共同语言。这个语言应该是C.
团队 A => C++ facade/stub => C 接口 => C++ facade/proxy => 团队 B.
立面应建在将要使用的环境中。