【最新】LuaJIT 32/64 位位元組碼,從編譯到使用全紀錄
網上關於 LuaJIT 的討論,已經顯得有些陳舊。如果你對 LuaJIT 編譯 Lua 原始檔為具體的 32位或64位位元組碼,極其具體使用感興趣的話,不妨快速讀一下這篇文章。此文章針對嘗試在 iOS 或 Android 上使用 LuaJIT 的小夥伴。限於篇幅,此處假定,你可以成功在 iOS/Android App 中集成了 LuaJIT,並且已經可以執行原始碼形式的 Lua 檔案。
我忍不住在開頭插一句: LuaJIT 編譯後,只有約 600k,可能也就是一張圖片的空間,但卻可以讓你的你App可以擁有一門完整的指令碼語言的能力 – 真的很酷!為許多問題,提供了許多新的思路,特別是 App 地動態性和可配置型方面。
環境
作業系統: macOS 10.13.4 【Linux 系統上,應該使用;Windows 系統上,僅供參考】
LuaJIT 版本: LuaJIT-2.1.0-beta3【官網最新版】
目錄結構預定義
為了便於下文指令的說明,此處簡單約定下目錄結構。實際使用時,按需設定和整理即可。
- tools:存放各種編譯指令碼和工具。
- source:存放編譯前的 Lua 原始碼。以後所有的 Lua 原始碼,都需要放在且只能放在此資料夾下。
- output: 用於存放編譯後的 Lua 位元組碼檔案。
編譯加密工具
Lua 的加密工具,本質上就是 Lua 的直譯器。此處使用的直譯器原始碼是 LuaJIT。LuaJIT 執行效率最高,且編譯出來的位元組碼無法逆向為 Lua 原始碼,更能保證原始碼安全性。LuaJIT 支援交叉編譯,即可以在電腦上編譯出 iOS 或 Android 手機上系統需要的位元組碼。如此,我們只需要編譯一次 32 和 64 位的 LuaJIT 直譯器各一個,備份存檔,後續可直接使用。
編譯 LuaJIT 直譯器,直接用官方的推薦指令即可。比較特殊的一點時,如果是想編譯出 64 位 LuaJIT,需要加上引數 CFLAGS=-DLUAJIT_ENABLE_GC6
。
# cd 到 LuaJIT 原始碼目錄
cd tools/LuaJIT-2.1.0-beta3
# 編譯 32 位 LuaJIT 直譯器
make clean && make && cp src/luajit ../luajit-32 && make clean
# 編譯 64 位 LuaJIT 直譯器
make clean && make CFLAGS=-DLUAJIT_ENABLE_GC64 && cp src/luajit ../luajit-64 && make clean
注意:重新解壓原始碼後,可能需要重新啟動命令列/終端,來清除可能的系統快取,才能正確 build 出想要的東西。
加密 Lua 原始檔
所謂的加密 Lua 原始檔,其實就是把 Lua 原始檔,編譯為 LuaJIT 位元組碼。相對於 Luac ,LuaJIT 位元組碼執行效率更高,而且無法被直接逆向為對應的 Lua 原始碼。
編譯位元組碼,用的是 -b 命令,需要注意的是,一定要使用對應位元組的 LuaJIT 直譯器來編譯,否則 iOS/Android App 中,可能無法載入。
編譯後的位元組碼檔案的字尾,可以根據自己需要自定義。此處我使用的是 “.yan” 和 “.yan64”。
# 編譯32位位元組碼 ,適用於Android全部手機,部分 iOS 手機。
./tools/luajit-32 -b ./source/main.lua ./output/main.yan
# 編譯64位位元組碼,僅用於部分 iOS 手機。
./tools/luajit-64 -b ./source/main.lua ./output/main.yan64
注意: 敏感資訊,不要直接以常量字串的形式使用。
在 iOS 中,根據不同的 CPU, 載入不同的位元組碼。
在 Android 手機上,一般只需要使用 32 位的 LuaJIT 位元組碼檔案即可。iOS 上,情況比較複雜,從 iOS11 之後,iOS 要求相對的庫必須有64位版本。也就意味著,如果 App 想相容 iPhone5s 以前的 32位CPU的裝置的話,就必須在專案中同時放置32位和64位的LuaJIT靜態庫。關於適用於手機端的 LuaJIT 靜態庫的編譯問題,暫不進一步展開。此處只討論,如何在 iOS 中,動態根據需要準確載入對應的 32 或 64 位的 LuaJIT 位元組碼檔案。
基於上文的討論,此處給出一個簡單的策略:
- Lua 原始檔,同時編譯生成32位和64位位元組碼的檔案。
- 編譯後的位元組碼檔案,僅檔案字尾不同,檔案路徑的其他部分保證是完全一致的。如 main.yan 和 main.yan64 是由 main.lua編譯得到。
- 在 iOS App 執行時,動態根據當前真正執行的是 32 還是 64 位的 LuaJIT 直譯器,來選擇對應的位元組碼檔案字尾即可。
分享一個 swift 版的實現:
private func luaFileSuffix() -> String{
#if (arch(i386) || arch(arm))
return ".yan"
#else
return ".yan64"
#endif
}