C++ 集成 Lua

449 阅读5分钟

一、Lua 定位

嵌入式语言:C 语言拥有控制权, Lua 语言被用作库

可扩展语言:Lua 语言拥有控制权,C 语言被用作库

无论哪一种,都需要用到 C API 进行交互。

C API 中大多数函数不会检查参数的正确性,所以必须保证在调用前确保参数的合法性,一旦出错,程序会崩溃而不会收到规范的错误信息。

可以通过使用宏定义 LUA_USE_APICHECK 来启用一些一致性检查

二、什么是 C API

C API 包括读写 Lua 全局变量的函数、调用 Lua 函数的函数、运行 Lua 代码段的函数、以及注册 C 函数(用于后面可以被 Lua 代码调用)的函数等。

通过 C API 就可以打通了 C 调用 Lua 以及 Lua 调用 C 的渠道。

三、将 Lua 集成到 C++ 项目中

第一步,下载需要的 Lua 版本源码

进入官网 www.lua.org/ftp/ 进行下载,我使用的是 5.4.4

下载后解压,进入到 src 目录,将目录下的文件复制到项目中的一个文件夹下。

Lua_CPP_2022 项目为例,放置在项目下的 lua_lib/lua-5.4.4 目录中。

第二步,编写 cmake 将源文件链接

# 设置 LUA_DIR 指向 lua-5.4.4 目录
set(LUA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lua-5.4.4)

# 设置 Lua 源码
set(LUA_RUNTIME_SOURCES
        "${LUA_DIR}/lapi.c"
        "${LUA_DIR}/lauxlib.c"
        "${LUA_DIR}/lbaselib.c"
        "${LUA_DIR}/lcode.c"
        "${LUA_DIR}/lcorolib.c"
        "${LUA_DIR}/lctype.c"
        "${LUA_DIR}/ldblib.c"
        "${LUA_DIR}/ldebug.c"
        "${LUA_DIR}/ldo.c"
        "${LUA_DIR}/ldump.c"
        "${LUA_DIR}/lfunc.c"
        "${LUA_DIR}/lgc.c"
        "${LUA_DIR}/linit.c"
        "${LUA_DIR}/liolib.c"
        "${LUA_DIR}/llex.c"
        "${LUA_DIR}/lmathlib.c"
        "${LUA_DIR}/lmem.c"
        "${LUA_DIR}/loadlib.c"
        "${LUA_DIR}/lobject.c"
        "${LUA_DIR}/lopcodes.c"
        "${LUA_DIR}/loslib.c"
        "${LUA_DIR}/lparser.c"
        "${LUA_DIR}/lstate.c"
        "${LUA_DIR}/lstring.c"
        "${LUA_DIR}/lstrlib.c"
        "${LUA_DIR}/ltable.c"
        "${LUA_DIR}/ltablib.c"
        "${LUA_DIR}/ltm.c"
        "${LUA_DIR}/lua.c"
        "${LUA_DIR}/lundump.c"
        "${LUA_DIR}/lutf8lib.c"
        "${LUA_DIR}/lvm.c"
        "${LUA_DIR}/lzio.c"
        )

add_library(
        LuaLib
        SHARED
        ${LUA_RUNTIME_SOURCES}
)

第三步,将 cmake 文件链接到主项目

# 将 lua_lib/lua-5.4.4 目录添加至编译器的搜索目录中
# 这样使用 Lua 的源文件时,#include 的文件路径就不需要使用 "lua_lib/lua-5.4.4" 了
# 如果没有这一句,使用 "lua.hpp" ,就需要 #include "lua_lib/lua-5.4.4/lua.hpp"
# 有了这一句,就只需要 #include "lua.hpp"
include_directories(lua_lib/lua-5.4.4)
# 将子目录添加到构建中
# 参数 source_dir( 即这里的 lua_lib )指定源 CMakeLists.txt 和代码文件所在的目录
# 这样就会把 lua_lib/CMakeLists.txt 加入到构建中
add_subdirectory(lua_lib)

# 添加链接库
target_link_libraries(Lua_CPP_2022 LuaLib)

这样就将 Lua 源代码链接进我们的项目了

第四步,使用以下代码进行验证是否集成成功

#import "lua.hpp"

/**
 * 验证 Lua 集成是否成功
 */
void verification() {
    int error;
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    error = luaL_loadstring(L, "print(\"jiang\")") || lua_pcall(L, 0, 0, 0);
    if (error) {
        fprintf(stderr, "%s\n", lua_tostring(L, -1));
        lua_pop(L, 1);
    }

    lua_close(L);
}

int main() {
    verification();
    return 0;
}

// --> jiang

四、引入的头文件简介

如果是使用 C 语言的话,则直接使用以下进行引用 Lua 头文件

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

如果使用 C++ 则需要嵌套 extern ,或是直接引用 lua.hpp

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

// 或是使用 lua.hpp
#import "lua.hpp"

其实 lua.hpp 内部也就是用 extern 进行嵌套这些头文件。

1、lua.h

lua.h 中为 Lua 提供的基础函数,所有的函数都以 lua_ 开头。

其中包括了 “创建新 Lua 环境的函数”、“调用 Lua 函数的函数”、“读写环境中的全局变量的函数”,以及 “注册供 Lua 语言调用的新函数的函数” 等等。

2、luaxlib.h

是一个辅助库,是基于 lua.h 提供的基础 API 提供更高层次的抽象,函数都以 luaL_ 开头。

luaxlib.h 提供的是对常见任务的实用性,lua.h 提供的是经济性和正交性。

3、lualib.h

Lua 中默认不带有任何的标准库,而所有的标准库都被打包成不同的包。lualib.h 中包含了打开这些库的函数

使用 luaL_openlibs 则打开了所有的标准库。

五、 lua_State

Lua 标准库中没有定义任何 c 语言全局变量,所有状态都保存在动态结构体 lua_Stata 中,而 Lua 中的所有函数都有接收 lua_State 类型的参数,从而可以实现多线程。

宿主程序 C/C++ 会通过 lua_State 跟 Lua 进行交互,一般的操作步骤为如下所示:

// 第一步:创建 lua_State
lua_State *L = luaL_newstate();

// 第二步:打开所有标准库
luaL_openlibs(L);

// 第三步:通过 lua_State 进行 Lua 的交互

// 第四步:关闭 lua_State
lua_close(L);

当然第三步的逻辑会很多,lua_State 可以被一直持有,一直到不需要的时候再执行第四步进行关闭释放内存。

第三步的 C/C++ 与 Lua 交互细节后续会有文章详细分享。

1、标准库

上面所述的标准库是指 Lua 中的 stringmath 等标准库,Lua 为了让语言最为精炼,所以初始化的时候是不默认加载的。

lua_openlibs 会加载全部的标准库,如果不需要加载全部,可以使用以下的函数进行加载需要的标准库:

函数描述
luaopen_base基础模块,包括:
- 全局函数(例如 print 等)
- 全局常量(nil 等)
- 核心库函数(load 等)
- 字符串操作函数
- 数学函数
- 表操作函数
- 迭代器函数(ipairs 等)
- 错误处理函数(error 等)
luaopen_package包管理模块
luaopen_coroutine协程模块
luaopen_table表操作模块
luaopen_io输入输出模块
luaopen_os操作系统模块
luaopen_string字符串处理模块
luaopen_math数学库模块
luaopen_utf8utf8 编码处理模块
luaopen_debug调试模块

六、写在最后

Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)

如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀

公众号搜索 “江澎涌”,更多优质文章会第一时间分享与你。