# lua_in_cpp **Repository Path**: weekend/lua_in_cpp ## Basic Information - **Project Name**: lua_in_cpp - **Description**: using lua in c++ - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-02-23 - **Last Updated**: 2025-07-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Using lua in C++ ## LUA调用CPP ### 1. 初始化lua状态机 ```cpp lua_State *L = luaL_newstate(); // 创建一个新的 Lua 状态机 luaL_openlibs(L); // 打开所有标准 Lua 库 ``` ### 2. 定义cpp函数给LUA ```cpp /** * @brief 从Lua调用的C++函数示例 * * 该函数演示了如何在Lua中调用C++函数,并处理参数和返回值。 * 函数接收一个整数参数,打印到控制台,然后返回该参数的两倍。 * * @param L Lua状态机指针,用于与Lua交互 * @return int 返回给Lua的值的数量(本例中返回1个值) */ int cpp_function(lua_State *L) { // 1. 从Lua栈中获取第一个参数(整数类型) // luaL_checkinteger会检查参数是否为整数,如果不是会抛出Lua错误 int arg = luaL_checkinteger(L, 1); // 2. 打印接收到的参数到标准输出 // 这用于调试和演示目的,实际应用中可能需要更复杂的日志记录 std::cout << "C++ function called from Lua with argument: " << arg << std::endl; // 3. 计算结果(参数乘以2) // 这里可以进行任何需要的计算或处理 // 4. 将结果压入Lua栈,准备返回给Lua // lua_pushinteger将整数压入栈顶 lua_pushinteger(L, arg * 2); // 返回值 // 5. 返回返回值的数量 // 告诉Lua调用者有多少个值被压入栈中作为返回值 // 本例中只返回1个值(arg * 2) return 1; // 返回值的数量 } ``` ### 3. 注册 C++ 函数到 Lua ```cpp lua_register(L, "cpp_function", cpp_function); ``` ### 4. 执行LUA脚本字符串,并在LUA脚本中调用CPP函数 ```cpp const char *lua_script = R"( print('Hello from Lua!') local result = cpp_function(10) print('Result from C++ function:', result) )"; // 1. 检查执行结果是否为LUA_OK(表示执行成功) // luaL_dostring会编译并执行给定的Lua脚本字符串 // 如果执行过程中发生错误(如语法错误、运行时错误等),会返回非LUA_OK的值 if (luaL_dostring(L, lua_script) != LUA_OK) { // 尝试执行Lua脚本字符串 // 2. 获取错误信息 // lua_tostring(L, -1)从Lua栈顶获取错误消息字符串 // Lua在发生错误时,会将错误消息压入栈顶 std::cerr << "Error: " << lua_tostring(L, -1) << std::endl; // 3. 清理Lua栈中的错误消息 // lua_pop(L, 1)从栈中弹出1个元素(即错误消息) // 这是为了避免错误消息留在栈中影响后续操作 lua_pop(L, 1); // 弹出错误消息 } ``` ### 4.1 执行LUA脚本,并在LUA脚本中调用CPP函数, hello.lua脚本 ```lua -- 调用 C++ 函数 local result = cpp_function(10) print('Result from C++ function:', result) -- 定义一个 Lua 函数,供 C++ 调用 function lua_function(x) print('Lua function called from C++ with argument:', x) return x * 3 end ``` ### 4.3 执行LUA脚本,并在LUA脚本中调用CPP函数 ```cpp if (luaL_dofile(L, "hello.lua") != LUA_OK) { // 尝试加载并执行指定的Lua脚本文件 // 1. 检查执行结果是否为LUA_OK(表示执行成功) // luaL_dofile会先加载文件内容,然后编译并执行其中的Lua代码 // 如果文件加载失败(如文件不存在)、编译失败(如语法错误)或运行时出错, // 都会返回非LUA_OK的值 // 2. 获取错误信息 // lua_tostring(L, -1)从Lua栈顶获取错误消息字符串 // Lua在发生错误时,会将错误消息自动压入栈顶 std::cerr << "Error: " << lua_tostring(L, -1) << std::endl; // 3. 清理Lua栈中的错误消息 // lua_pop(L, 1)从栈中弹出1个元素(即错误消息) // 这是为了避免错误消息留在栈中影响后续操作 lua_pop(L, 1); // 弹出错误消息 } ``` ### 5. 返回值处理 ```cpp // 5. 处理返回值 int return_count = lua_gettop(L); // 获取栈中剩余元素数量(即返回值数量) std::cout << "Lua function returned " << return_count << " values:" << std::endl; // 遍历所有返回值 for (int i = 1; i <= return_count; ++i) { // 检查返回值类型并提取 if (lua_isinteger(L, i)) { int int_val = lua_tointeger(L, i); std::cout << " Value "<< i << ": integer = " << int_val << std::endl; } else if (lua_isstring(L, i)) { const char* str_val = lua_tostring(L, i); std::cout << " Value "<< i << ": string = " << str_val << std::endl; } else if (lua_isboolean(L, i)) { bool bool_val = lua_toboolean(L, i); std::cout << " Value "<< i << ": boolean = " << (bool_val ? "true" : "false") << std::endl; } else { std::cout << " Value "<< i << ": unknown type" << std::endl; } } ``` ### 6. 清理 Lua 状态机 ```cpp // 6. 清理 Lua 状态机 lua_close(L); ``` ## CPP调用LUA ### 1. 初始化 ```cpp // 1. 创建 Lua 状态机 lua_State* L = luaL_newstate(); if (!L) { std::cerr << "Failed to create Lua state!" << std::endl; return 1; } // 2. 加载 Lua 标准库 luaL_openlibs(L); ``` ### 2. 获取LUA函数 ```cpp // 1. 获取 Lua 函数 lua_getglobal(L, "add"); if (!lua_isfunction(L, -1)) { std::cerr << "Error: 'add' is not a function!" << std::endl; lua_pop(L, 1); // 弹出非函数值 return; } ``` ### 3. LUA参数传递和函数调用 ```cpp // 2. 压入参数 lua_pushinteger(L, 10); // 第一个参数: 10 lua_pushinteger(L, 20); // 第二个参数: 20 // 调用 Lua 函数并检查执行结果 if (lua_pcall(L, 2, 1, 0) != LUA_OK) { // lua_pcall 执行失败时的错误处理 // 1. lua_pcall 参数说明: // - L: Lua 状态机指针 // - 2: 传递给 Lua 函数的参数数量(本例中是2个参数) // - 1: 期望 Lua 函数返回的值的数量(本例中期望1个返回值) // - 0: 错误处理模式(0表示使用默认错误处理,将错误信息压入栈顶) // 2. 当 lua_pcall 返回值不等于 LUA_OK 时,表示 Lua 函数执行过程中发生了错误 // 3. 获取错误信息 // - lua_tostring(L, -1) 从 Lua 栈顶(-1位置)获取错误消息字符串 // - Lua 在发生错误时会自动将错误信息压入栈顶 std::cerr << "Lua error: " << lua_tostring(L, -1) << std::endl; // 4. 清理错误消息 // - lua_pop(L, 1) 从栈中弹出1个元素(即错误消息) // - 这是为了避免错误消息留在栈中影响后续操作 lua_pop(L, 1); // 5. 提前返回,不再继续执行后续代码 return; } ``` ### 4. 返回值处理 ```cpp // 4. 获取返回值 if (lua_isnumber(L, -1)) { int result = lua_tointeger(L, -1); std::cout << "Result: " << result << std::endl; // 输出: 30 } else { std::cerr << "Error: 'add' did not return a number!" << std::endl; } ``` ### 5. LUA栈清理 ```cpp // void lua_settop(lua_State *L, int index); // ​​如果 index > 当前栈顶​​:在栈中​​压入 nil​​ 直到栈顶达到 index(扩展栈)。 // ​​如果 index < 当前栈顶​​:​​弹出(移除)栈顶元素​​直到栈顶变为 index(缩减栈)。 // ​​如果 index == 当前栈顶​​:无操作(栈保持不变)。 lua_settop(L, 0) // ​​清空整个栈​​(移除所有元素)。 lua_settop(L, 3); // 保留栈底前3个元素,弹出其余 lua_settop(L, 5); // 栈中已有元素不足时会填充 nil ``` ### 6. 清理 Lua 状态机 ```cpp // 6. 清理 Lua 状态机 lua_close(L); ``` ## fetch & build lua ```bash curl -L -R -O https://www.lua.org/ftp/lua-5.4.7.tar.gz tar zxf lua-5.4.7.tar.gz cd lua-5.4.7 make all test ``` ## build with cmake ```bash # 配置工程 cmake -DCMAKE_INSTALL_PREFIX=./lua_install -S lua-5.4.7 -B ./build # 编译,不指定config的话默认Debug, 其它配置Release cmake --build ./build --config RelWithDebInfo # 安装 cmake --install ./build --config RelWithDebInfo ``` ## 参考 Download https://www.lua.org/download.html Building Lua In Windows For Newbies http://lua-users.org/wiki/BuildingLuaInWindowsForNewbies