迁移指南

库版本中进行的重大更改列表,以及如何更新您的代码以适应这些更改。

v22.0 中的编译器更改

JSON 字段名称冲突

更改来源:PR #11349PR #10750

我们在处理 JSON 映射方面的字段名称冲突方面做了一些细微的更改。在 proto3 中,我们部分放松了限制,并且仅在字段名称生成区分大小写的 JSON 映射(原始名称的驼峰式大小写)时才给出错误。我们现在还检查 json_name 选项,并针对区分大小写的冲突给出错误。在 proto2 中,我们稍微加强了限制,如果两个 json_name 规范冲突,则会给出错误。如果隐式 JSON 映射(驼峰式大小写)存在冲突,我们将在 proto2 中给出警告。

我们提供了一个临时的消息/枚举选项来恢复旧版行为。如果您无法立即重命名冲突字段,请在特定消息/枚举上设置 deprecated_legacy_json_field_conflicts 选项。此选项将在将来的版本中删除,但为您提供了更多时间进行迁移。

v22.0 中的 C++ API 更改

4.22.0 对 C++ 运行时和 protoc 进行了重大更改,如 8 月份公告 中所述。

Autotools 弃用

更改来源:PR #10132

在 v22.0 中,我们从 protobuf 编译器和 C++ 运行时中删除了所有 Autotools 支持。如果您使用 Autotools 构建这两个中的任何一个,则必须迁移到 CMakeBazel。我们有一些 专门的说明 用于使用 CMake 设置 protobuf。

Abseil 依赖项

更改来源:PR #10416

使用 v22.0,我们对 Abseil 产生了显式依赖关系。这使我们能够删除大多数 存根,这些存根是从旧的内部代码中分支出来的,后来成为了 Abseil。存在许多细微的行为更改,但大多数对用户来说应该是透明的。一些值得注意的更改包括

  • string_view - absl::string_view 已替换我们许多 API 中的 const std::string&。这最常用于输入参数,对用户来说应该没有明显的更改。在少数情况下(例如虚方法参数或返回类型),用户可能需要进行显式更改以使用新的签名。

  • - 我们现在使用 Abseil 的 flat_hash_mapflat_hash_setbtree_mapbtree_set,而不是 STL 集合/映射。这些效率更高,并允许进行 异构查找。这应该对用户来说几乎是不可见的,但可能会导致一些与表排序相关的细微行为更改。

  • 日志记录 - Abseil 的 日志记录库 与我们旧的日志记录代码非常相似,只是拼写略有不同(例如,ABSL_CHECK 而不是 GOOGLE_CHECK)。最大的区别在于它不支持异常,并且现在在 FATAL 断言失败时始终会崩溃。(以前我们有一个 PROTOBUF_USE_EXCEPTIONS 标志来切换到异常。)由于这些仅在遇到严重问题时才会发生,因此我们认为无条件崩溃是合适的响应。

    日志记录更改的来源:PR #11623

  • 构建依赖项 - 新的构建依赖项始终可能导致下游用户的故障。我们需要 Abseil LTS 20230117 或更高版本才能构建。

    • 对于 Bazel 构建,当从您的 WORKSPACE 运行 protobuf_deps 时,Abseil 将自动下载并在固定 LTS 版本上构建。这应该是透明的,但如果您依赖于旧版本的 Abseil,则需要升级您的依赖项。

    • 对于 CMake 构建,我们将首先查找由顶级 CMake 配置引入的现有 Abseil 安装(请参阅 说明)。否则,如果 protobuf_ABSL_PROVIDER 设置为 module(其默认值),我们将尝试从我们的 git 子模块 构建和链接 Abseil。如果 protobuf_ABSL_PROVIDER 设置为 package,我们将查找预安装的系统版本 Abseil。

GetCurrentTime 方法的更改

在 Windows 上,GetCurrentTime() 是系统提供的宏的名称。在 v22.x 之前,Protobuf 错误地删除了 GetCurrentTime() 的宏定义。这使得在包含 <protobuf/util/time_util.h> 后,Windows 开发人员无法使用该宏。从 v22.x 开始,Protobuf 保留宏定义。这可能会破坏依赖于先前行为的客户代码,例如,如果他们使用表达式 google::protobuf::util::TimeUtil::GetCurrentTime()

要将您的应用程序迁移到新的行为,请更改您的代码以执行以下操作之一

  • 如果定义了 GetCurrent 宏,请显式取消定义 GetCurrentTime
  • 通过使用 (google::protobuf::util::TimeUtil::GetCurrentTime)() 或类似表达式来防止宏扩展

示例:取消定义宏

如果您不使用来自 Windows 的宏,请使用此方法。

之前

#include <google/protobuf/util/time_util.h>

void F() {
  auto time = google::protobuf::util::TimeUtil::GetCurrentTime();
}

之后

#include <google/protobuf/util/time_util.h>
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif

void F() {
  auto time = google::protobuf::util::TimeUtil::GetCurrentTime();
}

示例 2:防止宏扩展

之前

#include <google/protobuf/util/time_util.h>

void F() {
  auto time = google::protobuf::util::TimeUtil::GetCurrentTime();
}

之后

#include <google/protobuf/util/time_util.h>

void F() {
  auto time = (google::protobuf::util::TimeUtil::GetCurrentTime)();
}

C++20 支持

更改来源:PR #10796

为了支持 C++20,我们在 C++ 生成的 protobuf 代码中保留了新的 关键字。与其他保留关键字一样,如果您将它们用于任何字段、枚举或消息,我们将添加下划线后缀以使其成为有效的 C++。例如,concept 字段将生成一个 concept_() getter。在您有使用这些关键字的现有 proto 的情况下,您需要更新引用它们的 C++ 代码以添加适当的下划线。

最终类

更改来源:PR #11604

作为加强 Protobuf 库中做出的假设的更大努力的一部分,我们已将一些类标记为 final,这些类从未打算被继承。没有已知的继承这些类的用例,这样做可能会导致问题。如果您正在继承这些类,则没有缓解措施,但如果您认为您有一些使用继承的有效原因,则可以 打开一个问题

容器静态断言

更改来源:PR #11550

作为加强 Protobuf 库中做出的假设的更大努力的一部分,我们已向 MapRepeatedFieldRepeatedPtrField 容器添加了静态断言。这些确保您仅使用预期类型的这些容器,如 我们的文档中所述。如果您遇到这些静态断言,则应将代码迁移到使用 Abseil 或 STL 容器。std::vector 是重复字段容器的良好替代品,std::unordered_mapabsl::flat_hash_map 用于 Map(前者提供类似的指针稳定性,而后者效率更高)。

已清除元素弃用

更改来源:PR #11588PR #11639

围绕“已清除字段”的 RepeatedPtrField API 已弃用,并将在以后的重大版本中完全删除。这最初是为了作为在清除元素后重用元素的优化而添加的,但最终效果不佳。如果您使用此 API,则应考虑迁移到 arena 以获得更好的内存重用。

UnsafeArena 弃用

更改来源:PR #10325

作为删除 arena 不安全 API 的更大努力的一部分,我们已隐藏 RepeatedField::UnsafeArenaSwap。这是我们迄今为止删除的唯一一个,但在以后的版本中,我们将继续删除它们并提供帮助程序来处理 arena 之间的有效借用模式。在单个 arena(或堆栈/堆)中,SwapUnsafeArenaSwap 一样高效。好处是,如果您意外地在不同的 arena 中调用它,它不会导致无效的内存操作。

Map Pair 升级

更改来源:PR #11625

对于 v22.0,我们已开始清理 Map API 以使其与 Abseil 和 STL 更一致。值得注意的是,我们已将 MapPair 类替换为 std::pair 的别名。这对于大多数用户来说应该是透明的,但如果您直接使用该类,则可能需要更新您的代码。

新的 JSON 解析器 {:#json-parser}

更改来源:PR #10729

我们在本次发布中重写了 C++ JSON 解析器。它应该主要是一个隐藏的更改,但不可避免地,一些未记录的怪癖可能会发生变化;相应地进行测试。解析不是有效 RFC-8219 JSON 的文档(例如缺少引号或使用非标准布尔值的文档)已弃用,并将在将来的版本中删除。字段的序列化顺序现在保证与字段编号顺序匹配,而之前则不太确定性。

作为本次迁移的一部分,util/internal 下的所有文件已被删除。这些文件用于旧解析器,并且从未打算供外部使用。

Arena::Init

更改来源:PR #10623

Arena 中的 Init 方法是没有任何作用的代码,现在已被移除。如果您之前调用了此方法,您可能本意是想直接使用一组 ArenaOptions 调用 Arena 构造函数。您应该删除该调用或迁移到该构造函数。

ErrorCollector 迁移

更改来源:PR #11555

作为我们 Abseil 迁移的一部分,我们正在从 const std::string& 迁移到 absl::string_view。对于我们的三个错误收集器类,如果不破坏现有代码,则无法完成此操作。对于 v22.0,我们决定发布这两个变体,并将方法从 AddErrorAddWarning 重命名为 RecordErrorRecordWarning。旧签名已被标记为已弃用,并且效率会略低(由于字符串复制),但其他方面仍然可以工作。您应该将这些迁移到新版本,因为 Add* 方法将在以后的破坏性版本中删除。