protoc --go_opt=paths=source_relative vs --go-grpc_opt=paths=source_relative

r8xiu3jd  于 2023-08-01  发布在  Go
关注(0)|答案(2)|浏览(155)

我很难弄清楚protoc命令和go插件。
以下两者有何不同:

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
你能解释一下协议吗?文档没有提到--go-grpc_opt
protoc -h甚至不列出去作为一个OUT_DIR?
注意:我使用此doc安装

kninwzqo

kninwzqo1#

为什么要出去?
所以,这里要理解的是,gRPC与Protocol Buffers不同,gRPC使用Protocol Buffers,但也有其他框架也在使用它们。所以我们需要两者都产生。
现在,为了生成与Protocol buffer相关的代码,您需要使用您提到的--go_out。但是对于gRPC代码,您需要使用--go-grpc_out
和--go-grpc_opt生成grpc.pb.go文件
不,--go-grpc_out有。
你能在协议上加一些光吗?文档不会留下任何关于-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。相关讨论可以在here中找到。

tkclm6bt

tkclm6bt2#

protoc编译器支持不同的标志或选项,您在命令行上使用的标志决定了生成的go代码将被放置在哪里。
这些标志的官方[文档][1](至少对于paths=source_relativemodule=$PREFIX)不是很清楚,很难理解。

paths=source_relative

官方文件是这样说的
如果指定了paths=source_relative标志,则输出文件将与输入文件放在同一相对目录中。例如,输入文件protos/buzz.proto会导致输出文件protos/buzz. pb. go。
上面的语句可能会令人困惑,因为它没有提供完整的上下文和文件夹布局,说明文件如何放置在磁盘上。
对我来说,这个标志意味着当使用时,在--go_out指定的目录中生成go代码,并确保生成的go代码文件的目录树结构与proto文件的目录树结构相匹配。
假设我们有以下目录结构

❯ tree
.
├── go.mod
└── src
    └── protos
        ├── bar
        │   └── baz.proto
        └── foo.proto

5 directories, 3 files

字符串
考虑以下示例

protoc --proto_path=src/protos --go_out=. --go_opt=paths=source_relative foo.proto bar/baz.proto

❯ ls -l
drwxrwxr-x  3 rbhanot  staff    96 Jul  5 20:52 bar
-rw-rw-r--  1 rbhanot  staff  3912 Jul  5 20:52 foo.pb.go
-rw-rw-r--  1 rbhanot  staff    45 Jul  5 16:12 go.mod
drwxr-xr-x  3 rbhanot  staff    96 Jul  5 18:12 src

❯ ls -l bar
-rw-rw-r--  1 rbhanot  staff  4053 Jul  5 20:52 baz.pb.go


在上面的例子中,我们设置了--proto_path=src/protos,这意味着实际proto文件的目录路径将是foo.protobar/baz.proto,而pb文件将在当前目录(--go_out=.)中创建为foo.pb.gobar/baz.pb.go
现在让我们将上面命令中的--proto_path更改为src,看看会发生什么。

❯ protoc --proto_path=src --go_out=. --go_opt=paths=source_relative protos/foo.proto protos/bar/baz.proto

❯ ls -l
-rw-rw-r--  1 rbhanot  staff   45 Jul  5 16:12 go.mod
drwxrwxr-x  4 rbhanot  staff  128 Jul  5 21:00 protos
drwxr-xr-x  3 rbhanot  staff   96 Jul  5 18:12 src

~/dummy_go  
❯ ls -l protos
drwxrwxr-x  3 rbhanot  staff    96 Jul  5 21:00 bar
-rw-rw-r--  1 rbhanot  staff  4158 Jul  5 21:00 foo.pb.go


这一次创建了一个新的protos目录,在这个目录下我们有生成的go文件,为什么?因为当我们更改--proto-path=src时,proto文件的目录结构更改为protos/foo.protoprotos/bar/baz.proto
现在让我们最后把--go_out也放在这里,看看会发生什么

❯ mkdir out
❯ protoc --proto_path=src --go_out=out --go_opt=paths=source_relative protos/foo.proto protos/bar/baz.proto
❯ ls -l        
total 8
-rw-rw-r--  1 rbhanot  staff  45 Jul  5 16:12 go.mod
drwxrwxr-x  3 rbhanot  staff  96 Jul  5 21:05 out
drwxr-xr-x  3 rbhanot  staff  96 Jul  5 18:12 src

~/dummy_go  
❯ ls -lR out
drwxrwxr-x  4 rbhanot  staff  128 Jul  5 21:05 protos

out/protos:
drwxrwxr-x  3 rbhanot  staff    96 Jul  5 21:05 bar
-rw-rw-r--  1 rbhanot  staff  4158 Jul  5 21:05 foo.pb.go

out/protos/bar:
-rw-rw-r--  1 rbhanot  staff  4298 Jul  5 21:05 baz.pb.go


这与上一个示例完全相似,只是我们提供了一个自定义目录来保存生成的代码。

模块=$PREFIX

如果指定了module=$PREFIX标志,则输出文件将被放置在以Go包的导入路径命名的目录中,但指定的目录前缀将从输出文件名中删除。例如,输入文件protos/buzz.proto的Go导入路径为example.com/project/protos/fizz指定为模块前缀,输出文件为protos/fizz/buzz. pb. go。在模块路径之外生成任何Go包都会导致错误。此模式对于将生成的文件直接输出到Go模块中非常有用。
让我们看看这一点,以及在行动中,考虑以下proto文件

syntax = "proto3";

package foo;

option go_package = "github.com/rbhanot/dummy-app/greet";

message Foo {
    string name = 1;
}


请注意,我故意从go_package中删除了src,以显示此标志的行为

❯ protoc --proto_path=src --go_out=. --go_opt=module=github.com/rbhanot/dummy-app protos/foo.proto protos/bar/baz.proto

❯ ls -l
-rw-rw-r--  1 rbhanot  staff   45 Jul  5 16:12 go.mod
drwxrwxr-x  3 rbhanot  staff   96 Jul  5 21:14 greet
drwxr-xr-x  4 rbhanot  staff  128 Jul  5 21:14 src

❯ ls -l greet
-rw-rw-r--  1 rbhanot  staff  4274 Jul  5 21:17 baz.pb.go
-rw-rw-r--  1 rbhanot  staff  4133 Jul  5 21:17 foo.pb.go


我们看到greet目录,其中包含pb文件。因此,它基本上从go_package中删除了前缀(github.com/rbhanot/dummy-app),然后在当前目录(--go_out=.)中实际创建了go包。
现在让我们更改go_package = "github.com/rbhanot/dummy-app/src/greet";,运行上面的命令会产生以下结果

❯ protoc --proto_path=src --go_out=. --go_opt=module=github.com/rbhanot/dummy-app protos/foo.proto protos/bar/baz.proto

❯ ls -l src
drwxrwxr-x  4 rbhanot  staff  128 Jul  5 21:22 greet
drwxr-xr-x  4 rbhanot  staff  128 Jul  5 17:37 protos


这一次,我们看到在src目录中生成的greet包。
最后,让我们在这里也抛出相同的--go_out=out

❯ mkdir out

❯ protoc --proto_path=src --go_out=out --go_opt=module=github.com/rbhanot/dummy-app protos/foo.proto protos/bar/baz.proto

❯ ls -l out     
total 0
drwxrwxr-x  3 rbhanot  staff  96 Jul  5 21:24 src

❯ ls -lR out
total 0
drwxrwxr-x  3 rbhanot  staff  96 Jul  5 21:24 src

out/src:
total 0
drwxrwxr-x  4 rbhanot  staff  128 Jul  5 21:24 greet

out/src/greet:
total 32
-rw-rw-r--  1 rbhanot  staff  4298 Jul  5 21:24 baz.pb.go
-rw-rw-r--  1 rbhanot  staff  4158 Jul  5 21:24 foo.pb.go


这一次生成的代码没有放在src中,而是放在out中,请注意目录结构以及src/greet/foo.pb.go
我希望这能让事情变得更清楚(至少对我来说是这样),关于这些标志的行为。[1]:https://protobuf.dev/reference/go/go-generated/#invocation

相关问题