Calling Lua From C

Introduction

One very useful feature of Lua is how easy it is to work with from C. Unlike other scripting languages Lua’s C support goes to and from. Meaning you not only can call C from Lua but you can call Lua from C.

Often you’ll see applications written in a high level language with specific functionally written in C. Typically this is performance critical code where the optimization is using C instead of the high level language. With Lua you can do this but also the opposite. While you may not want to use Lua for performance critical sections of code it makes sense to call code written in Lua in certain cases. Complex string manipulation comes to mind.

The Lua Module to Call

For my wrapped C in Lua example, I used a simple counter object. I’m going to use this same counter but this time written in Lua. This Lua module uses the module concept I covered here.

counter.lua

local M = {}
local M_mt = { __metatable = {}, __index = M }

function M:new(start)
    if self ~= M then
    	return nil, "First argument must be self"
    end

    local o = setmetatable({}, M_mt)
    o._count = start 
    return o
end
setmetatable(M, { __call = M.new })

function M:add(amount)
    self._count = self._count + amount
end

function M:subtract(amount)
    self._count = self._count - amount
end

function M:increment()
    self:add(1)
end

function M:decrement()
    self:subtract(1)
end

function M:getval()
    return self._count
end

function M_mt:__tostring()
    return string.format("%d", self._count)
end

return M

Let Lua Do All the Work

One easy way to use Lua from C is to write the majority of code in Lua and run it. In this case we need to have our Lua files in the same directory as the C application. Here is an example script, which may look familiar, to demonstrate this approach.

counter_test.lua

cmod = require("counter")
c = cmod(0)
c:add(4)
c:decrement()
print("val=" .. c:getval())

c:subtract(-2)
c:increment()
print(c)

main.c

#include <stdio.h>

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

int main(int argc, char **argv)
{
    lua_State *L;

    L = luaL_newstate();
    luaL_openlibs(L);
    if (luaL_dofile(L, "counter_test.lua")) {
        printf("Could not load file: %s\n", lua_tostring(L, -1));
        lua_close(L);
        return 0;
    }

    lua_close(L);
    return 0;
}

All we’re doing with main.c is opening a Lua state (create a stack and load the standard libraries). Calling luaL_dofile reads the given file from disk, compiles it (if Lua text), and then runs the file though Lua. Since we put all of our logic in counter_test.lua it runs and we’re all done.

CMakeLists.txt

cmake_minimum_required (VERSION 3.0)
project (lua_embed C)

find_package(Lua REQUIRED)

include_directories (
    ${CMAKE_CURRENT_BINARY_DIR}
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${LUA_INCLUDE_DIR}
)

set (SOURCES
    main.c
)

add_executable (${PROJECT_NAME} ${SOURCES} ${LUA_LIBRARIES})
target_link_libraries (${PROJECT_NAME} lua)

Building and running the application we get the expected output. This isn’t surprising because all we’re really doing is using the C application as a launcher to run the a Lua application. Really all we’ve done is written a very basic lua command.

$ mkdir build
$ cd build
$ cmake ..
$ make
$ mv lua_embed ../
$ cd ..
$ ./lua_embed
val=3
6

Actually Using a Lua Module in C

Instead of using Lua to run Lua code we can create a counter object and directly access it’s functions from C. We’ll create a Lua stack, load the counter module, call the new function to create a counter object, then call the various counter functions with the same values as we did previously.

main.c

#include <stdio.h>

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

static lua_State *create_lua_counter(char *err, size_t errlen)
{
    lua_State *L;

    L = luaL_newstate();
    if (L == NULL)
        return NULL;

    /* Load the standard Lua libraries. */
    luaL_openlibs(L);
    /* lcounter = require("lcounter")
     * Put the counter module onto the stack. */
    if (luaL_dofile(L, "counter.lua")) {
        snprintf(err, errlen, "Could not load counter module");
        lua_close(L);
        return NULL;
    }

    /* Pull new out of the counter module. */
    lua_getfield(L, -1, "new");

    /* Verify that new is a function. */
    if (!lua_isfunction(L, -1)) {
        snprintf(err, errlen, "New not a valid function");
        lua_close(L);
        return NULL;
    }

    /* Move the counter module to be the first argument of new. */
    lua_insert(L, -2);

    /* Put our actual argument (start) onto the stack. */
    lua_pushinteger(L, 0);

    /* Call new(M, start). 2 arguments. 2 return values. */
    if (lua_pcall(L, 2, 2, 0) != 0) {
        snprintf(err, errlen, "%s", lua_tostring(L, -1));
        lua_close(L);
        return NULL;
    }

    /* Right now we will either have nil and an error string
     * (nil will be below the string on the stack because it
     * would be returned first and put onto the stack first),
     * or the counter object returned by new. */
    if (lua_type(L, -2) == LUA_TNIL) {
        snprintf(err, errlen, "%s", lua_tostring(L, -1));
        lua_close(L);
        return NULL;
    }

    /* Remove the empty filler nil from the top of the stack. The
     * lua_pcall stated 2 return values but on success we only
     * get one so we have nil filler after. */
    lua_pop(L, 1);

    if (lua_type(L, -1) != LUA_TTABLE) {
        snprintf(err, errlen, "Invalid type (%d) returned by new", lua_type(L, -1));
        lua_close(L);
        return NULL;
    }

    /* We're sure we have a table returned by new.
     * This is the only item on the stack right now. */
    return L;
}

static void counter_example(lua_State *L)
{
    int n;
    int isnum;

    /* c:add(4)
     * Pull out the add function so we can run it. */
    lua_getfield(L, -1, "add");
    /* Copy (don't move) the counter object so it's the
     * first argument. Meaning we're doing M:add.
     * We want to copy because we want to leave the counter
     * object at the bottom of the stack so we can keep using
     * it. We'll use this pattern for all functions we
     * want to call. */
    lua_pushvalue(L, -2);
    /* Add the argument. */
    lua_pushnumber(L, 4);
    /* Run the function. 2 arguments. No return. */
    if (lua_pcall(L, 2, 0, 0) != 0) {
        printf("Error calling add\n");
        return;
    }

    /* c:decrement() */
    lua_getfield(L, -1, "decrement");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 0, 0) != 0) {
        printf("Error calling decrement\n");
        return;
    }

    /* print("val=" .. c:getval()) */
    lua_getfield(L, -1, "getval");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 1, 0) != 0) {
        printf("Error calling getval\n");
        return;
    }
    n = lua_tointegerx(L, -1, &isnum);
    if (!isnum) {
        printf("Error getval didn't return a number\n");
        return;
    }
    printf("val=%d\n", n);
    /* Remove the return value from the stack. */
    lua_remove(L, -1);

    /* c:subtract(-2) */
    lua_getfield(L, -1, "subtract");
    lua_pushvalue(L, -2);
    lua_pushnumber(L, -2);
    if (lua_pcall(L, 2, 0, 0) != 0) {
        printf("Error calling subtract\n");
        return;
    }

    /* c:increment() */
    lua_getfield(L, -1, "increment");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 0, 0) != 0) {
        printf("Error calling increment\n");
        return;
    }

    /* print(c) */
    lua_getglobal(L, "print");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 0, 0) != 0) {
        printf("Error calling print(c)\n");
        return;
    }

    /* print(c) (Alternative) */
    printf("%s\n", luaL_tolstring(L, -1, NULL));
    /* luaL_tolstring returns the string and puts it on the
     * stack. This is what the function return is pointing
     * to. We need to remove it from the stack. */
    lua_remove(L, -1);

    /* Right now the only thing on the stack is the counter object. */
}

int main(int argc, char **argv)
{
    lua_State *L;
    char       err[256];

    L = create_lua_counter(err, sizeof(err));
    if (L == NULL) {
        printf("Error: %s\n", err);
        return 0;
    }

    counter_example(L);

    lua_close(L);
    return 0;
}

Function: create_lua_counter

Looking at the create_lua_counter function we create a Lua stack, load the standard libraries, then we open the counter module with luaL_dofile. Since the counter module file returns a table (which is the module) the top of the stack after calling luaL_dofile is the counter module itself. This is specifically due to how the counter module is constructed. It literally returns M which is the table that is the module.

Once we have the the module open we call the module’s new function to get a counter object. Calling counter:new isn’t strictly necessary because counter has a __call field so we can call the module as if it was a function which in turn calls the module’s new function. Since we directly called new we first have to push a copy of the module itself onto the stack because we need to call M.new(M,..). Using __call means we have to do a bit less work than if we use new directly.

If we were to call the module directly instead of calling new we wouldn’t need use lua_getfield or lua_insert. We also would tell pcall there is only 1 argument instead of 2. That said, both methods result in a new counter object. It really doesn’t matter which is chosen.

The function does some verification to ensure we get a proper counter object and we don’t have any errors during its creation. If we successfully create a counter object the only thing on the stack will be the counter object.

Function: counter_example

For each counter object function we want to call, we’ll use the same basic sequence.

First we use lua_getfield to pull the function we want to call out of the object and put it on the stack. Then we put a copy of the object on the stack using lua_pushvalue. Additional lua_push*’s are used to push any arguments onto the stack. Finally, lua_pcall is used to actually run the function.

Keep in mind that after any function call (on success) we ensure we remove any return values that are placed on the stack in order to keep it in a constituent state. We want to keep the counter object we created on the bottom of the stack (and the only thing on the stack between use). We don’t want to lose the the counter object because if we do we won’t be able to use it and it will be destroyed by the garbage collector. By always keeping it on the stack (instead of making it a global for example) we can keep using it until we don’t need it any more.

That said, if a function call fails we don’t clean up the stack. Right now it’s basically a fatal error. If lua_pcall fails for some reason the top of the stack should be an error string describing the error. We could use lua_tostring(L, -1) and return that error message along with our own. This also means that there is probably a string at the top of the stack. If we were going to continue using this stack we should remove everything except the counter object. We could do something like:

if (lua_gettop(L) > 1) {
    lua_pop(L, lua_gettop(L)-1);
}

Build and Run

Using the same CMakeLists.txt as before and the same build instructions we get the following output:

$ ./lua_embed
val=3
6
6

Notice that we have two 6’s printed instead of one like in the previous section. This example prints the object in two different ways. First by calling Lua’s `print` function with the counter as the argument. Second by using printf with the output of luaL_tolstring which directly calls the counter object’s __tostring (print does too) function.

Embedding Lua in C

Both of the above examples require that the Lua code be a file on the file system that can be found by the C application. While this can be useful in certain situations (user installable plugins) it might be better to embed the Lua code directly into the application.

First compile the Lua code into a binary chunk using luac. This will speed up loading because Lua won’t have to compile the text (it’s already done). Then use xxd to create a header with an ASCII (hex dump) representation of the binary data. If xxd isn’t available (Windows) there are other tools that can be used instead of xxd including a number written in Lua.

$ luac -o counter_lua counter.lu
$ xxd -i counter_lua counter_lua.h

counter_lua.h

unsigned char counter_lua[] = {
  0x1b, 0x4c, 0x75, 0x61, 0x52, 0x00, 0x01, 0x04, 0x08, 0x04, 0x08, 0x00,
  0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x01, 0x06, 0x1b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00,
  0x00, 0x4b, 0x80, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x4a, 0x80, 0x00,
  0x80, 0x4a, 0x00, 0x80, 0x80, 0xa5, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x00,
  0x81, 0x86, 0xc0, 0x40, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x0b, 0x41, 0x00,
  0x00, 0x47, 0x81, 0x40, 0x00, 0x0a, 0x41, 0x01, 0x82, 0x9d, 0x40, 0x80,
  0x01, 0xa5, 0x40, 0x00, 0x00, 0x0a, 0x80, 0x80, 0x82, 0xa5, 0x80, 0x00,
  0x00, 0x0a, 0x80, 0x00, 0x83, 0xa5, 0xc0, 0x00, 0x00, 0x0a, 0x80, 0x80,
  0x83, 0xa5, 0x00, 0x01, 0x00, 0x0a, 0x80, 0x00, 0x84, 0xa5, 0x40, 0x01,
  0x00, 0x0a, 0x80, 0x80, 0x84, 0xa5, 0x80, 0x01, 0x00, 0x4a, 0x80, 0x00,
  0x85, 0x1f, 0x00, 0x00, 0x01, 0x1f, 0x00, 0x80, 0x00, 0x0b, 0x00, 0x00,
  0x00, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f,
  0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x04, 0x08,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x69, 0x6e, 0x64,
  0x65, 0x78, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x6e, 0x65, 0x77, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c,
  0x65, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f,
  0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74,
  0x00, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e,
  0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x04, 0x0a, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x63, 0x72, 0x65, 0x6d, 0x65,
  0x6e, 0x74, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x67, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69,
  0x6e, 0x67, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c,
  0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x85, 0x00,
  0x00, 0x00, 0x58, 0x80, 0x00, 0x00, 0x17, 0x80, 0x00, 0x80, 0x84, 0x00,
  0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x80, 0x01, 0x86, 0x40,
  0xc0, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x01, 0x9d, 0x80,
  0x80, 0x01, 0x8a, 0x40, 0x00, 0x81, 0x9f, 0x00, 0x00, 0x01, 0x1f, 0x00,
  0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67,
  0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
  0x65, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74,
  0x61, 0x62, 0x6c, 0x65, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0d,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x63, 0x6f, 0x75, 0x6e,
  0x74, 0x65, 0x72, 0x2e, 0x6c, 0x75, 0x61, 0x00, 0x0d, 0x00, 0x00, 0x00,
  0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
  0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
  0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
  0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
  0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x73, 0x65, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d,
  0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f,
  0x00, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x05,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x45, 0x4e, 0x56, 0x00,
  0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x5f, 0x6d, 0x74,
  0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03,
  0x04, 0x00, 0x00, 0x00, 0x87, 0x00, 0x40, 0x00, 0x8d, 0x40, 0x00, 0x01,
  0x0a, 0x80, 0x00, 0x80, 0x1f, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x63, 0x6f,
  0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x63, 0x6f, 0x75,
  0x6e, 0x74, 0x65, 0x72, 0x2e, 0x6c, 0x75, 0x61, 0x00, 0x04, 0x00, 0x00,
  0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
  0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x65, 0x6c, 0x66, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
  0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00,
  0x87, 0x00, 0x40, 0x00, 0x8e, 0x40, 0x00, 0x01, 0x0a, 0x80, 0x00, 0x80,
  0x1f, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x40, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
  0x2e, 0x6c, 0x75, 0x61, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
  0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00,
  0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x73, 0x65, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6d,
  0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00,
  0x00, 0x01, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x40, 0x00,
  0xc1, 0x40, 0x00, 0x00, 0x5d, 0x40, 0x80, 0x01, 0x1f, 0x00, 0x80, 0x00,
  0x02, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x61, 0x64, 0x64, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x63, 0x6f, 0x75, 0x6e, 0x74,
  0x65, 0x72, 0x2e, 0x6c, 0x75, 0x61, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18,
  0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19,
  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x73, 0x65, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
  0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x4c,
  0x00, 0x40, 0x00, 0xc1, 0x40, 0x00, 0x00, 0x5d, 0x40, 0x80, 0x01, 0x1f,
  0x00, 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74,
  0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x40, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x6c,
  0x75, 0x61, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c,
  0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01,
  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73,
  0x65, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
  0x01, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x5f,
  0x00, 0x00, 0x01, 0x1f, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04,
  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x63, 0x6f, 0x75,
  0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x63, 0x6f, 0x75, 0x6e,
  0x74, 0x65, 0x72, 0x2e, 0x6c, 0x75, 0x61, 0x00, 0x03, 0x00, 0x00, 0x00,
  0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
  0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x73, 0x65, 0x6c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00,
  0x00, 0x01, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x46, 0x00, 0x40, 0x00,
  0x47, 0x40, 0xc0, 0x00, 0x81, 0x80, 0x00, 0x00, 0xc7, 0xc0, 0x40, 0x00,
  0x5e, 0x00, 0x80, 0x01, 0x5f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x80, 0x00,
  0x04, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x04, 0x07, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x00,
  0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x64, 0x00,
  0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x63, 0x6f,
  0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x63,
  0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x6c, 0x75, 0x61, 0x00, 0x07,
  0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24,
  0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24,
  0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x65, 0x6c, 0x66, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x45, 0x4e, 0x56,
  0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x40, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x2e,
  0x6c, 0x75, 0x61, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
  0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
  0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
  0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
  0x11, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
  0x13, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
  0x1d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
  0x1f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
  0x27, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x01, 0x00,
  0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x4d, 0x5f, 0x6d, 0x74, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1b,
  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x5f, 0x45, 0x4e, 0x56, 0x00
};
unsigned int counter_lua_len = 1796;

Now that the the Lua counter module has been compiled into a C header file. We need to make two changes to main.c

First include the header

#include "counter_lua.h"

Second, replace the luaL_dofile line with luaL_loadbuffer and lua_pcall. luaL_loadbuffer unlike luaL_dofile does not automatically run the loaded chunk. Which is why we need to run lua_pcall in this case.

if (luaL_dofile(L, "../counter.lua")) {

Change the above with this:

if (luaL_loadbuffer(L, (const char *)counter_lua, counter_lua_len, "counter.lua") || lua_pcall(L, 0, LUA_MULTRET, 0)) { 

The new main.c should look like the following:

main.c

#include <stdio.h>

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

#include "counter_lua.h"

static lua_State *create_lua_counter(char *err, size_t errlen)
{
    lua_State *L;

    L = luaL_newstate();
    if (L == NULL)
        return NULL;

    /* Load the standard Lua libraries. */
    luaL_openlibs(L);
    /* lcounter = require("lcounter")
     * Put the counter module onto the stack. */
    if (luaL_loadbuffer(L, (const char *)counter_lua, counter_lua_len, "counter.lua") || lua_pcall(L, 0, LUA_MULTRET, 0)) { 
        snprintf(err, errlen, "Could not load counter module");
        lua_close(L);
        return NULL;
    }

    /* Pull new out of the counter module. */
    lua_getfield(L, -1, "new");

    /* Verify that new is a function. */
    if (!lua_isfunction(L, -1)) {
        snprintf(err, errlen, "New not a valid function");
        lua_close(L);
        return NULL;
    }

    /* Move the counter module to be the first argument of new. */
    lua_insert(L, -2);

    /* Put our actual argument (start) onto the stack. */
    lua_pushinteger(L, 0);

    /* Call new(M, start). 2 arguments. 2 return values. */
    if (lua_pcall(L, 2, 2, 0) != 0) {
        snprintf(err, errlen, "%s", lua_tostring(L, -1));
        lua_close(L);
        return NULL;
    }

    /* Right now we will either have nil and an error string
     * (nil will be below the string on the stack because it
     * would be returned first and put onto the stack first),
     * or the counter object returned by new. */
    if (lua_type(L, -2) == LUA_TNIL) {
        snprintf(err, errlen, "%s", lua_tostring(L, -1));
        lua_close(L);
        return NULL;
    }

    /* Remove the empty filler nil from the top of the stack. The
     * lua_pcall stated 2 return values but on success we only
     * get one so we have nil filler after. */
    lua_pop(L, 1);

    if (lua_type(L, -1) != LUA_TTABLE) {
        snprintf(err, errlen, "Invalid type (%d) returned by new", lua_type(L, -1));
        lua_close(L);
        return NULL;
    }

    /* We're sure we have a table returned by new.
     * This is the only item on the stack right now. */
    return L;
}

static void counter_example(lua_State *L)
{
    int n;
    int isnum;

    /* c:add(4)
     * Pull out the add function so we can run it. */
    lua_getfield(L, -1, "add");
    /* Copy (don't move) the counter object so it's the
     * first argument. Meaning we're doing M:add.
     * We want to copy because we want to leave the counter
     * object at the bottom of the stack so we can keep using
     * it. We'll use this pattern for all functions we
     * want to call. */
    lua_pushvalue(L, -2);
    /* Add the argument. */
    lua_pushnumber(L, 4);
    /* Run the function. 2 arguments. No return. */
    if (lua_pcall(L, 2, 0, 0) != 0) {
        printf("Error calling add\n");
        return;
    }

    /* c:decrement() */
    lua_getfield(L, -1, "decrement");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 0, 0) != 0) {
        printf("Error calling decrement\n");
        return;
    }

    /* print("val=" .. c:getval()) */
    lua_getfield(L, -1, "getval");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 1, 0) != 0) {
        printf("Error calling getval\n");
        return;
    }
    n = lua_tointegerx(L, -1, &isnum);
    if (!isnum) {
        printf("Error getval didn't return a number\n");
        return;
    }
    printf("val=%d\n", n);
    /* Remove the return value from the stack. */
    lua_remove(L, -1);

    /* c:subtract(-2) */
    lua_getfield(L, -1, "subtract");
    lua_pushvalue(L, -2);
    lua_pushnumber(L, -2);
    if (lua_pcall(L, 2, 0, 0) != 0) {
        printf("Error calling subtract\n");
        return;
    }

    /* c:increment() */
    lua_getfield(L, -1, "increment");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 0, 0) != 0) {
        printf("Error calling increment\n");
        return;
    }

    /* print(c) */
    lua_getglobal(L, "print");
    lua_pushvalue(L, -2);
    if (lua_pcall(L, 1, 0, 0) != 0) {
        printf("Error calling print(c)\n");
        return;
    }

    /* print(c) (Alternative) */
    printf("%s\n", luaL_tolstring(L, -1, NULL));
    /* luaL_tolstring returns the string and puts it on the
     * stack. This is what the function return is pointing
     * to. We need to remove it from the stack. */
    lua_remove(L, -1);

    /* Right now the only thing on the stack is the counter object. */
}

int main(int argc, char **argv)
{
    lua_State *L;
    char       err[256];

    L = create_lua_counter(err, sizeof(err));
    if (L == NULL) {
        printf("Error: %s\n", err);
        return 0;
    }

    counter_example(L);

    lua_close(L);
    return 0;
}

Build and Run

Using the same CMakeLists.txt as before we get the following output. The difference this time is we’re not loading the Lua script from disk it’s embedded in the C binary.

$ mkdir build
$ cd build
$ cmake ..
$ make
$ ./lua_embed
val=3
6
6