protobuf 使我们经常使用的通信数据传输格式,为了方便lua直接使用proto 生成的文件,使用了protoc-gen-lua 工具,但是这个使用嵌套的proto 文件时,protoc.exe 无法正常引用,报错找不到对应的文件。所以后来参考下面两篇文章,修改了 protoc-gen-lua 这个Python文件,得到了想要的结果。废话不多说,直接上图:
目标文件
proto 文件夹结构option java_package = "com.road.ddt.pb.game.login";
option java_outer_classname = "LoginMsgProto";
import "com/net/TestInfo.proto";
/* 登陆请求 code:8002*/
message LoginMsg {
optional string userName = 1;
optional string unixTime = 2;
optional string signKey = 3;
optional string host = 4;
optional int32 port = 5;
optional int32 userId = 6;
optional int32 loginCode = 7;
repeated TestInfoProto reslut = 8;
}
option java_package = "com.road.ddt.pb.com.net";
option java_outer_classname = "TestMsg";
message TestInfoProto {
optional bool bool = 1;
optional int32 int = 2;
}
option java_package = "com.road.ddt.pb.client.login";
option java_outer_classname = "LoginOutMsgProto";
import "com/net/TestInfo.proto";
/* 登陆结果返回 code:2*/
message LoginOutMsg {
repeated TestInfoProto reslut = 1;
}
修改 protoc-gen-lua
修改 code_gen_field 方法
if field_desc.HasField('type_name'):
# type_name = env.get_ref_name(field_desc.type_name).upper().replace('.', '_')
if field_desc.type == FDP.TYPE_MESSAGE:
# 修改 引用其他文件夹下的message 时,把左边的文件名截取出来,再把右边的字段名大写处理 如: TestInfo_pb.TESTINFOPROTO
typeNameL = env.get_ref_name(field_desc.type_name).split(".")[0]
typeNameR = env.get_ref_name(field_desc.type_name).split(".")[1]
typeNameLL = typeNameL.split("/")
typeNameL = typeNameLL[len(typeNameLL) - 1]
type_name = typeNameL +"."+ (typeNameR.upper())
context('.message_type = %s\n' % type_name)
else:
type_name = env.get_ref_name(field_desc.type_name).upper().replace('.', '_')
context('.enum_type = %s\n' % type_name)
修改 code_gen_message 方法
def code_gen_message(message_descriptor, env, containing_type = None):
env.enter(message_descriptor.name)
full_name = env.get_local_name()
obj_name = full_name.upper().replace('.', '_')
# 修改 把local 去掉了,方便 TestInfo_pb.TESTINFOPROTO 能否直接访问到
env.descriptor.append(
"%s = protobuf.Descriptor();\n"% obj_name
)
# "local %s = protobuf.Descriptor();\n"% obj_name
修改 code_gen_file 方法
if is_gen:
lua = Writer()
write_header(lua)
lua('local protobuf = require "protobuf"\n')
for i in includes:
# 修改 将前面的local xx_pb 去掉 了,因为 这个require 返回的是 一个 true or false
lua('require("%s_pb")\n' % (i))
# lua('local %s_pb = require("%s_pb")\n' % (i, i))
# 修改 修改文件名,将文件名中的路径去掉
typeNameLL = env.filename.split("/")
typeNameL = typeNameLL[len(typeNameLL) - 1]
# 修改 增加了",package.seeall" 多传入一个package.seeall的参数,相当于 setmetatable(M, {__index = _G}) .
lua("module('%s_pb',package.seeall)\n" % typeNameL)
生成结果,保留了目录结构
image.pngLoginOutMsg_pb.lua
-- Generated By protoc-gen-lua Do not Edit
local protobuf = require "protobuf"
require("com/net/TestInfo_pb")
module('LoginOutMsg_pb',package.seeall)
LOGINOUTMSG = protobuf.Descriptor();
local LOGINOUTMSG_RESLUT_FIELD = protobuf.FieldDescriptor();
LOGINOUTMSG_RESLUT_FIELD.name = "reslut"
LOGINOUTMSG_RESLUT_FIELD.full_name = ".LoginOutMsg.reslut"
LOGINOUTMSG_RESLUT_FIELD.number = 1
LOGINOUTMSG_RESLUT_FIELD.index = 0
LOGINOUTMSG_RESLUT_FIELD.label = 3
LOGINOUTMSG_RESLUT_FIELD.has_default_value = false
LOGINOUTMSG_RESLUT_FIELD.default_value = {}
LOGINOUTMSG_RESLUT_FIELD.message_type = TestInfo_pb.TESTINFOPROTO
LOGINOUTMSG_RESLUT_FIELD.type = 11
LOGINOUTMSG_RESLUT_FIELD.cpp_type = 10
LOGINOUTMSG.name = "LoginOutMsg"
LOGINOUTMSG.full_name = ".LoginOutMsg"
LOGINOUTMSG.nested_types = {}
LOGINOUTMSG.enum_types = {}
LOGINOUTMSG.fields = {LOGINOUTMSG_RESLUT_FIELD}
LOGINOUTMSG.is_extendable = false
LOGINOUTMSG.extensions = {}
LoginOutMsg = protobuf.Message(LOGINOUTMSG)
TestInfo_pb.lua
-- Generated By protoc-gen-lua Do not Edit
local protobuf = require "protobuf"
module('TestInfo_pb',package.seeall)
TESTINFOPROTO = protobuf.Descriptor();
local TESTINFOPROTO_BOOL_FIELD = protobuf.FieldDescriptor();
local TESTINFOPROTO_INT_FIELD = protobuf.FieldDescriptor();
TESTINFOPROTO_BOOL_FIELD.name = "bool"
TESTINFOPROTO_BOOL_FIELD.full_name = ".TestInfoProto.bool"
TESTINFOPROTO_BOOL_FIELD.number = 1
TESTINFOPROTO_BOOL_FIELD.index = 0
TESTINFOPROTO_BOOL_FIELD.label = 1
TESTINFOPROTO_BOOL_FIELD.has_default_value = false
TESTINFOPROTO_BOOL_FIELD.default_value = false
TESTINFOPROTO_BOOL_FIELD.type = 8
TESTINFOPROTO_BOOL_FIELD.cpp_type = 7
TESTINFOPROTO_INT_FIELD.name = "int"
TESTINFOPROTO_INT_FIELD.full_name = ".TestInfoProto.int"
TESTINFOPROTO_INT_FIELD.number = 2
TESTINFOPROTO_INT_FIELD.index = 1
TESTINFOPROTO_INT_FIELD.label = 1
TESTINFOPROTO_INT_FIELD.has_default_value = false
TESTINFOPROTO_INT_FIELD.default_value = 0
TESTINFOPROTO_INT_FIELD.type = 5
TESTINFOPROTO_INT_FIELD.cpp_type = 1
TESTINFOPROTO.name = "TestInfoProto"
TESTINFOPROTO.full_name = ".TestInfoProto"
TESTINFOPROTO.nested_types = {}
TESTINFOPROTO.enum_types = {}
TESTINFOPROTO.fields = {TESTINFOPROTO_BOOL_FIELD, TESTINFOPROTO_INT_FIELD}
TESTINFOPROTO.is_extendable = false
TESTINFOPROTO.extensions = {}
TestInfoProto = protobuf.Message(TESTINFOPROTO)
调用方法示例
image.png调试结果
image.png注意事项
一、.proto 文件不能重名,必须保证名字唯一,因为这里的module 使用了文件名。
工具下载路径
参考
protoc-gen-lua多个proto嵌套的实现
protoc-gen-lua 编译、安装、使用教程
Lua中module函数的作用和用法
工具下载protoToLua
网友评论