Lua 技术说明 2

最小 Lua 4.0 安装

本说明解释了如何在内存较少的环境中构建 Lua,例如嵌入式系统。这是 技术说明 1 的版本,已针对 Lua 4.0 更新。

正如 “关于”页面 中明确指出的,我们 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%。因此,它们是删除的主要候选对象。不需要在运行时编译 Lua 代码的应用程序不需要解析模块。

我们设计代码时,考虑到了轻松移除这三个模块。只有一个模块 (ldo.o) 调用解析器,该解析器只有一个公共函数 (luaY_parser)。除了在 lua_open 中使用的初始化函数 (luaX_init) 外,调用词法分析器的唯一模块是解析器。除了 ldebug.olcode.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_oppropertieslcode.c 复制到此代码中。

包含上述代码的应用程序不会链接解析模块,并且尝试加载 Lua 源代码会生成错误。但是,您可能会问,应用程序如何加载 Lua 代码?答案是:通过加载预编译块,而不是源代码。预编译块使用 包含解析模块的 luac 创建,但它是一个外部应用程序。加载预编译块的模块是 lundump.o,它足够小。

尽管 lua_dofiledofile 会自动检测预编译块,但一种方便的方法是将 lua_dobuffer 与静态链接到应用程序的预编译块一起使用(您会发现 lua/etc/bin2c.c 对此很有用),因为嵌入式系统甚至没有文件系统。(这是一个快速解决方案,但会增加应用程序的大小,并且对您来说可能过于不灵活。)

移除解析模块后,我们只剩下一个只有 25296 字节的核心,略大于 24K。对于像 Lua 这样的强大语言来说,这确实非常小!还要注意,这种缩减是在不牺牲任何语言特性和不触及源代码的情况下完成的;我们只需要链接器的少量帮助。

此说明重点介绍了减少 Lua 库添加到应用程序的代码量。需要此功能的应用程序可能还更愿意对 Lua 中的数字使用整数,而不是浮点数。(微波炉需要浮点数吗?)这应该很容易做到,如 lua/config 中所述,但详细信息可能会在另一份 LTN 中讨论。


上次更新:2001 年 8 月 20 日星期一美国东部时间下午 2:35:00