迁移指南
v22.0 中的编译器更改
JSON 字段名称冲突
我们在处理 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 构建这两个中的任何一个,则必须迁移到 CMake 或 Bazel。我们有一些 专门的说明 用于使用 CMake 设置 protobuf。
Abseil 依赖项
更改来源:PR #10416
使用 v22.0,我们对 Abseil 产生了显式依赖关系。这使我们能够删除大多数 存根,这些存根是从旧的内部代码中分支出来的,后来成为了 Abseil。存在许多细微的行为更改,但大多数对用户来说应该是透明的。一些值得注意的更改包括
string_view -
absl::string_view
已替换我们许多 API 中的const std::string&
。这最常用于输入参数,对用户来说应该没有明显的更改。在少数情况下(例如虚方法参数或返回类型),用户可能需要进行显式更改以使用新的签名。表 - 我们现在使用 Abseil 的
flat_hash_map
、flat_hash_set
、btree_map
和btree_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 库中做出的假设的更大努力的一部分,我们已向 Map
、RepeatedField
和 RepeatedPtrField
容器添加了静态断言。这些确保您仅使用预期类型的这些容器,如 我们的文档中所述。如果您遇到这些静态断言,则应将代码迁移到使用 Abseil 或 STL 容器。std::vector
是重复字段容器的良好替代品,std::unordered_map
或 absl::flat_hash_map
用于 Map
(前者提供类似的指针稳定性,而后者效率更高)。
已清除元素弃用
围绕“已清除字段”的 RepeatedPtrField
API 已弃用,并将在以后的重大版本中完全删除。这最初是为了作为在清除元素后重用元素的优化而添加的,但最终效果不佳。如果您使用此 API,则应考虑迁移到 arena 以获得更好的内存重用。
UnsafeArena 弃用
更改来源:PR #10325
作为删除 arena 不安全 API 的更大努力的一部分,我们已隐藏 RepeatedField::UnsafeArenaSwap
。这是我们迄今为止删除的唯一一个,但在以后的版本中,我们将继续删除它们并提供帮助程序来处理 arena 之间的有效借用模式。在单个 arena(或堆栈/堆)中,Swap
与 UnsafeArenaSwap
一样高效。好处是,如果您意外地在不同的 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,我们决定发布这两个变体,并将方法从 AddError
和 AddWarning
重命名为 RecordError
和 RecordWarning
。旧签名已被标记为已弃用,并且效率会略低(由于字符串复制),但其他方面仍然可以工作。您应该将这些迁移到新版本,因为 Add*
方法将在以后的破坏性版本中删除。