tolua++ 是用來把 C++代碼 生成 在Lua中使用的接口的工具,編譯步驟比較繁瑣。
使用tolua有以下步驟:
- 工程建立
- 編寫c/c++文件.
- 編寫.pkg文件,填寫需要導出的c/c++接口.
- 使用tolua可執行程序將pkg接口導出成LuaVm可調用的棧交互c/c++文件.
- 將第三步生成的文件和其他c/c++文件一起編譯生成最終的可執行程序.
1. 工程建立:
1).下載http://www.lua.org/versions.html#5.3
2).下載tolua-5.2.4
Tulua官網http://webserver2.tecgraf.puc-rio.br/~celes/tolua/,更新到tolua-5.2.4,支持lua5.2.4。官網只提供了tolua的源代碼,沒有提供任何程序。
下載代碼解壓後,在src目錄下有三個目錄,如下:
Bin目錄中包含了生成tolua++.exe轉換程序的代碼,我以使用VS2015編譯,文章最後有下載地址。
Lib目錄包含了程序使用tolua時需要包含的庫的代碼,因爲代碼比較少,我一般直接將lib文件夾中的代碼直接包含到程序中。
Tests目錄包含了tolua的一些例子,這些例子我以全部使用VS2015進行了編譯,文章最後有下載地址。
3) VS2017工程建立
a. lua5.3.5: 在項目中去除掉lua.c和luac.c文件.
b. tolua在Bin目錄下有兩個.c文件,tolua.c、toluabind.c,將這兩個文件加入到項目中,另外項目中還須要lua5.2.4代碼和Lib目錄下的代碼.。如下:
1. tolua++.exe 生成
2. tolua++.lib
修改完成後再點擊編譯,終於生成“tolua++.exe”文件了:
編寫pkg文件
pkg文件語法,這裏不講解,具體情況tolua官網:http://webserver2.tecgraf.puc-rio.br/~celes/tolua/tolua-3.2.html。語法規則不多,與C++非常接近,很容易看懂。
導出源文件
上面講了使用 tolua 的三部曲,下面使用實際例子講解一下。首先,正常編寫 c++ 代碼,這裏我們創建一個類
原始頭文件
//mylib.h
class Test
{
public:
Test(int a, int b);
~Test();
void sayHello();
int add();
int getA();
private:
int a;
int b;
};
原始源文件
//mylib.cpp
#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;
}
package 文件
$#include "mylib.h"
class Test
{
Test(int, int);
~Test();
void sayHello();
int add();
int getA();
};
可以看到 package 文件和 c++ 頭文件基本一致,要注意的是要在文件頭引入頭文件,然後把 public 關鍵字去掉。所有公有的函數或數據都可以導出,如果不想導出某個函數,則在 package 文件中不要定義就可以了。
然後打開命令行,輸入下面的命令
tolua -n mylib -o tolua.cpp mylib.pkg
導出的文件名可以任意命名,但因爲我們已經有一個原始的源文件 mylib.cpp 了,所以這裏不能將導出的源文件命名爲 mylib.cpp,否則後面使用的時候就會有問題,這裏我命名爲 tolua.cpp。還有一個要注意的就是必須把 mylib.h 跟 mylib.pkg 放在一起,因爲 package 文件需要用到頭文件(第一行就已經引入頭文件了)
現在我們有了 mylib.h、mylib.cpp 和 tolua.cpp 這三個文件,接下來就可以在項目中使用了
在 c++ 程序中使用 tolua
新建一個 c++ 控制檯程序,因爲要使用到 lua 和 tolua,所以要把相應的頭文件和庫文件包含進來,頭文件有 lua.h、lualib.h、lauxlib.h、lua.hpp、luaconf.h 和 tolua.h,庫文件則有 lua.lib 和 tolua.lib。
首先,我們先來測試一下 lua 環境,新建一個 main.cpp 文件,輸入下面代碼
//main.cpp
#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 環境沒有問題,否則就檢查一下頭文件和庫文件是否正確引入了
接下來把 mylib.h、mylib.cpp 和 tolua.cpp 這三個文件添加到項目中,我們先來分析下 tolua.cpp 這個文件的內容
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){}
//sayHello
static int tolua_mylib_Test_sayHello00(lua_State* tolua_S){}
//add
static int tolua_mylib_Test_add00(lua_State* tolua_S){}
//getA
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){}
這裏只列出主要的幾個函數,可以看到 tolua 在導出 c++ 源碼的時候爲每個函數都生成一個對應的靜態函數;除此之外,還有幾個重要的函數,tolua_collect_Test 用於垃圾回收,tolua_reg_types 用於註冊類名,toluaopen_mylib 用於打開庫函數,tolua_mylib_open 用於打開 tolua,這是我們唯一關心的函數,在使用 tolua 之前必須先調用這個函數,這樣所有導出的 c++ 函數就可以在 lua 中使用了
接下來開始測試在 lua 中訪問 c++ 函數,新建一個 test.lua 文件,輸入下面代碼
local test = Test:new(1, 2)
test:sayHello()
print("a = " .. test:getA())
print("a + b = " .. test:add())
然後修改 main.cpp 文件
#include <iostream>
extern "C"
{
#include "lualib.h"
#include "lauxlib.h"
}
#include "mylib.h"
using namespace std;
int main()
{
int tolua_mylib_open(lua_State*);
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;
}
首先,要引入 mylib.h 頭文件,然後調用 tolua_mylib_open(state); 打開 tolua,這個函數在 tolua.cpp 文件中定義和實現,main.cpp 並不知道這個函數,所以要在使用前手動定義一下 int tolua_mylib_open(lua_State*);,之後就可以執行 test.lua 文件了
如果沒錯誤,將會看到下面的執行結果
如果沒錯誤,將會看到下面的執行結果