はじめに
protoc
を使って Go のコードを生成するときにハマったのでメモがてら気をつけることを書いておきます。
前提条件
-
protoc
がコマンドラインで使えるようになっていること - Golang の知識があること
- proto3 の文法がわかっていること
コマンドラインオプションを指定する
paths=source_relative を使う
proto ファイルの中で go_package
を指定しなければなりませんが、その proto ファイルが格納されているディレクトリと Go におけるパッケージ名は同一にすることが推奨されています。なので、proto ファイルの中の go_package
は以下のようになります。
option go_package = "github.com/your-account-name/protobuf-example-go/simple";
この上で、公式ドキュメントにも書いてあるのですが、protoc
を実行するときにオプションを渡してあげます。
protoc -I src/ --go_out=src/ --go_opt=paths=source_relative src/simple/simple.proto
この --go_opt=paths=source_relative
によって proto ファイルと同じ場所に生成されます。
ハマったこと
ここで以下のコマンドラインを実行すると
protoc -I src/ --go_out=src/ src/simple/simple.proto
出力される場所が /src/github.com/your-account-name/protobuf-example-go/simple/simple.pb.go
になってしまいました。ちなみにこの挙動は公式ドキュメントにも書いてあります。デフォルトの挙動です。ただそのことに気づかなかった自分は「あれ、proto ファイルの中でのパッケージの指定の仕方がちがうのかな」と思って以下のようにすると
option go_package = "simple";
protoc
を実行した段階で以下のようなエラーが表示されます。
The import path must contain at least one period ('.') or forward slash ('/') character.
不適切な方法
go_package を proto ファイルの中で適切に指定すること
実は proto ファイルの中でオプションの書き方を(適切ではない方法で)工夫してしまっても同じ場所に出力することが可能です。
option go_package = "./;simple";
まず go_package に対してセミコロンを使用することは公式ドキュメントで非推奨となっているので、その前提で読み進めてください。公式ドキュメントにはこのように書いてあります。
For example: "example.com/protos/foo;package_name". This usage is discouraged since the package name will be derived by default from the import path in a reasonable manner.
さて前述のオプションは何を意味しているかというと、セミコロンの前はディレクトリを指すことになります。つまりカレントディレクトリを指しています。そしてセミコロンの後は Go コードの中におけるパッケージ名を指すことになります。つまり、この状態で
protoc -I src/ --go_out=src/ src/simple/simple.proto
を実行すると同じ場所に simple.pb.go
が出力されます。そしてコードの中を見ると
package simple
ということで期待している結果が出力されることになります。ただし先ほども記載したとおり、この方法は非推奨です。proto ファイルが格納されているディレクトリ名と package 名は同一のものにしましょうと書いてあるので、この方法は取らないようにしましょう。
さいごに
Udemyの某コースで学習しているときにハマったものです。UdemyはYouTubeはとても役に立つのですが、教材を作ってくれた時点と自分たちが学習する時点は時間軸がずれているので、むやみに信じ込まずに学習する姿勢が重要だなあとあらためて思った次第です。