请选择 进入手机版 | 继续访问电脑版

risc-v中文社区

 找回密码
 立即注册
查看: 1444|回复: 0

Lua源码分析 - 扩展库篇 - 扩展库Open的实现(13)

[复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2022-6-20 15:54:54 | 显示全部楼层 |阅读模式
目录

一、扩展库 - Open扩展库的配置

二、扩展库 - 扩展库Lib的配置详解

三、扩展库 - 基础库Base的配置详解

上一章,我们讲解了如何将Require进来。本章节具体将一下扩展库启动的实现。

一、扩展库 - Open扩展库的配置
启动一个扩展库,首先需要进行两个基础配置:loadedlibs数组配置 & 库名称和回调函数的定义(lualib.h)

loadedlibs是一个二维数组。第一个参数为库名称,第二个参数库open函数。
loadedlibs数组中,第一个对象为全局基础方法聚合(luaopen_base)。常见的loadfile函数等都在这上面配置,在lua语言中,直接使用函数即可,无需使用库名称.方法名称(例如:string.find)方式。
数组最后一个对象,为{NULL,NULL},主要用于在循环的时候遍历退出。
//---------------------linit.c
/*
** these libs are loaded by lua.c and are readily available to any Lua
** program
** LUA标准库常量
**
** 定义标准库名称 & 启动的方法
*/
static const luaL_Reg loadedlibs[] = {
  {"_G", luaopen_base},
  {LUA_LOADLIBNAME, luaopen_package},
  {LUA_COLIBNAME, luaopen_coroutine},
  {LUA_TABLIBNAME, luaopen_table},
  {LUA_IOLIBNAME, luaopen_io},
  {LUA_OSLIBNAME, luaopen_os},
  {LUA_STRLIBNAME, luaopen_string},
  {LUA_MATHLIBNAME, luaopen_math},
  {LUA_UTF8LIBNAME, luaopen_utf8},
  {LUA_DBLIBNAME, luaopen_debug},
#if defined(LUA_COMPAT_BITLIB)
  {LUA_BITLIBNAME, luaopen_bit32},
#endif
  {NULL, NULL}
};
//......................lualib.h

LUAMOD_API int (luaopen_base) (lua_State *L);

#define LUA_COLIBNAME        "coroutine"
LUAMOD_API int (luaopen_coroutine) (lua_State *L);

#define LUA_TABLIBNAME        "table"
LUAMOD_API int (luaopen_table) (lua_State *L);

#define LUA_IOLIBNAME        "io"
LUAMOD_API int (luaopen_io) (lua_State *L);
二、扩展库 - 扩展库Lib的配置详解
我们以协程coroutine的扩展库作为例子来看。扩展库实现重点需要分三个部分:函数配置数组,扩展库加载方法,函数实现。

函数配置数组:主要定义了函数名称和对应的C语言函数。数组最后一个对象为{NULL,NULL},因为数组遍历的时候会根据NULL做判断进行弹出。
扩展库加载方法:入参为L,对当前的线程栈。方法内容必须实现luaL_newlib。该函数主要将配置数组中的方法,遍历注册到一个module[funcname]=func数组上。该module数组,作为加载方法openf的结果放入栈上。
函数实现:每个函数的入参都为lua_State *L,为当前线程栈。
大家可能会有疑问,为何每个函数入参都会L,那在lua中调用的时候如何进行多个参数入参。实际上,lua语言还会解析语法本身,对于多个参数入参,也都会通过lua_push*方法,放入栈上,所以当调用函数的时候,往栈上取参即可。

//方法配置数组
static const luaL_Reg co_funcs[] = {
  {"create", luaB_cocreate},
  {"resume", luaB_coresume},
  {"running", luaB_corunning},
  {"status", luaB_costatus},
  {"wrap", luaB_cowrap},
  {"yield", luaB_yield},
  {"isyieldable", luaB_yieldable},
  {NULL, NULL}
};

//启动函数
LUAMOD_API int luaopen_coroutine (lua_State *L) {
  luaL_newlib(L, co_funcs);
  return 1;
}


/**
* 协程挂起函数
*
* L为当前协程函数的协程栈
* lua_gettop(L)  获取当前操作函数到栈顶的栈个数
*/
static int luaB_yield (lua_State *L) {
  return lua_yield(L, lua_gettop(L));
}
三、扩展库 - 基础库Base的配置详解
Lua的基础库就是定义了一些常用的函数,例如:print。这些函数作为全局函数,可以在Lua语言中直接调用。lbaselib.c。

base_funcs:基础库的数组配置。主要定义函数名称和对应的方法。

luaopen_base:基础库的启动函数。主要有三步:

从全局注册表中获取全局环境变量数组LUA_RIDX_GLOBALS,并通过luaL_setfuncs方法将基础库的函数逐个塞进全局环境变量上LUA_RIDX_GLOBALS[name]=func
lua_pushvalue拷贝全局环境变量数组LUA_RIDX_GLOBALS,然后LUA_RIDX_GLOBALS[_G]=LUA_RIDX_GLOBALS,并将拷贝的数组pop弹出栈顶
lua_pushliteral栈顶设置一个字符串常量,用于存放版本信息,并设置LUA_RIDX_GLOBALS['_VERSION']=LUA_VERSION,然后将栈顶的版本信息pop弹出栈顶。
//基础库启动
LUAMOD_API int luaopen_base (lua_State *L) {
  /* 打开全局环境变量数组LUA_RIDX_GLOBALS,放置到栈顶L->top open lib into global table */
  lua_pushglobaltable(L);
  /* 将base_funcs中的函数,逐个设置到LUA_RIDX_GLOBALS数组上 */
  luaL_setfuncs(L, base_funcs, 0); //module 表
  /* set global _G */
  /* LUA_RIDX_GLOBALS[_G] = LUA_RIDX_GLOBALS*/
  lua_pushvalue(L, -1);
  lua_setfield(L, -2, "_G"); //弹出栈顶L->top--
  /* /* LUA_RIDX_GLOBALS[_VERSION] = LUA_VERSION set global _VERSION */
  lua_pushliteral(L, LUA_VERSION);
  lua_setfield(L, -2, "_VERSION"); //弹出栈顶L->top--
  return 1;
}

//基础库配置
static const luaL_Reg base_funcs[] = {
  {"assert", luaB_assert},
  {"collectgarbage", luaB_collectgarbage},
  {"dofile", luaB_dofile},
  {"error", luaB_error},
  {"getmetatable", luaB_getmetatable},
  {"ipairs", luaB_ipairs},
  {"loadfile", luaB_loadfile},
  {"load", luaB_load},
#if defined(LUA_COMPAT_LOADSTRING)
  {"loadstring", luaB_load},
#endif
  {"next", luaB_next},
  {"pairs", luaB_pairs},
  {"pcall", luaB_pcall},
  {"print", luaB_print},
  {"rawequal", luaB_rawequal},
  {"rawlen", luaB_rawlen},
  {"rawget", luaB_rawget},
  {"rawset", luaB_rawset},
  {"select", luaB_select},
  {"setmetatable", luaB_setmetatable},
  {"tonumber", luaB_tonumber},
  {"tostring", luaB_tostring},
  {"type", luaB_type},
  {"xpcall", luaB_xpcall},
  /* placeholders */
  {"_G", NULL},
  {"_VERSION", NULL},
  {NULL, NULL}
};

————————————————
版权声明:本文为CSDN博主「老码农zhuli」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/initphp/article/details/104374765

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



Archiver|手机版|小黑屋|risc-v中文社区

GMT+8, 2024-3-28 18:05 , Processed in 0.014325 second(s), 17 queries .

risc-v中文社区论坛 官方网站

Copyright © 2018-2021, risc-v open source

快速回复 返回顶部 返回列表