希望能够将 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 1
@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 1
@kanhongj lua 的 c api 编程,其实就是利用 api 去仿照 lua 语法语义组织执行语句,尤其是 gc 相关。
|
16
asuraa 2023-06-25 01:10:53 +08:00
太麻烦了 为啥不用 Luabridge
|