通常编译 protobuf 会使用 protoc 手动编译,更好一点可以写一个 Makefile 指令来做。
不过在 Go 中提供一种在源文件定义类似 Makefile 指令 generate。当运行 go generate 后,编译器会找到所有包含 //go:generate command argument... 的注释,然后运行后面的命令。
那这样的话就不需要再写一个 Makefile 指令了。
使用 go generate 工具编译 protobuf
新建一个文件目录 test,然后编辑 doc.go 文件。BTW,doc.go 是约定俗成写包文档的文件,通常不会写逻辑代码,所以这里写 generate 指令最好不过了。
| 1 | //go:generate protoc --go_out=. *.proto | 
generate 指令只能在 go 文件中使用,而且需要注意的是和传统注释不同的是 // 后面不能有空格。
然后编辑 test.proto 文件
| 1 | syntax="proto3"; | 
另外 go build 等其它命令不会调用 go generate,必须手动显式调用 go generate 。不过这报错了,提示找不到文件。
| 1 | *.proto: No such file or directory | 
这个问题在文档里有说明,generate 并不处理 glob。那我们这里修改 doc.go 当 sh 直接处理就行了。
| 1 | //go:generate sh -c "protoc --go_out=. *.proto" | 
另外也要注意,双引号会被 go 进行解析,所以该转义的地方需要注意转义。
自动生成 Stringer 接口
在 golang 博客中 generate code介绍了一种类似宏指令的方式。
假设定义一组不同类型的药物的枚举:
| 1 | package painkiller | 
通常为了能直接 print 其枚举名称,我们会给 Pill 实现 Stringer 接口。
| 1 | func (p Pill) String() string { | 
不过有了 generate 指令我们可以不用手写这些逻辑代码。
下载并安装 stringer
| 1 | go get golang.org/x/tools/cmd/stringer | 
在 Pill 包名称上添加一句 //go:generate stringer -type=Pill。通常为了和文档区分开,我们还要加一个空行。
| 1 | //go:generate stringer -type=Pill | 
这时候会自动生成 pill_string.go 
| 1 | // generated by stringer -type Pill pill.go; DO NOT EDIT | 
命令格式
| 1 | go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages] | 
还可以在命令中定义别名,不过只有当前文件内有效。
| 1 | //go:generate -command YACC go tool yacc | 
另外还支持下面这些变量:
| 1 | $GOARCH |