正如 歡迎頁面 中明確指出,Lua 實作的目標之一是低嵌入成本。這表示兩件事:首先,將 Lua 嵌入應用程式中應該很簡單;其次,Lua 的額外程式碼不應太大。
第一個需求透過 Lua 的 C API 簡單性來達成。第二個需求透過以下示範來達成。
以下是執行 Linux 的 Intel 電腦中編譯的 Lua 3.2 的一些數字(其他平台的數字會不同,但相對來說可能大致相同)
% size liblua.a liblualib.a text data bss dec hex filename 4483 121 0 4604 11fc lapi.o (ex liblua.a) 1037 0 0 1037 40d lauxlib.o (ex liblua.a) 345 0 0 345 159 lbuffer.o (ex liblua.a) 5193 272 0 5465 1559 lbuiltin.o (ex liblua.a) 3183 0 0 3183 c6f ldo.o (ex liblua.a) 381 0 0 381 17d lfunc.o (ex liblua.a) 1363 0 0 1363 553 lgc.o (ex liblua.a) 5429 108 0 5537 15a1 llex.o (ex liblua.a) 222 0 0 222 de lmem.o (ex liblua.a) 686 156 0 842 34a lobject.o (ex liblua.a) 8560 244 0 8804 2264 lparser.o (ex liblua.a) 446 4 0 450 1c2 lstate.o (ex liblua.a) 1845 36 0 1881 759 lstring.o (ex liblua.a) 1109 0 0 1109 455 ltable.o (ex liblua.a) 1293 202 0 1495 5d7 ltm.o (ex liblua.a) 2035 0 0 2035 7f3 lundump.o (ex liblua.a) 4864 8 0 4872 1308 lvm.o (ex liblua.a) 336 0 0 336 150 lzio.o (ex liblua.a) 25 0 0 25 19 linit.o (ex liblualib.a) 1489 56 0 1545 609 ldblib.o (ex liblualib.a) 4236 264 0 4500 1194 liolib.o (ex liblualib.a) 1651 184 0 1835 72b lmathlib.o (ex liblualib.a) 5277 88 0 5365 14f5 lstrlib.o (ex liblualib.a)在此清單中,
text
實際上是以位元組為單位的程式碼大小。我們得出結論,Lua 核心(liblua.a
)需要 42810 位元組,而 Lua 標準函式庫(liblualib.a
)需要 12678 位元組。因此,整個 Lua 程式碼需要 55488 位元組,或小於 54K。換句話說,Lua 在應用程式中的影響是 54K 的額外程式碼,這非常小。(當然,Lua 在執行階段會使用記憶體,但用量取決於應用程式。)
54K 在現今電腦擁有許多 MB 主記憶體的時代似乎非常少,但對於嘗試在微波爐或機器人中使用 Lua 的人來說,這可能有所不同。因此,讓我們看看如何將這 54K 減少到更少。(即使您沒有在嵌入式系統中使用 Lua,您也可能從以下說明中學到一些東西。)
第一件事是移除任何不需要的標準函式庫。例如,大多數應用程式可能不需要 ldblib.o
。但移除標準函式庫並不會讓您走得太遠,因為它們已經很小了。因此,讓我們再次查看核心的數字,但現在按大小排序
text %core %whole filename 222 1% 0% lmem.o 336 1% 1% lzio.o 345 1% 1% lbuffer.o 381 1% 1% lfunc.o 446 1% 1% lstate.o 686 2% 1% lobject.o 1037 2% 2% lauxlib.o 1109 3% 2% ltable.o 1293 3% 2% ltm.o 1363 3% 2% lgc.o 1845 4% 3% lstring.o 2035 5% 4% lundump.o 3183 7% 6% ldo.o 4483 10% 8% lapi.o 4864 11% 9% lvm.o 5193 12% 9% lbuiltin.o 5429 13% 10% llex.o 8560 20% 15% lparser.o此清單告訴我們,詞法分析器(
llex.o
)和剖析器(lparser.o
)佔核心的 33%(佔整體的 25%)。因此,它們是移除的主要候選者。不需要在執行階段編譯 Lua 程式碼的應用程式不需要詞法分析器和剖析器。
我們設計程式碼,以便輕鬆移除這兩個模組。只有一個模組(ldo.o
)呼叫剖析器,而剖析器只有一個公開函式(luaY_parser
)。唯一呼叫詞法分析器的模組是剖析器,除了 lua_open
中使用的初始化函式(luaX_init
)。因此,要移除詞法分析器和剖析器,您只需要將以下程式碼新增到您的應用程式中(您可以從 lua/src/luac/stubs.c
中擷取它,它在預設情況下已停用)
#include "llex.h" #include "lparser.h" void luaX_init(void){} TProtoFunc* luaY_parser(ZIO *z) { lua_error("parser not loaded"); return NULL; }
包含此程式碼的應用程式不會連結 llex.o
或 lparser.o
,而嘗試載入 Lua 原始碼會產生錯誤。但是,您可能會問,應用程式要如何載入 Lua 程式碼?答案是:載入預編譯的區塊,而不是原始碼。預編譯的區塊是用 luac
建立的,它會包含詞法分析器和剖析器,但它是一個外部應用程式。載入預編譯區塊的模組是 lundump.o
,它夠小。
儘管 lua_dofile
和 dofile
會自動偵測預編譯區塊,但一個便利的方法是將預編譯區塊與靜態連結到應用程式的 lua_dobuffer
一起使用(您會發現 lua/etc/bin2c.c
對此很有用),因為嵌入式系統甚至沒有檔案系統。(這是一個快速的解決方案,但會增加應用程式的規模,而且對您來說可能太過於不靈活。)
移除詞法分析器和剖析器後,我們只剩下一個只有 28821 位元組的核心,略大於 28K。對於像 Lua 這樣強大的語言來說,這真的很小!另外請注意,這個縮減是在不觸及原始碼的情況下完成的;我們只需要連結器的協助。
另一個可移除的候選者是 lbuiltin.o
,它包含內建函式。就像標準函式庫一樣,需要精簡 Lua 的應用程式應該考慮它真正需要的內建函式。檢視 lbuiltin.c
並移除不需要的函式很簡單。它們被分為區塊,並在註解中標記為相符的 {...}
,因此很容易辨識。如果不需要任何內建函式,最簡單的方法是新增
#include "lbuiltin.h" void luaB_predefine(void){}到上述的 stub 程式碼,並依賴連結器不載入
lbuiltin.o
。
此備註專注於減少 Lua 函式庫新增到應用程式的程式碼量。需要這樣做的應用程式可能也偏好對 Lua 中的數字使用整數,而不是浮點數。(微波爐需要浮點數嗎?)這應該很容易做到,如 lua/config
中所述,但詳細資訊可能會在另一份 LTN 中討論。