How to interface to my C/C++ libraries?
It is straightforward to bind Lua to C code. One reason is that Lua only has a few complex data types, so once you have learned to manage tables and userdata from the C side, you have mostly mastered the art of binding to Lua.
Arguments are taken off the stack, return results are pushed on the stack, and the C function returns the number of items it intends to return to the caller.
// build@ gcc -shared -I/home/sdonovan/lua/include -o mylib.so mylib.c
// includes for your code
#include <string.h>
#include <math.h>
// includes for Lua
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
// defining functions callable from Lua static int l_createtable (lua_State *L) {
int narr = luaL_optint(L,1,0); // initial array slots, default 0
int nrec = luaL_optint(L,2,0); // intialof hash slots, default 0
lua_createtable(L,narr,nrec);
return 1;
}
static int l_solve (lua_State *L) {
double a = lua_tonumber(L,1); // coeff of x*x
double b = lua_tonumber(L,2); // coef of x
double c = lua_tonumber(L,3); // constant
double abc = b*b - 4*a*c;
if (abc < 0.0) {
lua_pushnil(L);
lua_pushstring(L,"imaginary roots!");
return 2;
} else {
abc = sqrt(abc);
a = 2*a;
lua_pushnumber(L,(-b + abc)/a);
lua_pushnumber(L,(+b - abc)/a);
return 2;
}
}
static const luaL_reg mylib[] = {
{"createtable",l_createtable},
{"solve",l_solve},
{NULL,NULL}
};
int luaopen_mylib(lua_State *L)
{
luaL_register (L, "mylib", mylib);
return 1;
}
Note the convention; a library needs only to export one function, with the special name luaopen_LIBNAME
. It will usually return the table created.
For this to work on Windows, you either must put luaopen_mylib
into a .def file or use the modifier __declspec(dllexport)
before the exported function definition. Because of Windows runtime issues, you will usually need to compile the extension with the same compiler that your version of Lua was itself built with.
This little module exports two functions, which are both useful (but have little otherwise to do with each other!). mylib.solve
solves the quadratic equation and returns both roots; it properly detects the problem of imaginary roots and returns nil
and an error message, which is the normal convention for errors.
mylib.createtable
allows you to create a table with a preset capacity for new elements, which cannot otherwise be done from Lua itself. This can be useful if you have to fill a really big table, without taking the O(log(N))
hit for inserting table elements.
> m = require 'mylib'
> = m.solve(0.5,10,1)
-0.10050506338833 -18.899494936612
> = m.solve(2,1,1)
nil imaginary roots!
> t = m.createtable(20)
> for i=1,10 do t[i] = 2*i end
> = #t
10
Note that the table has initially zero size, and #t
gets updated as new elements are inserted.
As a general rule, only go down to C if you have something that needs special optimization, or have an existing library that already does the job well.
Using the raw API is mostly straightforward, but can be tedious. There are several tools that will semi-automatically do the hard work for you, and they understand C++ as well. see 7.5.