Calling C from Lua

The same title of the Chapter 26 of Roberto Ierusalimschy book Programming in Lua. Although the chapter (and all the book) is very clear, what is not so clear is where the pieces fit together and what to do to really call C from Lua, how to compile the library, etc.

It's pretty comprehensible he didn’t cover this: Lua runs on a variety different environments and it's impossible to cover them all. Here I'll cover a POSIX-compatible (pretty much a Unix-like, although there are non-Unix systems which are compatible too) system. Windows uses a very different approach.

First, fit all C pieces together. If this sounds ilogical, read the chapter. This is a complement, not the whole history.

/* mylib.c */
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

static int l_sin (lua_State *L) {
    double d = luaL_checknumber(L, 1);
    lua_pushnumber(L, sin(d));
    return 1;
}

static const struct luaL_Reg mylib [] = {
    {"mysin", l_sin},
    {NULL, NULL} /* sentinel */
};

/* main function */
int luaopen_mylib (lua_State *L) {
    luaL_register(L, "mylib", mylib); /* 5.1, LINE 22 */
    //luaL_newlib(L, mylib); /* 5.2, LINE 23 */
    return 1;
}

Note the line 22. You should link your library against Lua 5.1. Starting from 5.2, it uses a new function called luaL_newlib(). If you want to link agains Lua 5.2, it's just a matter to uncomment line 23 and to comment line 22.

You should locate where your Lua headers are installed. For third-party packages, they’re normally under /usr/local/include. Since I usually have both Lua 5.1 and 5.2, they are separated. In my case, they are in /usr/local/include/lua-5.1. This directory will serve as a parameter to the gcc -I option.

You should also locate where your shared libraries are. For third-party packages, they are usually under /usr/local/lib. This directory will serve as a parameter to the gcc -L option.

Shared libraries in the directory specified with -L have a lib*.so.* pattern. As an example, if your shared library file is called liblua5.1.so.5.1, your library is called lua5.1. If you don’t have a good understanding of it, this should help.

To compile your library, run the following command:

$ gcc -shared -I/usr/local/include/lua-5.1 -lm -omylib.so mylib.c

Some explanation of what options tells what to gcc:

  • -I and -L were explained above
  • -shared option tells gcc to create a shared library instead of an executable
  • -llua5.1 to link against Lua 5.1
  • -lm since we are using functions from the Standard C Library, we should link against it too
  • -o filename of the library

Time to use Lua hat. It's trivial to use this library:

/* main.lua */
#!/usr/bin/env lua

local mylib = require "mylib"

print(mylib.mysin(30))

On command-line, you should see this:

$ ./main.lua
-0.98803162409286
$

That's it. If you find any typos, errors, please notify me.

Edit: As pointed out by Philipp Janda in lua-l mailing list, on some Unices Lua exports its symbols from the executable by default, and linking with liblua isn’t necessary.

more ...

Wave

Wave is a function generator.

Wave (front)

It's based on the XR-2206 from Exar, and the board is a retired one from Sparkfun. The design is based on a circuit presented on the datasheet itself, so nothing fancy here.

Wave (inside)

The power supply for the function generator is a custom one, called Source, built with gEDA. gEDA is a full GPL'd suite and toolkit of Electronic Design Automation tools. The result is available here (for direct use with gschem + pcb, both part of the toolkit). The design includes the power supply for the signal generator itself plus 2 more channels, 1 asymmetric (3A max) and 1 normal (1A max). The prototype thing:

Source - prototype PCB (back)

Source - prototype PCB (front)

The real thing:

Source - PCB (new)

Source - PCB (production)

more ...