Lua | 调用C/C++的动态库
概述
最近在学习 云风的skynet
库,想自定义一个模块,目标是使用lua调用C/C++所编写的库。
当我们需要在Lua
里面调用c/c++
函数时,所有的函数都必须满足以下函数签名:
typedef int (*lua_CFunction) (lua_State *L);
换句话说,所有的函数必须接收一个lua_State作为参数,同时返回一个整数值。因为这个函数使用Lua栈作为参数,所以它可以从栈里面读取任意数量和任意类型的参数。而这个函数的返回值则表示函数返回时有多少返回值被压入Lua栈。(因为Lua的函数是可以返回多个值的)。
lua调用C/C++的动态库
lua调用C动态库有如下几个步骤:
- 写C动态库
- 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
遇到的问题
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
需要注意的几个点
- 在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
- 在C中则使用extern来修饰函数
luaopen_snpccfg
, 引用书中的话:
extern
是计算机语言中的一个关键字,可置于变量或者函数前,以表示变量或者函数的定义在别的文件中。提示编译器遇到此变量或函数时,在其它模块中寻找其定义,另外,extern也可用来进行链接指定。- extern 后面修饰的只能是一个全局变量。
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2021/02/dynamic/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接