概要
で紹介したprotoeasyがリンクごと消えて使えなくなったので、protoc
の使い方を整理するために書きます。
環境
- libprotoc 3.9.1
使い方
Goを例に基本的な使い方を説明します。
SRC_DIR
ディレクトリに.proto
ファイルがある場合、基本的には以下のようにコンパイルを実行します。
$ protoc -I./SRC_DIR --go_out=./OUT_DIR ./SRC_DIR/*.proto
各オプションをそれぞれ説明していきます。
-I
オプション
-I
オプションは.proto
ファイルでimportするファイルのPATHです。 --proto_path
の短縮形です。
機能
-I
オプションを指定すると、
.proto
ファイルでのimportを使える- import pathを省略できる
と言ったことが可能になります。
.proto
ファイルでのimportを使える
例えば
path/ ├── device.proto └── person.proto
という配置で、以下のように片方が別のprotoに依存している場合
syntax = "proto3"; package path; import 'device.proto'; // 依存 message Person { string name = 1; int32 id = 2; string email = 3; Device device = 4; }
-I
でPATHを通さないとエラーが発生します。
$ protoc --go_out=./path ./path/*.proto device.proto: File not found. path/person.proto:4:1: Import "device.proto" was not found or had errors. path/person.proto:10:3: "path.Device" seems to be defined in "path/device.proto", which is not imported by "path/person.proto". To use it here, please add the necessary import.
PATHを通すとコンパイルできます。
$ protoc -I./path --go_out=./path ./path/*.proto
import pathを省略できる
外部ライブラリのprotoを使う際、
-I${GOPATH}/src
だけならimportしたいxxx.protoでは
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
と冗長に書く必要がありますが、
-I${GOPATH}/src \ -I${GOPATH}/src/github.com/gogo/protobuf
のようにPATHに追加してあげれば
import "gogoproto/gogo.proto";
とだけ書けば良くなります。
書き方
様々な指定方法ができるので参考にいくつか例を示します。
例 | 説明 |
---|---|
-I. |
カレントディレクトリを指定 |
-I./proto |
./proto というディレクトリを指定 |
-I=./proto |
= をつけてもOK |
-I${GOPATH}/src |
GOPATHでGoのライブラリを使用 |
-I.:./proto:${GOPATH}/src |
: で複数指定も可能 |
xxx_outオプション
--xxx_out
はプラグイン&出力先の指定です。proto-gen-xxx
というプラグイン名だとxxx_out
という書き方になります。
具体的な例だと以下です。
アーキテクチャ
protocol buffersは多言語をサポートしており、その仕組みはpluginによる拡張機構です。
以下がそのアーキテクチャ図です。pluginバイナリを用意して以下のように実行されます。
書き方
Go(=protoc-gen-go)であればこれまで通り
$ protoc -I./SRC_DIR --go_out=OUT_DIR ./SRC_DIR/*.proto
ですし、Goで有名なgogoプラグイン(=protoc-gen-gogo)であれば
$ protoc -I./SRC_DIR --gogo_out=OUT_DIR ./SRC_DIR/*.proto
と書きます。
プラグインに渡す引数
プラグインによっては様々な機能を提供しており、それを使うために引数を渡す設定も可能です。
一般的な書き方は
$ protoc \ --foo_out=arg1=aaaaaa,arg2,arg3=cccccc:OUT_DIR \ input.proto
で、
- 引数の指定はカンマ区切りで繋げる
- ブール値はそのオプション名だけ書く
- それ以外のオプションは
name=value
形式で指定する
というルールがあります。
具体例1: gRPC
例えば以下のようにgRPCのprotoがあるとします。
syntax = "proto3"; package helloworld; service Greeter { rpc SayHello(HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
protoc-gen-goはgRPC
をサポートしているので、以下のように引数を渡すことができます。
$ protoc \ -I./plugin \ --go_out=plugins=grpc:./plugin \ ./plugin/*.proto
具体例2: grpc-gateway
protoc-gen-grpc-gatewayプラグインだと、
$ protoc-gen-grpc-gateway --help Usage of protoc-gen-grpc-gateway: -allow_colon_final_segments determines whether colons are permitted in the final segment of a path -allow_delete_body unless set, HTTP DELETE methods may not have a body -allow_patch_feature determines whether to use PATCH feature involving update masks (using google.protobuf.FieldMask). (default true) -allow_repeated_fields_in_body body allows to use repeated field in body and `response_body` field of `google.api.http` annotation option -alsologtostderr log to standard error as well as files -grpc_api_configuration string path to gRPC API Configuration in YAML format -import_path string used as the package if no input files declare go_package. If it contains slashes, everything up to the rightmost slash is ignored. -import_prefix string prefix to be added to go package paths for imported proto files -log_backtrace_at value when logging hits line file:N, emit a stack trace -log_dir string If non-empty, write log files in this directory -logtostderr log to standard error instead of files -paths string specifies how the paths of generated files are structured
このように多くのオプションを用意しているので
$ protoc \ -I./proto \ --grpc-gateway_out=logtostderr=true:./proto \ ./proto/*.proto
こんなふうに指定します。
複数使う
protoc-gen-go
プラグインはGoのprotoメッセージファイルとgrpcのファイルを生成し、protoc-gen-grpc-gateway
はgrpc-gateway用のファイルを生成するのでお互いが上書きするようなことがありません。
そういったプラグイン同士であれば
$ protoc \ -I=./proto \ -I=${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ --go_out=plugins=grpc:./proto \ --grpc-gateway_out=logtostderr=true:./proto \ ./proto/*.proto
このように複数まとめて指定して生成することも可能です。
サンプルコード
今回使ったサンプルコードはこちら
まとめ
一見複雑そうなprotoc
のコンパイル方法ですが、一定のルールを覚えると柔軟に使えるようになると思います。