在skynet中,咱们一般使用lua来写业务层的逻辑,而且每一个功能模块基本上就是一个运行在沙盒中的lua服务。可是,当须要咱们须要开发拓展的库或者进行高性能要求的模块开发时,仍是须要考虑在C语言层面来开发一个动态库(.so),并提供能够在lua中调用的接口,而后再lua中调用此C库。html
查看了Lua官方的关于如何注册C库(C Libraries)的内容,其中有一段以下:git
When you extend Lua with C functions, it is a good idea to design your code as a C library, even when you want to register only one C function: Sooner or later (usually sooner) you will need other functions. As usual, the auxiliary library offers a helper function for this job. The luaL_openlib function receives a list of C functions and their respective names and registers all of them inside a table with the library name.github
大体的意思就是:当咱们要使用c语言的功能函数来拓展Lua的功能时,将这些函数封装成一个C库是一个不错的选择。web
根据官方的引导,定义一个C库的时候,在定义能够被调用的方法时与普通的C语言定义方式并没有差异,只是须要额外添加一个数组和一个方法:shell
定义一个测试函数:ubuntu
static int l_dir (lua_State *L) {
... /* as before */
}
声明一个 luaL_reg
类型的数组:后端
static const struct luaL_reg mylib [] = {
{"dir", l_dir},
{NULL, NULL} /* sentinel */
};
这个数组的每一个item都至关于一个key-value
结构,包含两个属性 {"(lua调用时使用的函数名)",C定义函数名(函数指针)}
,这个数组就是用来指定此C库的各个函数以及他们在lua中被调用时对应使用的接口名称(注意:最后一个item必须是 {NULL, NULL}
,不可缺乏)。数组
定义一个 luaopen_*
函数,并调用 luaL_openlib
函数:ruby
int luaopen_mylib (lua_State *L) {
luaL_openlib(L, "mylib", mylib, 0);
return 1;
}
这个函数至关于做为此库的main函数。注意此函数的名称规则:app
luaopen_
是此函数的前缀,不可修改;require
引用此库时的字符串名称(假如名称中带有“”,在使用require
须要将“”替换为“.”,例如:“mylib_test”->“mylib.test”)。在Lua5.0中调用的是
luaL_openlib
,可是在Lua5.3中,则是使用luaL_newlib
根据上述的定制标准,这里咱们就来自定义一个本身C库,首先建立一个.c的文件,例如“mylib.c”,写几个测试方法:
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
static int mtest1(lua_State *L){
printf("--- mtest1\n");
return 0;
}
static int mtest2(lua_State *L){
//从传入参数table中获取第1个参数,转为整型
int num = luaL_checkinteger(L,1);
printf("--- mtest2:num=%d\n",num);
return 0;
}
int luaopen_mylib(lua_State *L){
luaL_Reg l[] = {
{"test1",mtest1},
{"test2",mtest2},
{NULL,NULL}
};
luaL_newlib(L,l);
return 1;
}
这里我使用在Linux环境下进行 C库的编译
和 lua引用测试的执行
,并且使用gnu make
来做为构建工具,关于如何编写Makefile文件,这里就不作赘述了,作后端开发的话,特别是C++/C,仍是应该学一下的。推荐教程:Linux下编写 makefile 详细教程
建立Makefile:
C语言文件类打包成动态库使用过Makefile来进行编译完成的,这里咱们就根据咱们建立的C源码文件来建立一个对应Makefile文件。
CC ?= gcc
CFLAGS = -g -O2 -Wall -I$(LUA_INC)
SHARED := -fPIC --shared
TARGET = myLualib.so
LUA_CLIB_PATH = ./
#引入lua头文件(根据你安装Lua库时的目录而定)
LUA_INC ?= /usr/local/src/lua-5.3.0/src
start: $(TARGET)
$(TARGET) : ./test.c
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
clean:
rm -fr $(TARGET)
$(LUA_CLIB_PATH) :
mkdir $(LUA_CLIB_PATH)
执行打包指令:
make
执行输出:
root@ubuntu:/application/tests# ls
Makefile test.c test.lua
root@ubuntu:/application/tests# make
cc -g -Wall -I/usr/local/src/lua-5.3.0/src -fPIC --shared test.c -o mylib.so
root@ubuntu:/application/tests# ls
Makefile mylib.so test.c test.lua
也能够直接执行以下指令进行编译:
gcc -g -Wall -I/usr/local/src/lua-5.3.0/src --shared -fPIC -o mylib.so ./test.c
执行编译的结果是咱们能获得一个 mylib.so
动态库文件,那么接下来咱们就要尝试在lua中引入此C库并调用其中的方法。
以上指令都须要在root权限下进行执行,假如当前不是root权限,须要输入
sudo su
进行切换。
新建一个测试的lua脚本,我这里取名为 test.lua
:
--设置.so搜寻路劲
package.cpath = "./?.so"
--加载咱们自定义的库mylib.so
local mylib = require "mylib";
--调用C库中的测试方法
mylib.test1()
mylib.test2(666)
lua test.lua
输出执行结果以下:
root@ubuntu:/application/tests# ls
Makefile mylib.so test.c test.lua
root@ubuntu:/application/tests# lua test.lua
--- mtest1
--- mtest2:num=666
参考以上的步骤,之后咱们就可以根据本身须要构建功能C库,而后导入到lua中进行使用,在使用skynet框架是尤其重要的技能。(发现了还有一个精简版的skynet,叫作hive)