Complex library APIs can often be quickly and almost completely wrapped using SWIG . The advantage of using SWIG in this case is that it’s easy to create SWIG shells that let you use the library in 18 major languages , including Lua, Perl, Python, Ruby, and Java.
If Lua is your preferred (and possibly the only) problem, then I recommend learning how to use luaL_register() in the core Lua module creation strategy in C. The advantage of building a module this way is that you save all your functions in one namespace without any overhead. You will need to create a wrapper function that complies with the convention of calling the Lua C function (just like you do with lua_register() ), and which collects Lua arguments from the stack, calls the wrapped function and pops the return value and displays the parameters back to the Lua glass . A good overview of how to do this can be found in the book “Programming in Lua”. An online copy of the first edition discusses the creation of the library in Chapter 26 , but was written for Lua 5.0. I urge anyone seriously using Lua to have a copy of the current version of PiL.
Unfortunately, one area where Lua 5.1 differs for the most part from 5.0 is the dynamic loading of modules (both C and Lua) using require .
Here is a complete (if small) example for the C library that works in Lua 5.1. Let's start by implementing the shell in the C file:
#include <lua.h> #include <luaxlib.h> #include <math.h> #undef PI #define PI (3.14159265358979323846) static int l_sin (lua_State *L) { double r = luaL_checknumber(L,1); lua_pushnumber(L, sin(r)); return 1; } static int l_cos (lua_State *L) { double r = luaL_checknumber(L,1); lua_pushnumber(L, cos(r)); return 1; } static const struct luaL_reg smlib [] = { {"sin", l_sin}, {"cos", l_cos}, {NULL, NULL} /* sentinel */ }; int luaopen_sm (lua_State *L) { luaL_openlib(L, "sm", smlib, 0); lua_pushnumber(L,PI); lua_rawset(L,-2,"pi"); return 1; }
Note that the only function that needs to be exported is luaopen_sm() , whose name must match the name of the module that will be used with require and the name of the DLL file. With this file compiled as a DLL named sm.dll (probably named libsm.so on Unix-like systems), then it can be downloaded and used in a Lua script as follows:
require "sm"
print (sm.sin (sm.pi / 3), sm.cos (sm.pi / 3));
This example, although untested, should compile and run. For a complete example of porting most functions from math.h see the source to the math module , which is distributed with Lua. Because these thin wrappers contain many duplicate codes, tools like SWIG can often create them with only the declarations of each function.
The methods for wrapping around a C ++ class are basically similar. Each Lua-invoked wrapper function will need an argument that can be mapped to this on the C ++ side, and it must be implemented either as a module-static function or a static member function that also finds an instance of the target object that converts other arguments. SWIG is especially good at creating this type of wrapper and hides many gory details along the way.