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++工具本身的更多相关文章
- cocos2dx之tolua++全面分析(二):类注册
tolua被作为库使用时,首先会做大量内部初始化工作: 一.tolua_open是入口点,它创建很多用于管理的内部变量,以下用_G指代全局表,_R指定registry table: 1._R.TOLU ...
- mysql性能瓶颈分析、性能指标、指标搜集方法与性能分析调优工具
本文主要讲解mysql的性能瓶颈分析.性能指标.性能指标信息的搜集工具与方法.分析调优工具的使用. 文章尚未完成. 性能瓶颈: 慢.写速度比读速度慢很多 主要的性能指标: 访问频度, 并发连接量, ...
- linux下源代码分析和阅读工具比较
Windows下的源码阅读工具Souce Insight凭借着其易用性和多种编程语言的支持,无疑是这个领域的“带头大哥”.Linux/UNIX环境下呢?似乎仍然是处于百花齐放,各有千秋的春秋战国时代, ...
- linux命令 host-常用的分析域名查询工具
博主推荐:更多网络测试相关命令关注 网络测试 收藏linux命令大全 host命令是常用的分析域名查询工具,可以用来测试域名系统工作是否正常. 语法 host(选项)(参数) 选项 -a:显示详细的 ...
- Qt qml调试,qml性能分析和优化工具
QML语言为qt推出的用于界面编程的语言. 1)如何在qt creator中进行调试qml: 以Qt Creator 4.6.2为例: 在qt creator的debug模式下,可以直接在qml中打断 ...
- tolua++实现分析
项目正在使用cocos2dx的lua绑定,绑定的方式是tolua++.对大规模使用lua代码信心不是很足,花了一些时间阅读tolua++的代码,希望对绑定实现的了解,有助于项目对lua代码的把控.从阅 ...
- cocos2d-x 纹理源码分析
转自:http://blog.csdn.net/honghaier/article/details/8068895 当一张图片被加载到内存后,它是以纹理的形式存在的.纹理是什么东西呢?纹理就是一块内存 ...
- Android APP性能分析方法及工具
近期读到<Speed up your app>一文.这是一篇关于Android APP性能分析.优化的文章.在这篇文章中,作者介绍他的APP分析优化规则.使用的工具和方法.我觉得值得大家借 ...
- 【Android端 APP 内存分析】使用工具进行APP的内存分析
Android端可以通过adb 命令直接获取内存信息,当然Android studio也提供了对内存的监控分析工具,并且后续可以结合MAT做分析 今天介绍的是通过Android studio和MAT工 ...
随机推荐
- Data Structure Array: Find if there is a subarray with 0 sum
http://www.geeksforgeeks.org/find-if-there-is-a-subarray-with-0-sum/ #include <iostream> #incl ...
- Data Structure Binary Tree: Morris traversal for Preorder
http://www.geeksforgeeks.org/morris-traversal-for-preorder/ #include <iostream> #include <v ...
- RabbitMQ之Exchange Topics模式
说明:此模式实在路由key模式的基础上,使用了通配符来管理消费者接收消息.生产者P发送消息到交换机X,type=topic,交换机根据绑定队列的routing key的值进行通配符匹配: 符号#:匹配 ...
- Myeclipse中集成的SVN的登录名与密码的切换方法
Eclipse的SVN插件Subclipse做得很好,在svn操作方面提供了很强大丰富的功能.但到目前为止,该插件对svn用户的概念极为淡薄,不但不能方便地切换用户,而且一旦用户的帐号.密码保存之后, ...
- POJ 1577 Falling Leaves(二叉搜索树)
思路:当时学长讲了之后,似乎有点思路----------就是倒着建一个 二叉搜索树 代码1:超时 详见超时原因 #include<iostream> #include<cstrin ...
- Unity3D连接WCF
Unity3D连接WCF: 一.最简单的案例 1.VS2015中: (1)建立WCF应用服务程序ForUnity: (2)将自动生成的IService1.cs与Service1.svc删除: (3 ...
- 常用的Hql语句(转)
原文地址:http://blog.csdn.net/v123411739/article/details/28644007 尊重原创,请访问原文地址 // HQL: Hibernate Que ...
- Java企业微信开发_06_素材管理之上传本地临时素材文件至微信服务器
一.本节要点 1.临时素材有效期 media_id是可复用的,同一个media_id可用于消息的多次发送(3天内有效) 2.上传文件时的http请求里都有啥 具体原理可参看: 为什么上传文件的表单需要 ...
- 数据交换格式XML和JSON对比
1.简介: XML:extensible markup language,一种类似于HTML的语言,他没有预先定义的标签,使用DTD(document type definition)文档类型定义来组 ...
- Code Chef - Chef and Graph Queries
传送门 题目大意 给定一个$n$个点$m$条边的无向图$(n,m\leq 200000)$. 有$q$每次询问$(q\leq 200000)$,每次给定一个区间$L,R$,求仅保留编号$\in[L,R ...