As explicitly stated in the welcome 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 3.2, compiled 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 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)In this listing,
text
actually is the size of the code in bytes.
We conclude that
the Lua core (liblua.a
) takes 42810 bytes and that
the Lua standard libraries (liblualib.a
) take 12678 bytes.
So,
the whole Lua code takes 55488 bytes, or less than 54K.
In other words,
the impact of Lua in an application is 54K of additional code,
which is quite small.
(Of course, Lua will use memory at run-time -- but how much depends on the
application.)
54K 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 54K 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.
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 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.oThis listing tells us that the lexer (
llex.o
)
and the parser
(lparser.o
)
represent 33% of the core (and 25% 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 lexer and the parser.
We have designed the code so that it is easy to remove these two 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
.
So,
to remove the lexer and the parser,
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(void){} TProtoFunc* luaY_parser(ZIO *z) { lua_error("parser not loaded"); return NULL; }
An application that contains this code
will not link llex.o
or lparser.o
,
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 lexer and the parser,
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 fast solution,
but it will increase the size of your application
and it may be too inflexible for you.)
Removing the lexer and the parser leaves us with a core of just 28821 bytes, a little more than 28K. This is tiny indeed for a powerful language like Lua! Note also that this reduction was done without touching the source code; we just need a little help from the linker.
The other candidate for removal is
lbuiltin.o
,
which contains the built-in functions.
Like the standard libraries,
an application that needs a slim Lua
should consider which built-in functions it really needs.
It is easy to go through lbuiltin.c
and
remove the functions that are not needed.
They are divided into blocks,
marked with matching {...}
inside comments,
and so are easily identified.
If no built-in functions are required,
then the easiest way is to add
#include "lbuiltin.h" void luaB_predefine(void){}to the stub code above and rely on the linker not to load
lbuiltin.o
.
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.