企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] ## 概述 最近在学习 云风的`skynet`库,想自定义一个模块,目标是使用lua调用C/C++所编写的库。 当我们需要在`Lua`里面调用`c/c++`函数时,所有的函数都必须满足以下函数签名: ```cpp typedef int (*lua_CFunction) (lua_State *L); ``` 换句话说,所有的函数必须接收一个lua\_State作为参数,同时返回一个整数值。因为这个函数使用Lua栈作为参数,所以它可以从栈里面读取任意数量和任意类型的参数。而这个函数的返回值则表示函数返回时有多少返回值被压入Lua栈。(因为Lua的函数是可以返回多个值的)。 ## lua调用C/C++的动态库 lua调用C动态库有如下几个步骤: 1. 写C动态库 2. lua调用C动态库 C动态库的重要部分 :定义一个 luaopen_* 函数,并调用 `luaL_newlib` 函数,这个函数相当于作为此动态库的main函数。需要注意: * `luaopen_`是此函数的前缀,不可修改。后面的内容是我们在lua中使用 require 引用此库时的字符串名称(假如名称中带有下划线,在使用require需要将下划线替换为点,例如:“mylib_test”->“mylib.test”)。 * 在Lua5.0中调用的是`luaL_openlib`,但是在Lua5.3中,则是使用`luaL_newlib` ### 示例 看一个示例: ``` //snpccfg.cc #ifdef __cplusplus extern "C" { #endif #include "lua.h" #include "lauxlib.h" #include "lualib.h" #ifdef __cplusplus } #endif #include <stdio.h> static int test(lua_State *L) { size_t len = 0; int num = luaL_checkinteger(L, 1); const char* str = luaL_checklstring(L, 2, &len); printf("come from test: num = %d,str = %s,len = %d\n", num, str, len); return 0; } extern "C" int luaopen_snpccfg(lua_State *L) { luaL_Reg l[] = { {"test",test}, // key-val,相当于{"(lua调用时使用的函数名)",C定义函数名(函数指针)} {NULL,NULL} // 必不可少 }; luaL_checkversion(L); luaL_newlib(L,l); return 1; } ``` `luaL_checkinteger()` 和 `luaL_checklstring()`是用来获取参数的。 生成动态库: ``` gcc -fPIC -shared -o snpccfg.so snpccfg.cc -I./lua -L./lua -llua ``` >需要通过-I和-L指定lua头文件和liblua.a库的路径 ``` --test.lua package.cpath = "./?.so" --库路径 local snpccfg = require "snpccfg" snpccfg.test(1, "12312") ``` 执行脚本 ``` $ lua test.lua come from test: num = 1 str = 12312 len = 5 ``` ### 遇到的问题 1.relocation R_X86_64_32S against `luaT_typenames_' can not be used when making a shared object; recompile with -fPIC 解决办法: 重新编译liblua.a库,Makefile:CFLAGS=加上-fPIC ,而后再编译安装 ``` make linux make install ``` ### 需要注意的几个点 1. 在C++中编译成动态库,需要在函数 `luaopen_snpccfg`前面增加 extern "C",否则在使用该动态库时会有如下错误: ``` lua: error loading module 'snpccfg' from file './snpccfg.so': ./snpccfg.so: undefined symbol: luaopen_snpccfg stack traceback: [C]: in ? [C]: in function 'require' test.lua:2: in main chunk [C]: in ``` 2. 在C中则使用extern来修饰函数`luaopen_snpccfg`, 引用书中的话: * `extern`是计算机语言中的一个关键字,可置于变量或者函数前,以表示变量或者函数的定义在别的文件中。提示编译器遇到此变量或函数时,在其它模块中寻找其定义,另外,extern也可用来进行链接指定。 * extern 后面修饰的只能是一个全局变量。