Mobile Development 22 min read

How to Embed Lua Across C, Java, Android, and iOS: A Step‑by‑Step Guide

This article explains how to embed the Lua scripting engine into native C programs, Java applications via LuaJava, Android apps using JNI, and iOS projects, covering environment setup, bridge functions, compilation commands, and runtime examples for each platform.

Art of Distributed System Architecture Design
Art of Distributed System Architecture Design
Art of Distributed System Architecture Design
How to Embed Lua Across C, Java, Android, and iOS: A Step‑by‑Step Guide

Embedding Lua in C

All examples target Lua 5.1.1. The typical workflow is:

Create a new Lua state with luaL_newstate().

Load the standard libraries via luaL_openlibs().

Execute a script file with luaL_dofile() or a script string with luaL_dostring().

Close the state with lua_close().

Simple C program that runs helloWorld.lua:

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dofile(L, "helloWorld.lua");
    lua_close(L);
    return 0;
}
helloWorld.lua

contains: print("Hello World!") Compile on Linux/macOS:

gcc helloWorld.c -o helloWorld.out -I/usr/local/include -L/usr/local/lib -llua && ./helloWorld.out

Output: Hello World!

Register a C function so Lua can call back:

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int sayHelloWorld(lua_State *L) {
    const char *str = lua_tostring(L, 1);
    lua_pushstring(L, str);
    return 1; // number of results
}
int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_register(L, "sayHelloWorld", sayHelloWorld);
    luaL_dofile(L, "helloWorld.lua");
    lua_close(L);
    return 0;
}
helloWorld.lua

: print(sayHelloWorld("Hello World!")) Result: the string returned by the C bridge function is printed.

Lua Calling C (C‑Dominated Interaction)

To expose C functions to Lua, write a bridge function that follows the Lua C‑API (receives lua_State*, pushes results, returns the result count) and register it in a module.

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int say(lua_State *L) {
    lua_pushstring(L, lua_tostring(L, 1));
    return 1;
}
static const luaL_Reg functions[] = {
    {"say", say},
    {NULL, NULL}
};
int luaopen_saySomething(lua_State *L) {
    luaL_register(L, "saySomething", functions);
    return 1;
}

Lua script:

require "saySomething"
print(saySomething.say("Hello Lua!"))

Compile the module as a shared library (Linux/macOS):

gcc -c -fPIC saySomething.c -I/usr/local/include
gcc -shared -fPIC -I/usr/local/include -L/usr/local/lib -llua -o saySomething.so saySomething.o

Running the script prints Hello Lua!

Embedding Lua in Java (LuaJava)

LuaJava provides JNI bindings that expose the Lua C‑API as Java methods. After adding luajava‑1.1.jar and the native library ( libluajava.so or luajava.dll) to the project, Lua can be driven from Java:

import org.keplerproject.luajava.LuaState;
import org.keplerproject.luajava.LuaStateFactory;
public class TestMain {
    public static void main(String[] args) {
        LuaState L = LuaStateFactory.newLuaState();
        L.openLibs();
        L.LdoFile("hello.lua");
    }
}
hello.lua

contains print("Hello World!"). The program prints the same message.

Lua on Android

Android uses the NDK, so Lua can be embedded via the same LuaJava JNI layer.

Place luajava.jar in the src folder and the compiled libluajava.so in libs/armeabi (or appropriate ABI).

Store Lua scripts in res/raw (e.g., hello.lua).

In an Activity, create a LuaState, load the script, retrieve globals, push arguments, and call functions.

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LuaState L = LuaStateFactory.newLuaState();
        L.openLibs();
        L.LdoString(toStringForStream(getResources().openRawResource(R.raw.hello)));
        L.getGlobal("getData");
        L.pushObjectValue("Lua^^");
        L.pcall(1, 1, 0);
        String text = L.toString(-1);
        TextView tv = new TextView(this);
        tv.setText(text);
        setContentView(tv);
    }
    private String toStringForStream(InputStream is) {
        BufferedReader r = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line;
        try {
            while ((line = r.readLine()) != null) {
                sb.append(line).append('
');
            }
        } catch (IOException e) { e.printStackTrace(); }
        return sb.toString();
    }
}
hello.lua

:

function getData(param)
    return "Hello " .. param
end

The app displays Hello Lua^^ .

Lua on iOS

iOS projects can link Lua as a static library and use it from Objective‑C (or Swift via bridging). The code mirrors the pure‑C example:

#import "ViewController.h"
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dostring(L, "text='Hello World!'");
    lua_getglobal(L, "text");
    _showLabel.text = [NSString stringWithUTF8String:lua_tostring(L, -1)];
    lua_close(L);
}
@end

The label shows Hello World! .

Configuration Overview

Desktop Lua : Download Lua 5.1 source from the official site. Build with make on Linux/macOS or use pre‑built binaries on Windows.

LuaJava (desktop) : Edit the config (or config.win) file to point to Lua include and library directories, then run make (Linux/macOS) or compile with Visual Studio (Windows). This produces luajava‑1.1.jar and a native library ( .so, .jnilib, or .dll).

Android : Either embed Lua and LuaJava source files into a C/C++ NDK project (configure Android.mk) or build the shared library separately with ndk-build, then include the generated libluajava.so in the app’s libs directory.

iOS : Add a Cocoa Touch Static Library target, add the Lua source folder to the target, and link the resulting static library with the main app target.

Across all platforms the key points are:

Lua runs on any environment that provides a C runtime.

Interaction between Lua and host code is performed via the Lua stack using the C‑API functions ( lua_push*, lua_tostring, lua_getglobal, lua_pcall, etc.).

To expose C functionality to Lua, write bridge functions that follow the lua_State* convention and register them with lua_register (for simple functions) or luaL_register inside a module.

To drive Lua from C/Java/Objective‑C, create a state, open libraries, load scripts (file or string), and manipulate globals or call Lua functions as needed.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaiOSAndroidCEmbeddingScriptingLua
Art of Distributed System Architecture Design
Written by

Art of Distributed System Architecture Design

Introductions to large-scale distributed system architectures; insights and knowledge sharing on large-scale internet system architecture; front-end web architecture overviews; practical tips and experiences with PHP, JavaScript, Erlang, C/C++ and other languages in large-scale internet system development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.