protoc 插件开发

2022-10-28  本文已影响0人  周群力

1. 原理

protoc 从proto文件中抠出来结构化的数据,然后以子进程的方式启动插件,调插件、把结构化数据传给插件,让插件做生成,然后 protoc 主进程把生成的内容写进文件里
https://www.hitzhangjie.pro/blog/2017-05-23-protoc%E5%8F%8A%E6%8F%92%E4%BB%B6%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90%E7%B2%BE%E5%8D%8E%E7%89%88

Q: 如何告诉 protoc 用什么插件
把插件编译好放进 path, 然后在运行 protoc 的时候带上命令行参数 –${NAME}_out, protoc 就会尝试运行该插件

image.png
https://rotemtam.com/2021/03/22/creating-a-protoc-plugin-to-gen-go-code/

以 protoc-gen-go 插件为例:
https://www.hitzhangjie.pro/blog/2017-05-23-protoc%E5%8F%8A%E6%8F%92%E4%BB%B6%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90%E7%B2%BE%E5%8D%8E%E7%89%88/#2-protoc%E6%8F%92%E4%BB%B6%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90
生成代码的核心原理还是拼字符串。
比如拼 enum:

image.png

再比如根据 service 生成 gRPC相关代码:


image.png

Q: gRPC 生成时,用的什么模板、传了什么struct 给模板
A: 没用模板文件,直接用代码命令式的拼字符串

2. protoc 插件开发示例

比如,先生成一个 interface, 作为供开发者实现的 ”component interface“, 或者叫 "handler interface":


image.png

不过 component interface 里用到的 struct 还是 pb.go 里的struct,没有和 pb 解耦

生成 server struct 和工厂函数:


image.png

让 server struct 实现 http api 里的每个 method,并且生成实现逻辑,即先检查字段,最后委托给 component interface


image.png

生成出来的 server struct 代码长这样:


image.png
image.png

检查字段的逻辑,其实是靠 proto 里的 option 声明,然后在代码里做计算、得到关键 flag,最后模板渲染时根据 flag 渲染字段检查逻辑:


image.png

3. 如何开发生成 go 代码的插件

最好基于一些开发框架来写插件,写起来更方便

3.1. 基于 protogen 开发

protogen 是官方提供的一个 go 开发框架
https://rotemtam.com/2021/03/22/creating-a-protoc-plugin-to-gen-go-code/

如果每次调试都需要编译一下会特别麻烦,也无法使用debug等工具


image.png

或者通过--descriptor_set_out 参数把整体结构打印到标准输出
protoc 工具插件和生态 - 白云辉 - 博客园 (cnblogs.com)
https://stackoverflow.com/questions/37730781/how-can-i-get-an-internal-representation-out-of-protoc
https://stackoverflow.com/questions/39171581/proto-descriptor-from-proto-schema-file-or-string

3.2. 基于 protoc-gen-gotemplate

moul/protoc-gen-gotemplate: generic protocol generator based on golang's text/template (grpc/protobuf) (github.com)
看着不错,但:

Idea:

上一篇 下一篇

猜你喜欢

热点阅读