一、编译及使用流程
1)编译lua静态库
必须先下载lua 1.5,下载好后,把/src目录的除开lua.c,luac.c的文件全部放到一个新建的静态链接库的工程项目里,然后编译出一个静态链接库lua.lib。
2)编译tolua++静态库
去tolua++官网下载一个tolua++的包,解压出来,再次新建一个静态链接库的项目,把tolua++的/src/lib里的.h .c的文件拷贝到静态链接库的项目里,然后编译出一个tolua++.lib 的库。
3)编译tolua++.exe
再次新建一个控制台程序的项目,把编译好的lua静态库和tolua++的静态库放在项目里附加,然后把tolua++的/src/bin/里的tolua.c,luabind.h,luabind.c文件放在项目里,然后把tolua++的/include里的tolua++.h和lua1.5的目录里的/src的所有头文件放到项目里,然后编译生成tolua++.exe
4)根据C/C++文件编写好对应的pkg文件,然后根据一创命令生成tolua
(1)C文件举例
#define FALSE 0
#define TRUE 1
enum {
POINT = 100,
LINE,
POLYGON
}
Object* createObejct (int type);
void drawObject (Object* obj, double red, double green, double blue);
int isSelected (Object* obj);
就会自动创建一个绑定上面代码到lua的C文件。因此,在lua代码里, 我们可以访问C代码。举个例子:
$pfile "XX.pkg" //$pfile是包含对应的pkg文件
$hfile "XXX.h" //$hfile是包含对应的.h头文件
$lfile "XXX.lua" //包含对应的.lua文件
...
myLine = createObject(LINE)
...
if isSelected(myLine) == TRUE then
drawObject(myLine, 1.0, 0.0, 0.0);
else
drawObject(myLine, 1.0, 1.0, 1.0);
end
...
(2)C++文件举例
#define FALSE 0
#define TRUE 1
class Shape
{
void draw (void);
void draw (double red, double green, double blue);
int isSelected (void);
};
class Line : public Shape
{
Line (double x1, double y1, double x2, double y2);
~Line (void);
};
如果tolua输入加载该文件,就会自动生成一个C++文件,例如tolua,从而为我们提供lua层访问C++层所需要的对应的代码。因此,以下的的lua代码是有效的:
...
myLine = Line:new (0,0,1,1) --new表示创建一个类的新对象,这个对象是myLine
...
if myLine:isSelected() == TRUE then --对象::对应函数表示调用对应函数
myLine:draw(1.0,0.0,0.0)
else
myLine:draw() --基类的函数也是直接调用就行
end
...
myLine:delete() --delete就是析构函数
...
二、C++调用lua
1)流程
(1)package还应当被明确初始化。为了从C/C++代码中初始化package,我们需要声明和调用初始化函数。初始化函数被定义为:
int tolua_pkgname_open (lua_State*); //这就是C++的函数,pkgname填写对应pkg的名字
(2)如果我们使用的是C++,我们可以选择自动初始化
tolua -a -n pkgname -o myfile.c myfile.pkg 不使用自动初始化是(下面的命令): tolua -n pkgname -o tolua_myfile.c myfile.pkg //生成tolua_myfile.c文件
2)注意点:
在这种情况下,初始化函数会被自动调用。然而,如果我们计划使用多个Lua State,自动初始化就行不通了,因为静态变量初始化的顺序在C++里没有定义。
- 补充
tolua生成的绑定代码使用了一系列tolua库里面的函数。因此,这个库同样需要被链接到应用程序中。tolua.h也是有必须要编译生成的代码。tolua生成的绑定代码使用了一系列tolua库里面的函数。因此,这个库同样需要被链接到应用程序中。tolua.h也是有必须要编译生成的代码。
3)要包含的库和头文件
库: lua.lib 和 tolua.lib 头文件:lua.h、lualib.h、lauxlib.h、luaconf.h
4)代码示例
#include <iostream>
extern "C"
{
#include "lualib.h"
#include "lauxlib.h"
}
using namespace std;
int main()
{
int tolua_mylib_open(lua_State*);
lua_State* state = luaL_newstate();
luaL_openlibs(state);
if (luaL_dostring(state, "print([[hello world]])") != 0)
{
cout << "excute lua file failed!" << endl;
}
lua_close(state);
system("pause");
return 0;
}
如果正确打印出 “hello world”,则说明 lua 环境没有问题,否则就检查一下头文件和库文件是否正确引入了
5)生成函数的API介绍
class Test
{
public:
Test(int a, int b);
~Test();
void sayHello();
int add();
int getA();
private:
int a;
int b;
};
#include "mylib.h"
#include <iostream>
Test::Test(int a, int b)
{
this->a = a;
this->b = b;
}
Test::~Test()
{
}
void Test::sayHello()
{
std::cout << "hello world" << std::endl;
}
int Test::add()
{
return this->a + this->b;
}
int Test::getA()
{
return this->a;
}
编译指令:tolua -n mylib -o tolua.cpp mylib.pkg
$#include "mylib.h"
class Test
{
Test(int, int);
~Test();
void sayHello();
int add();
int getA();
};
static int tolua_collect_Test (lua_State* tolua_S){}
static void tolua_reg_types (lua_State* tolua_S){}
static int tolua_mylib_Test_new00(lua_State* tolua_S){}
static int tolua_mylib_Test_delete00(lua_State* tolua_S){}
static int tolua_mylib_Test_sayHello00(lua_State* tolua_S){}
static int tolua_mylib_Test_add00(lua_State* tolua_S){}
static int tolua_mylib_Test_getA00(lua_State* tolua_S){}
LUALIB_API int luaopen_mylib (lua_State* tolua_S){}
TOLUA_API int tolua_mylib_open (lua_State* tolua_S){}
三、lua调用C++
1)代码
local test = Test:new(1, 2)
test:sayHello()
print("a = " .. test:getA())
print("a + b = " .. test:add())
#include <iostream>
extern "C"
{
#include "lualib.h"
#include "lauxlib.h"
}
#include "mylib.h"
using namespace std;
int main()
{
lua_State* state = luaL_newstate();
luaL_openlibs(state);
tolua_mylib_open(state);
if (luaL_dofile(state, "scripts/test.lua") != 0)
{
cout << "excute lua file failed!" << endl;
lua_close(state);
return 1;
}
lua_close(state);
system("pause");
return 0;
}
2)执行结果
四、lua调用tolua
这种方式其实和在 c++ 程序中使用 tolua 没什么区别,只是我们测试的项目是 c++ 项目还是 lua 项目而已。要在纯 lua 程序中使用 tolua,首先得导出一个 c++ 模块。新建一个 c++ 动态链接库项目,同样地将 lua 和 tolua 的头文件和库文件包含进来,还有 mylib.h、mylib.cpp 和 tolua.cpp 这三个文件也添加进项目来。
导出 c++ 模块,在模块内注册一个函数,在这个函数里打开 tolua,然后 tolua 绑定的所有 c++ 函数就可以在 lua 中使用了。我们创建一个 lib.h 和 lib.cpp 文件,用于导出 c++ 模块
#pragma once
#include "lua.h"
extern "C"
{
__declspec(dllexport) int luaopen_test(lua_State* L);
}
#include "mylib.h"
extern "C"
{
#include "lib.h"
#include "lualib.h"
#include "lauxlib.h"
}
static int export_tolua_test(lua_State* L)
{
int tolua_mylib_open(lua_State* L);
tolua_mylib_open(L);
return 1;
}
static const luaL_Reg toluaTest[] =
{
{ "export_tolua_test",export_tolua_test },
{ NULL,NULL }
};
extern "C"
{
__declspec(dllexport) int luaopen_test(lua_State* L)
{
luaL_newlibtable(L, toluaTest);
luaL_setfuncs(L, toluaTest, 0);
return 1;
}
}
编译之后得到一个 lib.dll 文件,在 lua 代码中加载这个动态链接库文件,得到一个模块,这个模块里面有 export_tolua_test 这个函数,调用这个函数就会执行 tolua_mylib_open(L);,从而打开 tolua,则在 mylib 中导出的所有 c++ 东西都可以在 lua 中使用了
-- main.lua
-- 加载 c++ 模块
local test = require("test")
-- 调用 c++ 模块注册的函数,这个函数会打开 tolua
test.export_tolua_test()
-- 调用 tolua 导出的类、函数等
local t = Test:new(10, 20)
t:sayHello()
print(t:getA())
print(t:add())
使用 lua 解释器运行该代码,看到下面的执行结果
|