Lua学习笔记:探究package
| 本篇在讲什么 理解Lua的package 本篇需要什么 对Lua语法有简单认知 对C++语法有简单认知 依赖Visual Studio工具 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 |
★提高阅读体验★ 👉 ♠ 一级标题 👈👉 ♥ 二级标题 👈👉 ♣ 三级标题 👈👉 ♦ 四级标题 👈 |
目录
- ♠ 前言
- ♠ 前瞻
- ♠ 注册标准库
- ♥ luaL_openlibs
- ♥ luaopen_package
- ♠ package的参数
- ♥ loaders
- ♥ cpath
- ♥ path
- ♥ loaded
- ♥ loadlib
- ♥ seeall
- ♠ 推送
- ♠ 结语
♠ 前言
本篇文章简单了解一下Lua的全局表package,及其表内字段功能
♠ 前瞻
阅读本篇文章需要准备编译Lua源码的工程,详情可参考下面文章
Lua学习笔记:在Visual Studio中调试Lua源码和打断点
阅读本篇文章前最好提前了解C/C++和Lua的交互原理,详情可参考下面文章
Lua学习笔记:C/C++和Lua的相互调用
♠ 注册标准库
首先我们要知道,在创建一个新的Lua虚拟机后,其环境内是没有定义任何函数的,我们需要注册一下标准库以供使用,代码如下
lua_State* L = luaL_newstate();
luaL_openlibs(L);
我们通过函数luaL_openlibs向Lua环境注册一些标准函数
♥ luaL_openlibs
函数原型在在脚本linit.c当中,代码如下所示
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);}
}
可以看到在for循环当中以此把lualibs数组内的函数和函数名字注册到了lua_State内
♥ luaopen_package
函数luaopen_package是注册package表的核心函数,其源码定义在脚本loadlib.c当中,如下所示
LUALIB_API int luaopen_package (lua_State *L) {int i;/* create new type _LOADLIB */luaL_newmetatable(L, "_LOADLIB");lua_pushcfunction(L, gctm);lua_setfield(L, -2, "__gc");/* create `package' table */luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
#if defined(LUA_COMPAT_LOADLIB) lua_getfield(L, -1, "loadlib");lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
#endiflua_pushvalue(L, -1);lua_replace(L, LUA_ENVIRONINDEX);/* create `loaders' table */lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1);/* fill it with pre-defined loaders */for (i=0; loaders[i] != NULL; i++) {lua_pushcfunction(L, loaders[i]);lua_rawseti(L, -2, i+1);}lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' *//* store config information */lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n"LUA_EXECDIR "\n" LUA_IGMARK);lua_setfield(L, -2, "config");/* set field `loaded' */luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2);lua_setfield(L, -2, "loaded");/* set field `preload' */lua_newtable(L);lua_setfield(L, -2, "preload");lua_pushvalue(L, LUA_GLOBALSINDEX);luaL_register(L, NULL, ll_funcs); /* open lib into global table */lua_pop(L, 1);return 1; /* return 'package' table */
}
我们挑重点来看,在开始向环境当中注册了一个名为package的表,并且在表中注册了两个名为loadlib和seeall的函数
static const luaL_Reg pk_funcs[] = {{"loadlib", ll_loadlib},{"seeall", ll_seeall},{NULL, NULL}
};/* create `package' table */
luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
随后依次为表package设置了loaders、path、cpath、config、loaded、preload参数
lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */
setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */
setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */
lua_setfield(L, -2, "config");
lua_setfield(L, -2, "loaded");
lua_setfield(L, -2, "preload");
最后又向loaded中的全局表_G中注册了两个名为require和module的函数
static const luaL_Reg ll_funcs[] = {{"module", ll_module},{"require", ll_require},{NULL, NULL}
};lua_pushvalue(L, LUA_GLOBALSINDEX);
luaL_register(L, NULL, ll_funcs); /* open lib into global table */
所以经过了上述一通操作,我们的全局表package最终变成了下面这个样子
{["config"] = "...",["cpath"] = "...",["loaded"] = {["_G"] = {["require"] = function,["module"] = function,}},["loaders"] = {},["loadlib"] = function,["path"] = "...",["preload"] = {},["seeall"] = function,
}
♠ package的参数
从上边创建package的时候我们其实已经知道,其中所包含的字段,这里我们简单了解一下这些个字段都是干嘛用的
通过pairs遍历package的key值,也可以很直观的看到package中所有的参数

♥ loaders
存储加载器的表,打印出来如下图所示

其对应的四个加载器,定义在loadlib.c中,代码如下图所示
static const lua_CFunction loaders[] ={loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
这个加载器可以理解为解析文件的方式,比如我们require了一个lua文件,那么会通过loader_Lua方法去解析文件,如果require了一个c文件,那么会通过loader_C方法去解析文件
后续得空专门为require的流程再写一遍笔记
♥ cpath
c加载器的搜索路径,loader_C方法会从package.cpath路径下搜索对应的文件

♥ path
Lua文件加载器的搜索路径,Luader_Lua方法会从package.path下搜索对应的Lua文件


我们在D盘某个路径下有个lua文件test3.lua,我们从c盘的一个lua文件正常是require不到他的,现在只要补充搜索路径即可,如下所示
package.path = package.path .. ";D:\\lua_src\\?.lua"
require "test3"
♥ loaded
管理全局函数和已经加载的标准库,在loaded内存在表__G,全局函数和全局表都会存其中管理

管理一些已经require的模块,require的时候首先会判断package.loaded内是否已经加载过了,如果加载过了直接返回

♥ loadlib
加载c库中的方法,返回的是一个lua_CFunction,只加载不执行
♥ seeall
为模块设置一个元表,其__index字段引用_G,以便该模块继承全局环境的值。作为功能模块的选项,功能等同于下面代码
setmetatable(M, {__index = _G});
♠ 推送
- Github
https://github.com/KingSun5
♠ 结语
若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。
相关文章:
Lua学习笔记:探究package
前言 本篇在讲什么 理解Lua的package 本篇需要什么 对Lua语法有简单认知 对C语法有简单认知 依赖Visual Studio工具 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 ★提高阅读体验★ 👉 ♠ 一级…...
【面试经典150 | 双指针】三数之和
文章目录 写在前面Tag题目来源题目解读解题思路方法一:暴力枚举方法二:双指针 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对…...
现代卷积网络实战系列3:PyTorch从零构建AlexNet训练MNIST数据集
1、AlexNet AlexNet提出了一下5点改进: 使用了Dropout,防止过拟合使用Relu作为激活函数,极大提高了特征提取效果使用MaxPooling池化进行特征降维,极大提高了特征提取效果首次使用GPU进行训练使用了LRN局部响应归一化(…...
Django系列:Django应用(app)的创建与配置
Django系列 Django应用(app)的创建与配置 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article…...
Linux查看程序和动态库依赖的动态库
一. 前言 在一些时候,我们需要知道一个程序或者动态库所依赖的动态库有哪些。比如,当我们运行一个程序的时候,发现可能会报错,提示找不到某个符号,这时我们就需要知道程序依赖了什么库,从而添加对应需要的动…...
vue3 无法使用pnpm安装依赖 或 Cannot find module preinstall.js
创建.npmrc文件在根目录 shamefully-hoisttrue auto-install-peerstrue strict-peer-dependenciesfalse删除 node_modules 和 pnpm-lock.yaml 文件 重新 pnpm i 就可以啦...
C/C++连接数据库,包含完整代码。
C/C连接数据库 本篇文章意在简洁明了的在linux环境下使用C/C连接远程数据库,并对数据库进行增删查改等操作。我所使用的环境是centos7,不要环境除环境配置外,代码是大同小异的。完整代码在最底部!!! 1.前…...
AUTOSAR词典:CAN驱动Mailbox配置技术要点全解析
AUTOSAR词典:CAN驱动Mailbox配置技术要点全解析 前言 首先,请问大家几个小小问题,你清楚: AUTOSAR框架下的CAN驱动关键词定义吗?是不是有些总是傻傻分不清楚呢?CAN驱动Mailbox配置过程中有哪些关键配置参…...
C语言 coding style
头文件 The #define Guard #define的保护文件的唯一性,防止被多重包含 格式 : <PROJECT>_< FILE>_H_ PROJECT : XS FILE : MV_CTR 头文件的包含顺序 C System FilesOther LibrariesUser LibraryConditional include 作用域 局部变量 -变量定义时需要…...
Python办公自动化之PDF
Python操作PDF 1、Python操作PDF概述2、批量拆分3、批量合并4、提取内容(文字)5、提取内容(表格)6、提取图片7、PDF添加水印8、加密与解密1、Python操作PDF概述 Python操作PDF主要有两个库:PyPDF2和pdfplumber PyPDF2是一个用于处理PDF文件的Python第三方库 官网文档参考:…...
【每日一题Day331】LC2560打家劫舍 IV | 二分查找 + 贪心
打家劫舍 IV【LC2560】 沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。 由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋 。 小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额…...
JVM 参数详解
GC有两种类型:Scavenge GC 和Full GC 1、Scavenge GC 一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,堆的Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到…...
uni-app获取地理位置
在uni-app中,可以通过uni.getLocation()方法获取地理位置。具体步骤如下: 在uni-app项目中的manifest.json文件中,添加需要获取地理位置的权限: {"mp-weixin": {"appid": "...","permission…...
Learn Prompt-Prompt 高级技巧:思维链 Chain of Thought Prompting
Jason Wei等作者对思维链的定义是一系列的中间推理步骤( a series of intermediate reasoning steps )。目的是为了提高大型语言模型(LLM)进行复杂推理的能力。 思维链通常是伴随着算术,常识和符号推理等复杂推理任务出…...
Vim编辑器使用入门
目录 一、Vim 编辑器基础操作 二、Vim 编辑器进阶操作 三、Vim 编辑器高级操作 四、Vim 编辑器文件操作 五、Vim 编辑器文件管理 六、Vim 编辑器进阶技巧 七、Vim 编辑器增强功能 Vim的三种工作模式 一、Vim 编辑器基础操作 1.移动光标 - 光标的移动控制 移动光标有两…...
早餐与风景
来吧,我用流水账描述下这一天。 时维九月,北京的早上有点冷,因为今天有个市场活动要去支撑,按照会议时间的要求,我需要在早上7点半就赶到会场,所以昨天晚上我加班到凌晨处理完了今天要给出去的材料…...
常用python代码串
记录新疆出差期间的一些代码 打开yaml文件python中的专有名词ctrlc 打开yaml文件 with open(/home/cyun/文档/cotton_ws/src/control/scripts/ControlParameter.yaml, r) as file:yaml_data yaml.load(file, Loaderyaml.FullLoader)后面发现像这种打开文件的最好是try一下 p…...
电脑桌面透明便签软件是哪个?
在现代快节奏的工作环境中,许多上班族都希望能够在电脑桌面上方便地记录工作资料、重要事项、工作流程等内容。为了解决这个问题,一款优秀的电脑桌面便签软件是必不可少的。在选择桌面便签软件时,许多用户也希望便签软件能够与电脑桌面壁纸相…...
Git创建干净分支,本地操作不依赖任何分支
clone远程项目: git clone gittest.git查看分支: git branch -a创建新分支: git checkout --orphan test, 返回Switched to a new branch test删除当前项目文件夹下所有文件: git rm -rf .提交变更: git commit -m "new branch for test"查看分支: git branch -a, 发…...
sqlmap tamper脚本编写
文章目录 tamper脚本是什么?指定tamper脚本运行sqlmap安全狗绕过tamper脚本 tamper脚本是什么? SQLMap 是一款SQL注入神器,可以通过tamper 对注入payload 进行编码和变形,以达到绕过某些限制的目的。但是有些时候,SQLM…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
