
希望能够将 cpp 文件编译成动态库, 以 lua 作为主要运行逻辑(main 函数)
稍微有点多,感谢耐心观看
#pragma once extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include <string> class Worker{ public: Worker(); ~Worker(); int SetName(std::string &name); int SetAge(int &age); int SetHight(float &hight); std::string GetName(); int GetAge(); float GetHight(); private: std::string name; int age; float hight; }; extern "C" int luaopen_cstudy(lua_State *L); #include "classstudy.h" #include <iostream> /* Class Worker 的函数定义省略 */ static int CreateNewWorker(lua_State *L){ //ligth_userdata // int n = luaL_checkany(L, 1); Worker **w1 = (Worker**)lua_newuserdata(L, sizeof(Worker*)); *w1 = new Worker(); if(luaL_getmetatable(L, "WorkerClass") == false){ printf("getmetatable nil\n"); } lua_setmetatable(L, -2); return 1; } static int SetWorkerName(lua_State *L){ luaL_checktype(L, -1, LUA_TSTRING); std::string var_name = lua_tostring(L, -1); printf("%s\n", var_name.c_str()); Worker **w1 = (Worker**)lua_newuserdata(L, sizeof(Worker*)); luaL_argcheck(L, w1 != NULL, 1, "invalid user data"); (*w1)->SetName(var_name); return 0; } static int SetWorkerAge(lua_State *L){ luaL_checktype(L, -1, LUA_TNUMBER); int var_age = lua_tointeger(L, -1); Worker **w1 = (Worker**)lua_newuserdata(L, sizeof(Worker*)); luaL_argcheck(L, w1 != NULL, 1, "invalid user data"); (*w1)->SetAge(var_age); return 0; } static int SetWorkerHight(lua_State *L){ luaL_checktype(L, -1, LUA_TNUMBER); float var_hight = lua_tonumber(L, -1); Worker **w1 = (Worker**)lua_newuserdata(L, sizeof(Worker*)); luaL_argcheck(L, w1 != NULL, 1, "invalid user data"); (*w1)->SetHight(var_hight); return 0; } static int GetWorkerInfo(lua_State *L){ Worker **w1 = (Worker**)lua_newuserdata(L, sizeof(Worker*)); luaL_argcheck(L, w1 != NULL, 1, "invalid user data"); printf("Name: %s\n", ((*w1)->GetName()).c_str()); printf("Age: %d\n", (*w1)->GetAge()); printf("Hight: %f\n", (*w1)->GetHight()); return 0; } static int DestoryInfo(lua_State* L) { // 释放对象 delete *(Worker**)lua_topointer(L, 1); return 0; } const static luaL_Reg mylib[] = { // {"NewWorker", CreateNewWorker}, {"SetName", SetWorkerName}, {"SetAge", SetWorkerAge}, {"SetHight", SetWorkerHight}, {"PrintInfo", GetWorkerInfo}, {NULL,NULL} }; int luaopen_cstudy(lua_State *L){ // C\++对象 = 私有数据 + 类(公共数据 + 公共方法) // Lua Table = 私有数据 + 元表(元数据 + 元函数) // luaL_newlib(L, mylib); lua_pushcfunction(L, CreateNewWorker); // 注册用于创建类的全局函数 lua_setglobal(L, "CWorker"); luaL_newmetatable(L, "WorkerClass"); // 设置自身 lua_pushstring(L, "__gc"); lua_pushcfunction(L, DestoryInfo); lua_settable(L, -3); // 设置元表 lua_pushstring(L, "__index"); // 设置元表为自己 lua_pushvalue(L, -2); lua_settable(L, -3); lua_pushstring(L, "SetName"); lua_pushcfunction(L, SetWorkerName); lua_settable(L, -3); lua_pushstring(L, "SetAge"); lua_pushcfunction(L, SetWorkerAge); lua_settable(L, -3); lua_pushstring(L, "SetHight"); lua_pushcfunction(L, SetWorkerHight); lua_settable(L, -3); lua_pushstring(L, "PrintInfo"); lua_pushcfunction(L, GetWorkerInfo); lua_settable(L, -3); // lua_pop(L, 1); return 1; } local csl = require("cstudy") local Worker = CWorker() print(debug.getregistry()) Worker.SetName("hello") Worker.PrintInfo() -- csl.SetAge(23) -- csl:SetHight(180.0) -- csl:PrintInfo() 1 anytk 2022-01-06 11:32:58 +08:00 元表是对象,也就是你的 worker 的元表,包含对象的方法,在方法中检查第一个参数为对应元表名的 userdata, 其他为参数。 模块本身只提供创造对象的方法和必要全局参数。 参考: ```c #include <lua.h> #include <lauxlib.h> static int xxx_read(lua_State *L) { struct XXX **xxx = luaL_checkudata(L, 1, "xxx.xxx"); // ... } static int xxx_write(lua_State *L) { struct XXX **xxx = luaL_checkudata(L, 1, "xxx.xxx"); // ... } static int xxx_close(lua_State *L) { struct XXX **xxx = luaL_checkudata(L, 1, "xxx.xxx"); if (*xxx) { // ... } return 0; } static luaL_Reg XXX_METHODS[] = { { "read", xxx_read }, { "write", xxx_write }, { "close", xxx_close }, { "__gc", xxx_close }, { NULL, NULL }, }; static int xxx_new(lua_State *L) { lua_Integer type = luaL_checkinteger(L, 1); const char *url = luaL_checkstring(L, 2); int err = 0; struct XXX *xxx = create_xxx(...); if (!xxx) { lua_pushnil(L); return 1; } else { struct XXX **udata = lua_newuserdata(L, sizeof(struct XXX *)); *udata = NULL; luaL_setmetatable(L, "xxx.xxx"); *udata = xxx; return 1; } } static luaL_Reg XXX_LIBS[] = { { "new", xxx_new }, { NULL, NULL }, }; int luaopen_xxx.xxx(lua_State *L) { luaL_newmetatable(L, "xxx.xxx"); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); luaL_setfuncs(L, XXX_METHODS, 0); lua_pop(L, 1); luaL_newlib(L, XXX_LIBS); return 1; } ``` |
2 fengjianxinghun 2022-01-06 11:36:50 +08:00 何必这么麻烦,改用 luajit 的 ffi 走起。 |
3 ysc3839 2022-01-06 11:41:50 +08:00 既然是 C++ 的话推荐找一个封装好的库,lua 使用栈传递参数,手写很麻烦还容易出错。 |
5 kanhongj OP |
6 guo4224 2022-01-06 12:27:45 +08:00 @fengjianxinghun +11111 |
7 ysc3839 2022-01-06 12:36:43 +08:00 via Android @kanhongj 啥意思?我说的是用封装好的调用 lua api 的库,lua 的 C API 使用栈传递参数,手写很麻烦还容易出错。 |
8 paoqi2048 2022-01-06 13:22:26 +08:00 不是有一堆 binding 吗?如果是出于学习的目的就当我没说 |
9 kanhongj OP |
10 kanhongj OP @anytk 这个示例我尝试成功了,受教了,但是还是有些疑惑的地方: 1. luaopen_xxx.xxx 函数里边,为什么生成了一个 xxx.xxx 表,且设定了元表,又给 pop 出去了, 这样 new_xxx 方法里边的 luaL_setmetatable(L, "xxx.xxx") 怎么找到的。 2. lua 代码里又一个 local csl = require("xxx.xxx") 这里的 csl 包含了一个 new 方法调用,csl 是上文的 metatable , 还是 luaL_newlib ? |
11 kanhongj OP @kanhongj 这个是我的 lua 代码: ```lua local csl = require("cstudy") local Worker = csl.new() Worker:SetName("hello") -- Worker:PrintInfo() Worker:SetAge(23) Worker:SetHight(180.0) Worker:PrintInfo() ``` |
12 kanhongj OP @kanhongj 这个是我的 lua 代码: ```lua local csl = require("cstudy") local Worker = csl.new() Worker:SetName("hello") -- Worker:PrintInfo() Worker:SetAge(23) Worker:SetHight(180.0) Worker:PrintInfo() ``` |
13 anytk 2022-01-07 11:19:25 +08:00 @kanhongj 1. 元表是给对象准备的,设置 __index 实现面向对象,所有的方法都绑定到元表中,对象的方法通过 __index 去执行元表内的方法。luaL_newmetatable 这个 api 会将元表加到 REGISTRY 中,这是个全局 table , 所以设定好后,这个元表就可以 pop 掉了,因为 REGISTRY 保存了引用,所以不用担心被回收。 luaL_setmetatable API 同样是从 REGISTRY 中用名称获取元表并绑定对象,可以看看这几个 luaL_ 开头的 api 注释。 2. new 方法是 luaL_newlib 出来的模块 table 方法,不是元表的。 |
14 anytk 2022-01-07 11:22:16 +08:00 @kanhongj lua 的 c api 编程,其实就是利用 api 去仿照 lua 语法语义组织执行语句,尤其是 gc 相关。 |
16 asuraa 2023-06-25 01:10:53 +08:00 太麻烦了 为啥不用 Luabridge |