Skip to content

Latest commit

 

History

History
282 lines (187 loc) · 9.56 KB

XMAKE_INTEGRATION.md

File metadata and controls

282 lines (187 loc) · 9.56 KB

Integrating Lunet into Your Project

Just want a runtime? A prebuilt release archive needs no toolchain at all - see "Get a runtime" in README.md. Build from source only when you must compile on the target box or want to get into the low levels.

This guide helps you build and use Lunet in your own application. No prior xmake experience required.

What is xmake?

Lunet uses xmake as its build system. xmake is a lightweight, cross-platform build tool (similar to CMake or Make). You don't need to learn xmake in depth - just follow the commands below.

Install xmake:

# Linux / macOS (curl)
curl -fsSL https://xmake.io/install.sh | bash

# Or via package manager
# macOS: brew install xmake
# Ubuntu: add-apt-repository ppa:xmake-io/xmake && apt install xmake

Quick Start: Build Lunet

1. Clone and build

git clone https://github.com/lua-lunet/lunet.git
cd lunet
xmake f -m release --lunet_trace=n --lunet_verbose_trace=n -y
xmake build

What this does:

  • xmake f = configure
  • -m release = optimized build (fast, smaller binary)
  • --lunet_trace=n = no debug tracing (recommended for production)
  • -y = accept defaults without prompting

Output files:

  • build/<platform>/<arch>/release/lunet.so - the Lua module
  • build/<platform>/<arch>/release/lunet-run - standalone runner

1b. Optional native modules

Lunet ships optional native modules as separate xmake targets. Build only what you need.

Examples:

# Database drivers
xmake build lunet-sqlite3
xmake build lunet-mysql
xmake build lunet-postgres

# Outbound HTTPS client (libcurl)
xmake build lunet-httpc

2. Run your app with lunet-run

LUNET_BIN=$(find build -path '*/release/lunet-run' -type f | head -1)
"$LUNET_BIN" path/to/your_app.lua

2b. Optional: Embed Lua scripts into lunet-run

For deployments where Lua source should not live on disk, enable script embedding in release builds:

xmake f -c -m release --lunet_embed_scripts=y --lunet_embed_scripts_dir=lua -y
xmake build lunet-bin

When enabled, lunet-run extracts the embedded script tree into a private temp directory at startup and prepends that location to package.path and package.cpath. The temp directory is removed again at shutdown.

Note: the entry script argument must be a safe relative path inside the embedded tree (for example main.lua). Absolute paths, .. segments, and scripts outside the blob are rejected - there is no fallback to running a file from disk in an embed build.

For release consumers who need their own native main() and an embedded Lua application, see EMBEDDING.md instead of rebuilding Lunet as an xmake subproject.

3. Or load lunet.so from plain LuaJIT

If you prefer to use luajit directly:

export LUA_CPATH="$(pwd)/build/$(xmake l print(os.host()))/$(xmake l print(os.arch()))/release/?.so;;"
luajit -e 'local lunet=require("lunet"); print(type(lunet))'

4. Use Lunet as an xmake subproject

If your app has its own xmake.lua, include Lunet as a subproject and link it with add_deps("lunet"):

set_project("myapp")
set_languages("c99")
add_rules("mode.debug", "mode.release")

includes("lunet")

add_requires("pkgconfig::luajit", "pkgconfig::libuv")

target("myapp")
    set_kind("binary")
    add_files("src/*.c")
    add_deps("lunet")
    add_packages("luajit", "libuv")
target_end()

Lunet keeps the Lua module output as lunet.so and also emits a compatibility liblunet.so for toolchains that link dependencies via -l<name>.


Build Profiles (When to Use Each)

Profile Use case Command
Release Production, best performance xmake f -c -m release --lunet_trace=n --lunet_verbose_trace=n -y
Debug + trace Development, catches bugs xmake f -c -m debug --lunet_trace=y --lunet_verbose_trace=n -y
Verbose trace Detailed debugging, logs every event xmake f -c -m debug --lunet_trace=y --lunet_verbose_trace=y -y
ASan + EasyMem Memory bugs (ASan + allocator integrity diagnostics) xmake f -c -m debug --lunet_trace=y --asan=y -y

Tip: Use -c to force a clean reconfigure when switching profiles.


CI Setup for Your Project

If your app uses Lunet and you run CI (e.g. GitHub Actions), test with these profiles:

  1. Release - --lunet_trace=n --lunet_verbose_trace=n
  2. Debug trace - --lunet_trace=y --lunet_verbose_trace=n
  3. Verbose trace - --lunet_trace=y --lunet_verbose_trace=y
  4. ASan + EasyMem - --asan=y --lunet_trace=y

This catches most lifecycle and coroutine issues early.


Running Tests (xmake test)

xmake test

This runs three steps in order:

  1. xmake check-types - validates the LuaCATS annotations in types/ with lua-language-server. Type errors abort the run before any test executes.
  2. xmake build lunet-httpc - builds the outbound HTTP client C module so spec/httpc_spec.lua always runs; a platform that cannot build it fails here instead of skipping.
  3. busted spec/ - the Lua suite: spec/httpc_spec.lua (tests against the lunet.httpc C module) and spec/lint_spec.lua (runs luajit bin/lint_c_safety.lua).

Output is teed to .tmp/logs/<timestamp>/busted.txt.

busted runs under LuaJIT (5.1 ABI only)

lunet's C modules link libluajit-5.1, so loading one into a PUC Lua process puts two incompatible Lua runtimes in one address space: the suite segfaults on Linux and hangs on macOS. The busted wrapper on PATH cannot be trusted to avoid that - luarocks bakes whichever interpreter it detected at install time into the wrapper (exec /usr/bin/lua5.1 … bin/busted on Debian/Ubuntu even when installed with --lua-dir pointing at LuaJIT; lua5.5 under Homebrew).

xmake test therefore ignores the wrapper and launches busted's Lua entry point itself:

luajit bin/busted_runner.lua spec/

LUA_PATH / LUA_CPATH are seeded from luarocks --lua-version=5.1 path, so busted is found in the 5.1 user and system trees regardless of the interpreter's own default paths. Overrides: $LUNET_LUAJIT (interpreter) and $LUNET_BUSTED (path to busted's Lua entry script).

Pending tests fail the run

Any test left in busted's pending state fails the whole run:

error: busted reported N pending test(s) -- pending tests are forbidden ...

For local iteration only, set LUNET_ALLOW_PENDING=1 to bypass the guard - never set it in CI. (The guard parses the captured busted output, so it applies on the Unix path only.)

Standalone type checking

xmake check-types

Runs lua-language-server --check over types/ with the project .luarc.json and parses the JSON report as the gate (LuaLS 3.15+ exits 0 even when it reports diagnostics). Its meta cache (--metapath) is pointed at a writable per-run directory under .tmp/logs/; without this LuaLS writes into its own install directory, which is root-owned in CI and silently drops all built-in types (hundreds of bogus undefined-doc-name errors).

CI

The ubuntu-latest build job in .github/workflows/build.yml runs the suite via make test (the Makefile test target delegates to xmake test).


Local Preflight Safety Gate (run before pushing)

Use the built-in EasyMem preflight task to run the same fast leak/smoke checks locally that CI uses for the EasyMem+ASan profile:

xmake preflight-easy-memory

What it does:

  • configures debug + trace + ASan + EasyMem
  • builds lunet-bin and DB modules (MySQL/Postgres optional if deps are missing locally)
  • runs test/ci_easy_memory_db_stress.lua
  • runs test/ci_easy_memory_lsan_regression.lua
  • writes all step logs to .tmp/logs/YYYYMMDD_HHMMSS/easy_memory_preflight/

EasyMem Opt-In Modes

Lunet supports EasyMem/easy_memory as an allocator backend.

Automatic enablement

EasyMem is enabled automatically when either of these is enabled:

  • --lunet_trace=y
  • --asan=y

Manual opt-in

Enable EasyMem explicitly in a development profile without enabling trace:

xmake f -c -m debug --lunet_trace=n --lunet_verbose_trace=n --easy_memory=y -y
xmake build

Release builds should keep EasyMem stripped by default.

Arena sizing

Tune EasyMem arena capacity in MB:

xmake f --easy_memory_arena_mb=256 -y

Default is 128 MB (minimum clamped to 8 MB).


Optional: LuaJIT + Lunet ASan (macOS)

For deep memory debugging (LuaJIT + Lunet both instrumented), use the macOS-only helpers:

xmake luajit-asan
xmake build-debug-asan-luajit
xmake repro-50-asan-luajit

These helpers configure --asan=y --lunet_trace=y, so EasyMem is also enabled automatically.

LuaJIT version pins are in xmake.lua. Override if needed:

xmake f --luajit_snapshot=2.1.0+openresty20250117 --luajit_debian_version=2.1.0+openresty20250117-2 -y

Troubleshooting

Problem Solution
xmake: command not found Install xmake (see "What is xmake?" above)
libuv not found Install: apt install libuv1-dev (Linux), brew install libuv (macOS)
luajit not found Install: apt install libluajit-5.1-dev (Linux), brew install luajit (macOS)
Build fails after changing options Run xmake f -c -y then reconfigure
Wrong architecture Use xmake f -a arm64 (or x64) to target a specific arch
--asan=y fails on a specific Windows toolchain Ensure your MSVC/clang-cl version supports /fsanitize=address

Performance Note

Debug tracing adds roughly 7–8% overhead in typical workloads. Use release builds (--lunet_trace=n) for production.