这是为Quick-3.3[下面使用Quick]绑定自定义C++类做知识储备的博客,后面还有多个篇幅,直到最终介绍使用最方便的方式绑定自定义C++类。
上一篇是内容是配置lua运行及开发环境。
我的系统:MacOSX 10.10
我们学习Quick,在测试使用tolua++绑定自定义C++类,最好是使用Quick中使用的tolua++版本。这样测试结果可以保证和Quick一致。
打开文件夹quick-3.3/external/lua/ltoua/,这就是Quick集成的tolua++源代码目录。
在tolua++.h文件中看到
#define TOLUA_VERSION "tolua++-1.0.93"
好了,方便起见,我们去官网下载tolua++1.0.93版本的源代码,tolua++-1.0.93.tar.bz2
解压到目录 /Users/wx4/Downloads/工具/tolua++-1.0.93/
1.cd /Users/wx4/Downloads/工具/tolua++-1.0.93/src/lib
2.执行 gcc -c *.c -I../../include -I/usr/local/include
【注释1:(gcc -c表示只编译不链接,生成目标文件.o),-I(这是大写的i)代表头文件搜索路径】
3.运行 ar rcsv libtolua++.a *o,生成libtolua++.a
4.拷贝libtolua++.a到../../lib中
5.cd /Users/wx4/Downloads/工具/tolua++-1.0.93/src/bin
6.执行 gcc tolua.c toluabind.c -I../../include -L../../lib -I/usr/local/include -L/usr/local/lib -ltolua++ -llua -o tolua++,生成tolua++可执行文件。
7.将/Users/wx4/Downloads/工具/tolua++-1.0.93_x86_64/include中的tolua++.h拷贝到/usr/local/include目录下;将libtolua++.a拷贝到/usr/local/lib目录下;将tolua++可执行文件拷贝到/usr/local/bin目录下。
至此,tolua++的运行环境和开发环境我们就设置好了。
打开终端输入:tolua++ -v
出现版本号,说明配置正确。
wx4deMac-mini:~ wx4$ tolua++ -v
tolua++-1.0.93 (written by W. Celes, A. Manzur)
现在我们写个类,测试下tolua++,并学习如何使用tolua++绑定自定义C++类。
使用toLua++的标准做法是:
1、准备好自己的C++类,该怎么写就怎么写
2、仿造这个类的.h文件,改一个.pkg文件出来,具体格式要按照toLua++的规定,比如移除所有的private成员等
3、建一个专门用来桥接C++和Lua之间的C++类,使用特殊的函数签名来写它的.h文件,.cpp文件不写,等着toLua++来生成
4、给这个桥接的C++类写一个.pkg文件,按照toLua++的特殊格式来写,目的是把真正做事的C++类给定义进去
5、在命令行下用toLua++生成桥接类的.cpp文件
6、程序入口引用这个桥接类,执行生成的桥接函数,Lua环境中就可以使用真正做事的C++类了
toLua++这种自己手写.pkg文件的方式古老又难受,所以我没有仔细地去学习,这套流程放在10年前的那个年代是没有太大问题的,作者怎么规定就怎么用好了,但是放在2014年的今天,任何程序的架构设计都讲究学习成本低、轻量化、符合以往的习惯,因此toLua++用起来我觉得其实是难受的。
下面我以尽量最少的代码来走一遍toLua++的流程,注意这是在纯C++环境下,跟任何框架都没关系,也不考虑内存释放等细节:
MyClass.h
class MyClass {
public:
MyClass() {};
int foo(int i);
};
MyClass.cpp
#include "MyClass.h"
int MyClass::foo(int i)
{
return i + 100;
}
MyClass.pkg
class MyClass
{
MyClass();
int foo(int i);
};
MyLuaModule.h
extern "C" {
#include "tolua++.h"
}
#include "MyClass.h"
TOLUA_API int tolua_MyLuaModule_open(lua_State* tolua_S);
MyLuaModule.pkg
$#include "MyLuaModule.h"
$pfile "MyClass.pkg"
main.cpp
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#include "MyLuaModule.h"
int main()
{
lua_State *L = lua_open();
luaL_openlibs(L);
tolua_MyLuaModule_open(L);
luaL_dofile(L, "main.lua");
lua_close(L);
return 0;
}
main.lua
local test = MyClass:new()
print(test:foo(122))
打开终端执行
tolua++ -o MyLuaModule.cpp MyLuaModule.pkg
此命令用来生成桥接文件MyLuaModule.cpp。注意命令行中-o参数的顺序不能随意摆放,从这个小事也能看出tolua++的古老和难用
生成好MyLuaModule.cpp文件后,就能看到它里面的那一大堆桥接代码了,比如tolua_beginmodule
、tolua_function
等。以后看到这些东西就不陌生了,就明白这些函数只是toLua++用来做桥接的必备代码了,简单看一下代码,就理解toLua++是怎样把MyClass这个C++类注册进Lua中的了:
接下来,用g++来编译:
g++ MyClass.cpp MyLuaModule.cpp main.cpp -I/usr/local/include -L/usr/local/lib -ltolua++ -llua -o main
生成main可执行文件。
在终端下运行main
wx4deMac-mini:tolua++test wx4$ ./main
222
可以看到正确的打印结果啦~
至此,对toLua++的运作原理心里就透亮了,无非就是:
1、把自己该写的类写好
2、写个.pkg文件,告诉toLua++这个类暴露出哪些接口给Lua环境
3、再写个桥接的.h和.pkg文件,让toLua++去生成桥接代码
4、在程序里使用这个桥接代码,类就注册进Lua环境里了