lua模块注册
Lua自带的模块并不多,好处就是Lua足够的小,毕竟它的设计目标是定位成一个嵌入式的轻量级语言的.
相关的函数index2adr
static TValue *index2adr (lua_State *L, int idx) {
if (idx > 0) {
TValue *o = L->base + (idx - 1);
api_check(L, idx <= L->ci->top - L->base);
if (o >= L->top) return cast(TValue *, luaO_nilobject);
else return o;
}
else if (idx > LUA_REGISTRYINDEX) {
api_check(L, idx != 0 && -idx <= L->top - L->base);
return L->top + idx;
}
else switch (idx) { /* pseudo-indices */
case LUA_REGISTRYINDEX: return registry(L);
case LUA_ENVIRONINDEX: {
Closure *func = curr_func(L);
sethvalue(L, &L->env, func->c.env);
return &L->env;
}
case LUA_GLOBALSINDEX: return gt(L);
default: {
Closure *func = curr_func(L);
idx = LUA_GLOBALSINDEX - idx;
return (idx <= func->c.nupvalues)
? &func->c.upvalue[idx-1]
: cast(TValue *, luaO_nilobject);
}
}
}
一个Lua函数栈由两个指针base和top来指定,base指向函数栈底,top则指向栈顶.
回到index2addr函数中,几种情况:
- 如果索引为正,则从函数栈底为起始位置向上查找数据
- 如果索引为负,则从函数栈顶为起始位置向下查找数据
- 紧跟着是几种特殊的索引值,都定义了非常大的数据,由于Lua栈限定了函数的栈尺寸,所以不会有那么大的索引,大可放心使用.
索引值为LUA_REGISTRYINDEX时,则返回的是全局数据global_state的l_registry表;如果索引值为LUA_GLOBALSINDEX,则返回该Lua_State的l_gt表.
lua模块注册
Lua内部所有模块的注册都在linit.c的函数luaL_openlibs中提供.可以看到的是,它依次访问一个数组,数组中定义了每个模块的模块名及相应的模块注册函数,依次调用函数就完成了模块的注册.
static const luaL_Reg lualibs[] = {
{"", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib = lualibs;
for (; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_pushstring(L, lib->name);
lua_call(L, 1, 0);
}
}
我没有详细的查看每个模块的注册函数,不过还是以最简单的例子来讲解,就是最常用的print函数.
由于这个函数没有前缀,因此的它所在的模块是”",也就是一个空字符串,因此它是在base模块中注册的,调用的注册函数是luaopen_base.
紧跟着继续看luaopen_base内部调用的第一个函数base_open:
static void base_open (lua_State *L) {
/* set global _G */
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setglobal(L, "_G");
/* open lib into global table */
luaL_register(L, "_G", base_funcs);
// ....
}
首先来看最前面的两句:
/* set global _G */
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setglobal(L, "_G");
这两句首先将LUA_GLOBALSINDEX对应的值压入栈中,其次调用”lua_setglobal(L, “_G”);”,这句代码的意思是在Lua_state的l_gt表中,当查找”_G”时,查找到的是索引值为LUA_GLOBALSINDEX的表.如果觉得有点绕,可以简单这个理解,在Lua中的G表,也就是全局表,满足这个等式”_G = _G["_G"]“,也就是这个叫”_G”的表,内部有一个key为”_G”的表是指向自己的.怀疑这个结论的,可以在Lua命令行中执行print(_G)和print(_G["_G"])看看输出结果是不是一致的.
Lua中要这么处理的理由是:为了让G表和处理其它表使用同样的机制.查找一个变量时,最终会一直查到G表中,这是很自然的事情;所以为了也能按照这个机制顺利的查找到自己,于是在G表中有一个同名成员指向自己.
好了,前面两句的作用已经分析完毕.其结果有两个:
- _G = _G["_G"]
- _G表的值压入函数栈中方便了下面的调用.
继续看下面的语句:
luaL_register(L, “_G”, base_funcs);
它最终会将base_funcs中的函数注册到G表中,但是里面还有些细节需要看看的.
LUALIB_API void luaI_openlib (lua_State *L, const char *libname,
const luaL_Reg *l, int nup) {
if (libname) {
int size = libsize(l);
/* check whether lib already exists */
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
lua_getfield(L, -1, libname); /* get _LOADED[libname] */
if (!lua_istable(L, -1)) { /* not found? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
luaL_error(L, "name conflict for module " LUA_QS, libname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
}
lua_remove(L, -2); /* remove _LOADED table */
lua_insert(L, -(nup+1)); /* move library table to below upvalues */
}
// ...
}
注册这些函数之前,首先会到l_registry表的成员_LOADED表中查找该库,如果不存在则再在G表中查找这个库,不存在则创建一个表.因此,不管是lua中内部的库或者是外部使用require引用的库,都会走这个流程并最终在G表和l_registry["_LOADED"]中存放该库的表.最后,再遍历传进来的函数指针数组,完成库函数的注册.
比如,注册os.print时,首先将print函数绑定在一个函数指针上,再去l_registry["_LOADED"]和G表中查询该名为”os”的库是否存在,不存在则创建一个表,即:
G["os"] = {}
紧跟着注册print函数,即: G["os"]["print"] = 待注册的函数指针.这样,在调用lua代码os.print(1)时,首先根据”os”到G表中查找对应的表,再在这个表中查找”print”成员得到函数指针,最后完成函数的调用.
注册外部模块
luaL_newlibtable 它仅仅是创建了一个table,然后把数组里的函数放进去而已
luaL_setfuncs它把数组l中的所有函数注册入栈顶的table,并给所有函数绑上nup个upvalue
define luaL_newlibtable(L, l)
lua_createtble(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
define luaL_newlib(L, l)
(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)
LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup){
luaL_checkversion(L);
luaL_checkstack(L, nup, "too_many_upvalue");
for(; l->name != NULL; i++){/* fill the table with given functions*/
int i;
for(i = 0; i < nup; i++)/copy upvalues to the top/
lua_pushvalue(L, -nup);
lua_pushclosure(L, l->func, nup);/closure with those upvalues/
lua_setfield(L, -(nup + 2), l->name);
}
lua_pop(L, nup);/remove upvalues/
}
lua模块注册的更多相关文章
- Lua和C++交互 学习记录之八:C++类注册为Lua模块
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- Lua和C++交互 学习记录之七:C++全局函数注册为Lua模块
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- lua 模块与环境
编写一个模块的最简单方法: -- complex.lua -- 模块实际上是一个表 complex = {} -- 定义模块函数 function complex.add(c1,c2) ... end ...
- cocos2d-x 2.2.0 如何在lua中注册回调函数给C++
cocos2d-x内部使用tolua进行lua绑定,但是引擎并没有提供一个通用的接口让我们可以把一个lua函数注册给C++层面的回调事件.翻看引擎的lua绑定代码,我们可以仿照引擎中的方法来做.值得吐 ...
- vim编译安装+lua模块
vim编译安装+lua模块 使用背景:代码自动补全插件,需要安装lua模块 安装准备,首先下载安装vim所依赖的其它安装包,ncurses,lua,readline,vim 源码下载,编译安装 ncu ...
- lua 模块
lua 模块 概述 lua 模块类似于封装库 将相应功能封装为一个模块, 可以按照面向对象中的类定义去理解和使用 使用 模块文件示例程序 mod = {} mod.constant = "模 ...
- lua模块demo(redis,http,mysql,cjson,本地缓存)
1. lua模块demo(redis,http,mysql,cjson,本地缓存) 1.1. 配置 在nginx.conf中设置lua_shared_dict my_cache 128m; 开启ngi ...
- Lua模块的加载与内存释放
今天早上听说一件事情让我觉得很诡异的事情:公司线上的一款游戏,加载一份配置资源后,内存涨了几十M,然后内存再也下不来了.因为好奇,所以要来了最大的一个配置文件(4.5M,去除空格与换行后的大小),进行 ...
- nginx 增加 lua模块
Nginx中的stub_status模块主要用于查看Nginx的一些状态信息. 本模块默认是不会编译进Nginx的,如果你要使用该模块,则要在编译安装Nginx时指定: ./configure –wi ...
随机推荐
- Alpha 冲刺报告(2/10)
Alpha 冲刺报告(2/10) 队名:洛基小队 团队困难汇总:在开始正式编码的时候遇到了很严重的问题,Cocos Creator的教程过少,之前浏览的官网上的教程以为很齐全,但是在最重要的脚本方面还 ...
- sql按月模糊查询
select * from tb where convert(varchar(7),date,120) = '2011-05'
- C#中控件Control的Paint事件和OnPaint虚函数的区别
句柄 : 句柄,是整个Windows编程的基础.一个句柄是指使用的一个唯一的整数值,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类对象中的不同的实例,诸如,一个窗口,按 ...
- IS服务器下做301永久重定向设置方法
以前也没怎么关注301重定向,第一因为没有网站要重定向,第二对于不带www的域名我都是用的转发到带www的域名. 不过一场风波之后,很多服务商已经不提供转发服务了,虽说易名现在还可以享用到免费的转发服 ...
- Java日志框架中真的需要判断log.isDebugEnabled()吗?
在项目中我们经常可以看到这样的代码: if (logger.isDebugEnabled()) { logger.debug(message); } 简单来说,就是用isDebugEnabled方法判 ...
- kaggle _Titanic: Machine Learning from Disaster
A Data Science Framework: To Achieve 99% Accuracy https://www.kaggle.com/ldfreeman3/a-data-science-f ...
- ping不通linux服务器排查
很久没启动linux了,今天打开试了下 ssh root@192.168.229.128 ping 一直超时 老规矩挨着来排查 检查网络设备器改为Net 模式 重启网络服务 service netw ...
- PAT乙级1030
1030 完美数列 (25 分) 给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列. 现在给定参数 p 和一些正整数,请你从中选择 ...
- block本质探寻六之修改变量
说明: <1>阅读本文章,请参照前面的block文章加以理解: <2>本文的变量指的是auto类型的局部变量(包括实例对象): <3>ARC和MRC两种模式均适用: ...
- Linux服务-ftp
目录 1. ftp简介 2. ftp架构 3. ftp数据连接模式 4. 用户认证 5. vsftpd 5.1 vsftpd安装 5.2 vsftpd配置 5.3 vsftpd实验配置 5.3.1 安 ...