バージョン 23.x のニュース発表

Protocol Buffers バージョン 23.x に関する発表された変更点。

以下の発表はバージョン 23.x に固有のものです。時系列順の情報については、ニュースを参照してください。

Ruby ジェネレータの変更

この GitHub PR (23.x リリースに収録予定) は、Ruby コードジェネレータが DSL の代わりにシリアライズされた proto を出力するように変更します。

これは、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 (損失が多い) からシリアライズされた記述子 (すべての情報を保持する) に移行することの副作用です。

後方互換性

この変更は、2021年9月にリリースされた Ruby Protobuf >= 3.18.0 と 100% 互換性があるはずです。さらに、既存のすべてのユーザーとデプロイメントとも互換性があるはずです。

このレベルの後方互換性を実現するために挿入された特別な互換性コードがあり、注意が必要です。互換性コードがないと、後方互換性を損なう可能性のあるエッジケースがあります。以前のコードは緩い部分がありましたが、新しいコードはより厳密になります。

完全なシリアライズされた記述子を使用する場合、このファイルによってインポートされたすべての .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.protobar.protofoo/bar.proto という 2 つの異なる正規名で参照されていることです。これはユーザーエラーです。各インポートは常に一貫したフルパスで参照される必要があります。このようなユーザーエラーはまれであることを願っていますが、試してみないとわかりません。

この変更のコードは、このエッジケースが発生したことを検出した場合、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.

この場合、2 つの可能な修正方法があります。1 つは、インポートに bar.proto という名前を一貫して使用することです (-I. を削除)。もう 1 つは、インポートに foo/bar.proto という名前を一貫して使用することです (インポート行を import "foo/bar.proto" に変更し、-Ifoo を削除)。

この互換性コードは、次のメジャーバージョンで削除する予定です。

Bazel 5.3 未満のサポート終了

v23 では Bazel 4 のサポートを終了します。Protobuf は、Bazel 5.3 を最小必須バージョンとして Bazel 5 LTS を引き続きサポートします。これは、Foundational C++ Support Policy に記載されているビルドサポートポリシー、および Foundational C++ Support のバージョンに反映されているとおりです。

構文リフレクションの非推奨

v23 では、リフレクションを使用して構文バージョンを確認する機能を非推奨にします。非推奨は、ビルド時の警告として含まれます。この機能は将来のリリースで削除されます。