我很难弄清楚protoc
命令并去插件。
两者有什么区别:
protoc
# Directory where you want the compiler to write your Go output.
--go_out=.
# vs ?
--go_opt=paths=source_relative
# vs ?
--go-grpc_out=.
# vs ?
--go-grpc_opt=paths=source_relative
如果--go_opt
生成
<name>.pb.go
文件
并--go-grpc_opt
生成
<name>_grpc.pb.go
文件
为什么还要--go_out
?
你能对 protoc 有所了解吗 - 文档没有说任何关于--go-grpc_opt
的事情?
而且protoc -h
甚至没有将围棋列为OUT_DIR?
注意:我使用此文档安装
为什么还要有--go_out?
因此,这里要了解的是,gRPC 与协议缓冲区不同,gRPC 使用协议缓冲区,但还有其他框架也在使用它们。因此,我们需要同时生成两者。
现在,为了生成与协议缓冲区相关的代码,您需要使用您提到的--go_out
。 但是对于 gRPC 代码,您需要使用--go-grpc_out
.
go-grpc_opt 生成 _grpc.pb.go 文件
不,--go-grpc_out
做到了。
你能对 protoc 进行一些说明吗 - 文档不会保留任何关于 --go-grpc_opt 的内容?
然后,在生成代码之前,您可以传递一些选项,这就是--go_opt
和--go-grpc_opt
的用途。第一个传递 Protobuf 生成的选项,第二个传递 gRPC 生成的选项。选项非常晦涩难懂,并且没有所有选项的官方列表,但是您使用了source_relative
(告诉protoc使用相对路径)作为路径,并且还有module
选项(帮助protoc知道go模块名称以在正确的文件夹中生成)
而且 protoc -h 甚至没有将 go 列为OUT_DIR?
最后,protoc 不正式支持 Go 作为输出,您需要安装一个外部插件,这就是为什么protoc -h
不显示--go_out
的原因。可以在此处找到相关讨论。
protoc
编译器支持不同的标志或选项,您在命令行上使用的标志决定了生成的 go 代码的放置位置。
这些标志的官方文档(至少对于paths=source_relative
和module=$PREFIX
)不是很清楚,可能很难。
路径=source_relative
这是官方文档所说的
如果指定了 paths=source_relative 标志,则输出文件为 放置在与输入文件相同的相对目录中。例如 输入文件 protos/buzz.proto 生成一个输出文件,网址为 Protos/buzz.pb.go.
上述陈述一开始可能会令人困惑且难以理解,因为 它没有提供文件在磁盘上放置方式的完整上下文和文件夹布局。
这是我的理解,当使用此标志时,编译器会在指定的目录中生成 go 代码--go_out
并确保生成的go代码的目录树结构 文件与源原型文件的目录树结构匹配。词源 在这里很重要,因为它可以根据--proto_path
的值而变化
假设我们有以下目录结构
❯ tree
.
├── go.mod
├── go.sum
└── src
└── protos
├── baz
│ └── bar.proto
└── foo.proto
4 directories, 4 files
这是protoc
命令的一般语法
protoc --proto_path=<IMPORT_DIRECTORY> --go_out=. --go_opt=paths=source_relative <ONE_OR_MORE_SOURCE_PROTO_FILES>
现在让我们考虑以下示例
#1
❯ protoc --proto_path=src/protos --go_out=. --go_opt=paths=source_relative foo.proto baz/bar.proto
❯ ls
baz foo.pb.go go.mod go.sum src
~/development/personal/craftup/go-grpc/proto-buffers
❯ ls -R baz
bar.pb.go
在上面的例子中,我们通过设置--proto_path=src/protos
指定了导入目录 这使得源原型文件的实际路径要foo.proto
和baz/bar.proto
,因此生成的pb文件被放置在当前 目录 (--go_out=.
) 作为foo.pb.go
和bar/baz.pb.go
。
现在让我们将上述命令中的--proto_path
更改为src
,看看有什么好玩的。
**# 2**
❯ protoc --proto_path=src --go_out=. --go_opt=paths=source_relative protos/foo.proto protos/bar/baz.proto
❯ ls -R src
protos
src/protos:
baz foo.proto
src/protos/baz:
bar.proto
这次创建了一个新的protos
目录,并放置了生成的 go 文件 在里面,为什么?因为这次我们将导入路径更改为--proto-path=src
源原型文件的路径更改为protos/foo.proto
和protos/baz/bar.proto
。
#3
现在让我们最终在这里混合--go_out
标志,看看会发生什么
❯ mkdir out
❯ protoc --proto_path=src --go_out=out --go_opt=paths=source_relative protos/foo.proto protos/bar/baz.proto
❯ ls -R out
protos
out/protos:
baz foo.pb.go
out/protos/baz:
bar.pb.go
这与上一个示例完全相同,只是我们提供了一个自定义目录来保存生成的代码。
模块=$PREFIX
如果指定了 module=$PREFIX 标志,则输出文件将放在 以 Go 包的导入路径命名的目录,但具有 从输出文件名中删除了指定的目录前缀。为 例如,输入文件 protos/buzz.proto 的 Go 导入路径为 example.com/project/protos/fizz 和 example.com/project 指定为 模块前缀在Protos/Fizz/buzz.pb.go上生成输出文件。 在模块路径之外生成任何 Go 包会导致 错误。此模式对于直接输出生成的文件很有用 进入 Go 模块。
让我们看看这个以及实际操作,考虑以下原型文件 包含以下内容的地点src/baz/bar.proto
syntax = "proto3";
package bar;
option go_package = "github.com/rbhanot/proto-buffers-practise/bar";
message GreetBar {
string name = 1;
}
❯ protoc --proto_path=src --go_out=. --go_opt=module=github.com/rbhanot/proto-buffers-practise protos/foo.proto protos/baz/bar.proto
❯ ls
bar foo go.mod go.sum src
~/development/personal/craftup/go-grpc/proto-buffers
❯ ls -R foo bar
bar:
bar.pb.go
foo:
foo.pb.go
让我们看看这里发生了什么,编译器从中删除了模块前缀(github.com/rbhanot/proto-buffers-practise
) 在 proto 文件中指定的go_package
,然后在当前目录中创建了包目录(--go_out=.
) 以go_package
选项中的其余路径命名,这些路径被foo
和bar
,并转储其中的代码文件。
现在让我们更改go_package = "github.com/rbhanot/proto-buffers-practise/src";
并运行与上面相同的命令
❯ protoc --proto_path=src --go_out=out --go_opt=module=github.com/rbhanot/proto-buffers-practise protos/foo.proto protos/baz/bar.proto
❯ ls
go.mod go.sum out src
~/development/personal/craftup/go-grpc/proto-buffers
❯ ls out/src
bar.pb.go foo.pb.go
这次我们看到 go 代码是在out/src
目录中生成的。
我希望这能让事情更清楚(至少对我来说是这样)这些标志的行为方式。