Go语言 协议存在大量问题

doinxwow  于 2023-05-27  发布在  Go
关注(0)|答案(2)|浏览(160)

我试图让protoc将生成的文件输出到我所有.proto文件所在的文件夹中的一个文件夹。首先,我希望我们都能同意,这些命令令人困惑,而且不是很直观。我偶然发现了这个documentation,它似乎可以解释一切,但事情并不起作用。所以我的protobuf文件在一个名为proto的文件夹中。我有几个protobuf文件,导入另一个protobuf文件。我这样导入它们:

package proto;

option go_package = "github.com/me/golang-grpc-server/proto";

import "proto/another_proto.proto";

message Proto1 {
    ...
    ...
    repeated proto.AnotherProto another_proto = 6;
}

应该可以吧protoc不知道该怎么办。如果我运行这个命令。

protoc --proto_path=proto --go_out=out --go_opt=paths=source_relative --go-grpc_out=out --go-grpc_opt=paths=source_relative proto1.proto another_proto.proto

protoc会给予以下错误:

proto/another_proto.proto: File not found.
proto1.proto:7:1: Import "proto/another_proto.proto" was not found or had errors.
proto1.proto:16:14: "proto.AnotherProto" is not defined.
proto1.proto:40:14: "AnotherProto" is not defined.

如果我把another_proto.proto放在proto1.proto前面,我会得到以下错误:

proto/another_proto.proto: File not found.
proto1.proto:7:1: Import "proto/another_proto.proto" was not found or had errors.
proto1.proto:16:14: "proto.AnotherProto" seems to be defined in "another_proto.proto", which is not imported by "proto1.proto".  To use it here, please add the necessary import.
proto1.proto:40:14: "proto.AnotherProto" seems to be defined in "another_proto.proto", which is not imported by "proto1.proto".  To use it here, please add the necessary import.

然后,如果我删除--proto_path=proto并在每个protobuf前面添加proto\,我不会得到这些错误,但生成的文件将被放置在out\proto中,这非常令人困惑,因为我认为--go_opt=paths=source_relative告诉protoc将输出放在protobuf的位置,如这里所述,在我的情况下是文件夹proto
如果指定了paths=source_relative标志,则输出文件将与输入文件放在同一相对目录中。例如,输入文件protos/buzz.proto会导致输出文件protos/buzz. pb. go。
我尝试使用--go_out=proto/out,但恼人的是它将生成的文件放在proto/out/proto中。我猜这是因为protobuf前面的proto/,因为前面提到的错误,我可能不得不坚持out/proto现在,因为它是目前最明智的路径。
更新:
我不太确定我是否正确地理解了@Daz,但这是我对你的指示的解释。
所以我对Proto1做了以下修改:

package src;

option go_package = "github.com/me/golang-grpc-server/proto/src";

import "src/another_proto.proto";

message Proto1 {
    ...
    ...
    repeated src.AnotherProto another_proto = 6;
}

我将所有其他protobufs移动到proto下的一个文件夹中,当然将每个protobufs的go_package更改为最后的/src,并更改了导入部分以反映更改。然后我将protoc命令修改为:

protoc --proto_path=proto/src --go_out=./out --go_opt=paths=source_relative --go-grpc_out=./out --go-grpc_opt=paths=source_relative proto/src/*.proto

*太棒了。同样的事情在这里,修改它,以反映所做的更改文件夹结构。不幸的是,从protobuf本身开始,这些更改不起作用。import似乎不承认go_packagepackage中的更改。如果我使用“src/another_proto.proto”作为导入路径,linter会说路径“not found or has errors”。然后当我使用“proto/src/another_proto.proto”时,错误就消失了,但是当我运行protoc时,它会抛出以前的“not found...”错误。
更新:
伙计,这是一些非常令人愤怒的情况,可能是由protoc go上的bug或缺少功能引起的。因此,我试图将命令推送到一个更符合逻辑的目录中,因此我修改了protoc命令,使其具有更长的--proto_path,因为我认为这样做可以将文件夹修剪到最终的输出路径。每次我添加一个文件夹到--proto_path,我修改了protobufgo_packageimport以及,因为错误“找不到”protobuf会出现。在我当前的命令中,protobufs看起来像这样:

package src;

option go_package = "github.com/me/golang-grpc-server/proto/src";

import "another_proto.proto";

message Proto1 {
    ...
    ...
    repeated AnotherProto another_proto = 6;
}

看起来很漂亮但是,林特不喜欢它。我猜,正如@Daz提到的,因为protobuf并没有真正使用Golangs包系统,所以linter不知道如何引用import。现在,我有一个项目,我认为应该建立,但有2个文件的错误。这是我当前的命令,它将存根放在与proto文件夹相同级别的另一个文件夹中:

protoc --proto_path=proto/src --go_out=out --go_opt=paths=source_relative --go-grpc_out=out --go-grpc_opt=paths=source_relative proto/src/*.proto
vnjpjtjt

vnjpjtjt1#

是的,很有挑战性。
好消息是:一旦你理解了这个过程,它就会始终如一地工作。我在Linux上使用Golang,Rust和Python的方法,它对我很有效。

1. Protobuf源、包和文件夹

Protobuf源文件定义了一个包(!)层次结构。
我将使用Google的Well-known Types (WKT)作为示例。这些文件位于protobuf(!)包google.protobuf。安装protoc时,通常这些文件也安装在一个名为include的文件夹中,每个WKT例如Timestamp.proto存在于从package名称(!):

{SOME-FOLDER}/include/google/protobuf/timestamp.pro

因此Protobuf包路径Map到文件系统文件夹路径**,但**它们必须锚定在某个文件系统文件夹上(例如include在这种情况下)。此根文件夹{SOME-FOLDER}/includeprotoc中的proto_path值。并且希望在这个根文件夹下导入protos的来自其他proto源的包引用是相对于这个proto_path值作为根的,例如。import "google/protobuf/timestamp.proto";(无include,但必须反映此根目录的文件夹路径)。

2.编译后的protos(stub)、包和文件夹

Protobuf支持编译成多种语言,每种语言都有其独特的特点。既然你问了Golang,我就提供Golang的答案。
Protobuf和Golang在包命名上有相似之处,但重要的是要记住-在许多情况下-protobuf源代码(!)package不一定Map到语言的包。
对于Golang,你必须告诉protoc你想要使用的Golang包:

option go_package="example.com/path/to/package";

WKT Timestamp由Google Timestamppbgoogle.golang.org/protobuf/types/known/timestampb包中实现(与google.protobuf完全无关
所以...
在你的例子中,我认为你应该删除protobuf源代码中的proto引用,因为这个文件夹代表你的项目层次结构而不是protobuf package层次结构。
如你有(!)父文件夹(!)成为你的proto_path,因为你的包层次结构从proto开始(或者你有proto/proto,这会让人困惑):

package proto;

import "proto/another_proto.proto";

或者,正如我所推荐的(!)您可以选择另一个软件包foo(或删除该软件包),继续将proto_path锚定在${SOME_FOLDER}/proto上并更正导入机制:

proto
└── foo
    ├── another_proto.proto
    └── some.proto

some.proto

package foo;

// Golang package is {GO-MODULE}/{GO-PACKAGE}
// Generally GO-PACKAGE={PROTO_PATH}/{PACKAGE} but it need not be
// You can change "${MODULE}/some/random/bar" here without problem
option go_package="github.com/me/golang-grpc-server/proto/foo";

// `another_proto.proto` is in the same `package` and thus same folder
import "foo/another_proto.proto";

// Proto1 is a message that ...
message Proto1 {
    ...
    ...
    // Type references must include the full `package` path e.g. `foo`
    repeated foo.AnotherProto another_proto = 6;
}

使用--go_opt=paths=source_relative很常见,但我的首选(主要是因为它对我有意义)如下:

# Golang Module name
# Protobuf sources will be `option go_package="${MODULE}/proto/foo";`
MODULE="github.com/me/golang-grpc-server"

go mod init ${MODULE}

# proto_path roots the source on "proto"
# Individual protos reflect the package in the folder under "proto"
# Using "foo" as the `package` name requires proto/foo/...
protoc \
--proto_path=${PWD}/proto
--go_out=${PWD} \
--go_opt=module=${MODULE} \
${PWD}/proto/foo/some.proto \
${PWD}/proto/foo/another_proto.proto

因为所有内容都在${PWD}/proto/foo下,所以您也可以只使用${PWD}/proto/foo/*.proto
产量:

.
├── go.mod
├── go.sum
└── proto
    └── foo
        ├── another_proto.pb.go
        ├── another_proto.proto
        ├── some.pb.go
        └── some.proto
j2cgzkjk

j2cgzkjk2#

最后,感谢@DazWilkin最初的回答,我终于找到了做我想做的事情的命令。这就是:

protoc --proto_path=proto/src --go_out=./proto/out --go_opt=paths=source_relative --go-grpc_out=./proto/out --go-grpc_opt=paths=source_relative proto/src/*.proto

我认为这里最重要的一点是--proto_path。使它有确切的文件夹,我的protobuf的,使我能够使用任何--go_out,我想。所以protoc不需要添加--proto_path中缺少的附加/前导文件夹,如果它不是确切的文件夹。
然后在protobuf s上,你必须这样做:

package src;

option go_package = "github.com/me/golang-grpc-server/proto/src";

import "another_proto.proto";

message Proto1 {
    ...
    ...
    repeated AnotherProto another_proto = 6;
}

正如我上次更新中提到的,linter似乎不喜欢这样,因为它可能不知道如何在这种设置中处理protobuf

相关问题