问题描述
在 test.proto 文件中引用了一个外部包:
1 | import "google/api/annotations.proto"; |
当使用命令编译的时候提示找不到包:
1 | # protoc --go_out=plugins=grpc:. ./test.proto |
解决方案
去 GitHub 上将对应的包下载下来放在 $GOPATH/src 下,例如这里缺失 google/api。
去 googleapis 将项目下载下来,并将整个项目放到 $GOPATH/src,此时的完整路径应该是:
1 | $GOPATH/src/google/api/annotations.proto |
这才完成了第一步,如果这时候去直接执行 protoc 编译命令,依旧会得到上面的报错信息,protoc 并没有成功的获取到外部 proto 文件。
为了解决问题,首先了解下 protoc 中 import 的两条规则:
- import 不允许使用相对路径:
Backslashes, consecutive slashes, ".", or ".." are not allowed in the virtual path - import 导入路径应该使用从根开始的绝对路径:
google/api/annotations.proto
这个根开始的绝对路径指的是 $GOPATH/src 开始的路径,这个需要先了解。
假设此时的目录结构为:
1 | src |
test.proto 中引用了 google/api/annotations.proto,此时我们命令的执行位置为:
1 | src/test |
执行的命令为:
1 | protoc --go_out=plugins=grpc:. ./test.proto |
protoc 有一个参数 -I,表示引入文件的目录路径,这里有坑。
-I 参数简单来说,就是如果多个 proto 文件之间有互相依赖,生成某个 proto 文件时,需要 import 其他几个 proto 文件,这时候就要用 -I 来指定搜索目录。如果没有指定 -I 参数,则在当前目录进行搜索。
例如这里的 import "google/api/annotations.proto";,这里的这个路径,其实是从 $GOPATH/src 开始的路径。
也就是说,首先要用 -I 参数将引入包的路径设置到 $GOPATH/src 目录下,即
1 | protoc -I ../ |
完整命令:
1 | # pwd |
每个 -I 参数都引入一个目录,proto 文件中引入了几个外部 proto 文件理论来说就需要多少个 -I(同一目录的可以一次性引入),再加上待编译的 proto 也需要引入,所以上面这里就用了两个 -I 来引入目录文件。
推荐使用 $GOPATH/src 的方式来引入
简单直观不容易出错
1 | protoc -I ./ \ |
针对 JS 版本的动态引入
grpc-node 提供了结合 @grpc/proto-loader 进行动态引入 proto 的功能。
如果使用该方式,则忽略上面提到的 import 的两条规则。
即优先考虑使用相对路径引入,否则报错:Error: ENOENT: no such file or directory
1 | // eg:test.proto中需要这样写 |
