Version 23.x 新聞公告

Protocol Buffers 23.x 版的變更公告。

以下公告是針對 Version 23.x。如需依時間順序呈現的資訊,請參閱新聞

Ruby 產生器變更

此 GitHub PR 將出現在 23.x 版本中,會變更 Ruby 程式碼產生器以發出序列化的 proto,而不是 DSL。

它從程式碼產生器中移除 DSL,以預期將 DSL 分割到不同的套件中。

假設有如下所示的 .proto 檔案

syntax = "proto3";

package pkg;

message TestMessage {
  optional int32 i32 = 1;
  optional TestMessage msg = 2;
}

變更前產生的程式碼

# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: protoc_explorer/main.proto

require 'google/protobuf'

Google::Protobuf::DescriptorPool.generated_pool.build do
  add_file("test.proto", :syntax => :proto3) do
    add_message "pkg.TestMessage" do
      proto3_optional :i32, :int32, 1
      proto3_optional :msg, :message, 2, "pkg.TestMessage"
    end
  end
end

module Pkg
  TestMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("pkg.TestMessage").msgclass
end

變更後產生的程式碼

# frozen_string_literal: true
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: test.proto

require 'google/protobuf'

descriptor_data = "\n\ntest.proto\x12\x03pkg\"S\n\x0bTestMessage\x12\x10\n\x03i32\x18\x01 \x01(\x05H\x00\x88\x01\x01\x12\"\n\x03msg\x18\x02 \x01(\x0b\x32\x10.pkg.TestMessageH\x01\x88\x01\x01\x42\x06\n\x04_i32B\x06\n\x04_msgb\x06proto3"
begin
  Google::Protobuf::DescriptorPool.generated_pool.add_serialized_file(descriptor_data)
rescue TypeError => e
  # <compatibility code, see below>
end

module Pkg
  TestMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("pkg.TestMessage").msgclass
end

此變更修正了先前幾乎所有剩餘的一致性問題。這是從 DSL (有損) 移至序列化描述符 (會保留所有資訊) 的副作用。

回溯相容性

此變更應 100% 相容於 2021 年 9 月發行的 Ruby Protobuf >= 3.18.0。此外,它應相容於所有現有使用者和部署。

為了達到此回溯相容性等級,我們插入了一些特殊相容性程式碼,您應該注意。如果沒有相容性程式碼,在某種邊緣情況下可能會破壞回溯相容性。先前的程式碼在某方面較為寬鬆,而新程式碼會更嚴格。

當使用完整序列化描述符時,它會包含此檔案匯入的所有 .proto 檔案清單 (而 DSL 從未正確新增依附元件)。請參閱 descriptor.proto 中的程式碼。

add_serialized_file 會驗證描述符中列出的所有依附元件是否先前已透過 add_serialized_file 新增。一般而言,這應該沒問題,因為產生的程式碼會包含所有依附元件的 Ruby require 陳述式,而且如果依附的類型先前未在 DescriptorPool 中定義,描述符無論如何都無法載入。

但是,如果檔案路徑周圍存在歧義,則可能會出現問題。例如,考慮以下情境

// foo/bar.proto

syntax = "proto2";

message Bar {}
// foo/baz.proto

syntax = "proto2";

import "bar.proto";

message Baz {
  optional Bar bar = 1;
}

如果您像這樣叫用 protoc,它會正常運作

$ protoc --ruby_out=. -Ifoo foo/bar.proto foo/baz.proto
$ RUBYLIB=. ruby baz_pb.rb

但是,如果您像這樣叫用 protoc,而且沒有任何相容性程式碼,則會無法載入

$ protoc --ruby_out=. -I. -Ifoo foo/baz.proto
$ protoc --ruby_out=. -I. -Ifoo foo/bar.proto
$ RUBYLIB=foo ruby foo/baz_pb.rb
foo/baz_pb.rb:10:in `add_serialized_file': Unable to build file to DescriptorPool: Depends on file 'bar.proto', but it has not been loaded (Google::Protobuf::TypeError)
    from foo/baz_pb.rb:10:in `<main>'

問題在於 bar.proto 正以兩個不同的標準名稱參照:bar.protofoo/bar.proto。這是使用者錯誤:每個匯入都應始終以一致的完整路徑參照。希望這類使用者錯誤很少見,但在嘗試之前很難知道。

如果我們偵測到發生此邊緣情況,此變更中的程式碼會使用 warn 印出警告

$ RUBYLIB=foo ruby foo/baz_pb.rb
Warning: Protobuf detected an import path issue while loading generated file foo/baz_pb.rb
- foo/baz.proto imports bar.proto, but that import was loaded as foo/bar.proto
Each proto file must use a consistent fully-qualified name.
This will become an error in the next major version.

在這種情況下,有兩種可能的修正方法。一種是針對匯入始終如一地使用名稱 bar.proto (移除 -I.)。另一種是針對匯入始終如一地使用名稱 foo/bar.proto (將匯入行變更為 import "foo/bar.proto" 並移除 -Ifoo)。

我們計劃在下一個主要版本中移除此相容性程式碼。

停止支援 Bazel <5.3

v23 將停止支援 Bazel 4。Protobuf 將繼續支援 Bazel 5 LTS,最低要求版本為 Bazel 5.3。這是根據 基礎 C++ 支援政策 中描述的建構支援政策,並反映在 基礎 C++ 支援 中的版本。

語法反射機制淘汰

v23 將淘汰使用反射機制檢查語法版本的功能。淘汰將以建構時的警告形式包含在內。此功能將在未來版本中移除。