「概要」ページ で明示的に述べられているように、私たちの Lua 実装の目標の1つは、低い組み込みコストです。これは、次の2つのことを意味します。まず、Lua をアプリケーションに組み込むのが容易であるべきです。次に、Lua 用の追加コードが大きすぎないようにする必要があります。
最初の要件は、Lua の C API の単純さによって満たされています。2番目の要件は、以下に示すように実証によって満たされています。
以下は、Linux を実行している Intel マシンで、デフォルトオプションでコンパイルされた Lua 4.0 のいくつかの数値です(他のプラットフォームの数値は異なりますが、相対的にはほぼ同じになるでしょう)。
% 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 コードをコンパイルする必要がないアプリケーションは、解析モジュールを必要としません。これらの 3 つのモジュールを簡単に削除できるようにコードを設計しました。1 つのモジュール (ldo.o
) のみがパーサーを呼び出し、パーサーには 1 つの公開関数 (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"
を追加し、lcode.c
から luaK_opproperties
をこのコードにコピーする必要があります。上記のコードを含むアプリケーションは、解析モジュールをリンクせず、Lua ソースコードをロードしようとするとエラーが発生します。では、アプリケーションはどのようにして Lua コードをロードするのでしょうか?答えは、ソースコードの代わりにプリコンパイルされたチャンクをロードすることです。プリコンパイルされたチャンクは luac
で作成されます。luac
は解析モジュールを含みますが、外部アプリケーションです。プリコンパイルされたチャンクをロードするモジュールは lundump.o
で、十分に小さいです。
lua_dofile
および dofile
はプリコンパイルされたチャンクを自動的に検出しますが、埋め込みシステムにはファイルシステムさえも存在しないため、プリコンパイルされたチャンクをアプリケーションに静的にリンクして lua_dobuffer
を使用するのが便利な方法の1つです (このためには lua/etc/bin2c.c
が役立ちます)。(これは簡単な解決策ですが、アプリケーションのサイズが増加し、柔軟性に欠ける可能性があります。)
解析モジュールを削除すると、コアはわずか 25296 バイト、つまり 24K 強になります。これは、Lua のような強力な言語にとってはまさに微々たるものです!また、この削減は、言語機能を犠牲にしたり、ソースコードに触れたりすることなく行われたことに注意してください。リンカーからの少しの助けが必要なだけです。
このノートでは、Lua ライブラリによってアプリケーションに追加されるコード量を削減することに焦点を当てています。これを必要とするアプリケーションは、Lua の数値に浮動小数点数ではなく整数を使用することを好むでしょう。(電子レンジに浮動小数点数は必要ですか?) これは、lua/config
で説明されているように簡単に行う必要がありますが、詳細はおそらく別の LTN で議論されるでしょう。