Embedding Lua: Possessing the Host Application

Lua was designed from the ground up to be embedded. Its C API is minimal yet powerful, allowing any C application to gain the flexibility of a scripting language without sacrificing performance.

Setting Up the Lua State

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main(void) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    if (luaL_dofile(L, "config.lua") != LUA_OK) {
        fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
        lua_pop(L, 1);
    }

    lua_close(L);
    return 0;
}

The Stack: Lua's Communication Channel

All data exchange between C and Lua happens through a virtual stack. Understanding the stack is the single most important concept for Lua embedding:

// Push a global function onto the stack
lua_getglobal(L, "my_function");
// Push arguments
lua_pushinteger(L, 42);
lua_pushstring(L, "hello");
// Call: 2 arguments, 1 result
lua_pcall(L, 2, 1, 0);
// Get the result
int result = lua_tointeger(L, -1);
lua_pop(L, 1);

Exposing C Functions to Lua

static int l_add(lua_State *L) {
    double a = luaL_checknumber(L, 1);
    double b = luaL_checknumber(L, 2);
    lua_pushnumber(L, a + b);
    return 1;  // Number of return values
}

// Register the function
lua_pushcfunction(L, l_add);
lua_setglobal(L, "add");

The Registry

The Lua registry is a special table accessible only from C. Use it to store references that persist across function calls without polluting the global namespace. Use luaL_ref() and luaL_unref() for safe reference management.

When you embed Lua, your C application gains a soul. It becomes configurable, extensible, and alive.