cocos2dx之tolua++全面分析(一):tolua++工具本身

在cocos2dx/tools/tolua++下面,有大量pkg文件,这些是按tolua++要求格式写好的、需要导出到lua中的c++类描述文件。

每当在c++类里增加了新函数需要导出时,应同步修改相应的pkg文件,然后运行此目录下的build.sh,就会重新生成cocos2dx/script/lua/cocos2dx_support/LuaCocos2d.cpp,里面就包含了对新增函数的封装代码。

build.sh的内容如下:

${TOLUA} -L basic.lua -o
../../scripting/lua/cocos2dx_support/LuaCocos2d.cpp Cocos2d.pkg

在运行标准的tolua++之前,还加载了额外的脚本basic.lua,这是由于cocos2dx在lua绑定方面并未完全遵照tolua++的默认做法,因此需要对其进行定制,basic.lua主要做的事情是:

1、将所有导出的CCXXXX类的push函数(也就是将cpp
obj传进lua时调用的函数)修改为自己的toluafix_pushusertype_ccobject

2、将function和table两种类型的to和is函数(分别是指将lua
obj传进cpp时调的函数、判断一个变量是否为本类型时调的函数)修改为toluafix_is/to_funtion/table

以上两条是tolua++本身提供的用户类型定制方法,也就是通过定义tolua++认别的3个特殊变量_to/push/is_function[classname]
= XXX来实现。

至于为什么要做这些定制到后面分析tolua++的绑定实现时再详细说明。

下面还有一些通过强制替换输出的cpp胶水代码来实现的针对某一个类型的特殊定制:

3、将

ccColor3B color = *((ccColor3B*)
tolua_tousertype(tolua_S,4,(void*)&(const
ccColor3B)ccBLACK));

改为

const ccColor3B clr = ccBLACK;

ccColor3B color = *((ccColor3B*)
tolua_tousertype(tolua_S,4,(void*)&clr));

这里的原因是某些函数声明里,给ccColor3B类的参数带了默认值ccBLACK,因此tolua++会转出前者代码,而ccBLACK实际是个const定义,无法取地址,因此强制替换成后者。这个问题其实很典型,在我以前自己做lua绑定库时也遇到过,即c++的默认参数只是个语法糖,在实际生成汇编指令时,所有参数都是要齐备的,而调用方未提供的实参,自然是由编译器帮助补上了(编译期),因此在导出到lua里被调用时,早已无默认参数的概念(运行期),要么lua代码必须提供所有参数,要么就是胶水层代码提供。我当时的做法是胶水层没有管这个事情,也就是写lua代码时根本不要想默认参数这回事。而cocos2dx这里的做法则是在胶水层搞定,给lua代码提供了便利。

4、将

tolua_usertype(tolua_S,"LUA_FUNCTION");

删除,将作为参数的

*((LUA_FUNCTION*)

也删除,也就是普通的lua
function不做为usertype使用(注册、取参)。照理说lua自己的基本类型本就不该做为usertype,为什么tolua++会生成这样的本不该有的代码呢?出现这种情况的原因是,cocos2dx里有一些接受某个lua回调函数作为参数的函数,如

void registerScriptObserver(CCObject
*target,int handler,const
char* name);

这种函数在c++代码里,使用int作为回调函数参数的类型是很自然的,因为cocos2dx除了lua还要支持js等其它脚本语言,不可能直接使用某一个语言特有的函数类型来表示此参数,因此将其抽象为一个int型的handler。(虽然实际上lua本身也恰好是用int来表示函数引用的)

但是在pkg文件里,以上声明被改写为:

void registerScriptObserver(CCObject *target,LUA_FUNCTION
funcID,const char* name);

这里int换成了LUA_FUNCTION。因为如果不换,那么tolua++生成的胶水代码就不知道这里要提取一个function,而是直接生成提取一个int变量的错误代码了。为了让tolua++生成正确的代码,需要hook它生成此处代码的逻辑,所以这里实际上包含两步,一是首先通过将int修改为LUA_FUNCTION使tolua++意识到这里有一个特殊类型(即不是基础类型)的参数,二是通过上述第2条所做的事让tolua++使用cocos2dx针对此类型提供的专有存取函数。如果不做第一步,直接给int提供push/to/is函数,当然也可以达到hook插入自有代码的目的,但是所有使用int做参数的地方(而非仅是用int表示脚本回调函数处)就全受影响了,因此LUA_FUNCTION在这里就是起到一个标识回调函数——hook只限于此——用途的作用。

可以在basic.lua里将此处注释掉(包括第2条)来检查生成代码的差异:

@@ -13018,7 +13018,7 @@ static int
tolua_Cocos2d_CCNotificationCenter_registerScript
{

CCNotificationCenter* self = (CCNotificationCenter*)
tolua_tousertype(tolua_S,1,
CCObject* target = ((CCObject*)
tolua_tousertype(tolua_S,2,0));
- LUA_FUNCTION funcID = (
toluafix_ref_function(tolua_S,3,0));
+ LUA_FUNCTION funcID =
*((LUA_FUNCTION*) tolua_tousertype(tolua_S,3,0));
const char* name =
((const char*) tolua_tostring(tolua_S,4,0));

-对应的是正确的代码,调用专门提供的toluafix_ref_function来取得一个lua
function的ref,其返回值类型定义正是pkg中形参类型,也恰好是lua本身的一个typedef,语法完全正确。

+对应的是注释之后生成的错误的代码,对于lua
function型参数,用普通的tolua_tousertype去提取,完全对不上型号。

5、将

toluafix_pushusertype_ccobject(tolua_S,(void*)tolua_ret

替换为

int nID = (tolua_ret) ? (int)tolua_ret->m_uID : -1;

int* pLuaID = (tolua_ret) ? &tolua_ret->m_nLuaID : NULL;

toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID,
(void*)tolua_ret

这也是无奈之举,第1条虽然用_push_function修改了usertype的push函数名,但传参列表却没有改,为了结合cocos2dx自己的CCObject::nID/LuaID机制,这里只好强行替换函数调用语句,加上提取出这两个参数。具体这两个ID的用处也待后面说明。

除了LuaCocos2d.cpp,同目录下还有几个胶水文件:

LuaCocoStudio.cp: 与上述一样,用大量pkg和一个定制lua脚本通过tolua++自动生成

下面这些看起来似乎都是手写的了,各有各的特殊逻辑要处理(都不是tolua++常规途径能解决的),就先不一一细说了。

lua_cocos2dx_manual.cpp:

lua_cocos2dx_cocostudio_manual.cpp:

lua_web_socket.cpp:

lua_extensions_CCB.cpp:

CCBProxy.cpp:

关于tolua++自身的编译:有个特别一点的地方,即它先编出一个tolua++_boostrap,用途是将src/bin/lua下的一堆lua文件转成二进制字节数组的c文件(toluabind.c),然后再加进这个c文件生成最后的tolua++,好处是发布最终程序时,就是一个裸的可执行程序,不需要再携带一堆lua脚本了(通常容易带来各种定位麻烦)。至于那一堆lua文件,除了package.lua是用来做lua文件转字节数组外,大部份是用来做pkg文件解析的,也就相当于一个微型类c++头文件解析器了,这一点使我觉得tolua++很蛋疼,因为c++语法解析(即使只是弱化版的头文件)本来就很复杂,非要自己做,还写那么大一堆冗长晦涩的lua代码,不是原作者根本没法看懂,想对pkg格式做点修改扩展什么的几乎下不了手,只能把它当一个将就能用的东西用了,所以也才出现了上面cocos2dx对它各种修改替换的结果。

cocos2dx之tolua++全面分析(一):tolua++工具本身,布布扣,bubuko.com

时间: 2024-10-29 19:12:10

cocos2dx之tolua++全面分析(一):tolua++工具本身的相关文章

cocos2dx之tolua++全面分析(二):类注册

tolua被作为库使用时,首先会做大量内部初始化工作: 一.tolua_open是入口点,它创建很多用于管理的内部变量,以下用_G指代全局表,_R指定registry table: 1._R.TOLUA_VALUE_ROOT={}, 这个表是cocos2dx自己加的,它把所有传入lua的cppobj/userdata都塞到这个表里,而且这还不是一个弱表,也就意味着cocos2dx创建的cpp obj,永远都不会被gc!只有在c++层面被delete时,才会去这个表里删除自己.因此,每一个coco

mysql性能瓶颈分析、性能指标、指标搜集方法与性能分析调优工具

本文主要讲解mysql的性能瓶颈分析.性能指标.性能指标信息的搜集工具与方法.分析调优工具的使用. 文章尚未完成. 性能瓶颈: 慢.写速度比读速度慢很多  主要的性能指标: 访问频度, 并发连接量, 缓存命中率, index使用, slow log开启与分析, query Log,查询log Threads_cached:连接线程缓存是否开启  -> ONthread_cache_size :线程缓存数的大小query_cache_size: 查询缓存大小join_buffer_size :jo

cocos2d-x CCScrollView 源码分析

版本源码来自2.x,转载请注明 1.继承树结构 可以看出,CCScrollView本质是CCLayer的一种,具备层的一切属性和方法.关于CCLayer的源码分析,后续会有. 2.重要的成员  1.  CCScrollViewDelegate* m_pDelegate; cocos2d-x中,运用了很多delegate这种模式.下面简单的说明下delegate这种模式.(至于delegate与proxy的区别,请先参考下headfirst中的proxy三种情况,然后可以google区别,这里不再

【Cocos2d-x】源码分析之 2d/ui/UILayoutDefine.h

#ifndef __UILAYOUTDEFINE_H__ #define __UILAYOUTDEFINE_H__ #include "cocos2d.h" NS_CC_BEGIN namespace ui { /** *控件 距离四周的间隙 *设置间隙之后 相当于控件的大小扩大了 *不会和周围控件紧挨着 有一定间距 * */ class Margin { public: float left; float top; float right; float bottom; public:

【Cocos2d-x】源码分析之 2d/ui/Widget

从今天开始 咱也模仿 红孩儿这些大牛分析源码 ,由于水平有限 不对之处欢迎狂喷.哈哈. #ifndef __UIWIDGET_H__ #define __UIWIDGET_H__ #include "ui/CCProtectedNode.h" #include "ui/UILayoutDefine.h" #include "ui/UILayoutParameter.h" #include "ui/GUIDefine.h" NS

内存泄露分析之MAT工具简单使用

使用了Heap视图的方式来分析内存泄露之后,我们尝试用MAT插件来分析下. MAT,提供了太强大的功能,以至于在测试的过程中也是懵懂的,没有彻底的研究. 1. 安装Android Sdk,Java SDK,Eclipse之类的软件之后, 2. 安装Eclipse MAT插件 3. 调出DDMS的Heap视图 4. 手机连接电脑之后,选择要测试的进程,并点击Heap 5. 在手机上操作需要测试的功能 6. 选择Dump HPROF file功能. 7. 如果Eclipse中直接安装了MAT插件之后

【Cocos2d-x】源码分析之 2d/ui/UILayout

#ifndef __LAYOUT_H__ #define __LAYOUT_H__ #include "ui/UIWidget.h" NS_CC_BEGIN namespace ui { typedef enum { LAYOUT_COLOR_NONE,//空 LAYOUT_COLOR_SOLID,//单一固定颜色的 LAYOUT_COLOR_GRADIENT//有梯度变化的 }LayoutBackGroundColorType;//容器背景颜色类型 typedef enum { LA

C#最佳工具集合:IDE、分析、自动化工具等

原文:C#最佳工具集合:IDE.分析.自动化工具等 C#是企业中广泛使用的编程语言,特别是那些依赖微软的程序语言.如果您使用C#构建应用程序,则最有可能使用Visual Studio,并且已经寻找了一些扩展来对您的开发进行管理.但是,这个工具列表可能会改变您编写C#代码的方式. C#编程的最佳工具有以下几类: IDE VS扩展 编译器.编辑器和序列化 反编译和代码转换工具 构建自动化和合并工具 版本控制 测试工具和VS扩展 性能分析 APM 部署自动化 容器 使用上面的链接直接跳转到特定工具,或

20150501调试分析之 自制工具<寄存器编辑器>

20150501调试分析之 自制工具<寄存器编辑器> 2015-05-1 Lover雪儿 今天还是继续我们内核错误调试,今天是制作一个寄存器编辑器,可以自由的读写某些我们需要调试的寄存器. 一.首先完成一个可自动创建设备节点的字符设备驱动程序 这儿我们前面都写过了N遍,此处不再赘述,直接附上代码: 1 /****************************** 2 内核调试之自制寄存器读写工具(驱动) 3 *****************************/ 4 #include