As explicitly stated in the "about" page, one of the goals of our Lua implementation is low embedding cost. This means two things: first, it should be easy to embed Lua in an application; second, the additional code for Lua should not be too large.
The first requirement is fulfilled by the simplicity of Lua's C API. The second requirement is fulfilled by demonstration, as follows.
Here are a few numbers for Lua 4.0, compiled with the default options in an Intel machine running Linux (the numbers for other platforms will be different, but probably roughly the same in relative terms):
% 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)In this listing,
text
actually is the size of the code in bytes.
We conclude that
the Lua core (liblua.a
) takes 41746 bytes and that
the Lua standard libraries (liblualib.a
) take 22528 bytes.
So,
the whole Lua code takes 64274 bytes, or less than 63K.
In other words,
the impact of Lua in an application is 63K of additional code,
which is quite small.
(Of course, Lua will use memory at run-time -- but how much depends on the
application.)
63K seem very little in these days that machines have many megabytes of main memory, but they might make a difference for someone trying to use Lua in a microwave oven or in a robot. So, let's see how to reduce these 63K to even less. (Even if you're not using Lua in embedded systems, you might learn something from the description below.)
The first thing is to remove any standard libraries that are not needed.
For instance,
ldblib.o
will probably not be needed in most applications,
and liolib.o
will probably not make sense for a microwave oven.
But removing standard libraries will not get you very far,
because they are small already.
So,
let's look at the numbers for the core again, but now sorted by size:
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.oThis listing tells us that the parsing modules -- the lexer
llex.o
,
the parser lparser.o
,
and the code generator
lcode.o
--
represent 40% of the core (and 26% of the whole).
So,
they are the main candidates for removal.
An application that does not need to compile Lua code at run-time does
not need the parsing modules.
We have designed the code so that it is easy to remove these three modules.
Only one module (ldo.o
) calls the parser,
which has only one public function (luaY_parser
).
The only module that calls the lexer is the parser,
except for an initialization function (luaX_init
) used
in lua_open
.
The only module that calls the code generator is the parser,
except that
ldebug.o
uses the array
luaK_opproperties
from lcode.o
.
So,
to remove the parsing modules
you only need to add the code below to your application
(you can extract it from lua/src/luac/stubs.c
,
where it is disabled by default):
#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; }To remove the code generator too, you need to add
#include "lcode.h"
and
copy luaK_opproperties
from lcode.c
into this code.
An application that contains the code above will not link the parsing modules
and
trying to load Lua source code will generate an error.
But then,
you ask,
how does the application load Lua code at all?
The answer is:
by loading precompiled chunks instead of source code.
Precompiled chunks are created with luac
,
which will contain the parsing modules,
but which is an external application.
The module that loads precompiled chunks is lundump.o
,
which is small enough.
Although
lua_dofile
and dofile
automatically detect
precompiled chunks,
one convenient way is to use lua_dobuffer
with precompiled chunks statically linked to your application
(you will find lua/etc/bin2c.c
useful for this),
because embedded systems don't even have filesystems.
(This is a quick solution,
but it will increase the size of your application
and it may be too inflexible for you.)
Removing the parsing modules leaves us with a core of just 25296 bytes, a little more than 24K. This is tiny indeed for a powerful language like Lua! Note also that this reduction was done without sacrificing any language features and without touching the source code; we just need a little help from the linker.
This note has focused on reducing the amount of code added to the application
by the Lua library.
Applications that need this will probably also prefer to use integers instead
of floating-point numbers for the numbers in Lua.
(Does a microwave oven need floating-point?)
This should be simple to do,
as described in lua/config
,
but the details will probably be discussed in another LTN.