Lua 技術備註 1

最小 Lua 3.2 安裝

此備註說明如何在記憶體不足的環境中建置 Lua。

正如 歡迎頁面 中明確指出,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.olparser.o,而嘗試載入 Lua 原始碼會產生錯誤。但是,您可能會問,應用程式要如何載入 Lua 程式碼?答案是:載入預編譯的區塊,而不是原始碼。預編譯的區塊是用 luac 建立的,它包含詞法分析器和剖析器,但它是一個外部應用程式。載入預編譯區塊的模組是 lundump.o,它夠小。

儘管 lua_dofiledofile 會自動偵測預編譯區塊,但一個便利的方法是將預編譯區塊與靜態連結到應用程式的 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 中討論。


最後更新:2001 年 2 月 11 日星期日下午 6:45:01 美國東部時間,作者為 lhf