因为需求,最近又重新回忆了下tolua++的相关流程, 以 3.9的 lua stack 的初始化相关代码开始解析:
_state = lua_open();
luaL_openlibs(_state);
toluafix_open(_state);
// Register our version of the global "print" function
const luaL_reg global_functions [] = {
{"print", lua_print},
{"release_print",lua_release_print},
{nullptr, nullptr}
};
luaL_register(_state, "_G", global_functions);
g_luaType.clear();
register_all_cocos2dx(_state);
register_all_cocos2dx 如下:
TOLUA_API int register_all_cocos2dx(lua_State* tolua_S)
{
tolua_open(tolua_S);
tolua_module(tolua_S,"cc",0);
tolua_beginmodule(tolua_S,"cc");
lua_register_cocos2dx_Ref(tolua_S);
...
tolua_endmodule(tolua_S);
return 1;
}
TOLUA_API void tolua_open (lua_State* L)
{
int top = lua_gettop(L);
lua_pushstring(L,"tolua_opened");
lua_rawget(L,LUA_REGISTRYINDEX);
if (!lua_isboolean(L,-1))
{
lua_pushstring(L,"tolua_opened");
lua_pushboolean(L,1);
lua_rawset(L,LUA_REGISTRYINDEX);
// create value root table
lua_pushstring(L, TOLUA_VALUE_ROOT);
lua_newtable(L);
lua_rawset(L, LUA_REGISTRYINDEX);
/* create object ptr -> udata mapping table */
lua_pushstring(L,"tolua_ubox");
lua_newtable(L);
/* make weak value metatable for ubox table to allow userdata to be
garbage-collected */
lua_newtable(L);
lua_pushliteral(L, "__mode");
lua_pushliteral(L, "v");
lua_rawset(L, -3); /* stack: string ubox mt */
lua_setmetatable(L, -2); /* stack: string ubox */
lua_rawset(L,LUA_REGISTRYINDEX);
lua_pushstring(L,"tolua_super");
lua_newtable(L);
lua_rawset(L,LUA_REGISTRYINDEX);
lua_pushstring(L,"tolua_gc");
lua_newtable(L);
lua_rawset(L,LUA_REGISTRYINDEX);
/* create gc_event closure */
lua_pushstring(L, "tolua_gc_event");
lua_pushstring(L, "tolua_gc");
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushstring(L, "tolua_super");
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushcclosure(L, class_gc_event, 2);
lua_rawset(L, LUA_REGISTRYINDEX);
tolua_newmetatable(L,"tolua_commonclass");
tolua_module(L,NULL,0);
tolua_beginmodule(L,NULL);
tolua_module(L,"tolua",0);
tolua_beginmodule(L,"tolua");
tolua_function(L,"type",tolua_bnd_type);
tolua_function(L,"takeownership",tolua_bnd_takeownership);
tolua_function(L,"releaseownership",tolua_bnd_releaseownership);
tolua_function(L,"cast",tolua_bnd_cast);
tolua_function(L,"isnull",tolua_bnd_isnulluserdata);
tolua_function(L,"inherit", tolua_bnd_inherit);
#ifdef LUA_VERSION_NUM /* lua 5.1 */
tolua_function(L, "setpeer", tolua_bnd_setpeer);
tolua_function(L, "getpeer", tolua_bnd_getpeer);
#endif
tolua_function(L,"getcfunction", tolua_bnd_getcfunction);
tolua_function(L,"iskindof", tolua_bnd_iskindof);
tolua_endmodule(L);
tolua_endmodule(L);
}
lua_settop(L,top);
}
对 tolua_open 解析如下:
tolua_open:
LUA_REGISTRYINDEX["tolua_opened"] = true
LUA_REGISTRYINDEX[TOLUA_VALUE_ROOT] = {}
LUA_REGISTRYINDEX["tolua_ubox"] = setmetatable({}, {__mode = v})
LUA_REGISTRYINDEX["tolua_super"] = {}
LUA_REGISTRYINDEX["tolua_gc"] = {}
LUA_REGISTRYINDEX["tolua_gc_event"] = class_gc_event [closure: LUA_REGISTRYINDEX["tolua_gc"] LUA_REGISTRYINDEX["tolua_super"]]
tolua_newmetatable(L, "tolua_commonclass")
mt = {}
LUA_REGISTRYINDEX["tolua_commonclass"] = mt
LUA_REGISTRYINDEX[mt] = "tolua_commonclass"
tolua_classevents(mt)
tolua_module(L,NULL,0); 确保拥有该模块, 该木块没有 moduleevent __index, __newindex
tolua_beginmodule(L,NULL); push _G (not .isclass, a normal table not mt)
tolua_module(L,"tolua",0); _G["tolua"] = {}
tolua_beginmodule(L,"tolua"); push _G["tolua"]
tolua_function(L,"type",tolua_bnd_type); _G["tolua"]["type"] = tolua_bnd_type
...
tolua_endmodule(L); pop
tolua_endmodule(L); pop
restore stack
需要留意的:
2.当push的 userdata 类的 mt 中没有 tolua_ubox 则这个userdata 会放入到这个 全局 tolua_ubox 中
3.tolua_super 存储注册到lua中类的继承关系,例如 c_derived 继承 c_base 那么 tolua_super[mt_c_derived] = {cbaseName = true}, cbaseName为 c_base 在注册表的 class name
4.注册的lua类的基类都会索引 tolua_commonclass, 他的 __index, __newindex, __gc 值得注意下,
其他流程用伪代码解析如下:
主流程调用:
register_all_cocos2dx: //栈顶已经有一个 _G 了
tolua_open(tolua_S); //见核心一
tolua_module(tolua_S,"cc",0); //确保拥有 _G["cc"]
tolua_beginmodule(tolua_S,"cc"); //push _G["cc"]
lua_register_cocos2dx_Ref(tolua_S);
...
tolua_endmodule(tolua_S); //pop
注册详细信息:
int lua_register_cocos2dx_Ref(lua_State* tolua_S)
{
tolua_usertype(tolua_S,"cc.Ref");:
tolua_newmetatable("cc.Ref")
tolua_newmetatable("const cc.Ref")
mapsuper(L,type,ctype);:
mapsuper (lua_State* L, const char* name, const char* base)
mt = LUA_REGISTRYINDEX[name]
LUA_REGISTRYINDEX["tolua_super"][mt] = {$base = true}
mtbase = LUA_REGISTRYINDEX[base]
merge(LUA_REGISTRYINDEX["tolua_super"][mt], LUA_REGISTRYINDEX["tolua_super"][mtbase]) 右侧内容 merge 到左侧
tolua_cclass(tolua_S,"Ref","cc.Ref","",nullptr);:
tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col):
mapinheritance(L,name,base);
mapinheritance(L,cname,name);
mapinheritance (lua_State* L, const char* name, const char* base)
push mt_name as mt
push mt_base or LUA_REGISTRYINDEX["tolua_commonclass"] as base_mt
set_ubox(L);:
mt["tolua_ubox"] = base_mt["tolua_ubox"] or setmetatable({}, {__mode = v})
setmetatable(mt, base_mt)
mapsuper(L,cname,cbase);
mapsuper(L,name,base);
LUA_REGISTRYINDEX[name][".collector"] = col
LUA_REGISTRYINDEX[cname][".collector"] = col
module[lname] = setmetatable({[".isclass"] = true}, mt_name)
// stack: module
tolua_beginmodule(tolua_S,"Ref");
tolua_function(tolua_S,"release",lua_cocos2dx_Ref_release);
...
tolua_endmodule(tolua_S);
std::string typeName = typeid(cocos2d::Ref).name();
g_luaType[typeName] = "cc.Ref";
g_typeCast["Ref"] = "cc.Ref";
return 1;
}
OK,完毕, 知道了这些, 在 lua中 扩充、派生 那些注册进lua中的类就已经不是问题了。
干吧爹~,争取这几周内把框架搭建出来。