Usage of the Lua C API

A Brief overview of Lua

Lua is a very simple scripting lanaguage. It has many quirks, such as:

Lua Example

print("Hello, World!") -- prints to stdout

do -- a new scope (like { statements; } in C)
	global_var = 4319 -- Will be present in the whole program
	local local_var = 3043 -- Will only be present in this scope
end
print(global_var) --> 4319
print(local_var)  --> nil

local x, y = 12, 903.44 -- numbers can be floating-point
local a, b, c = 'together', "c and", [[
see
plus
plus!!!
]] -- multiline string literal
	 

Lua Example

-- In lua, if you don't specify table keys, they start at 1, and get incremented.
local table_as_arr = {43, 12, "lua", 32.49}
print(table_as_arr[1]) --> 43
print(table_as_arr[4]) --> 32.49
print(#table_as_arr)   --> 4
-- Iterate over the table with `ipairs` to get all integer keys.
for k, v in ipairs(table_as_arr) do
	print(k, v)
end

-- This table has string and number keys that are stated.
-- It behaves like a hashmap (ex: an object in JS).
local table_as_obj = {key = "val", foo = 98, [0.32] = "a", [".?ex="] = "b"}
-- Iterate over the table with `pairs` to get all keys.
for k, v in pairs(table_as_obj) do
	print(k, v)
end
	

Lua Example

-- Lua has functions.
function add(a, b)
	return a + b
end
print(add(1, 2)) --> 3
-- functions are first-class.
local p = add
print(p(1, 2)) --> 3

function run(cb)
	print(cb("hello", 1, 2))
end
run(function(s, a, b)
	return string.format("a, b, s = %s, %d, %d", a, b, s)
end) --> a, b, s = 1, 2, hello

Lua is a very small language, so although there is a lot left to cover, there is not too much. You can learn more about the Lua language by scouring the Web.

The Lua C API

Lua is widely used as a configuration language, since it can easily be embedded into other programs. Lua is actually a library, and the interpreter is just a program that uses that library. Your program can also use that library in order to interface with a script for configuration. Some programs which embed Lua:

Lua Library Versions

There are many versions of Lua, like 5.1, 5.2, 5.3, and 5.4. Unlike JavaScript, there is not a big push to use the latest version of Lua. I will be using Lua 5.1 for this tutorial because of LuaJIT, which I will explain right now.

Regular Lua vs LuaJIT

The LuaJIT C API

LuaJIT has a C API just like regular Lua, and it models Lua 5.1's API. This means that if you write code that interfaces with Lua 5.1, you can link with LuaJIT instead of Lua 5.1 and get a much faster performance! This is why I am going to teach Lua 5.1's API for this tutorial.

To compile the program, link with either Lua 5.1 or LuaJIT:

gcc test.c `pkg-config --cflags --libs luajit` # compile with LuaJIT
gcc test.c -I/path/to/luajit -lluajit          # if you don't have pkg-config
gcc test.c `pkg-config --cflags --libs lua5.1` # compile with regular Lua 5.1
	

Run a Lua File

The following program will run a file test.lua in the same way that you would do lua test.lua.

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

int main() {
	lua_State* L = luaL_newstate(); // This state will be passed around a lot
	luaL_openlibs(L); // Open the standard libraries
	luaL_dofile(L, "test.lua"); // Run the Lua file
	lua_close(L); // Free the state
}

After compiling the executable, put print('hello') in test.lua. Run the executable, and it should print hello.

Now, let's learn how to pass data in and out of a Lua script.

Get Data from a Lua Script

You can get global variables from a Lua script with lua_getglobal().

lua_getglobal(L, "my_global");
double x = lua_tonumber(L, -1);
printf("x is %f\n", x);
	

Since global functions are just global variables, you can call functions like this.

lua_getglobal(L, "print");
lua_pushstring(L, "Hello, World!");
// The first argument is the number of args,
// The second argument is the number of returns,
// The third argument is weird.
lua_pcall(L, 1, LUA_MULTRET, 0);
	

Q&A

Q & A
Date: 2022-08-05        Presenter: TooManyUsersHaveThisUsername#8367 discord.gg/tccpp
Slide