跳到主要内容

11 — 多版本管理(Unity / Lua / 安装)

包内 携带完整 libil2cpp 树;安装时在当前 Unity 自带源码上叠加 patch + zlua-runtime + 选定 Lua。 本文是 UPM 包布局、LocalInstaller、Lua 版本切换、原生 DLL 命名,以及 Il2Cpp ZLuaConf.inc / Compatible 头(§12)的实现规范。 Lua 可见语义仍以本目录其它 spec 为准;本文不改变互操作语义。


1. 目标与非目标

1.1 目标

目标说明
可升级 Unity不随每个 Unity 版本整包携带 libil2cpp
可切换 Lua 源码Settings 指定版本;PUC-Rio 从 lua.org 下载到本地缓存,LuaJIT 手动 clone
Editor DLL 按系列逻辑名 lua5{minor}(如 lua53);二进制由开发者自行替换
改动可审计对上游(Unity libil2cpp、PUC-Rio / LuaJIT)的修改以 patch 文件 形式存在
失败可见patch 上下文不匹配或缺少源码时 Install 失败并报错,禁止静默跳过

1.2 非目标(本阶段)

说明
同 Editor 进程内热切换已加载的原生 DLLWindows 下已加载 DLL 无法可靠覆盖;换系列 DLL 后须 重启 Editor
随包携带每个源码小版本的 Editor DLLEditor 开发对 patch 号无实质要求;需要时可自行替换 luaXX.dll
在只读 Package 内生成并引用 C# 源文件UPM 缓存只读;LUA_DLL 仅按 API 族宏 映射(§8)
一次交付全部历史 Lua / Unity 组合先打通主推组合(见 §10),再按需加 patch / 源码目录

2. 包内目录布局(ZLua~

权威包数据根:Packages/com.code-philosophy.zlua/ZLua~

ZLua~/
├── zlua-runtime/ # ZLua native,安装时复制到 libil2cpp/zlua
│ ├── ZLuaCommon.h # 组装 Compatible + 定义 ZLUA_LUA_VERSION
│ ├── LuaCompatible.h # 多 Lua / LuaJIT API shim(手写)
│ ├── Il2CppCompatible.h # 多 Unity / 团结 il2cpp API shim(手写)
│ └── generated/
│ └── ZLuaConf.inc # Install/Generate 写入(仅宏,见 §12)
├── patches/
│ ├── libil2cpp/
│ │ ├── 2021.3/
│ │ │ └── 2021.3.0.patch # 覆盖 2021.3.x(共用区间最小版本)
│ │ ├── 2022.3/
│ │ │ └── 2022.3.0.patch # 覆盖 2022.3.x;若某小版本断点再增 2022.3.N.patch
│ │ └── 6000/ # Unity 6:先试 6000.{minor}/,再回退本目录
│ │ └── 6000.0.0.patch
│ └── lua/
│ ├── lua-5.1/
│ │ ├── 5.1.0.patch # 覆盖 5.1.0–5.1.1;gettable FastMT + Win32 ANSI loadlib
│ │ └── 5.1.2.patch # 覆盖 5.1.2–5.1.5
│ ├── lua-5.2/ # 5.2.0 / 5.2.1 / 5.2.2 / 5.2.4 floors(见包内 README)
│ ├── lua-5.3/ # 见包内 README;含 5.3.0…5.3.3 floors
│ └── lua-5.4/
│ ├── 5.4.0.patch # 覆盖 5.4.0…直至下一 floor 文件之前
│ ├── 5.4.4.patch # 共用区间只保留最小版本号文件名
│ └── 5.4.7.patch
├── lualib/
└── link.xml

不随包携带 Lua / LuaJIT 上游源码。Install 时写入工程本地缓存:

Library/ZLua/LuaSrcCache/
├── downloads/ # 可选:保存 .tar.gz
├── lua-5.5.0/ # 从 lua.org 下载并解压
├── lua-5.4.8/
├── lua-5.2.4/
├── lua-5.1.5/
└── luajit-2-1/ # 开发者自行 clone(不自动下载)

缓存目录名 LuaSrcCache 可用;若更偏好层级化,等价可采用 Library/ZLua/cache/lua(实现以代码 CommonDirs.LuaSrcCacheDir 为准)。

2.1 目录 / 版本 id 命名

种类规则示例
Settings / PUC-Rio idlua-{major}.{minor}.{patch}lua-5.5.0
PUC-Rio 下载 URLhttps://lua.org/ftp/lua-{ver}.tar.gzhttps://lua.org/ftp/lua-5.5.0.tar.gz
PUC-Rio 缓存目录与 id 相同LuaSrcCache/lua-5.5.0/
Settings / LuaJIT idluajit-{major}.{minor}luajit-2.1
LuaJIT 缓存目录luajit-{major}-{minor}(开发者 clone)LuaSrcCache/luajit-2-1/
Lua patch 目录patches/lua/lua-{major}.{minor}/patches/lua/lua-5.4/
Lua patch 文件{major}.{minor}.{patch}.patch default.patch);共用区间只保留区间最小版本文件名5.4.0.patch / 5.4.4.patch / 5.4.7.patch
Unity patch 目录patches/libil2cpp/{major}.{minor}/,Unity 6 另可回退到 patches/libil2cpp/{major}/2022.3/6000/
Unity patch 文件{major}.{minor}.{patch}.patch default.patch);共用区间只保留区间最小版本文件名2022.3.0.patch / 6000.0.0.patch

Lua / Unity patch 选择(floor,相同规则): 在选定系列目录内取版本号 当前产品版本的 最大 {X.Y.Z}.patch;若存在与当前版本同名(或去字母后缀后同名)的文件,即为该规则的快速命中。apply 失败 → Install 失败(不静默换其它文件)。 生成 / 维护: 若多个小版本可共用同一份 patch 内容,只保留该共用区间的最小版本号文件禁止 default.patch(Lua 与 libil2cpp 皆然)。 Unity 系列目录: 先尝试 {major}.{minor}/(如 2022.3/6000.3/),再对 Unity 6(major >= 6000)回退 {major}/(如 6000/);目录选定后再在该目录内做 floor 选文件。

禁止ZLua~ 下放置完整 libil2cpp-{unity} 树或整棵上游 Lua 源码树作为安装源。

2.2 开发期源码权威

内容开发编辑位置合入包内
zlua C++build-win64/.../libil2cpp/zlua同步到 ZLua~/zlua-runtime
Lua 上游Install 下载到 Library/ZLua/LuaSrcCache(不进包)patches/lua
对 Unity libil2cpp 的改动patches/libil2cpp 提交整棵 libil2cpp

3. 安装流水线(LocalInstaller

安装输出根:Library/ZLua/LocalIl2CppData-{platform}/(路径以 CommonDirs 为准)。

3.1 顺序(必须)

  1. 解析 Settings luaVersionId(空则默认 lua-5.5.0,见 §6.2)
  2. 确保 Lua 源码在 Library/ZLua/LuaSrcCache:已缓存则复用;PUC-Rio 缺失则从 lua.org 下载;LuaJIT 缺失则失败并提示手动 clone
  3. 从当前 Editor 复制官方 il2cpp(含 stock libil2cpp)到 Local 目录
  4. 解析并应用 libil2cpp patches(§4)
  5. ZLua~/zlua-runtime 复制/覆盖Local.../libil2cpp/zlua
  6. 将缓存中的选定 Lua 安装到 Local.../libil2cpp/luaPUC-Rio 拷贝(并按 §5 patch)可编译 src/LuaJIT 仅安装公共头文件(见 build/02-LUAJIT.md);并保证 ZLUA_FAST_METATABLE 符合 §5.4 / §12.5
  7. 写入工程 Scripting Define Symbols(§7)
  8. 写入 ZLuaConf.inc(§12;权威输出在 Local libil2cpp/zlua/generated/
  9. 若包内缺少对应系列 Editor 插件 DLL,警告(不阻断 Install);DLL 由开发者自行替换(§8)
  10. 写入 install fingerprint(§9)
  11. 清理 Il2Cpp / Bee 缓存;系列 / Define 变更时提示 重启 Editor

3.2 与旧行为的差异

用包内完整 libil2cpp-* 整目录替换stock + patch + zlua-runtime
包内携带 Lua 源码不携带LuaSrcCache + 网络下载 / 手动 clone
包内嵌完整 Unity 树zlua-runtime + patches

4. libil2cpp patch 选择

对 Unity stock libil2cpp 的修改应尽量少(量级:数十行 hook),一律以 patch 文件维护。

4.1 选择算法

设当前 Unity 为 2022.3.62f1(比较时忽略 f1 / t11 等字母后缀,按 2022.3.62 三元组):

  1. 按序尝试系列目录:{major}.{minor}/,若 major >= 6000 再回退 {major}/(例:6000.3/6000/
  2. 第一个存在的系列目录内:
    • 若存在精确文件(完整版本字符串 / 去后缀 2022.3.62 等)→ 选用(floor 快速路径)
    • 否则在目录内所有 {major}.{minor}.{patch}.patch 中,取版本号 2022.3.62最大 者(例:仅有 2022.3.0.patch → 选用它)
  3. 所有候选目录均无可用 patch → Install 失败
  4. 再使用 default.patch

选定文件后 apply 失败 → Install 失败(不得再静默换另一个文件)。

维护约定(与 Lua §5.3 相同): 能共用同一内容的连续 Editor 小版本,只提交区间 最小 版本号文件;上游上下文变化导致旧 floor 无法 apply 时,再新增该断点版本的 patch。

4.1.1 已维护系列与差异要点

目录基线 Editor(制作参考)适用范围包内 floor 文件
2021.3/2021.3.45f22021.3.x2021.3.0.patch(无 AnUnresolvedCallStubWasNotFound*;提供 no-op return false
2022.3/2022.3.62f32022.3.x2022.3.0.patch(真实 unresolved stub 检测 + LuaAppDomain::Initialize
6000/6000.0.71f16000.0.x / 6000.3.x / 6000.5.x(及同系列回退)6000.0.0.patch(floor 命中;若有 6000.{minor}/ 精确目录则优先)

4.2 应用与校验

  • 推荐 unified diff;Install 前可 --check / 干跑
  • 应用后应做最小校验(例如约定 hook 符号或锚点文件内容出现)
  • 上下文漂移(Unity 小版本改动周围代码)→ 失败,需新增该断点版本的 floor patch({major}.{minor}.{patch}.patch)或更新既有共用文件

4.3 与 zlua-runtime 的边界

归属内容
patches/libil2cpp对 Unity 原有 .cpp/.h 的插入/小改(初始化、编译列表等)
zlua-runtimeZLua 自有源码树; 通过改 Unity 文件「塞进」大段实现

zlua-runtime 若依赖随 Unity / Lua 变化的内部 API,在 runtime 内用 §12 Compatible + conf 条件编译解决,不要 因此重新携带整棵 libil2cpp。


5. Lua 源码与 patch

5.1 获取源码(不进 UPM 包)

引擎行为
PUC-RioLuaSrcCache/{id} 已含完整 src/ 则复用;否则下载 https://www.lua.org/ftp/{id}.tar.gz 并解压到该目录
LuaJIT自动下载;开发者将源码 clone 到 LuaSrcCache/(目录名以实现为准,如 luajit-2.1)。Il2Cpp 整树拷贝进 libil2cpp/lua,见 build/02-LUAJIT.md

支持 VM patch 的系列(见 §5.2),ZLua 对 VM 的修改以包内 patches/lua 表达;Install 时对缓存中的干净树 apply。

5.2 是否应用 Lua VM patch

Settings / 引擎Install 是否 apply patches/lua写入 libil2cpp/lualuaPatchKey(fingerprint)
PUC-Rio 5.1.x(§5.3 floor;目录 patches/lua/lua-5.1/完整可编译 src/(去入口文件)实际选用的 {X.Y.Z}.patch 文件名
PUC-Rio 5.2.x(§5.3 floor;目录 patches/lua/lua-5.2/完整可编译 src/(去入口文件)实际选用的 {X.Y.Z}.patch 文件名
PUC-Rio 5.3+(含 lua-5.3.0 …)(§5.3 floor)完整可编译 src/(去入口文件)实际选用的 {X.Y.Z}.patch 文件名
LuaJIT仅公共头文件;静态库由开发者放 Plugins(build 文档none

说明:

  • PUC-Rio 5.1+(含 5.2.x)必须 apply 对应系列目录下的 floor patch;缺文件或 apply 失败 → Install 失败。
  • LuaJIT 不得 尝试查找或 apply 系列 patch。
  • 无 FastMT / 无 VM patch 的组合下,Install 必须 保证 ZLUA_FAST_METATABLE 0(PUC 写入本地 luaconf.h;LuaJIT 写入已安装头文件中的 luaconf.h,见 §5.4)。
  • fingerprint 的 luaPatchKey 在无 patch 时为 none(§9)。
  • LuaJIT 为何不能整树源码编译、Il2Cpp 平台面(Android/iOS .a、WebGL 禁用)以 build/02-LUAJIT.md 为准。

5.3 patch 选择算法(仅 §5.2「需要 patch」的系列)

设 Settings 为 lua-5.4.8,系列目录为 patches/lua/lua-5.4/

  1. 确保缓存源码可用(§5.1)
  2. 在系列目录列出所有 {major}.{minor}.{patch}.patch(忽略其它文件名,含历史 default.patch 若误留则不得选用)
  3. 选择版本号 5.4.8 的文件中 最大 者(例:有 5.4.0 / 5.4.4 / 5.4.7 → 选用 5.4.7.patch;若存在 5.4.8.patch 则直接命中)
  4. 无满足条件的文件,或 apply 失败 → Install 失败(不自动降级到其它系列,也不回退到「更大」版本的 patch)
  5. 将 patch 后的 src/ 拷入 Local.../libil2cpp/lua
  6. 再按 §5.4 校验 / 强制 ZLUA_FAST_METATABLE

维护约定: 能共用同一内容的连续小版本,只提交区间 最小 版本号的那一个文件;上游上下文变化导致旧 floor 无法 apply 时,再新增该断点版本的 patch(仍以最小号命名该新区间)。

不要把 IDE 辅助文件(如 .clangd)打进 patch。

5.4 ZLUA_FAST_METATABLE(FastMT)支持矩阵

ZLUA_FAST_METATABLE 由 Install 后的 libil2cpp/lua/luaconf.h 决定(§12.1);Il2Cpp runtime 与 Lua VM 必须 同宏值编译。

引擎 / 小版本FastMTInstall / patch 要求
PUC-Rio 5.1.0–5.1.5可启用(floor:5.1.0 / 5.1.2;挂 luaV_gettable / luaV_settable先 raw get必须应用 patches/lua/lua-5.1/ floor patch(含 zlua_fastmt.*、Table 缓存字段、Win32 ANSI loadlib
PUC-Rio 5.2.0–5.2.4可启用(floor:5.2.0 / 5.2.1 / 5.2.2 / 5.2.4;同上 gettable 挂点 + raw-first)必须应用 patches/lua/lua-5.2/ floor patch(另含 Il2Cpp lump 下 luai_num* / luai_hashnum 放开)
PUC-Rio 5.3.0 / 5.3.1可启用(floor patch 设为 1;挂 luaV_gettable / luaV_settable先 raw get应用系列 VM patch
PUC-Rio ≥ 5.3.2(含 5.3.3…5.3.6、5.4.x、5.5.x)可启用(默认由对应 floor patch 设为 1,挂 luaV_finishget / finishset应用系列 VM patch
LuaJIT不支持(必须为 0 apply VM patch;Install 仅装头文件并注入 ZLUA_FAST_METATABLE 0ZLuaCommon.h 可对 ZLUA_USE_LUAJIT && ZLUA_FAST_METATABLE#error

原因摘要:

  • ≥ 5.3.2:FastMT 挂点是 luaV_finishget / finishset
  • 5.1.x / 5.2.x / 5.3.0 / 5.3.1:无 finishget / finishset;FastMT 挂 luaV_gettable / luaV_settable。实现上 必须先 luaH_get(raw),仅在 miss 后走 sealed FastMT(否则类型表字段如 FullName 会被拦截)。
  • LuaJIT:无 PUC-Rio FastMT 系列 patch;一律 legacy / Dispatch,宏固定为 0

手动 -DZLUA_FAST_METATABLE=1 覆盖不受支持组合 → 未定义行为;Installer 应对不支持组合写回 0

5.5 Editor DLL 与 Player 的关系

路径PUC-RioLuaJIT
Il2Cpp Player缓存中的精确小版本 源码libil2cpp/lua;§5.2 需要时再加 patches/lua仅头文件libil2cpp/luaAndroid/iOS 静态 .a 由开发者放入 Plugins(见 build/02-LUAJIT.md
Editor(Mono)Plugins/lua/<series>/(如 lua53/{lua53.dll,lua53.dylib});Mono 实现 FastMTPlugins/lua/luajit20/luajit21/;另需 zlua_mono_gate(同目录);Mono 实现 FastMT

Editor 与 Player 所用补丁号 / 构建选项不必逐位相同,但 API 族与关键宏 应一致。缺 Editor 原生库时 Install 仅警告,不阻断。切换系列后须重启 Editor。

本包 Editor 随附(维护现状):

系列WindowsmacOS
lua51lua55.dll.dylib(universal 优先)
luajit21.dll.dylib
luajit20.dll.dylib仅 x86_64;上游 2.0 无 arm64)
zlua_mono_gatePlugins/lua/zlua_mono_gate.dllPlugins/lua/libzlua_mono_gate.dylib(universal)

EmmyLua 调试库随附见 build/04-EMMYLUA-DEBUGGER.mdemmylua/luajit/ 不区分 2.0/2.1)。

LuaJIT + Il2Cpp: 发布面 仅 Android / iOS(开发者提供静态 .a);不支持 Win / macOS / Linux / WebGL 等 Il2Cpp Player。细则见 build/02-LUAJIT.md


6. Settings:选定 Lua 版本

字段含义
luaVersionIdlua-5.4.8 / luajit-2.1;空见 §6.2

6.1 变更后义务

切换后须重新 Install;Define / 系列 DLL 变更后提示重启 Editor。未 Install 或 fingerprint 不匹配时,Il2Cpp 打包应阻断。

6.2 默认版本

  • 字段默认值 / 空值:固定为 lua-5.5.0
  • Install 时若为空则写回该默认值
  • 下载失败(例如官方 FTP 无此版本)→ Install 失败并提示检查版本号;不得静默改用其它大版本

7. 编译符号(Scripting Define Symbols)

由 Installer(或 Settings 保存并触发的同一逻辑)写入 工程 Define, 在只读 Package 内生成 C# 文件。

7.1 宏命名(须带 ZLUA_ 前缀)

何时定义用途
ZLUA_USE_LUAJIT选定 LuaJIT引擎差异;与 ZLUA_LUAJIT_2_0 / ZLUA_LUAJIT_2_1 搭配选 luajit20 / luajit21
ZLUA_LUAJIT_2_1luajit-2.1Editor 逻辑名 luajit21
ZLUA_LUAJIT_2_0luajit-2.0Editor 逻辑名 luajit20
ZLUA_LUA_5_5PUC-Rio 5.5.x(任意小版本)API 族 + Editor DLL 逻辑名 lua55
ZLUA_LUA_5_4PUC-Rio 5.4.x(任意小版本)API 族 + Editor DLL 逻辑名 lua54
ZLUA_LUA_5_3PUC-Rio 5.3.x(任意小版本)API 族 + Editor DLL 逻辑名 lua53
ZLUA_LUA_5_2PUC-Rio 5.2.x(任意小版本)API 族 + Editor DLL 逻辑名 lua52
ZLUA_LUA_5_1PUC-Rio 5.1.x(非 JIT)API 族 + Editor DLL 逻辑名 lua51

说明:

  • 不需要 ZLUA_LUA_5_4_7 这类精确小版本宏:源码小版本只影响 Install 拷贝的树与 fingerprint,不进入 LUA_DLL 映射。
  • API 族宏对应原讨论中的「LUA_FEAT_5_4_X」语义,命名用 ZLUA_LUA_5_4不要 使用易误解的 _X 后缀。
  • LuaJIT:定义 ZLUA_USE_LUAJIT,并按小版本定义 ZLUA_LUAJIT_2_0ZLUA_LUAJIT_2_1(与 LuaDllName / Plugins 目录一致)。

7.2 互斥

同一时刻仅允许一套「引擎 + API 族 / JIT 小版本」组合。Installer 在写入前移除旧的 ZLUA_LUA_* / ZLUA_USE_LUAJIT / ZLUA_LUAJIT_2_*,再按当前 luaVersionId 写入新集。


8. 原生 DLL 命名与 LuaDllName(按系列)

8.1 随包策略

规则
布局Plugins/lua/<series>/(PUC / LuaJIT)+ 同目录下的 zlua_mono_gate*(见 03
携带粒度可选随包带某系列库;开发者可按所用系列自行替换
逻辑名(PUC)lua + major + minorlua51lua55(无 patch 位)
逻辑名(LuaJIT)luajit20 / luajit21(与 Settings luajit-2.0 / luajit-2.1 对应;不是 笼统 luajit
Install缺失时 警告,不失败
Settings 源码 id(示例)API 族 / JIT 宏Editor 逻辑名WindowsmacOS
lua-5.1.5ZLUA_LUA_5_1lua51lua51.dlllua51.dylib
lua-5.2.4ZLUA_LUA_5_2lua52lua52.dlllua52.dylib
lua-5.3.6 / lua-5.3.0ZLUA_LUA_5_3lua53lua53.dlllua53.dylib
lua-5.4.7 / lua-5.4.1ZLUA_LUA_5_4lua54lua54.dlllua54.dylib
lua-5.5.0ZLUA_LUA_5_5lua55lua55.dlllua55.dylib
luajit-2.0ZLUA_USE_LUAJIT + ZLUA_LUAJIT_2_0luajit20luajit20.dllluajit20.dylib仅 x86_64
luajit-2.1ZLUA_USE_LUAJIT + ZLUA_LUAJIT_2_1luajit21luajit21.dllluajit21.dylib

同一系列下切换源码小版本(如 5.4.15.4.7不改变 LUA_DLL 与 Plugins 文件名,只改变 Il2Cpp 内嵌源码树。 用户若要在 Editor 使用其它构建,自行替换 Plugins/lua/<series>/ 下对应文件即可(注意 Windows 已加载锁定,须重启 Editor)。

EmmyLua 调试模块目录名 emmylua/luajit/ 与上表 Editor 逻辑名不同:2.0/2.1 共用 一份 emmy_core(见 04)。

8.2 LuaDllName.cs

单独文件(建议路径):

Packages/com.code-philosophy.zlua/Runtime/Mono/Lvm/LuaDllName.cs

职责:仅按 API 族 / JIT 定义 LUA_DLLLuaDll.cs 只引用该常量。

namespace ZLua
{
public static class LuaDllName
{
#if UNITY_IPHONE && !UNITY_EDITOR
public const string LUA_DLL = "__Internal";
#elif ZLUA_LUAJIT_2_1
public const string LUA_DLL = "luajit21";
#elif ZLUA_LUAJIT_2_0
public const string LUA_DLL = "luajit20";
#elif ZLUA_USE_LUAJIT
public const string LUA_DLL = "luajit21";
#elif ZLUA_LUA_5_5
public const string LUA_DLL = "lua55";
#elif ZLUA_LUA_5_4
public const string LUA_DLL = "lua54";
#elif ZLUA_LUA_5_3
public const string LUA_DLL = "lua53";
#elif ZLUA_LUA_5_2
public const string LUA_DLL = "lua52";
#elif ZLUA_LUA_5_1
public const string LUA_DLL = "lua51";
#else
// Default matches Settings default lua-5.5.0 → series lua55.
public const string LUA_DLL = "lua55";
#endif
}
}

新增 系列 时:增加系列 DLL、LuaDllName 分支、API 族宏与 Installer 映射。 新增同系列 源码小版本 时:只需增加 lua-versions(及必要 patch),不必LuaDllName 或新增 Plugins 文件名。

8.3 LuaDll.cs 的 API 裁剪

API 族 / JIT 宏启用或禁用声明(可分文件)。源码小版本差异不进入 #if

8.4 Windows 加载锁定

  • 换系列(lua53lua54)或替换正在使用的同名 DLL 后,须 重启 Editor
  • Install 在系列或 Define 变更时须提示重启。

9. Fingerprint 与重新安装

Fingerprint(建议 JSON 或等价键值)至少包含:

字段说明
unityVersion安装时的 Application.unityVersion
luaVersionId实际使用的源码 id(含 §6.2 默认解析结果)
luaSerieslua-5.3 / lua-5.4 / luajit(便于对照 DLL)
libil2cppPatchKey实际选用的 patch 目录键(精确或大版本)
luaPatchKey实际选用的 lua patch 目录键,或 none
packageContentStamp包内容变更戳(可为现有 max mtime 策略的演进)
defines写入的 ZLUA_* 集合(便于诊断)

以下任一变化 → NeedReinstall 为真:

  • 包内容戳变化
  • Settings luaVersionId(或默认解析结果)与 fingerprint 不一致
  • 当前 Unity 版本与 fingerprint 不一致
  • Local 树缺失

10. 分阶段支持范围

阶段范围
P0默认 lua-5.5.0 + 下载缓存 + lua-5.3 patch + Unity 2022.3 patch + zlua-runtime
P1lua-5.1.x / lua-5.2.x(全小版本 FastMT + 系列 patch)+ lua-5.4.x / lua-5.5.x 与对应系列 patch / DLL
P2LuaJIT(手动 clone;Editor ✅;Il2Cpp 仅 Android / iOS

11. 实现检查清单

  • ZLua~ 无完整 libil2cpp、无随包 Lua 上游源码
  • PUC-Rio:缓存未命中则从 lua.org/ftp 下载
  • LuaJIT:仅接受 LuaSrcCache/luajit-{major}-{minor} 手动源码
  • 默认 luaVersionId = lua-5.5.0
  • Plugins DLL 缺失仅警告
  • libil2cpp patch:floor(≤ 当前的最大 {X.Y.Z}.patch),无 default.patch;失败不降级
  • lua patch:PUC-Rio 5.1+(含 5.2.x)apply(§5.2);仅 LuaJIT 跳过且 luaPatchKey=none
  • FastMT:全部 PUC-Rio 5.x 可启用;仅 LuaJIT 强制 ZLUA_FAST_METATABLE 0(§5.4)
  • Define / LuaDllName / fingerprint / 重启提示齐全
  • LuaCompatible.h / Il2CppCompatible.h / ZLuaConf.inc 符合 §12
  • Install 写 Local ZLuaConf.inc;Generate/All 校验或复写,禁止过期静默使用

12. Il2Cpp 运行时兼容层(ZLuaConf / Compatible)

本节只约束 Il2Cpp Player 原生树(zlua-runtime)。 Editor Mono 继续使用 §7 Scripting Define + §8 LuaDllName 消费 ZLuaConf.inc

12.1 设计目标

用三套互不覆盖的真相源表达版本事实:

真相源表达内容
生成的 ZLuaConf.inc引擎族(是否 JIT)、Lua API 族、Unity / 团结版本、对账字符串
Lua 头文件LUA_VERSION_NUM 等)官方 Lua 数值版本;经 ZLuaCommon.h 映射为 ZLUA_LUA_VERSION
luaconf.h(Install + §5.4 后)唯一 决定 ZLUA_FAST_METATABLE(conf / Compatible 不得 再定义);不支持 FastMT 的组合必须为 0

12.2 文件职责

文件性质职责
zlua-runtime/generated/ZLuaConf.inc生成仅宏;无 #include、无逻辑、勿手改
zlua-runtime/LuaCompatible.h手写先可用 conf → 再选 Lua 头(官方 lua.hpp / JIT extern "C")→ API shim(如 AbsIndex、IsInteger、NewUserData、PCall)
zlua-runtime/Il2CppCompatible.h手写团结 vs Unity 的 il2cpp API 差(如 Calloc);依赖 conf 中引擎宏
zlua-runtime/ZLuaCommon.h手写组装上述头;#define ZLUA_LUA_VERSION LUA_VERSION_NUM;断言 / 架构宏;不再 堆散落兼容细节
libil2cpp/lua/luaconf.h上游 ± patch ± Install 强制定义 ZLUA_FAST_METATABLE(§5.4)

ZLuaCommon.h include 顺序(约定):

  1. generated/ZLuaConf.inc
  2. LuaCompatible.h(内部再 include Lua 头并提供 shim)
  3. Il2CppCompatible.h(il2cpp 头 + 引擎 shim)
  4. 然后:
#ifndef ZLUA_LUA_VERSION
#define ZLUA_LUA_VERSION LUA_VERSION_NUM
#endif

/* ZLUA_FAST_METATABLE 必须已由 luaconf.h 定义 */
#ifndef ZLUA_FAST_METATABLE
#error "ZLUA_FAST_METATABLE must be defined by lua/luaconf.h"
#endif

12.3 ZLuaConf.inc 生成宏

取值说明
ZLUA_USE_LUAJIT0 | 1与 C# Scripting Define ZLUA_USE_LUAJIT 对齐;不要 使用旧名 ZLUA_LUAJIT
ZLUA_LUA_API_FAMILY501 / 502 / 503 / 504 / 505API 族:官方取自选定系列(5.1→501,5.2→502,5.3→503…);LuaJIT 约定 501(能力判断仍优先看 ZLUA_USE_LUAJIT
ZLUA_TUANJIE_ENGINE0 | 11 = 团结引擎,0 = Unity
ZLUA_UNITY_VERSION十进制整数见 §12.4;Unity 与团结上均填写「Unity 版本线」编码
ZLUA_TUANJIE_VERSION0 或十进制Unity 上固定 0;团结上为团结引擎版本编码(与 Unity 版本不同)
ZLUA_CONF_ID字符串字面量日志 / 对账,例:`"lua-5.3.8

明确不生成:

原因
ZLUA_LUA_VERSIONZLuaCommon.h 中映射自 LUA_VERSION_NUM,不写进 conf
ZLUA_FAST_METATABLE仅由 luaconf.h 决定,保持 Table ABI 与 VM 一致

12.4 数值编码规则

禁止前导 0(C 预处理器会按八进制解析,且含 8/9 时非法)。

编码示例
ZLUA_UNITY_VERSIONYYYY * 10000 + minor * 100 + patch(minor/patch 各两位,通常 < 100)2021.3.4520210345
ZLUA_TUANJIE_VERSIONmajor * 10000 + minor * 100 + patch(同上;Unity 上为 01.9.310903
ZLUA_LUA_API_FAMILYmajor * 100 + minor(无 patch)5.4504;JIT → 501

比较示例:#if ZLUA_UNITY_VERSION >= 20220300

精确小版本字符串对账用 ZLUA_CONF_ID 与 Install fingerprint(§9),不要 用数值宏冒充 patch 级身份。

12.5 能力判断优先级

场景写法
是否 LuaJIT#if ZLUA_USE_LUAJIT
官方 API 族(5.3 vs 5.4…)#if !ZLUA_USE_LUAJIT && (LUA_VERSION_NUM >= 504),或 ZLUA_LUA_API_FAMILY >= 504
精确 id 对账ZLUA_CONF_ID / fingerprint
团结 vs Unity API#if ZLUA_TUANJIE_ENGINE,必要时叠加 ZLUA_UNITY_VERSION / ZLUA_TUANJIE_VERSION
FastMT#if ZLUA_FAST_METATABLE(仅 luaconf.h);支持面见 §5.4(全部 PUC-Rio 5.x 可开;仅 LuaJIT 必须为 0

不支持 FastMT 的组合:Install 必须 使 luaconf.hZLUA_FAST_METATABLE0ZLuaCommon.h 可对 ZLUA_USE_LUAJIT && ZLUA_FAST_METATABLE#error 防护。

12.6 生成时机与权威路径

步骤职责
LocalInstaller(权威)每次 Install 成功后必须 写入 Local libil2cpp/zlua/generated/ZLuaConf.inc;内容来自 Settings luaVersionIdApplication.unityVersion、团结检测
ZLua/Generate/All(校验)复写或校验同一语义;与 Settings / fingerprint 不一致则 失败或强制刷新,禁止静默使用过期 conf
Player 编译只认 Local 树中的 conf;包内 ZLua~/zlua-runtime/generated 与现有 stub 策略一致,不是 唯一真相源(UPM 只读时可能无法写入)

Editor 侧须集中版本编码(建议 EngineVersionUtil,与 LuaVersionUtil 并列):团结判定、ZLUA_UNITY_VERSION / ZLUA_TUANJIE_VERSION / ZLUA_CONF_ID 生成,避免散落解析。

12.7 示例

官方 Lua 5.3.8 + Unity 2021.3.45:

/* Generated by ZLua Install/Generate. Do not edit. */
#define ZLUA_USE_LUAJIT 0
#define ZLUA_LUA_API_FAMILY 503
#define ZLUA_TUANJIE_ENGINE 0
#define ZLUA_UNITY_VERSION 20210345
#define ZLUA_TUANJIE_VERSION 0
#define ZLUA_CONF_ID "lua-5.3.8|unity-2021.3.45|tuanjie-0"

LuaJIT 2.1 + 团结(示意):

/* Generated by ZLua Install/Generate. Do not edit. */
#define ZLUA_USE_LUAJIT 1
#define ZLUA_LUA_API_FAMILY 501
#define ZLUA_TUANJIE_ENGINE 1
#define ZLUA_UNITY_VERSION 20220362
#define ZLUA_TUANJIE_VERSION 10903
#define ZLUA_CONF_ID "luajit-2.1|unity-2022.3.62|tuanjie-1.9.3"

12.8 与 Mono / C# Define 对照

Il2Cpp(conf / 头)Editor Mono
ZLUA_USE_LUAJIT(0/1)#define ZLUA_USE_LUAJIT(有则启用)
ZLUA_LUA_API_FAMILYZLUA_LUA_5_1 / ZLUA_LUA_5_3 / …(互斥一套)
ZLUA_UNITY_* / ZLUA_TUANJIE_*无对等 conf;Mono 不依赖
ZLUA_LUA_VERSIONLUA_VERSION_NUM无;P/Invoke 按 §8.3 API 族裁剪
ZLUA_FAST_METATABLE(luaconf)不适用(无嵌入 Lua VM 源码)

13. 文档地图更新说明

本文件纳入 spec/** 后:

  • 包布局、Install、多版本与 Il2Cpp conf/Compatible本文 为准
  • 00-OVERVIEW 中「包内 libil2cpp-2022 整树」等过时表述应随实现同步修订
  • impl/IL2CPP.md 等实现笔记不得覆盖本文;冲突时先修订本文或征求确认