lua(wiki 中文 官方社区:lua-users)是一门开源、简明、可扩展且高效的弱类型解释型脚本语言。
由于其实现遵循C标准,它几乎能在所有的平台(windows、linux、OS X、Android、iOS、PlayStation、XBox、wii等)上运行。
当前最新的lua版本为5.3.5;前两位版本号为lua的大版本,相同的大版本之间是兼容的;即5.3.5向下兼容5.3.4~0等版本
版本信息定义在lua.h中,即宏LUA_RELEASE
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "3" #define LUA_VERSION_NUM 503 #define LUA_VERSION_RELEASE "4" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2017 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
lua非常小巧精简,其解释器加上周边的库函数也不过1w多行代码。以下是Lua5.3.5的源文件:
核心文件:
文件名 | 作用 | 对外接口前缀 |
lapi.c | c语言接口 | lua_ |
lcode.c | 源码生成器 | luaK_ |
ldebug.c | 调试库 | luaG_ |
ldo.c | 函数调用及栈管理 | luaD_ |
ldump.c | 序列化预编译的lua字节码 | |
lfunc.c | 提供操作函数原型及闭包的辅助函数 | luaF_ |
lgc.c | GC | luaC_ |
llex.c | 词法分析 | luaX_ |
lmem.c | 内存管理 | luaM_ |
lobject.c | 对象管理 | luaO_ |
lopcodes.c | 字节码操作 | luaP_ |
lparser.c | 语法分析 | luaY_ |
lstate.c | 全局状态机 | luaE_ |
lstring.c | 字符串操作 | luaS_ |
ltable.c | 表操作 | luaH_ |
ltm.c | tag方法 | luaT_ |
lundump.c | 加载预编译字节码 | luaU_ |
lvm.c | 虚拟机 | luaV_ |
lzio.c | 缓存流接口 | luaZ_ |
内嵌库文件:
文件名 | 作用 |
lauxlib.c | 库编写时需要用到的辅助函数库 |
lbaselib.c | 基础库 |
lbitlib.c | bit位操作库 |
lcorolib.c | 协程库 |
lctype.c | 封装c标准库中的ctype文件 |
ldblib.c | 调试库 |
linit.c | 负责内嵌库的初始化 |
liolib.c | IO库 |
lmathlib.c | 数学库 |
loadlib.c | 动态扩展库加载器 |
loslib.c | OS库 |
lstrlib.c | 字符串操作库 |
ltablib.c | 表操作库 |
lutf8lib.c | utf8库 |
解释器、编译器文件:
文件名 | 作用 |
lua.c | 解释器 |
luac.c | 编译器 |
lua很容易编译成静态库、动态库或以源代码的形式集成到应用程序中,并方便地与c/c++及其他语言进行互操作,因此其被称为胶水语言(glue language)。
如果不想自己编译lua,可从LuaBinaries下载编译好的各个平台上静态库、动态库及基于这些库实现的lua、wlua解释器、luac编译器等工具.。
由于其动态性,支持热更,上手难度低等特点,在游戏行业常常被用来开发业务逻辑。
可使用跨平台vsCode来编辑和调试lua脚本(注:调试需要安装actboy168的LuaDebug插件 其github在这里,可在vscode的Extensions面板中搜索lua找到它然后直接安装)。
腾讯也提供了一款vsCode的lua调试器插件:LuaPanda 其github在这里
lua/wlua解释器
lua.exe、wlua.exe解释器都可以通过传入lua文件,来执行lua脚本 如:lua.exe/wlua.exe D:/LuaTest/test1.lua // 将Hello World!字符串打印到控制台和写入到e:/test.txt文件中
D:/LuaTest/test1.lua内容如下:
print("Hello World!") file = io.open("e:/test.txt", "w") file:write("Hello World!", " ") file:close()
lua.exe是subsystem:console类型程序,可在控制台交互式地接受用户的输入,并能使用print等函数将结果输出到控制台中
wlua.exe是subsystem:windows类型程序,无控制台窗口,因此不能将结果输出到控制台中,但可输出到文件;另外通过加载GUI dll插件模块,可使用模块中的接口来创建窗口程序
在lua5.1.5及之前版本,luaforwindows(googlecode上的站点)项目会集成lua在windows上的各个插件,方便大家在windows上使用lua,如今该项目已停更
如:在luaforwindows中就集成了alien插件,该插件中提供的lua版的windows api,配合wlua.exe来运行以下脚本
require "alien" local MessageBox = alien.User32.MessageBoxA MessageBox:types{ret = "long", abi = "stdcall", "long", "string", "string", "long" } MessageBox(0, "Hello World!", "My Window Title", 0x00000040)
lua.exe命令行
lua.exe --help // 查看lua.exe的用法
lua.exe -v // 显示出Lua版本号 Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
lua.exe // 进入交互模式 windows系统按Ctrl+C、linux系统按Ctrl+D可退出交互模式
lua.exe - // 从标准设备读入脚本,输完后按回车,然后按Ctrl+Z并回车,会执行输入内容 注:进入输入模式后可按Ctrl+C强制退出
lua.exe e:LuaTest.lua // 加载并执行e:LuaTest.lua
lua.exe -e "print(type(100))" // 通过-e参数执行一段lua代码
注:对于5.3版本的Lua,lua.exe在开始执行前,会读取环境变量LUA_INIT_5_3的值,若其没定义,则会尝试另外一个环境变量LUA_INIT;
若该值不以@开头,会将其作为一段lua代码进行执行;若以@开头,则将其作为lua文件路径载入并执行
lua.exe -e "myPrint=print" e:LuaTest.lua 100 200
e:LuaTest.lua中的内容如下:
myPrint("Hello") -- 打印所有传入的命令行参数 for i, v in pairs(arg) do myPrint(i, v) end
输出结果为:
在运行以前,Lua使用所有参数构造arg表。脚本名e:LuaTest.lua索引为0,脚本的参数从1开始增加,脚本前面的参数从-1开始减少
lua.exe -e "myPrint=print" e:LuaTest2.lua 1 "hello" true
e:LuaTest2.lua中的内容如下:
local a, b, c, d = ... myPrint(a) -- 1 myPrint(b) -- hello myPrint(c) -- true myPrint(d) -- nil
lua.exe -i e:LuaTest3.lua // 执行e:LuaTest3.lua脚本后,进入交互模式
lua.exe -lmisc.Test4 // 搜索misc.Test4模块,找到后加载并执行模块
lua.exe -e "print(package.path);print(package.cpath)" -l misc.Test4 // 打印出lua模块和c模块的搜索路径,按照这些路径来搜索misc.Test4模块,找到后加载并执行模块
E:Lualua?.lua;E:Lualua?init.lua;E:Lua?.lua;E:Lua?init.lua;E:Lua..sharelua5.3?.lua;E:Lua..sharelua5.3?init.lua;.?.lua;.?init.lua // 将?替换为miscTest4来搜索lua模块
E:Lua?.dll;E:Lua..liblua5.3?.dll;E:Lualoadall.dll;.?.dll;E:Lua?53.dll;.?53.dll // 将?替换为miscTest4来搜索c模块
注1:对于5.3版本的Lua,package.path会被设置成环境变量LUA_PATH_5_3的值,若其没定义,则会尝试另外一个环境变量LUA_PATH;若都没定义,则使用编译时定义的默认路径(如上)
注2:对于5.3版本的Lua,package.cpath会被设置成环境变量LUA_CPATH_5_3的值,若其没定义,则会尝试另外一个环境变量LUA_CPATH;若都没定义,则使用编译时定义的默认路径(如上)
注3:在使用环境变量时,可以添加;;来带上默认路径;如:将LUA_PATH定义为c:public;; package.path则会变成c:public和默认路径(如上)的集合
注4:若命令行带上-E参数,则会在阻止使用环境变量,强制使用默认路径(如上)
Lua C#解释器
Lua Interpreter使用C#实现的解释器,它允许使用C#模块,并能在lua代码中调用这些C#模块中的函数
Lua JIT
LuaJIT是(wiki)一款支持JIT的Lua代码解释器,使用C语言编写,已开源(git);当前发布的稳定版本为2.0.5,最新的版本为2.1.0-beta3,只兼容Lua的5.1版本
编译技术大约分为两种,一种AOT,将源代码、中间码等提前静态地编译成本地机器码,目标用户直接用本地机器码的程序来运行
另一种是JIT(Just In Time,即时编译),一个JIT引擎要想快,它会通过搜集runtime信息,识别出程序的热点(2/8原则),会将这部分代码编译成本地机器码并缓存起来,以便下一次直接运行;
而对于只执行一次或少量次数的代码,JIT编译带来的执行速度的提升也未必能抵消掉其编译带来的时间开销,这部分代码JIT引擎会仍然选择解释的方式执行
从官网上下载源码解压后,在Visual Studio 2008 Command Prompt命令行中,切换当前路径到<LuaJIT>src,然后执行msvcbuild.bat
在src目录中,会得到生成出luajit.exe及依赖文件
要编译得到64位的luajit,则需要在Visual Studio 2008 x64 Win64 Command Prompt命令行中编译
如果想调试运行luajit.exe,可按照如下步骤来
① 在msvcbuild.bat脚本搜索/O2,将/O2改为/Od
② 执行msvcbuild.bat debug来生成luajit.exe
③ 用visual studio建立一个命令行工程,如:luajitcmd
④ 把<LuaJIT>src下所有.h和.c代码加入工程
⑤ 把工程的调试路径设置为
命令:$(ProjectDir)....srcluajit.exe
工作目录:$(ProjectDir)....src
⑥ 此时就可以正常按f5下断点调试了
luajit的命令行参数用法与lua.exe/wlua.exe是一致的,只是在其基础上增加了几个命令行参数(详见:这里),可通过luajit.exe --help查看详细用法
luajit.exe -b Hello.lua Hello.luajit // 将Hello.lua代码编译成luajit字节码(缺省是开启O3最高优化)
luajit.exe -O0 Hello.lua // 关闭优化,执行Hello.lua代码
luajit.exe -joff Hello.lua // 关闭jit,仅仅使用解释器执行Hello.lua代码
关于luajit字节码的详细格式详见:【技术分享】Lua程序逆向之Luajit文件格式
更多请阅读:
lua反编译工具
工具名称 | 下载地址 | 说明 |
Unluac | java语言实现,lua反编译器开源项目,可将lua字节码反编译为lua代码 | |
Luadec | c语言实现,结合lua引擎源码写的开源lua反编译器,解析整个lua字节码文件并尽可能的还原为源码 | |
Chunkspy |
lua语言实现,将lua字节码翻译成lua汇编 该工具还包括了一个交互式的命令,可以将输入的lua脚本转换成lua字节码汇编,这对学习lua字节码非常有帮助 Luadec工具中集成了Chunkspy |
|
luajit-decomp | https://github.com/bobsayshilol/luajit-decomp | au3语言实现,先通过luajit原生的exe文件将luajit字节码文件转换成汇编,然后使用该工具将luajit汇编转换成lua代码 |
ljd | https://github.com/NightNord/ljd | python语言实现,一款luajit反编译工具 |
lua性能分析工具
工具名称 | 下载地址 | 说明 |
pLua | https://github.com/esrrhs/pLua | lua函数热点分析 |
lua-snapshot | lua内存泄漏 | |
lua_memleak | https://github.com/radiotail/lua_memleak | lua内存泄漏 |
游戏引擎lua插件
插件名称 | 支持引擎 | 下载地址 | 说明 |
xlua | unity | https://github.com/Tencent/xLua | G6 |
unlua | ue4 | https://github.com/Tencent/UnLua | G6 |
slua | unity | https://github.com/pangweiwei/slua | 潘多拉(Pandora) |
sluaunreal | ue4 | https://github.com/Tencent/sluaunreal | 潘多拉(Pandora) |
ulua | unity | https://github.com/jarjin/uLua | |
tolua | unity | https://github.com/topameng/tolua | |
unreal.lua | ue4 | https://github.com/asqbtcupid/unreal.lua | tianle |
常用库的lua版本
插件名称 | 下载地址 | 说明 |
pb的lua化方案1 protoc-gen-lua |
https://github.com/memoryoff/protoc-gen-lua-bin-fix |
需将proto生成lua代码 protoc-gen-lua很久没维护了 protoc-gen-lua-bin适配了lua53版本,并对其做了一些修正 protoc-gen-lua-bin-fix对protoc-gen-lua-bin做了一点修正 支持int64类型补丁:int64 encoder _VarintSize error! |
pb的lua化方案2 pbc |
不需要将proto生成lua代码 提供c函数来序列化和反序列化pb字节流 |
|
pb的lua化方案3 lua-protobuf |
||
luasocket |
LuaSocket 是 Lua 的网络模块,提供了对 TCP、UDP、DNS、HTTP 等多种网络协议的访问操作, 包括了两部分:①使用 C 编写的针对 TCP 和 UDP 传输层的访问;②用 Lua 编写,负责应用功能的网络接口处理。 |