a9f64e7d39b67fd55b0cd7bd289b31d954190363
raw

Build & Test Systems

Build system

Lilush uses a custom build generator (buildgen/generate.lua) that compiles Lua modules into LuaJIT bytecode, links them with C libraries, and produces a single static binary. The generator itself runs on plain LuaJIT with no external Lua dependencies.

Docker is used purely as a build medium — it provides the Alpine toolchain and LuaJIT, then runs the generator. No runtime images are produced.

Testing system

Lilush uses a minimal custom test framework called testimony (src/testimony/) for regression prevention and refactoring safety.

Tests live in tests/ and organized into subdirs per module.

Building

./build.bash [app]

app defaults to lilush. In-tree apps: lilu, lilush (each has a buildgen/apps/<app>.lua config). The built binary is placed in the repo root. To install system-wide, do sudo mv [app] /usr/[local]/bin/

Building an external LILPACK into a custom binary

Some apps live in their own LILPACK repos rather than in-tree (e.g. RECALL), yet can still be compiled into a custom, tailored static binary instead of being installed at runtime:

./build.bash --pack <git-url> --ref <tag-or-sha> --name <binary>

The pack is cloned at --ref (use an immutable tag or commit SHA) and built from its own build/<name>.lua descriptor. The pack's own Lua modules are auto-scanned from its tree (names derived from file paths, exactly like the LILPACK packer); the descriptor only lists the shared lilush module groups (luamods/c_libs) it depends on. The same repo can also be lilpack packed into a signed .lilpack for runtime install — one source, two outputs.

A pack binary reports its own version via -v, taken from the pack's lilpack.json, alongside the lilush toolchain it was built against — e.g. recall -v prints recall 0.3.1 (lilush 0.8.5). In-tree builds (lilush, lilu) keep the plain version 0.8.5 form.

Running Tests

Testing after recent changes

After making changes, build lilush and run:

  • For running all tests (requires the binary to be in the repo root, which is default after build):

    ./run_tests.bash
  • You can also use a subdirectory name to run all tests for a module:

    ./run_tests.bash std
    ./run_tests.bash term
  • Or run individual test files:

    ./lilush tests/std/test_tbl.lua

File layout

Dockerfile                          Docker build template (takes APP build arg)
build.bash                          Build entry point
buildgen/
  generate.lua                      Build orchestrator (runs under luajit)
  c_tmpl                            C source template with preload infrastructure
  modinfo.lua                       Module registry (Lua module names -> C identifiers)
  default_main.c                    Default main() for apps without a custom one
  apps/
    version                         Lilush toolchain version (drives {{LILUSH_VERSION}} and the {{VERSION_STRING}} shown by -v)
    lilush.lua                      App config for lilush
    lilu.lua                        App config for lilu
  entrypoints/
    <app>/
      *.lua                         Lua entrypoint code (embedded as C string constants)
      main.c                        Custom main() (optional, per-app)

App configs

Each app config (buildgen/apps/<app>.lua) returns a table:

Build pipeline

What generate.lua does, in order:

  1. Load config — reads the app config and modinfo.lua

  2. Generate entrypoint constants — reads each .lua file referenced in start_code, escapes it for C, and emits static const char declarations

  3. Compile C modules — runs make -C src/<lib> for each C library, strips debug symbols from the resulting .o files

  4. Compile Lua modules — for each Lua module group, finds all .lua files under src/<mod>/, compiles each to a bytecode header with luajit -b, and patches the header to use the project's naming scheme

  5. Assemble C source — fills the c_tmpl template with:

    • {{START_CODE}} — the entrypoint constant declarations

    • {{LUAMODS}} — bytecode #includes and the lua_preload[] table

    • {{CLIBS}}extern declarations and the c_preload[] table

    • Appends the app's main() (custom or default)

    • Substitutes {{VERSION_STRING}} (the -v line), {{LILUSH_VERSION}} (exposed to Lua as the LILUSH_VERSION global), and {{APP_NAME}}

  6. Build static libraryar rcs all .o files into liblilush.a

  7. Link binaryclang with static linking against LuaJIT and liblilush.a

The output is written to /build/<binary> inside the Docker container.

Docker

Dockerfile accepts a single build arg APP (the app name). It installs the Alpine build toolchain, compiles LuaJIT from source, copies src/ and buildgen/ into the container, and runs generate.lua apps/${APP}.lua.

build.bash builds the Docker image, copies the binary out, and cleans up the container.

Build dependencies

Provided by the Docker image (Alpine):

Built from source inside Docker:

Cryptographic primitives are provided by LITLS (src/litls/), which ships in-tree and requires no external library installation.