網上關於 LuaJIT 的討論,已經顯得有些陳舊。如果你對 LuaJIT 編譯 Lua 源文件為具體的 32位或64位位元組碼,極其具體使用感興趣的話,不妨快速讀一下這篇文章。此文章針對嘗試在 iOS 或 Android 上使用 LuaJIT 的小伙伴。限於篇幅,此處假定,你可以成功在 iOS/And... ...
網上關於 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
}