使用向后兼容的使用Boost的ABI创建库

时间:2009-05-07 20:33:09

标签: c++ unix boost compatibility abi

我正在研究某个C ++库(或更多框架)。我想让它落后 兼容以前的版本,不仅保留了API兼容性,还保留了ABI(就像Qt那样出色的工作)。

我使用Boost的许多功能,对我来说,这使得向后兼容性变得不可能,除非我强迫用户拥有完全相同(有时是旧版本)的B​​oost。

有没有办法(没有重写1/2的Boost)在其命名空间周围做一些“前缀”/重命名它以防止它干扰用户版本的Boost?

例如我的libXYZ使用Boost 1.33并且它有类boost::foo。在版本1.35 boost::foo已升级并添加了新成员,因此,boost::foo来自1.33和1.35 不兼容ABI。因此,libXYZ的用户必须使用Boost 1.33或重新编译libXYZ 提升1.35(可能已经以XYZ无法编译的方式破坏了某些API)。

注意:我说的是带有ELF的UNIX / Linux操作系统,其中动态链接类似于静态链接,因此您无法链接两个不同版本的库,因为符号会干扰。 / p>

我可能想到的一个合适的解决方案是将Boost放在其他私有命名空间中。因此,libXYZ将使用::XYZ::boost::foo而不是::boost::foo。这可以防止与用户可能使用的其他版本的Boost发生冲突。

因此,libXYZ将继续使用Boost 1.33与其他命名空间静态或动态链接,假设它:

  • 不会在外面公开Boost API。
  • 将保持公开的私有版API。

有没有办法用Boost做这些事情?

编辑:最后,我决定创建一个脚本,将源中的所有提升符号重命名为某个自定义符号。

基本原理:简化构建过程,独立于编译器可见性支持,此外,它的可见性仅适用于动态库,对于静态,这不起作用,因此我需要为每种类型的库提供单独的构建和依赖。

脚本可在那里找到:http://art-blog.no-ip.info/files/rename.py

编辑2:最新版本的Boost BCP支持命名空间重命名。

4 个答案:

答案 0 :(得分:29)

基本上,只需确保库的公共接口不会暴露Boost。您可以随时在内部使用它。通常,让库的接口依赖于另一个库是不好的(除非它依赖于像STL这样的标准库)。 Boost几乎适合“标准”库类别,但其ABI变化太大,以至于您的界面不应该使用它。

为确保不暴露Boost符号,您可以执行以下操作:

一个。使用-fvisibility=hidden进行编译,并使用__attribute__((visibility("default")))标记所有公共符号。您可以使用宏来简化这一过程:

#define ABI __attribute__((visibility("default")))

B中。做这样的事情:

#pragma GCC visibility push(hidden)
#include <boost/whatever.hpp>
#pragma GCC visibility pop

您还应将其包裹在您不想导出的所有其他内部符号周围,或使用__attribute__((visibility("hidden")))声明此内容。同样,您可以使用宏来简化这一过程:

#define INTERNAL __attribute__((visibility("hidden")))

在这些选项中,我更喜欢A,因为它会让您明确考虑导出哪些符号,因此您不会意外导出您不想要的内容。

顺便说一句,您可以在Ulrich Drepper的How to Write Shared Libraries中找到有关制作DSO的更多信息。

答案 1 :(得分:5)

一般来说,除了标准的C绑定之外,你不能依赖C ++中的任何类型的ABI。但根据您做出的假设,您可以在界面中使用越来越多的C ++。

我发现了this关于让您的API变成稳定ABI的步骤的精彩文章。例如,永远不要在您的接口上传递标准C ++库(或Boost)数据类型;如果修复了一个小错误,它可能会收支平衡。

发布ABI兼容API时需要注意的一些问题示例如下:

  • Windows Debug heap。您必须确保所有分配和解除分配都位于“模块”的同一侧(即可执行文件或DLL)。
  • Fragile Binary Interface问题。即使系统的两端始终使用相同的编译器和库,您也必须在C ++中小心关于在.h文件中发布的内容以及分配发生的位置。

如果您关注链接文章,您将找到解决这些问题和其他问题的方法。

修改

我还发现了一个有趣的article published by Microsoft,它描述了COM接口如何工作,通过采用C ++项目并将其转换为COM。我认为微软开发COM的主要原因之一是解决C ++所具有的脆弱二进制接口问题,因此他们可以使用面向发布对象的API发布DLL。

答案 2 :(得分:3)

考虑使用abi-compliance-checker工具来维护稳定的API / ABI接口。

答案 3 :(得分:0)

你应该可以这样做:

namespace XYZ
{
#include <boost/my_library.hpp>
}

它应该将boost标头转储到名称空间XYZ中。但请注意,这仅适用于仅限标头的库。