找回密码
 立即注册
查看: 404|回复: 0

ToLua原理和使用教程

[复制链接]
发表于 2021-8-12 16:33 | 显示全部楼层 |阅读模式
ToLua原理和使用教程

Tolua是用来实现C++程序中的类、变量、函数等绑定到lua程序中。绑定后lua代码可以直接调用C++程序中的类、变量、函数等等。

Tolua原理

Tolua做了哪些事

要想知道tolua原理,先了解tolua到底做了些什么事。先看一下下面“lua实现get/set方法”的例子。这个例子包含了三个文件luaBind.cpp文件、Main.cpp文件、a.lua文件。
luaBind.cpp文件
  1. extern "C" {
  2. #include "lua\lua.h"
  3. #include "lua\lualib.h"
  4. #include "lua\lauxlib.h"
  5. }
  6. const char *HandlesGetSet = "HandlesGetSet";
  7. extern double a /*= 166*/;
  8. int a_get(lua_State*L)
  9. {
  10.         lua_pushnumber(L, a);
  11.         return 1;
  12. }
  13. int a_set(lua_State *L)
  14. {
  15.         if (lua_isnumber(L, 1))
  16.         {
  17.                 a = lua_tonumber(L, 1);
  18.         }
  19.         return 0;
  20. }
  21. int index_event(lua_State*L)
  22. {
  23.         //从 registry  中获取变量的get set 方法
  24.         luaL_getmetatable(L, HandlesGetSet);
  25.         lua_pushvalue(L, 2);
  26.         lua_rawget(L, -2);
  27.         if (lua_isnil(L, -1))// 没有get set方法
  28.         {
  29.                 lua_pop(L, 2);
  30.                 lua_rawget(L, -2);
  31.         }
  32.         else
  33.         {
  34.                 lua_pushstring(L, "get");
  35.                 lua_rawget(L, -2);
  36.                 lua_pcall(L, 0, 1, 0);//调用get方法
  37.         }
  38.         return 1;
  39. }
  40. int newindex_event(lua_State *L)
  41. {
  42.         //从 registry  中获取变量的get set 方法
  43.         luaL_getmetatable(L, HandlesGetSet);
  44.         lua_pushvalue(L, 2);
  45.         lua_rawget(L, -2);
  46.         if (lua_isnil(L, -1))// 没有get set方法
  47.         {
  48.                 lua_pop(L, 2);
  49.                 lua_rawset(L, -3);
  50.         }
  51.         else
  52.         {
  53.                 lua_pushstring(L, "set");//调用set方法
  54.                 lua_rawget(L, -2);
  55.                 lua_pushvalue(L, 3);
  56.                 lua_pcall(L, 1, 0, 0);
  57.         }
  58.         return 0;
  59. }
  60. void BindLua(lua_State *L)
  61. {
  62.         //获取 _G表
  63. #if defined (LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 /* after lua 5.2 */
  64.         lua_pushvalue(L, LUA_REGISTRYINDEX); /* registry */
  65.         lua_pushnumber(L, LUA_RIDX_GLOBALS); /* registry globalsindex */
  66.         lua_rawget(L, -2);                  /* registry registry[globalsindex] */
  67.         lua_remove(L, -2);                  /* registry */
  68. #else
  69.         lua_pushvalue(L, LUA_GLOBALSINDEX);
  70. #endif
  71.         //创建 _G表的元表
  72.         lua_newtable(L);
  73.         lua_pushstring(L, "__index");
  74.         lua_pushcfunction(L, index_event);
  75.         lua_rawset(L, -3);
  76.         lua_pushstring(L, "__newindex");
  77.         lua_pushcfunction(L, newindex_event);
  78.         lua_rawset(L, -3);
  79.         lua_setmetatable(L, -2);//设置 _G表的元表
  80.         lua_pop(L, 1);
  81.         //创建一张表存储在 registry  中
  82.         luaL_newmetatable(L, HandlesGetSet);
  83.         //注册 a 变量的get set方法
  84.         lua_pushstring(L, "a");
  85.         lua_newtable(L);
  86.         lua_pushstring(L, "get");
  87.         lua_pushcfunction(L, a_get);
  88.         lua_rawset(L, -3);
  89.         lua_pushstring(L, "set");
  90.         lua_pushcfunction(L, a_set);
  91.         lua_rawset(L, -3);
  92.         lua_rawset(L, -3);
  93.         lua_pop(L, 1);
  94. }
复制代码
Main.cpp文件
  1. #include<iostream>
  2. extern "C" {
  3. #include "lua\lua.h"
  4. #include "lua\lualib.h"
  5. #include "lua\lauxlib.h"
  6. }
  7. using namespace std;
  8. double a = 166;
  9. void BindLua(lua_State *L);
  10. int main()
  11. {
  12.         lua_State *L = luaL_newstate();
  13.         luaL_openlibs(L);
  14.         BindLua(L);
  15.         a = 99;
  16.         if (0 != luaL_dofile(L, "a.lua"))
  17.         {
  18.                 printf("%s\n", lua_tostring(L, -1));
  19.         }
  20.         printf("a = %f\n\n\n", a);
  21.         a = a+1000;
  22.         if (0 != luaL_dofile(L, "a.lua"))
  23.         {
  24.                 printf("%s\n", lua_tostring(L, -1));
  25.         }
  26.         printf("a = %f\n", a);
  27.         lua_close(L);
  28.         return 0;
  29. }
复制代码

a.lua文件
  1. print(a)
  2. a = a+1
  3. print("c=", c)
  4. b = "adas"
  5. print("b=", b)
复制代码

这个个例子实现了将C++程序中的double a变量绑定到了lua程序中。在C++程序中改变了变量a的值,lua程序中可以获取改变后的值,同样lua程序中对变量a赋值后,C++程序也可以获取赋值后的值,具体原理参见:Lua任意类型的get/set方法,
三个文件的作用如下。
luaBind.cpp文件:  实现将变量double a 绑定到lua程序中
Main.cpp文件: C程序代码
a.lua文件:lua程序代码

可以看到为了绑定double a变量,luaBind.cpp中的代码并不少。为了简化这种绑定,我们可以使用tolua来实现绑定。Tolua可以帮我们生成luaBind.cpp文件,我们只需要将生成后的文件加入到程序中即可完成绑定。
如何生成lua绑定文件

要生成绑定文件,首先我们需要一个tolua++.exe的程序,然后还需要一个.pkg文件。.pkg文件是一个代码文件,代码格式与C++类似。我们首先需要编写一个pkg文件,有了这个文件之后,然后使用tolua++程序对pkg程序进行转换,转换后就就会生成相应的绑定文件。具体操作,请看后续文章。

Tolua使用

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进行了编译,文章最后有下载地址。

VS2015编译tolua++.exe程序

在Bin目录下有两个.c文件,tolua.c、toluabind.c,将这两个文件加入到项目中,另外项目中还须要lua5.2.4代码和Lib目录下的代码。如下:



编写pkg文件

pkg文件语法,这里不讲解,具体情况tolua官网:http://webserver2.tecgraf.puc-rio.br/~celes/tolua/tolua-3.2.html。语法规则不多,与C++非常接近,很容易看懂。

这里编写一个绑定double a变量的方法。

Bindlua.pkg文件
$extern double a;

double a;


生成绑定文件

Tolua++.exe支持的命令参数。



执行以下命令生成绑定文件。



使用绑定文件

将生成的绑定文件Bindlua.cpp添加到项目中,另外还需要添加tolua源代码src/lib目录下的文件到项目中。如下:



更多有关tolua的例子请参见官方的例子,官方提供我已经转换成VS2015项目,文章结尾由相应的下载地址。
补充:

文中的代码,以及提到到tolua学习资源下载地址:https://pan.baidu.com/s/1boWtfw7


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 09:28 , Processed in 0.091109 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表