ProtoBuffer官方提供了C++、Java、Python等语言的生成器,但不支持Erlang语言,为了让Erlang也可以使用ProtoBuffer,需要下载一个第三方生成工具。我这里使用的是gbp。
1.安装git工具,并将git下的bin目录添加到path路径中。
2.安装mingw,并添加到path路径中。
3.从https://github.com/tomas-abrahamsson/gpb中checkout源码。
4.进入到gpb根目录,直接make进行编译。另外一种编译方式是使用rebar,需要下载rebar工具,可以直接下载到gpb的根目录然后使用escript rebar compile指令编译。
5.编译我们的ProtoBuffer文件,假定我们将ProtoBuffer文件XX.proto复制到gpb/bin目录下,并在此目录下创建一个pb目录,我们在gpb/bin目录中再创建一个批处理来生成Erlang文件,批处理文件compile.bat内容如下:
escript protoc-erl -I. -o ./pb XX.proto
pause
该命令会将生成的Erlang文件放到gbp/bin/pb目录中。这是只有一个PB文件的情况,在实际项目中,我们一般会有多个PB文件,这些PB文件可能还会有依赖关系,比如我们有两个PB文件XX.proto和YY.proto:
YY.proto:
package Protocol;
option optimize_for = LITE_RUNTIME;
option cc_generic_services = false;
enum EValue
{
VA = 0;
VB = 1;
VC = 2;
VD = 3;
};
XX.proto:
package Protocol;
import "YY.proto";
option optimize_for = LITE_RUNTIME;
option cc_generic_services = false;
message Msg
{
YY.EValue v1 = 1;
int32 v2 = 2;
};
这个时候运行compile.bat,会产生一个错误:
in msg Msg, field v1: undefined reference YY.EValue
说明目前的gpb还不支持具有依赖关系的PB,为了解决这个问题,我对源码进行了调试,发现gpb在解析PB文件时并没有去处理依赖关系,既然没处理依赖,那我们加上依赖的处理即可。找问题需要花时间,只要找到问题的根源了,解决起来也许就是一小段代码就可以解决的事情。经调试查找,gpb解析PB源文件的源码在gpb_parse.yrl文件中,而解决PB依赖关系的代码是由:
resolve_ref(Defs, Ref, Root, FullName)
函数处理的,我们只需要加一个解决依赖的代码,然后在上面的函数中调用一下即可,完整代码如下:
filterRef([_,'.',Type]) -> [Type];
filterRef(Other) -> Other.
%% -> {found, {msg,FullName}|{enum,FullName}} | not_found
resolve_ref(Defs, Ref0, Root, FullName) ->
Ref = filterRef(Ref0),
case is_absolute_ref(Ref) of
true ->
FullRef = ensure_path_prepended(Root, Ref),
find_typename(FullRef, Defs);
false ->
PossibleRoots = compute_roots(FullName),
find_ref_rootwards(PossibleRoots, Ref, Defs)
end.
现在执行compile.bat就不会报错了,可以在gpb/bin/pb目录下看到四个文件。
Btw:写完本博客才发现之前有写过一类似的博客,当时CSDN无法登录,在博客园写的,参见:https://www.cnblogs.com/witton/p/6858117.html
祝玩得开心!