命名冲突
protobuf文件在初始化时,会把文件本身,以及文件中定义的message注册到全局注册表中,注册的key默认是根据当前包名加文件名推算。
如果一个项目引入了多个第三方库,不巧这些库有相同protobuf名字,则会产生类似于panic: proto: file “xxx.proto” is already registered这样的错误。
解决的方法,就是在定义protobuf文件的时候,在其中加入package字段,如下所示,这个package跟外部程序的package没有关系,仅仅是一个标示,指的是proto文件的namespace,用于避免注册冲突:
syntax = "proto3"; package x.y.z.common; import "github.com/gogo/protobuf/gogoproto/gogo.proto";
如果是第三方库,没有办法修改protobuf怎么办呢?这种问题就很大,很大可能程序逻辑就有问题,因此最新版本的proto默认会crash。也最好是crash,想办法采用不冲突的第三方库。
当然,如果你很清楚发生的命名冲突对程序完全无害,那也可以在编译时加一个参数,避免crash。
build -ldflags "-X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn"
也可以在程序启动时加一个环境变量:
GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn ./main
目前有三个可选的冲突处理策略:crash, warn和ignore。
protoc如何处理import
加入protobuf中引用了其他protobuf,在protoc时如何处理呢:
syntax = "proto3"; package x.y.z.common; import "github.com/gogo/protobuf/gogoproto/gogo.proto";
那就使用proto_path参数:
protoc --go_out=. --proto_path=/Users/xx/projects/go/src/ --proto_path=. --go_opt=Mmerkle/common/types.proto=merkle/common merkle/common/types.proto
proto_path可以指定多个,需要同时指定import的路径,以及目标proto文件的路径。
比如例子中,目标proto为:merkle/common/types.proto。
则第一个proto_path指定的是import “github.com/gogo/protobuf/gogoproto/gogo.proto”的路径,也就是gogo.proto的最终路径为:/Users/xx/projects/go/src/github.com/gogo/protobuf/gogoproto/gogo.prot。
第二个proto_path指定的是目标文件路径,也就是我需要编译的proto文件位置为:./merkle/common/types.proto
–go_opt=Mmerkle/common/types.proto=merkle/common merkle/common/types.proto采用了–go_opt=M语法。等同于在proto文件中option go_package指令,用于设置生成后的文件路径。
Ref
- https://protobuf.dev/reference/go/faq/
- https://segmentfault.com/a/1190000042909964#item-1
回复 cytotec abortion pill 取消回复