正如 「關於」頁面 中明確說明的,我們的 Lua 實作目標之一是低嵌入成本。這表示兩件事:首先,Lua 應易於嵌入應用程式中;其次,Lua 的額外程式碼不應過大。
第一個需求由 Lua 的 C API 簡單性達成。第二個需求則由以下示範達成。
以下列出幾個 Lua 4.0 的數字,這些數字是在執行 Linux 的 Intel 電腦中使用預設選項編譯的(其他平台的數字會不同,但相對而言可能大致相同)
% size liblua.a text data bss dec hex filename 3328 0 0 3328 d00 lapi.o (ex liblua.a) 4054 0 0 4054 fd6 lcode.o (ex liblua.a) 3031 0 0 3031 bd7 ldebug.o (ex liblua.a) 2372 0 0 2372 944 ldo.o (ex liblua.a) 574 0 0 574 23e lfunc.o (ex liblua.a) 1874 0 0 1874 752 lgc.o (ex liblua.a) 4909 0 0 4909 132d llex.o (ex liblua.a) 225 0 0 225 e1 lmem.o (ex liblua.a) 734 0 0 734 2de lobject.o (ex liblua.a) 7634 0 0 7634 1dd2 lparser.o (ex liblua.a) 598 0 0 598 256 lstate.o (ex liblua.a) 953 0 0 953 3b9 lstring.o (ex liblua.a) 1651 0 0 1651 673 ltable.o (ex liblua.a) 0 0 0 0 0 ltests.o (ex liblua.a) 1495 0 0 1495 5d7 ltm.o (ex liblua.a) 2491 0 0 2491 9bb lundump.o (ex liblua.a) 5487 0 0 5487 156f lvm.o (ex liblua.a) 336 0 0 336 150 lzio.o (ex liblua.a) % size liblualib.a text data bss dec hex filename 1437 0 0 1437 59d lauxlib.o (ex liblualib.a) 5619 0 0 5619 15f3 lbaselib.o (ex liblualib.a) 1674 0 2 1676 68c ldblib.o (ex liblualib.a) 5288 0 0 5288 14a8 liolib.o (ex liblualib.a) 2301 0 0 2301 8fd lmathlib.o (ex liblualib.a) 6209 0 0 6209 1841 lstrlib.o (ex liblualib.a)在此清單中,
text
實際上是以位元組為單位的程式碼大小。我們得出結論,Lua 核心(liblua.a
)佔用 41746 位元組,而 Lua 標準函式庫(liblualib.a
)佔用 22528 位元組。因此,整個 Lua 程式碼佔用 64274 位元組,或小於 63K。換句話說,Lua 在應用程式中的影響是 63K 的額外程式碼,這相當小。(當然,Lua 在執行時會使用記憶體,但用量取決於應用程式。)
在現今電腦擁有數百萬位元組主記憶體的時代,63K 似乎非常少,但對於嘗試在微波爐或機器人中使用 Lua 的人來說,這可能會造成影響。因此,讓我們看看如何將這 63K 減少得更少。(即使您沒有在嵌入式系統中使用 Lua,您也可能從以下說明中學到一些東西。)
首先移除任何不需要的標準函式庫。例如,ldblib.o
在大多數應用程式中可能不需要,而 liolib.o
對微波爐來說可能沒有意義。但移除標準函式庫並不會讓您走得太遠,因為它們已經很小了。因此,讓我們再次查看核心的數字,但現在按大小排序
text %core %whole filename 0 0% 0% ltests.o 225 1% 0% lmem.o 336 1% 1% lzio.o 574 1% 1% lfunc.o 598 1% 1% lstate.o 734 2% 1% lobject.o 953 2% 1% lstring.o 1495 4% 2% ltm.o 1651 4% 3% ltable.o 1874 4% 3% lgc.o 2372 6% 4% ldo.o 2491 6% 4% lundump.o 3031 7% 5% ldebug.o 3328 8% 5% lapi.o 4054 10% 6% lcode.o 4909 12% 8% llex.o 5487 13% 9% lvm.o 7634 18% 12% lparser.o此清單告訴我們,解析模組(詞法分析器
llex.o
、解析器 lparser.o
和程式碼產生器 lcode.o
)佔核心的 40%(和整體的 26%)。因此,它們是移除的主要候選對象。不需要在執行時編譯 Lua 程式碼的應用程式不需要解析模組。
我們設計程式碼,以便輕鬆移除這三個模組。只有一個模組(ldo.o
)呼叫解析器,而解析器只有一個公開函式(luaY_parser
)。除了 lua_open
中使用的初始化函式(luaX_init
)之外,呼叫詞法分析器的唯一模組是解析器。除了 ldebug.o
使用 lcode.o
中的陣列 luaK_opproperties
之外,呼叫程式碼產生器的唯一模組是解析器。因此,若要移除解析模組,您只需要將以下程式碼新增到您的應用程式(您可以從 lua/src/luac/stubs.c
中擷取它,它在預設情況下已停用)
#include "llex.h" #include "lparser.h" void luaX_init(lua_State *L) { UNUSED(L); } Proto *luaY_parser(lua_State *L, ZIO *z) { UNUSED(z); lua_error(L,"parser not loaded"); return NULL; }若要移除程式碼產生器,您需要加入
#include "lcode.h"
並將 luaK_opproperties
從 lcode.c
複製到此程式碼中。
包含上述程式碼的應用程式將不會連結解析模組,而嘗試載入 Lua 原始碼會產生錯誤。但是,您可能會問,應用程式如何載入 Lua 程式碼?答案是:載入預編譯的區塊,而不是原始碼。預編譯的區塊是用 luac
建立的,它會包含解析模組,但它是一個外部應用程式。載入預編譯區塊的模組是 lundump.o
,它夠小。
雖然 lua_dofile
和 dofile
會自動偵測預編譯的區塊,但一個方便的方法是將預編譯的區塊與您的應用程式靜態連結,使用 lua_dobuffer
(您會發現 lua/etc/bin2c.c
對此很有用),因為嵌入式系統甚至沒有檔案系統。(這是一個快速的解決方案,但會增加應用程式的規模,而且對您來說可能太過死板。)
移除解析模組後,我們只剩下一個核心,只有 25296 位元組,比 24K 稍大一點。對於像 Lua 這樣強大的語言來說,這的確很小!另外請注意,這個縮減是在不犧牲任何語言功能和不修改原始碼的情況下完成的;我們只需要連結器的協助。
此說明重點在於減少 Lua 函式庫新增到應用程式的程式碼量。需要這樣做的應用程式可能也會偏好使用整數,而不是浮點數,作為 Lua 中的數字。(微波爐需要浮點數嗎?)這應該很容易做到,如 lua/config
中所述,但詳細資訊可能會在另一份 LTN 中討論。