如何在 go 模块中使用生成的 protobuf 包?

如何解决如何在 go 模块中使用生成的 protobuf 包?

我遇到了 Go 模块管理和生成 protobuffers 的问题(使用 go1.16,protoc-gen-go@latest)。

我有这个项目结构:

subproj
├── go.mod         (module company.tld/proj/subproj)
├── subproj.go     (entry point : package main)
├── proto          (folder containing .proto files)
├── packageFolder
|   └── file1.go   (package packageFolder)
└── Makefile       (used to generate *.pb.go and build subproj binary)

proto 文件夹被其他项目使用(显然...)(通过 git 子模块)。
原型如下:

syntax = "proto3"
option csharp_namespace = "Proj.Proto";
option go_package = "company.tld/proj/projpb";
package entity.proj
...

由于消息版本不同,很少有protobuffer文件需要在另一个“命名空间”中:

option go_package = "company.tld/proj/projpb/other";
package entity.proj.other

在我的 Makefile 中,我尝试在正确的位置生成正确的 *.pb.go:

# Proto sources
PROTO= $(wildcard ${PROTODIR}/*.proto)
PBGO=  $(PROTO:.proto=.pb.go)

MODULE_NAME=company.tld/proj
GO_OPT_FLAG=   --go_opt=module=${MODULE_NAME}     
GRPC_OPT_FLAG= --go-grpc_opt=module=${MODULE_NAME}
#GO_OPT_FLAG=   --go_opt=paths=import
#GRPC_OPT_FLAG= --go-grpc_opt=paths=import

.PHONY: clean install proto

## Builds the project
build: proto
    go build ${LDFLAGS} -o ${BINARY}

$(PROTOBUF_GO_PLUGIN):
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

$(GRPC_GO_PLUGIN):
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

%.pb.go: %.proto | $(PROTOBUF_GO_PLUGIN) $(GRPC_GO_PLUGIN)
    protoc --proto_path=${PROTODIR} --go_out=. ${GO_OPT_FLAG} --go-grpc_out=. ${GRPC_OPT_FLAG} $<

proto: $(PBGO)

因此,取决于与 protoc 编译器一起使用的选项:
→ 用--go_opt=paths=import

文件夹树 company.tld/proj/projpb 由 protoc 在项目的根目录创建。每个对象都在名为 projpbother 的包中,位于子包 other 中。

生成的 Proto 对象,包括 other 命名空间-d 对象,具有导入路径 import other "company.tld/proj/projpb/other"(由 go_package 选项带来,但这是错误的,因为它不是现有模块 - go mod tidy/vendor 抱怨它找不到它)。

普通项目文件需要以下导入路径才能到达生成的原型对象:
import pb "company.tld/proj/subproj/company.tld/proj/projpb"
这看起来很奇怪,而且不是正确的做法。

→ 与 --go_opt=module=company.tld/proj

一个文件夹 projpb 由 protoc 在项目的根目录创建,每个生成的 .pb.go 都有包 projpbother,在子包其他。

生成的 Proto 对象,包括 other 命名空间-d 对象,仍然具有导入路径 import other "company.tld/proj/projpb/other"(它仍然由 go_package 选项带来并且仍然是错误的因为这仍然是一个不存在的模块 - 这些是生成的文件......为什么我要创建这些模块?)。

很酷的事情是,有了这个 go_opt,访问生成的类型看起来更正常了
import pb "company.tld/proj/subproj/projpb"

我终于试过了

  • 在 .proto 文件中的 go_package 选项上使用本地导入路径(在构建时被拒绝,因为生成的 protobuffer 对象中会有一个 import other "./projpb/other"
  • 像这样使用 go.mod 文件中的 replace 指令:
replace (
    company.tld/proj/projpb => ./projpb
    company.tld/proj/projpb/other => ./projpb/other
)

(但是 go mod tidy/vendor 抱怨在生成的文件夹 ./projpb 中找不到 go.mod 文件)

有人遇到过类似的问题吗?或者我是否缺少告诉 Go 的命令选项,«我在包中生成 protobuffer 对象,或者在包中生成包,我只是想使用它们。它们不是模块,所以请为生成的对象提供正确的导入路径,让我在我的代码中使用它们»。


[更新 01]
我尝试了 go_opt=paths=source_relative(受此 ticket 的启发)。
我在Makefile中创建了文件夹,protoc在里面生成文件。
备注:

  • 生成的原型使用由 go_package 选项指定的完整路径来相互关联。
  • 只要 go_package 选项需要完整路径,Go (go mod tidy/vendor) 就会在创建的文件夹中搜索 go.mod 文件,其中包含生成的原型。

告诉 Go 我不是在寻找模块,但仍然满足 protobuffer 文件中 go_package 选项的完整路径约束的正确方法是什么?

解决方法

在 proto 文件中多次更改 go_package 选项后,更改 protoc 编译器命令上的 go_opt,这是我发现使用生成的 protobuffers 编译项目的唯一方法,尊重每个 Go 约束都是通过动态创建 go.mod 文件...

final proto «header»(尊重 go_package 选项中的全部内容)

syntax = "proto3";
option csharp_namespace = "Proj.Proto";
option go_package = "company.tld/proj/projpb";
// or for subpackages...
option csharp_namespace = "Proj.Proto.Other";
option go_package = "company.tld/proj/projpb/other";

我的 Makefile(为生成的 proto 文件创建一个 go.mod 文件)


# Proto sources
PROTO= $(shell find ${PROTODIR} -type f -name '*.proto')
PBGO=  $(PROTO:.proto=.pb.go)

DEST_DIR=.
MODULE_NAME=company.tld/proj
GO_OPT_FLAG=   --go_opt=module=${MODULE_NAME}
GRPC_OPT_FLAG= --go-grpc_opt=module=${MODULE_NAME}

PROTO_PKG_DIR=projpb
PROTO_MODULE_NAME=${MODULE_NAME}/${PROTO_PKG_DIR}
PROTO_GOMOD_FILE=${PROTO_PKG_DIR}/go.mod

.PHONY: clean install proto gomod

build: proto gomod
    go build ${LDFLAGS} -o ${BINARY}

%.pb.go: %.proto | $(PROTOBUF_GO_PLUGIN) $(GRPC_GO_PLUGIN) $(DEST_DIR)
    ${PROTOC} --proto_path=${PROTODIR} --go_out=${DEST_DIR} ${GO_OPT_FLAG} --go-grpc_out=${DEST_DIR} ${GRPC_OPT_FLAG} $<

proto: $(PBGO)

gomod: ${PROTO_GOMOD_FILE}

${PROTO_GOMOD_FILE}:
    cd ${PROTO_PKG_DIR} && go mod init ${PROTO_MODULE_NAME} && cd ..

我的主要 go.mod 文件(将即时创建的模块重定向到项目范围内的本地文件夹)

module company.tld/proj/subproj

go 1.16

require (
    // ...
    company.tld/proj/projpb v0.0.0
)

replace company.tld/proj/projpb v0.0.0 => ./projpb

感谢 replace 指令,go mod tidy/vendor 很高兴,不要尝试在远程存储库中搜索模块。
生成的 *.pb.go 文件具有正确的导入路径:company.tld/proj/projpb(子包的 company.tld/proj/projpb/other)。
使用生成的原型的导入语句在主项目中运行良好。

我希望有一个更简单、更漂亮的解决方案,但唉...

对不起,感谢那些考虑过它的人!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res