英文:
protoc --go_opt=paths=source_relative vs --go-grpc_opt=paths=source_relative
问题
我正在努力弄清楚protoc
命令和Go插件的使用方法。
以下是这些选项的区别:
--go_out=.
:指定编译器将Go输出写入的目录。--go_opt=paths=source_relative
:指定生成的Go文件中导入路径的相对路径。--go-grpc_out=.
:指定编译器将Go gRPC输出写入的目录。--go-grpc_opt=paths=source_relative
:指定生成的Go gRPC文件中导入路径的相对路径。
如果使用--go_opt
选项,将生成<name>.pb.go
文件;如果使用--go-grpc_opt
选项,将生成<name>_grpc.pb.go
文件。那么为什么还需要--go_out
选项呢?
关于--go-grpc_opt
选项,protoc
的文档中没有提到。而且,protoc -h
命令中也没有将Go列为OUT_DIR选项。
注意:你可以按照这个文档进行安装。
英文:
I am having a hard time figuring out protoc
command and go plugin.
What is the different between:
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
If --go_opt
generate
<name>.pb.go
file
and --go-grpc_opt
generate
<name>_grpc.pb.go
file
why even have --go_out
?
Can you shed some light on protoc - the doc do not say anything about --go-grpc_opt
?
And and protoc -h
do not even list go as an OUT_DIR?
Note: I install using this doc
答案1
得分: 15
为什么要使用--go_out?
首先要理解的是,gRPC和Protocol Buffers不是同一回事,gRPC使用Protocol Buffers,但还有其他框架也在使用它们。所以我们需要生成两者的代码。
现在,为了生成与Protocol Buffers相关的代码,你需要使用--go_out
,就像你提到的那样。但是对于gRPC代码,你需要使用--go-grpc_out
。
--go-grpc_opt生成
不是,是--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
的原因。相关讨论可以在这里找到。
英文:
> why even have --go_out?
So, the thing to understand here is that gRPC is not the same as Protocol Buffers, gRPC uses Protocol Buffers but there are other frameworks that are using them as well. So we need to generate both.
Now, in order to generate the Protocol buffer related code, you need to use --go_out
as you mentioned. but for the gRPC code you need to use --go-grpc_out
.
> and --go-grpc_opt generate <name>_grpc.pb.go file
No, --go-grpc_out
does.
> Can you shade some light on protoc - the doc do not stay anything about --go-grpc_opt?
Then, before the generation of code you can pass some options and that's what --go_opt
and --go-grpc_opt
are for. The first one passes options for Protobuf generation and the second one for gRPC generation. Options are pretty obscure, and there is not official list of all of them, but you used source_relative
(which tell protoc to use relative paths) for path and there is also the module
option (which help protoc know the go module name to generate in proper folder)
> And and protoc -h do not even list go as an OUT_DIR?
And finally, protoc doesn't officially support Go as output, you need to install an external plugin and that's why protoc -h
doesn't show --go_out
. A related discussion can be found here.
答案2
得分: 1
protoc
编译器支持不同的标志或选项,你在命令行上使用的标志决定了生成的Go代码的放置位置。
关于这些标志的官方文档(至少对于paths=source_relative
和module=$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.proto
和bar/baz.proto
,而pb文件被创建在当前目录(--go_out=.
)中,分别命名为foo.pb.go
和bar/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
目录下创建了一个新的protos
目录,其中包含生成的go文件,为什么?因为当我们将--proto-path=src
更改为src
时,proto文件的目录结构变为protos/foo.proto
和protos/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
这与上一个示例完全相同,只是我们提供了一个自定义目录来保存生成的代码。
module=$PREFIX
> 如果指定了module=$PREFIX
标志,输出文件将放置在以Go包的导入路径命名的目录中,但输出文件名中将删除指定的目录前缀。例如,具有Go导入路径为example.com/project/protos/fizz
和example.com/project
作为模块前缀的输入文件protos/buzz.proto
将生成一个输出文件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
。
希望这样对于这些标志的行为更加清晰(至少对我来说是这样的)。
英文:
The protoc
compiler supports different flags or options and the flags you use on the command line decides where the generated go code will be placed.
The official docs for these flags(atleast for paths=source_relative
and module=$PREFIX
) are not very clear and can be hard to understand.
paths=source_relative
Here is what official docs says
> If the paths=source_relative flag is specified, the output file is
> placed in the same relative directory as the input file. For example,
> an input file protos/buzz.proto results in an output file at
> protos/buzz.pb.go.
The above statement might be confusing because it is not giving complete context and folder layout of how the files are placed on the disk.
To me what this flag means is that when used generates the go code in the directory specified by --go_out
and ensures that directory tree structure of the generated go code files matches the directory tree structure of proto files.
Let's say we have the following directory structure
❯ tree
.
├── go.mod
└── src
└── protos
├── bar
│ └── baz.proto
└── foo.proto
5 directories, 3 files
Consider the following examples
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
In the above example we set the --proto_path=src/protos
which means the directory path for the actual proto files would be foo.proto
and bar/baz.proto
, and the pb files were created in the current directory (--go_out=.
) as foo.pb.go
and bar/baz.pb.go
.
Now let's change the --proto_path
in the above command to src
and see what happnes.
❯ 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
This time a new protos
directory was created under which we have the generated go files, why ? Because when we changed the --proto-path=src
the directory structure of proto files changed to protos/foo.proto
and protos/bar/baz.proto
.
Now let's finally throw the --go_out
as well in here and see what happens
❯ 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
This is exactly similar to last example except that we provided a custom directory to hold the generated code.
module=$PREFIX
> If the module=$PREFIX flag is specified, the output file is placed in
> a directory named after the Go package’s import path, but with the
> specified directory prefix removed from the output filename. For
> example, an input file protos/buzz.proto with a Go import path of
> example.com/project/protos/fizz and example.com/project specified as
> the module prefix results in an output file at protos/fizz/buzz.pb.go.
> Generating any Go packages outside the module path results in an
> error. This mode is useful for outputting generated files directly
> into a Go module.
Lets see this as well as in action, consider the following proto file
syntax = "proto3";
package foo;
option go_package = "github.com/rbhanot/dummy-app/greet";
message Foo {
string name = 1;
}
Note carefully I have intentionally remove the src
from the go_package
to show the behaviour of this flag
❯ 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
We see the greet
directory with the pb files in it. So it basically removed the prefix(github.com/rbhanot/dummy-app
) from the go_package
and then actually created the go package in the current directory(--go_out=.
).
Now lets change go_package = "github.com/rbhanot/dummy-app/src/greet";
and running the above command yields following
❯ 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
This time we see the greet package generated inside our src
directory.
Finally lets throw in the same --go_out=out
here as well
❯ 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
This time the generated code was not put in src
but inside the out
and note the directory structure as well src/greet/foo.pb.go
.
I hope this makes things more clear (it atleast did for me) wrt to how these flags behave.
1: https://protobuf.dev/reference/go/go-generated/#invocation
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论