The foundation layer for your Lua environment.
Like the regolith that blankets the Moon's surface, this project is the loose but essential layer everything else sits on.
lua-regolith builds a self-contained, relocatable Lua 5.4 installation — no system packages required. Use it to:
- Run Lmod on HPC clusters, containers, or any system where you control the software stack.
- Create standalone executables with luastatic.
- Embed a batteries-included Lua interpreter in your own projects.
Lmod's SourceForge tarball bundles its Lua dependencies for Lua 5.1. If you want to run Lmod on Lua 5.4+, you need to provide those dependencies yourself — luaposix, luafilesystem, lpeg, dkjson, and lua-term — compiled against the same interpreter and installed where it can find them.
lua-regolith does exactly that: one make install gives you a Lua
interpreter with hardcoded package paths pointing at all the bundled modules.
No LUA_PATH or LUA_CPATH juggling, no version mismatches, no chasing
down five separate build systems.
Developers benefit too: every C module is also installed as a static library
(.a), so you can link them into standalone binaries with luastatic or
embed them in your own C/C++ application.
- Quick Start
- For Lmod Users
- For Developers
- Bundled Modules
- Build Guide
- Version Resilience
- License
- Contributing
git clone https://github.com/JBlaschke/lua-regolith.git
cd lua-regolith
make download
make PREFIX=/opt/lua-regolith all
make PREFIX=/opt/lua-regolith test
make PREFIX=/opt/lua-regolith installThis downloads all sources, builds everything, runs the test suite, and
installs to PREFIX. See Build Guide for requirements and
options.
No cmake? Use
make -f Makefile.liteinstead — it needs onlycc,make, andwget. See Makefile vs Makefile.lite.
Once lua-regolith is installed, point Lmod's configure at it:
git clone https://github.com/TACC/Lmod.git
cd Lmod
./configure --prefix=/opt/lmod \
--with-lua=/opt/lua-regolith/bin/lua \
--with-luac=/opt/lua-regolith/bin/luac
make installLmod's configure will detect luaposix, lfs, lpeg, dkjson, and lua-term
from the bundled interpreter's hardcoded package paths. No LUA_PATH or
LUA_CPATH environment variables needed.
To activate:
source /opt/lmod/lmod/lmod/init/bash # or .csh, .zsh, .fish
module availThings to know:
- Lmod hardcodes
LUA_PATH/LUA_CPATHat configure time to protect itself from user environment changes. Your lua-regolith prefix must be final before you./configureLmod. - luafilesystem is a hard Lmod requirement. Without it, spider cache generation and many internal operations fail immediately.
- lua-term isn't strictly required, but without it
module availoutput defaults to 80 columns regardless of terminal width. - lpeg and dkjson are used by various Lmod internals. They're small and easy to include, so there's no good reason to skip them.
$PREFIX/
├── bin/
│ ├── lua # interpreter (paths hardcoded to $PREFIX)
│ ├── luac # compiler
│ └── lua-static # (optional) fully static interpreter
├── include/
│ ├── lua.h, luaconf.h, lualib.h, lauxlib.h
│ └── luv.h
├── lib/
│ ├── liblua.a ─┐
│ ├── liblua.so │
│ ├── libluaposix.a │ static + shared libs
│ ├── libluv.a │ for luastatic / linking
│ ├── libluv.so │
│ ├── libluv_libuv.a │
│ ├── liblfs.a │
│ ├── liblpeg.a │
│ ├── static-lua.a │
│ ├── static-lua.o │
│ ├── libluaterm.a ─┘
│ ├── lua/5.4/
│ │ ├── posix.so ─┐
│ │ ├── posix/ │ shared modules loaded by
│ │ │ └── sys/ │ the interpreter at runtime
│ │ ├── luv.so │
│ │ ├── lfs.so │
│ │ ├── lpeg.so │
│ │ └── term/ │
│ │ └── core.so ─┘
│ └── pkgconfig/
│ └── lua5.4.pc
└── share/lua/5.4/
├── posix/ # pure-Lua parts of luaposix
├── term/ # init.lua, cursor.lua, colors.lua
├── re.lua # regex module built on lpeg
└── dkjson.lua # JSON library
luastatic main.lua \
/opt/lua-regolith/lib/liblua.a \
/opt/lua-regolith/lib/libluaposix.a \
/opt/lua-regolith/lib/liblfs.a \
/opt/lua-regolith/lib/liblpeg.a \
/opt/lua-regolith/lib/libluaterm.a \
/opt/lua-regolith/lib/libluv.a \
/opt/lua-regolith/lib/libluv_libuv.a \
-I/opt/lua-regolith/include \
-lpthread -lm -ldlInclude only the .a files for modules your script actually uses.
Tip
Build the static-lua target, this will generate a static-lua.a fat
archive containing all the libraries above.
If you build the fully static interpreter, then the static-lua.a archive is
created for convenience. It contains all components used for the static
interpreter (below). This simplifies the luastatic command:
luastatic main.lua \
/opt/lua-regolith/lib/static-lua.a \
-I/opt/lua-regolith/include \
-lpthread -lm -ldl
Note
In some cases the far archive won't get properly linked -- requiring extra
arguments (e.g. luastatic main.lua ... -Wl,-force_load,/opt/lua-regolith/lib/static-lua.a ...
on mac os; or luastatic main.lua ... -Wl,--whole-archive /opt/lua-regolith/lib/static-lua.a -Wl,--no-whole-archive ...
on linux -- to help with those cases, we provide a "raw" relocatable object:
static-lua.o
make PREFIX=/opt/lua-regolith static-lua
make PREFIX=/opt/lua-regolith installProduces $PREFIX/bin/lua-static — the real lua.c interpreter (readline,
-e, -l, -i, full REPL) with all C modules registered in
package.preload. The pure-Lua modules (dkjson, term/.lua, re.lua,
posix/.lua) still need to be on LUA_PATH or baked in via luastatic.
Platform notes:
- Linux (glibc):
-staticworks; NSS caveats apply. For clean static builds, build on Alpine (musl). - macOS: Can't fully static-link; dynamically links libSystem.
| Module | Type | Purpose |
|---|---|---|
| luaposix | C + Lua | POSIX bindings (required by Lmod) |
| luv | C (cmake) | libuv bindings for async I/O |
| lfs | C (1 file) | Filesystem operations (required by Lmod) |
| lpeg | C | PEG parsing library (used by Lmod) |
| lua-term | C + Lua | Terminal detection (used by Lmod for width) |
| dkjson | pure Lua | JSON encode/decode (used by Lmod) |
The re.lua module ships with lpeg and provides a regex-like interface on
top of PEG patterns. It's installed automatically.
Makefile (full):
- GCC or Clang (C99), GNU Make, CMake ≥ 3.10, wget
- libreadline-dev, python3
- POSIX system (Linux, macOS, *BSD)
Makefile.lite (minimal):
- GCC or Clang (C99), GNU Make, wget
- libreadline-dev
- Linux, macOS, or FreeBSD
# Debian/Ubuntu (full)
sudo apt install build-essential cmake wget libreadline-dev python3
# Debian/Ubuntu (lite — no cmake or python3)
sudo apt install build-essential wget libreadline-dev
# Alpine (for fully static builds)
apk add build-base cmake wget readline-dev readline-static linux-headers python3If cmake isn't available (minimal HPC nodes, containers, locked-down
environments), use Makefile.lite:
make -f Makefile.lite download
make -f Makefile.lite PREFIX=/opt/lua-regolith all
make -f Makefile.lite PREFIX=/opt/lua-regolith test
make -f Makefile.lite PREFIX=/opt/lua-regolith installBoth Makefiles produce identical install layouts and are
interchangeable — make test validates the same things either way.
Makefile |
Makefile.lite |
|
|---|---|---|
| Build deps | cc, make, cmake, python3 | cc, make |
| libuv build | cmake (auto platform detection) | Direct compilation (manual file list) |
| luv build | cmake | Direct compilation |
| linit.c patch | python3 | sed + tac |
| Platform support | Any (cmake handles it) | Linux, macOS, FreeBSD |
The tradeoff with Makefile.lite is that libuv's platform-specific source
file list is maintained in the Makefile rather than discovered by cmake.
The list is stable across libuv 1.4x releases; if you bump to libuv 2.x,
audit it against their CMakeLists.txt.
| Variable | Default | Purpose |
|---|---|---|
PREFIX |
/usr/local |
Install location |
RELOCATABLE |
0 |
1 = exe-relative package paths |
LUA_VER |
5.4.7 |
Lua version |
LUAPOSIX_VER |
36.2.1 |
luaposix version |
LUV_VER |
1.48.0-2 |
luv version |
LIBUV_VER |
1.48.0 |
libuv version |
LFS_VER |
1.9.0 |
luafilesystem version |
LPEG_VER |
1.1.0 |
lpeg version |
LUATERM_VER |
0.8 |
lua-term version |
DKJSON_VER |
2.8 |
dkjson version |
LUA_SHORT (e.g. 5.4) is derived automatically from LUA_VER — you
don't need to set it separately.
make testTests every module: luaposix (including nested posix.sys.stat), luv
(including event loop timer), lfs (dir listing, attributes), lpeg (pattern
matching), lua-term (isatty function), and dkjson (JSON roundtrip).
The Makefile is designed to survive Lua version bumps (including to 5.5)
without edits beyond changing LUA_VER. Three things that commonly break in
version-pinned build systems are handled dynamically:
1. Source file list — Instead of hardcoding the list of .c files, the
Makefile uses $(wildcard $(LUA_SRC)/*.c) and filters out lua.c and
luac.c. If Lua 5.5 adds or removes source files, they're picked up
automatically.
2. luaconf.h patching — Instead of sed-matching internal formatting
(which changes between releases), the Makefile appends #undef / #define
overrides to the end of luaconf.h. The C preprocessor uses the last
definition, so our LUA_ROOT, LUA_PATH_DEFAULT, and LUA_CPATH_DEFAULT
always win, regardless of how the stock file is formatted.
3. Static interpreter's linit.c — Instead of hardcoding the standard
library opener table (luaopen_base, luaopen_math, etc.), the Makefile
copies the real linit.c from the source tree and patches it with a small
python3 script (or sed in Makefile.lite) that inserts the
preload_bundled_modules() call before the closing brace of
luaL_openlibs. If Lua 5.5 adds a new standard library, it's included
automatically.
4. Header installation — All .h and .hpp files in src/ are
installed dynamically rather than from a hardcoded list.
What still needs manual attention when bumping to a new major Lua version: the C modules (luaposix, luv, lfs, lpeg, lua-term) must support that version's C API. Check their release notes.
lua-regolith is offered under a dual-licensing model. You may choose
one of the following licenses:
-
Open Source License: GNU Affero General Public License, version 3 or later — SPDX:
AGPL-3.0-or-laterSee:LICENSE-AGPL(and/orLICENSE) -
Commercial License: A separate commercial license is available from Johannes Blaschke without the conditions of the GNU Affero GPL. See:
COMMERCIAL.md
If you do not have a commercial license agreement with Johannes Blaschke, your use of this project is governed by the AGPL-3.0-or-later.
The bundled components have their own licenses (all permissive): Lua (MIT), luaposix (MIT), luv (Apache 2.0), libuv (MIT), luafilesystem (MIT), lpeg (MIT), lua-term (MIT), dkjson (MIT).
- The AGPL is an OSI-approved open-source license. You may use
lua-regolithcommercially under the AGPL if you comply with its terms. - If you modify
lua-regolithand run it to provide network access to users (e.g., as a service), the AGPL includes obligations related to offering the corresponding source code of the version you run. - If your organization cannot or does not want to comply with the AGPL's requirements, you can obtain a commercial license.
For commercial licensing inquiries: Johannes Blaschke, johannes@blaschke.science
We welcome contributions!
To preserve the ability to offer lua-regolith under both open-source and
commercial licenses, all contributions must be made under the Contributor
License Agreement:
- See:
CLA.md
By submitting a pull request (or otherwise contributing code), you agree that your contribution is made under the terms of the CLA.
Copyright (c) 2026 Johannes Blaschke