1、skynet基础知识
1.1、lua源码获取
尝试着编译了一下lua的源码,源码地址如下:
http://www.lua.org/download.html
获取后先解压,解压后如下:
[zhu_shiyong1@hitry161 local]$
doc Makefile README src
输入make linux test开始编译
部分编译信息如下:
[zhu_shiyong1@hitry161 lua-5.4.0]$ make linux test
make[1]: Entering directory `/home/zhu_shiyong1/lua-5.4.0/src'
make all SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl"
make[2]: Entering directory `/home/zhu_shiyong1/lua-5.4.0/src'
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX -c -o lapi.o lapi.c
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX -Os -c lcode.c
......
......
gcc -std=gnu99 -o lua lua.o liblua.a -lm -Wl,-E -ldl
gcc -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX -c -o luac.o luac.c
gcc -std=gnu99 -o luac luac.o liblua.a -lm -Wl,-E -ldl
make[2]: Leaving directory `/home/zhu_shiyong1/lua-5.4.0/src'
make[1]: Leaving directory `/home/zhu_shiyong1/lua-5.4.0/src'
make[1]: Entering directory `/home/zhu_shiyong1/lua-5.4.0/src'
./lua -v
Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio
make[1]: Leaving directory `/home/zhu_shiyong1/lua-5.4.0/src'
此时src目录下有lua可执行文件“lua”和lua静态文件“liblua.a”生成
make install可将生成的文件安装到指定的目录
打开Makefile文件,默认的安装路径如下:
INSTALL_TOP= /usr/local
为防止安装后覆盖之前所安装的版本(lua版本不一样),于是修改了安装路径如下:
#安装到用户目录下
INSTALL_TOP= ~/usr/local
执行make install
自此,lua的环境已经部署完毕,相关文件信息如下:
[zhu_shiyong1@hitry161 local]$ pwd
/home/zhu_shiyong1/usr/local
[zhu_shiyong1@hitry161 local]$ ls
bin include lib man share
生成bin include lib man share 5个文件夹
[zhu_shiyong1@hitry161 local]$ tree
.
├── bin
│ ├── lua
│ └── luac
├── include
│ ├── lauxlib.h
│ ├── luaconf.h
│ ├── lua.h
│ ├── lua.hpp
│ └── lualib.h
├── lib
│ ├── liblua.a
│ └── lua
│ └── 5.4
├── man
│ └── man1
│ ├── lua.1
│ └── luac.1
└── share
└── lua
└── 5.4
10 directories, 10 files
[zhu_shiyong1@hitry161 local]$
1.2、lua调用c函数
(1).c函数作为应用程序的一部分
代码如下:
代码出处:https://www.cnblogs.com/sifenkesi/p/3876745.html
#include <stdio.h>
#include <string.h>
//#include "lua.hpp"
#include <lauxlib.h>
#include <lualib.h>
//待Lua调用的C注册函数。
static int add2(lua_State* L)
{
//检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
//如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
//将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
lua_pushnumber(L,op1 + op2);
//返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
return 1;
}
//另一个待Lua调用的C注册函数。
static int sub2(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 - op2);
return 1;
}
const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
int main()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
//将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码
//在调用C函数时使用的全局函数名,第二个参数为实际C函数的指针。
lua_register(L, "add2", add2);
lua_register(L, "sub2", sub2);
//在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
if (luaL_dostring(L,testfunc))
printf("Failed to invoke.\n");
lua_close(L);
return 0;
}
编译运行:
[zhu_shiyong1@hitry161 ~]$ gcc lua_c.c -I./usr/local/include/ -L./usr/local/lib/ -llua -o lua_c -ldl -lm
[zhu_shiyong1@hitry161 ~]$ ./lua_c
3.0
1.1
(2).c函数库成为lua的模板
说到底就是编写lua可以require的库文件
lua_cso.c文件如下:
代码出处:https://www.cnblogs.com/sifenkesi/p/3876745.html
#include <stdio.h>
#include <string.h>
//#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>
//待注册的C函数,该函数的声明形式在上面的例子中已经给出。
//需要说明的是,该函数必须以C的形式被导出,因此extern "C"是必须的。
//函数代码和上例相同,这里不再赘述。
static int add(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 + op2);
return 1;
}
static int sub(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 - op2);
return 1;
}
//luaL_Reg结构体的第一个字段为字符串,在注册时用于通知Lua该函数的名字。
//第一个字段为C函数指针。
//结构体数组中的最后一个元素的两个字段均为NULL,用于提示Lua注册函数已经到达数组的末尾。
static luaL_Reg mylibs[] = {
{"add", add},
{"sub", sub},
{NULL, NULL}
};
//该C库的唯一入口函数。其函数签名等同于上面的注册函数。见如下几点说明:
//1. 我们可以将该函数简单的理解为模块的工厂函数。
//2. 其函数名必须为luaopen_xxx,其中xxx表示library名称。Lua代码require "xxx"需要与之对应。
//3. 在luaL_register的调用中,其第一个字符串参数为模块名"xxx",第二个参数为待注册函数的数组。
//4. 需要强调的是,所有需要用到"xxx"的代码,不论C还是Lua,都必须保持一致,这是Lua的约定,
// 否则将无法调用。
//extern "C" __declspec(dllexport)
int luaopen_mylib(lua_State* L)
{
//const char* libName = "mytestlib";
luaL_newlib(L,mylibs);
//lual_register(L,mylibs);
return 1;
}
[zhu_shiyong1@hitry161 ~]$ gcc lua_cso.c -shared -fPIC -I./usr/local/include/ -L./usr/local/lib -llua -o mylib.so
本以为上述命令可以直接生成mylib.so,无奈编译报错,指出编译liblua.a时没有加上-fPIC参数
/usr/bin/ld: ./usr/local/lib/liblua.a(lapi.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
好吧,重新编译lua源码
注意:需修改lua的Makefile文件,在src/Makefile里面
找到这行代码
CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS)
修改为
CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS) -fPIC #后面加的-fPIC表示要编译位置无关代码
感谢下面小伙伴的帮助
https://www.jianshu.com/p/91fac87bd6d3
最后编译出了带有-fPIC的liblua.a的版本,并cp到/usr/local/lib里
再重新编译
[zhu_shiyong1@hitry161 ~]$ gcc lua_cso.c -shared -fPIC -I./usr/local/include/ -L./usr/local/lib -llua -o mylib.so
此时mylib.so库生成
[zhu_shiyong1@hitry161 ~]$ ll mylib.so
-rwxr-xr-x 1 zhu_shiyong1 hitry 186704 Sep 2 14:18 mylib.so
试试效果如何:
[zhu_shiyong1@hitry161 ~]$ ./usr/local/bin/lua
Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio
> lib = require"mylib"
> print(lib.add(1,2))
3.0
>
ok,大功告成!此时c库已成为lua的模板库。
1.3、c调用lua
代码出处:https://www.cnblogs.com/coderkian/p/4057750.html
test.c代码如下:
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <math.h>
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0,0,0)){
printf("error %s\n", lua_tostring(L,-1));
return -1;
}
lua_getglobal(L,"add");
lua_pushnumber(L, 10);
lua_pushnumber(L, 20);
if(lua_pcall(L, 2, 1, 0) != 0){
printf("error %s\n", lua_tostring(L,-1));
return -1;
}
int z = lua_tonumber(L, -1);
printf("z = %d \n", z);
lua_pop(L, 1);
lua_close(L);
return 0;
}
说明:
1.luaL_newstate创建一个新的lua_State,C和lua的所有操作都要依赖这个lua环境, luaL_openlibs将lualib.h中定义的lua标准库加载到进lua_State。
2.luaL_loadfile从文件中加载lua代码并编译,编译成功后的程序块被压入栈中,
3.lua_pcall会将程序块弹出并在保护模式下解释执行。代码中调用lua_pcall就在lua_State中定义了 width和 length两个全局变量。
4.lua_getglobal将全局变量的值压入栈中,width先入栈,在-2的位置,length在栈顶。
test.lua代码如下:
function add(x,y)
return x+y
end
效果如下:
[zhu_shiyong1@hitry161 ~]$ gcc test.c -I./usr/local/include/ -L./usr/local/lib -llua -o test -lm -ldl
[zhu_shiyong1@hitry161 ~]$ ./test
z = 30
1.4、lua协程
coroutine:协同程序
摘自:https://www.runoob.com/lua/lua-coroutine.html
coroutine.create() 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用
coroutine.resume() 重启 coroutine,和 create 配合使用
coroutine.yield() 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
coroutine.status() 查看 coroutine 的状态
注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序
coroutine.wrap() 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复
coroutine.running() 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号