遷移指南
v30.0 版的變更
以下是程式庫版本中重大變更的清單,以及如何更新您的程式碼以適應這些變更。
這涵蓋了 v30.x 的最新消息公告 和 v30.0 的版本資訊 中宣告的重大變更。
將 CMake 子模組替換為擷取的依附元件
先前,我們的預設 CMake 行為是使用 Git 子模組來抓取釘選的依附元件。指定 -Dprotobuf_ABSL_PROVIDER=package
會翻轉我們的 CMake 設定,以尋找 Abseil 的本機安裝 (jsoncpp 和 gtest 也有類似的選項)。這些選項已不存在,而預設行為是先尋找我們所有依附元件的安裝,然後在需要時退回從 GitHub 擷取釘選的版本。
若要防止任何退回擷取 (類似於舊的 package
行為),您可以使用以下方式呼叫 CMake:
cmake . -Dprotobuf_LOCAL_DEPENDENCIES_ONLY=ON
若要一律從固定版本擷取依附元件 (類似於舊的預設行為),您可以使用以下方式呼叫 CMake:
cmake . -Dprotobuf_FORCE_FETCH_DEPENDENCIES=ON
string_view 傳回類型
針對下列描述元 API,傳回類型現在為 absl::string_view
,這可節省記憶體
MessageLite::GetTypeName
UnknownField::length_delimited
- 描述元 API 名稱函式,例如
FieldDescriptor::full_name
我們預期未來的重大版本將繼續將其他 API 遷移至 absl::string_view
。
在大多數情況下,您應該嘗試更新類型以在安全的情況下使用 absl::string_view
,或在需要時明確複製到原始類型。如果這是函式中傳回的內容,您可能也需要更新呼叫端。
如果受影響的 API 方法傳回的字串用作
類型 | 遷移 |
---|---|
| 明確轉換為 或者,切換至效能更高的 |
| 遷移至 如果不可行 (例如由於大量依附元件),則複製到 |
| 如果可為 Null,則遷移至 否則,遷移至 呼叫 |
對於常見的容器和其他 API,您可能可以遷移至與 absl::string_view
相容的變體。以下是一些常見的範例。
類別 | 遷移前 | 遷移 |
---|---|---|
插入到 std::vector<std::string> 中 |
|
|
針對 map 或 set 插入 |
|
|
針對 map 或 set 查閱 |
| 遷移至 Abseil 容器。 或者,定義透明比較子。
|
字串串連 |
|
無論如何,基於效能考量,建議使用這些方法。請參閱 https://abseil.io/tips/3。 |
另請參閱 https://abseil.io/tips/1,以取得有關使用 absl::string_view
的一般秘訣。
Poison MSVC + Bazel
Windows 上的 Bazel 使用者應切換為使用 clang-cl,方法是將下列內容新增至其專案,如此 範例 中所示。
.bazelrc
common --enable_platform_specific_config build:windows
--extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl
--extra_execution_platforms=//:x64_windows-clang-cl
MODULE.bazel
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_cc", version = "0.0.17")
# For clang-cl configuration
cc_configure = use_extension("@rules_cc//cc:extensions.bzl", "cc_configure_extension")
use_repo(cc_configure, "local_config_cc")
WORKSPACE
load("//:protobuf_deps.bzl", "PROTOBUF_MAVEN_ARTIFACTS", "protobuf_deps")
protobuf_deps()
load("@rules_cc//cc:repositories.bzl", "rules_cc_dependencies", "rules_cc_toolchains")
rules_cc_dependencies()
rules_cc_toolchains()
BUILD
適用於僅需要與 Bazel 8 相容的使用者。
platform(
name = "x64_windows-clang-cl",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
"@bazel_tools//tools/cpp:clang-cl",
],
)
適用於需要與 Bazel 7 和 8 相容的使用者。
platform(
name = "x64_windows-clang-cl",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
# See https://github.com/bazelbuild/rules_cc/issues/330.
"@rules_cc//cc/private/toolchain:clang-cl",
],
)
使用者也可以暫時停用錯誤,方法是在下一個重大版本發佈之前,設定停用旗標 --define=protobuf_allow_msvc=true
。
或者,希望繼續使用 MSVC 的使用者可以切換為使用 CMake。這可以使用 Visual Studio 完成,或透過 CMake 命令列提供 MSVC 產生器。例如
cmake -G "Visual Studio 17 2022" -A Win64 .
從 FieldDescriptor 選項中移除 ctype
我們已停止公開 FieldDescriptor
選項中的 ctype
。您可以使用 v28 版本 中新增的 FieldDescriptor::cpp_string_type()
API 來取代它。
修改偵錯 API 以編輯敏感欄位
Protobuf C++ 偵錯 API (包括 Protobuf AbslStringify、proto2::ShortFormat
、proto2::Utf8Format
、Message::DebugString
、Message::ShortDebugString
、Message::Utf8DebugString
) 已變更為編輯以 debug_redact
註解的敏感欄位;這些 API 的輸出包含每個程序隨機化的前置字串,且不再可由 Protobuf TextFormat 剖析器剖析。使用者應針對大多數需要人類可讀取輸出的情況 (例如記錄) 採用新的編輯偵錯格式,或考慮切換至二進位格式以進行序列化和還原序列化。需要舊的可還原序列化格式的使用者可以使用 TextFormat.printer().printToString(proto)
,但這不會編輯敏感欄位,因此應謹慎使用。
如需更多資訊,請參閱 2024 年 12 月 4 日發佈的新聞文章。
移除已淘汰的 API
我們移除了下列公用執行階段 API,這些 API 已標示為已淘汰 (例如 ABSL_DEPRECATED
) 至少一個次要或主要版本,並且已過時或已取代。
API: Arena::CreateMessage
取代項目: Arena::Create
API: Arena::GetArena
取代項目: value->GetArena()
API: RepeatedPtrField::ClearedCount
取代項目: 遷移至 Arena (遷移指南)。
API: JsonOptions
取代項目: JsonPrintOptions
已停止支援 C++14
此版本已停止支援 C++ 14 作為最低支援版本,並根據 Foundational C++ Support matrix 將其提高至 17。
使用者應升級至 C++17。
在 Arena 上清除 Oneof 訊息後導入 ASAN Poisoning
此變更新增了強化檢查,會影響使用 Arena 的 C++ protobuf。現在會在偵錯中清除 protobuf arena 上配置的 Oneof 訊息,並在 ASAN 模式中進行 Poisoning。在呼叫 clear 之後,未來嘗試使用記憶體區域將導致 ASAN 中發生當機,因為使用後釋放錯誤。
此實作需要 C++17。
已停止我們的 C++ CocoaPods 版本
我們已停止我們的 C++ CocoaPods 版本,該版本自 v4.x.x 以來已損壞。C++ 使用者應改為直接使用我們的 GitHub 版本。
Python 的變更
Python 將其主要版本從 5.29.x 升級至 6.30.x。
已停止支援 Python 3.8
最低支援的 Python 版本為 3.9。使用者應升級。
移除 bazel/system_python.bzl 別名
我們移除了舊版 bazel/system_python.bzl
別名。
移除對 system_python.bzl
的直接參考,改為使用 protobuf_deps.bzl
。如果您需要直接參考,請使用 v5.27.0 中移動的 python/dist/system_python.bzl
。
欄位 Setter 驗證變更
Python 和 upb 的欄位 setter 現在會根據 2023 年版本驗證封閉列舉。以無效值更新的封閉列舉欄位會產生錯誤。
移除已淘汰的 py_proto_library 巨集
已移除 protobuf.bzl
中已淘汰的內部 py_proto_library
Bazel 巨集。它已由官方 py_proto_library
取代,後者已在 v29.x 中移動到 protobuf 中的 bazel/py_proto_library
。此實作先前在 v29.x 之前的 rules_python
中可用。
移除已淘汰的 API
我們移除了下列公用執行階段 API,這些 API 已標示為已淘汰至少一個次要或主要版本。
反射方法
API: reflection.ParseMessage
、reflection.MakeClass
取代項目: message_factory.GetMessageClass()
RPC 服務介面
API: service.RpcException
、service.Service
、service.RpcController
和 service.RpcChannel
取代項目: 從 2.3.0 版開始,RPC 實作不應嘗試以此為基礎建置,而應提供程式碼產生器外掛程式,以產生特定於特定 RPC 實作的程式碼。
MessageFactory 和 SymbolDatabase 方法
API: MessageFactory.GetPrototype
、MessageFactory.CreatePrototype
、MessageFactory.GetMessages
、SymbolDatabase.GetPrototype
、SymbolDatabase.CreatePrototype
和 SymbolDatabase.GetMessages
取代項目: message_factory.GetMessageClass()
和 message_factory.GetMessageClassesForFiles()
。
GetDebugString
API: GetDebugString
取代項目
沒有取代項目。它僅在不再發佈的 Python C++ 中。純 Python 或 UPB 中不支援它。
Python setdefault Map 欄位的行為變更
setdefault
類似於 ScalarMap
的 dict
,但必須同時設定索引鍵和值。setdefault
會被 MessageMaps
拒絕。
Python 巢狀訊息類別 __qualname__ 包含外部訊息名稱
Python 巢狀訊息類別 __qualname__
現在包含外部訊息名稱。先前,巢狀訊息的 __qualname__
與 __name__
的結果相同,因為未包含外部訊息名稱。
例如
message Foo {
message Bar {
bool bool_field = 1;
}
}
nested = test_pb2.Foo.Bar()
self.assertEqual('Bar', nested.__class__.__name__)
self.assertEqual('Foo.Bar', nested.__class__.__qualname__) # It was 'Bar' before
Objective-C 的變更
這是 Objective-C 的第一個重大版本.
Objective-C 將其主要版本從 3.x.x 升級至 4.30.x。
徹底檢查未知欄位處理 API,淘汰大多數現有 API
我們淘汰了 GPBUnknownFieldSet
,並以 GPBUnknownFields
取代它。新類型會保留來自原始輸入或 API 呼叫的未知欄位順序,以確保在將訊息寫回時,維持順序的任何語意意義。
作為此作業的一部分,GPBUnknownField
類型也具有 API 變更,幾乎所有現有 API 都已淘汰,並新增了新的 API。
已淘汰的屬性 API
varintList
fixed32List
fixed64List
lengthDelimitedList
groupList
已淘汰的修改 API
addVarint
addFixed32
addFixed64
addLengthDelimited
addGroup
已淘汰的初始化程式 initWithNumber:
。
新的屬性 API
type
varint
fixed32
fixed64
lengthDelimited
group
此類型在其值中模擬單一欄位編號,而不是群組給定欄位編號的所有值。用於建立新欄位的 API 是 GPBUnknownFields
類別上的 add*
API。
我們也淘汰了 -[GPBMessage unknownFields]
。取而代之的是,有新的 API 可用於擷取和更新訊息的未知欄位。
移除已淘汰的 API
我們移除了下列公用執行階段 API,這些 API 已標示為已淘汰至少一個次要或主要版本。
GPBFileDescriptor
API: -[GPBFileDescriptor
syntax]
取代項目: 已過時。
GPBMessage mergeFrom:extensionRegistry
API: -[GPBMessage mergeFrom:extensionRegistry:
]
取代項目: -[GPBMessage mergeFrom:extensionRegistry:error:
]
GPBDuration timeIntervalSince1970
API: -[GPBDuration timeIntervalSince1970
]
取代項目: -[GPBDuration timeInterval
]
GPBTextFormatForUnknownFieldSet
API: GPBTextFormatForUnknownFieldSet()
取代項目: 已過時 - 使用 GPBTextFormatForMessage()
,其中包含任何未知欄位。
GPBUnknownFieldSet
API: GPBUnknownFieldSet
取代項目: GPBUnknownFields
GPBMessage unknownFields
API: GPBMessage unknownFields
屬性
取代項目: -[GPBUnknownFields initFromMessage:
]、-[GPBMessage mergeUnknownFields:extensionRegistry:error:
] 和 -[GPBMessage clearUnknownFields
]
移除舊版 Gencode 的已淘汰執行階段 API
此版本移除了已淘汰的執行階段方法,這些方法支援 3.22.x 版本之前的 Objective-C gencode。當舊版產生的程式碼啟動時,程式庫也會在執行階段發出記錄訊息。
API: +[GPBFileDescriptor allocDescriptorForClass:file:fields:fieldCount:storageSize:flags:]
取代項目: 使用程式庫的目前版本重新產生。
API: +[GPBFileDescriptor allocDescriptorForClass:rootClass:file:fields:fieldCount:storageSize:flags:]
取代項目: 使用程式庫的目前版本重新產生。
API: +[GPBEnumDescriptor allocDescriptorForName:valueNames:values:count:enumVerifier:]
取代項目: 使用程式庫的目前版本重新產生。
取代項目: 使用程式庫的目前版本重新產生。
API: -[GPBExtensionDescriptor initWithExtensionDescription:]
取代項目: 使用程式庫的目前版本重新產生。
Poison Pill 警告
我們更新了 Poison Pill,針對新的滾動升級原則下可運作,但在下一個主要版本升級中會中斷的舊版 gencode + 新版執行階段組合發出警告。例如,Python 4.x.x gencode 應可針對 5.x.x 執行階段運作,但會警告即將針對 6.x.x 執行階段中斷。
C# 和 Ruby 中 UTF-8 強制執行的變更
我們納入了修正程式,以使 UTF-8 強制執行在各種語言之間保持一致。字串欄位中具有錯誤的非 UTF-8 資料的使用者可能會更早看到浮現的 UTF-8 強制執行錯誤。
JSON 剖析中的 Ruby 和 PHP 錯誤
我們修正了 JSON 剖析中數字欄位中字串的不一致性,根據 JSON 規格。
此修正程式未伴隨主要版本升級,但 Ruby 和 PHP 現在會針對數字欄位中的非數字字串 (例如 ""
、"12abc"
、"abc"
) 引發錯誤。v29.x 包含針對這些錯誤案例的警告。
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 的明確依附元件。這讓我們能夠移除我們的大部分 stubs,這些 stubs 是從舊版內部程式碼分支出來的,後來成為 Abseil。有一些細微的行為變更,但大多數對於使用者而言應是透明的。一些值得注意的變更包括
string_view - 在我們的許多 API 中,
absl::string_view
已取代const std::string&
。這最常被用於輸入引數,使用者應不會注意到任何變更。在少數情況下 (例如虛擬方法引數或傳回類型),使用者可能需要明確變更以使用新的簽章。tables - 我們現在使用 Abseil 的
flat_hash_map
、flat_hash_set
、btree_map
和btree_set
,而不是 STL set/map。這些效率更高,並允許 異質查閱。這對於使用者而言應大多是不可見的,但可能會導致一些與表格排序相關的細微行為變更。logging - Abseil 的 logging 程式庫 與我們的舊版記錄程式碼非常相似,只是拼寫略有不同 (例如,
ABSL_CHECK
而不是GOOGLE_CHECK
)。最大的差異在於它不支援例外狀況,並且現在在FATAL
判斷提示失敗時將一律當機。(先前我們有一個PROTOBUF_USE_EXCEPTIONS
旗標可切換至例外狀況。) 由於這些僅在遇到嚴重問題時才會發生,因此我們認為無條件當機是合適的回應。記錄變更的來源:PR #11623
建置依附元件 - 新的建置依附元件始終可能導致下游使用者中斷。我們需要 Abseil LTS 20230125 或更新版本才能建置。
對於 Bazel 建置,當從您的
WORKSPACE
執行protobuf_deps
時,將會自動下載並建置釘選 LTS 版本的 Abseil。這應是透明的,但如果您依賴舊版 Abseil,則需要升級您的依附元件。對於 CMake 建置,我們將首先尋找由最上層 CMake 設定提取的現有 Abseil 安裝 (請參閱 指示)。否則,如果
protobuf_ABSL_PROVIDER
設定為module
(預設值),我們將嘗試從我們的 git 子模組 建置和連結 Abseil。如果protobuf_ABSL_PROVIDER
設定為package
,我們將尋找預先安裝的系統版本 Abseil。
GetCurrentTime 方法的變更
在 Windows 上,GetCurrentTime()
是系統提供的巨集名稱。在 v22.x 之前,Protobuf 錯誤地移除了 GetCurrentTime()
的巨集定義。這使得 Windows 開發人員在包含 <protobuf/util/time_util.h>
之後無法使用該巨集。從 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++ 程式碼,以新增適當的底線。
Final 類別
變更來源: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
。這是目前為止唯一移除的 API,但在之後的版本中,我們會繼續移除這些 API,並提供輔助工具來處理 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
下的所有檔案(位於 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*
方法將在之後的重大版本中移除。