Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight configuration language for any program that needs one. Lua is implemented as a library, written in clean C (that is, in the common subset of ANSI C and C++). It's also a really tiny language, less than 6000 lines of code, which compiles to <100 kilobytes of binary code. It can be found at http://www.lua.org
eLua stands for Embedded Lua (can be thought of as a flavor of Lua) and offers the full implementation of the Lua programming language to the embedded world, extending it with specific features for efficient and portable software embedded development. eLua runs on smaller devices like microcontrollers and provides the full features of the regular Lua desktop version. More information on eLua can be found here: http://www.eluaproject.net
The current SWIG implementation is designed to work with Lua 5.0.x, 5.1.x and 5.2.x. It should work with later versions of Lua, but certainly not with Lua 4.0 due to substantial API changes. It is possible to either static link or dynamic link a Lua module into the interpreter (normally Lua static links its libraries, as dynamic linking is not available on all platforms). SWIG also supports eLua and works with eLua 0.8. SWIG generated code for eLua has been tested on Stellaris ARM Cortex-M3 LM3S and Infineon TriCore.
Suppose that you defined a SWIG module such as the following:
%module example
%{
#include "example.h"
%}
int gcd(int x, int y);
extern double Foo;
To build a Lua module, run SWIG using the -lua option.
$ swig -lua example.i
If building a C++ extension, add the -c++ option:
$ swig -c++ -lua example.i
This creates a C/C++ source file example_wrap.c or example_wrap.cxx. The generated C source file contains the low-level wrappers that need to be compiled and linked with the rest of your C/C++ application to create an extension module.
The name of the wrapper file is derived from the name of the input file. For example, if the input file is example.i, the name of the wrapper file is example_wrap.c. To change this, you can use the -o option. The wrapped module will export one function "int luaopen_example(lua_State* L)" which must be called to register the module with the Lua interpreter. The name "luaopen_example" depends upon the name of the module.
To build an eLua module, run SWIG using -lua and add either -elua or -eluac.
$ swig -lua -elua example.i
or
$ swig -lua -eluac example.i
The -elua option puts all the C function wrappers and variable get/set wrappers in rotables. It also generates a metatable which will control the access to these variables from eLua. It also offers a significant amount of module size compression. On the other hand, the -eluac option puts all the wrappers in a single rotable. With this option, no matter how huge the module, it will consume no additional microcontroller SRAM (crass compression). There is a catch though: Metatables are not generated with -eluac. To access any value from eLua, one must directly call the wrapper function associated with that value.
The following table list the additional commandline options available for the Lua module. They can also be seen by using:
swig -lua -help
| Lua specific options | |
|---|---|
| -elua | Generates LTR compatible wrappers for smaller devices running elua. |
| -eluac | LTR compatible wrappers in "crass compress" mode for elua. |
| -nomoduleglobal | Do not register the module name as a global variable but return the module table from calls to require. |
Normally Lua is embedded into another program and will be statically linked. An extremely simple stand-alone interpreter (min.c) is given below:
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
extern int luaopen_example(lua_State* L); // declare the wrapped module
int main(int argc,char* argv[])
{
lua_State *L;
if (argc<2)
{
printf("%s: <filename.lua>\n",argv[0]);
return 0;
}
L=lua_open();
luaopen_base(L); // load basic libs (eg. print)
luaopen_example(L); // load the wrapped module
if (luaL_loadfile(L,argv[1])==0) // load and run the file
lua_pcall(L,0,0,0);
else
printf("unable to load %s\n",argv[1]);
lua_close(L);
return 0;
}
A much improved set of code can be found in the Lua distribution src/lua/lua.c. Include your module, just add the external declaration & add a #define LUA_EXTRALIBS {"example",luaopen_example}, at the relevant place.
The exact commands for compiling and linking vary from platform to platform. Here is a possible set of commands of doing this:
$ swig -lua example.i -o example_wrap.c $ gcc -I/usr/include/lua -c min.c -o min.o $ gcc -I/usr/include/lua -c example_wrap.c -o example_wrap.o $ gcc -c example.c -o example.o $ gcc -I/usr/include/lua -L/usr/lib/lua min.o example_wrap.o example.o -o my_lua
For eLua, the source must be built along with the wrappers generated by SWIG. Make sure the eLua source files platform_conf.h and auxmods.h are updated with the entries of your new module. Please note: "mod" is the module name.
/* Sample platform_conf.h */ #define LUA_PLATFORM_LIBS_ROM\ _ROM( AUXLIB_PIO, luaopen_pio, pio_map )\ _ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\ _ROM( AUXLIB_MOD, luaopen_mod, mod_map )\ ....
/* Sample auxmods.h */ #define AUXLIB_PIO "pio" LUALIB_API int ( luaopen_pio )(lua_State *L ); #define AUXLIB_MOD "mod" LUALIB_API int ( luaopen_mod )(lua_State *L ); ....
More information on building and configuring eLua can be found here: http://www.eluaproject.net/doc/v0.8/en_building.html
Most, but not all platforms support the dynamic loading of modules (Windows & Linux do). Refer to the Lua manual to determine if your platform supports it. For compiling a dynamically loaded module the same wrapper can be used. Assuming you have code you need to link to in a file called example.c, the commands will be something like this:
$ swig -lua example.i -o example_wrap.c $ gcc -I/usr/include/lua -c example_wrap.c -o example_wrap.o $ gcc -c example.c -o example.o $ gcc -shared -I/usr/include/lua -L/usr/lib/lua example_wrap.o example.o -o example.so
The wrappers produced by SWIG can be compiled and linked with Lua 5.1.x and later. The loading is extremely simple.
require("example")
For those using Lua 5.0.x, you will also need an interpreter with the loadlib function (such as the default interpreter compiled with Lua). In order to dynamically load a module you must call the loadlib function with two parameters: the filename of the shared library, and the function exported by SWIG. Calling loadlib should return the function, which you then call to initialise the module
my_init=loadlib("example.so","luaopen_example") -- for Unix/Linux
--my_init=loadlib("example.dll","luaopen_example") -- for Windows
assert(my_init) -- make sure it's not nil
my_init() -- call the init fn of the lib
Or can be done in a single line of Lua code
assert(loadlib("example.so","luaopen_example"))()
If the code didn't work, don't panic. The best thing to do is to copy the module and your interpreter into a single directory and then execute the interpreter and try to manually load the module (take care, all this code is case sensitive).
a,b,c=package.loadlib("example.so","luaopen_example") -- for Unix/Linux
--a,b,c=package.loadlib("example.dll","luaopen_example") -- for Windows
print(a,b,c)
Note: for Lua 5.0:
The loadlib() function is in the global namespace, not in a package. So it's just loadlib().
if 'a' is a function, this is all working fine, all you need to do is call it
a()
to load your library which will add a table 'example' with all the functions added.
If it doesn't work, look at the error messages, in particular message 'b'
The specified module could not be found.
Means that is cannot find the module, check your the location and spelling of the module.
The specified procedure could not be found.
Means that it loaded the module, but cannot find the named function. Again check the spelling, and if possible check to make sure the functions were exported correctly.
'loadlib' not installed/supported
Is quite obvious (Go back and consult the Lua documents on how to enable loadlib for your platform).
Assuming all goes well, you will be able to this:
$ ./my_lua > print(example.gcd(4,6)) 2 > print(example.Foo) 3 > example.Foo=4 > print(example.Foo) 4 >
By default, SWIG tries to build a very natural Lua interface to your C/C++ code. This section briefly covers the essential aspects of this wrapping.
The SWIG module directive specifies the name of the Lua module. If you specify `module example', then everything is wrapped into a Lua table 'example' containing all the functions and variables. When choosing a module name, make sure you don't use the same name as a built-in Lua command or standard module name.
Global functions are wrapped as new Lua built-in functions. For example,
%module example int fact(int n);
creates a built-in function example.fact(n) that works exactly like you think it does:
> print example.fact(4) 24 >
To avoid name collisions, SWIG create a Lua table which it keeps all the functions and global variables in. It is possible to copy the functions out of this and into the global environment with the following code. This can easily overwrite existing functions, so this must be used with care.
> for k,v in pairs(example) do _G[k]=v end > print(fact(4)) 24 >
It is also possible to rename the module with an assignment.
> e=example > print(e.fact(4)) 24 > print(example.fact(4)) 24
Global variables (which are linked to C code) are supported, and appear to be just another variable in Lua. However the actual mechanism is more complex. Given a global variable:
%module example extern double Foo;
SWIG will effectively generate two functions example.Foo_set() and example.Foo_get(). It then adds a metatable to the table 'example' to call these functions at the correct time (when you attempt to set or get examples.Foo). Therefore if you were to attempt to assign the global to another variable, you will get a local copy within the interpreter, which is no longer linked to the C code.
> print(example.Foo) 3 > c=example.Foo -- c is a COPY of example.Foo, not the same thing > example.Foo=4 > print(c) 3 > c=5 -- this will not effect the original example.Foo > print(example.Foo,c) 4 5
It is therefore not possible to 'move' the global variable into the global namespace as it is with functions. It is however, possible to rename the module with an assignment, to make it more convenient.
> e=example > -- e and example are the same table > -- so e.Foo and example.Foo are the same thing > example.Foo=4 > print(e.Foo) 4
If a variable is marked with the %immutable directive then any attempts to set this variable will cause a Lua error. Given a global variable:
%module example %immutable; extern double Foo; %mutable;
SWIG will allow the reading of Foo but when a set attempt is made, an error function will be called.
> print(e.Foo) -- reading works ok
4
> example.Foo=40 -- but writing does not
This variable is immutable
stack traceback:
[C]: ?
[C]: ?
stdin:1: in main chunk
[C]: ?
For those people who would rather that SWIG silently ignore the setting of immutables (as previous versions of the Lua bindings did), adding a -DSWIGLUA_IGNORE_SET_IMMUTABLE compile option will remove this.
Unlike earlier versions of the binding, it is now possible to add new functions or variables to the module, just as if it were a normal table. This also allows the user to rename/remove existing functions and constants (but not linked variables, mutable or immutable). Therefore users are recommended to be careful when doing so.
> -- example.PI does not exist > print(example.PI) nil > example.PI=3.142 -- new value added > print(example.PI) 3.142
If you have used the -eluac option for your eLua module, you will have to follow a different approach while manipulating global variables. (This is not applicable for wrappers generated with -elua)
> -- Applicable only with -eluac. (num is defined) > print(example.num_get()) 20 > example.num_set(50) -- new value added > print(example.num_get()) 50
In general, functions of the form "variable_get()" and "variable_set()" are automatically generated by SWIG for use with -eluac.
Because Lua doesn't really have the concept of constants, C/C++ constants are not really constant in Lua. They are actually just a copy of the value into the Lua interpreter. Therefore they can be changed just as any other value. For example given some constants:
%module example
%constant int ICONST=42;
#define SCONST "Hello World"
enum Days{SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY};
This is 'effectively' converted into the following Lua code:
example.ICONST=42 example.SCONST="Hello World" example.SUNDAY=0 ....
Constants are not guaranteed to remain constant in Lua. The name of the constant could be accidentally reassigned to refer to some other object. Unfortunately, there is no easy way for SWIG to generate code that prevents this. You will just have to be careful.
If you're using eLua and have used -elua or -eluac to generate your wrapper, macro constants and enums should be accessed through a rotable called "const". In eLua, macro constants and enums are guaranteed to remain constants since they are all contained within a rotable. A regular C constant is accessed from eLua just as if it were a regular global variable, just that the property of value immutability is demonstrated if an attempt at modifying a C constant is made.
> print(example.ICONST) 10 > print(example.const.SUNDAY) 0 > print(example.const.SCONST) Hello World
C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information. Given a wrapping of the <file.h> interface:
%module example FILE *fopen(const char *filename, const char *mode); int fputs(const char *, FILE *); int fclose(FILE *);
When wrapped, you will be able to use the functions in a natural way from Lua. For example:
> f=example.fopen("junk","w")
> example.fputs("Hello World",f)
> example.fclose(f)
Unlike many scripting languages, Lua has had support for pointers to C/C++ object built in for a long time. They are called 'userdata'. Unlike many other SWIG versions which use some kind of encoded character string, all objects will be represented as a userdata. The SWIG-Lua bindings provides a special function swig_type(), which if given a userdata object will return the type of object pointed to as a string (assuming it was a SWIG wrapped object).
> print(f) userdata: 003FDA80 > print(swig_type(f)) FILE * -- it's a FILE*
Lua enforces the integrity of its userdata, so it is virtually impossible to corrupt the data. But as the user of the pointer, you are responsible for freeing it, or closing any resources associated with it (just as you would in a C program). This does not apply so strictly to classes & structs (see below). One final note: if a function returns a NULL pointer, this is not encoded as a userdata, but as a Lua nil.
> f=example.fopen("not there","r") -- this will return a NULL in C
> print(f)
nil
If you wrap a C structure, it is also mapped to a Lua userdata. By adding a metatable to the userdata, this provides a very natural interface. For example,
struct Point{
int x,y;
};
is used as follows:
> p=example.new_Point() > p.x=3 > p.y=5 > print(p.x,p.y) 3 5 >
Similar access is provi