文档菜单
文档首页
/ / /
C++ 驱动程序
/

ABI 版本控制

在本页

  • 二进制兼容性
  • 构建系统兼容性
  • 根命名空间重新声明
  • 弃用和移除

C++ 驱动程序使用 Ulrich Drepper 的关于 定义稳定性 的指南、Linux 共享库 "soname" 规范以及 CMake 的 SOVERSION 目标属性进行 ABI 版本管理。SOVERSION 目标属性用于表示 ABI 版本。

根据Ulrich Drepper:

因此,稳定性的定义应使用 已记录 的接口作为基础。接口的合法使用不应受实现更改的影响;以未定义的方式使用接口将使保修无效。使用完全未记录的内部符号也是如此。这些符号根本不应使用。

根据 Linux 文档项目:

每个共享库都有一个特殊名称,称为 "soname"。soname 以 "lib" 为前缀,后跟库的名称," .so" 短语,然后是一个点和一个版本号,每当接口更改时(作为一个特殊例外,最低级别的 C 库不以 "lib" 开头)。完全限定的 soname 以包含它所在目录的前缀;在一个工作系统中,完全限定的 soname 简单地是共享库 "真实名称" 的符号链接。

根据 CMake 文档:

对于共享库,可以使用 VERSIONSOVERSION 分别指定构建版本和 ABI 版本。如果平台支持符号链接并且连接器支持 so-name,则在构建或安装时会创建适当的符号链接。如果只指定其中之一,则缺失的假定具有相同的版本号。

为了 ABI 版本管理的目的,我们区分 稳定 ABI不稳定 ABI

每当稳定 ABI 发生向后不兼容的更改时,都会增加 ABI 版本号。

重要

仅通过ABI版本号传达稳定ABI的稳定性。不稳定ABI的向后(不)兼容更改不通过ABI版本号传达。

注意

ABI版本策略仅适用于共享库。它不适用于静态库。

在库的根命名空间内声明了一个ABI命名空间(参见源兼容性),以字母v开头,后跟整数或_noabi

ABI命名空间的示例包括(相对于全局命名空间作用域)

  • bsoncxx::v_noabi

  • bsoncxx::v1

  • bsoncxx::v2

  • bsoncxx::v99

不稳定ABI命名空间是具有名称v_noabi的命名空间。任何其他ABI命名空间是稳定ABI命名空间。根命名空间不是ABI命名空间。

稳定ABI是一组由公共API使用的导出符号,并在稳定ABI命名空间中声明,有以下例外

  • 符号或相应的公共API实体明确记录为实验性或尚未准备进行ABI稳定性。

  • 实体未在ABI命名空间内声明。

包括这些例外,所有其他导出符号都视为不稳定ABI的一部分。

只有通过导出宏显式声明的对应API实体的符号才会被导出,由CXX_VISIBILITY_PRESET目标属性控制。此外,声明为inline的实体,无论是显式(例如,使用inline)还是隐式(例如,类定义中的成员函数定义、变量/函数模板实例化等),都不会导出,由VISIBILITY_INLINES_HIDDEN目标属性控制。

如果有符号应该被导出或作为稳定ABI的一部分,但目前没有,请提交错误报告。

重要

不支持绕过公共API直接使用导出符号。所有导出符号(稳定或不稳定)都必须通过公共API使用。如果有符号应该被导出或作为稳定ABI的一部分,但目前没有,请提交错误报告。

重要

一个符号只需被公共API(即使间接地)使用,就可以被认为是稳定ABI的一部分。如果一个导出符号在之前的任何版本中都没有被任何公共API实体使用过,那么它不被认为是稳定ABI的一部分(见上述说明)。

重要

稳定ABI符号的行为也是稳定ABI的一部分。这是为了确保具有相同ABI版本号的共享库之间运行时行为的兼容性。行为必须与使用该符号的公共API实体(即使间接地)的文档一致,以确保在具有相同ABI版本号的发布之间,公共API行为没有可观察的变化(在明确记录的范围内)。

注意

一些属于公共API的实体可能不是稳定ABI的一部分(例如,内联函数、内联变量以及函数和变量的模板实例化)。相反,一些属于稳定ABI的实体可能不是公共API的一部分(例如,导出的私有成员函数)。参见API版本控制

关于构建系统属性的稳定ABI策略主要与公共API策略相同(见API构建系统兼容性),以下有一些不同

  • 与直接影响公共API的属性不同,直接影响稳定ABI的属性被视为稳定ABI的一部分。

  • soname被视为稳定ABI的一部分。这意味着,与公共API相反,BSONCXX_OUTPUT_NAME被视为稳定ABI的一部分,因为它直接影响了生成的bsoncxx共享库的soname。

  • 在Windows上,“soname”不适用。请参阅共享库(仅限MSVC)。

注意

我们支持每个构建配置的稳定API的稳定性。我们不支持跨不同构建配置的稳定API的兼容性。例如,使用BSONCXX_OUTPUT_NAME=bsoncxx生成的共享库与使用构建配置BSONCXX_OUTPUT_NAME=bsoncxx-custom-basename产生的稳定ABI编译的程序不兼容。(这在使用Visual Studio等多配置生成器时尤其重要!)

根命名空间提供了对ABI命名空间中声明的实体的“重声明”。

例如,以下所有重声明可能同时存在

  • bsoncxx::example::foo --> bsoncxx::v_noabi::example::foo

  • bsoncxx::example::bar --> bsoncxx::v1::example::bar

  • bsoncxx::example::baz --> bsoncxx::v2::example::baz

根命名空间重声明设计用于允许在 vB 中添加不兼容的二进制符号,同时不破坏 vA 符号的二进制兼容性。它们便于稳定 ABI 符号的弃用,同时提供从 vAvB 清晰过渡的机会,而不会破坏二进制兼容性。它们允许用户选择参与“重声明升级”,以减少从 vAvB 过渡时对源代码的更改。

这些重声明升级旨在支持从弃用、即将删除的 ABI 符号到发布之间的清晰过渡。因此,鼓励用户默认使用根命名空间声明来选择这些升级。然而,根据他们自己的稳定性策略,用户可能需要在引用自己的稳定 ABI 中的 C++ 驱动程序实体时使用显式的 ABI 命名空间限定符。

以下兼容性表描述了由于不兼容更改何时必须增加 API 主版本号或 ABI 版本号

更改类型

源兼容

二进制兼容

添加新的 vB 符号

将重声明从 vA 升级到 vB

可能 [1]

从公共 API 中删除 vA 符号

可能 [2]

从稳定 ABI 中删除 vA 符号

可能 [2]

[1] vB 实体可能完全与 vA API 兼容,尽管需要使用新的、不兼容的稳定 ABI 符号。
[2](1, 2) 可以从公共 API 中删除稳定 ABI 符号(例如,通过文档或从公共头文件中删除),同时仍然提供向后兼容的导出符号定义。这种情况可能不太可能发生,但如果确实发生,那么它将是一个罕见的情况,其中源代码和不兼容的更改可以分开发布。

重要

ABI 命名空间使用的整数不直接对应于 ABI 版本号。每当发生任何二进制不兼容的更改时,都会增加 ABI 版本号,即使是从稳定 ABI 中删除单个符号。从 AB 的 ABI 版本号增加并不暗示弃用或删除 ABI 命名空间 vA 中声明的符号(如果存在)。

稳定 ABI 中符号的弃用和删除策略与公共 API 相同。有关更多信息,请参阅API 弃用和删除。

包含二进制不兼容更改的版本将增加ABI版本号,而不是API主版本号。然而,当ABI版本号增加时,API主版本号也可能增加,因为二进制不兼容更改很可能也是源代码不兼容更改。

返回

API 版本控制