Configuration¶
A Chariot project has three files of interest:
| File | Purpose | Committed? |
|---|---|---|
chariot_config.toml |
Global project settings: the rootfs, the target prefix, global environment. | Yes |
chariot.lua |
The sources, tools and packages the project builds. | Yes |
.chariot.toml |
Per developer settings: source overrides, build directory caching. Optional. | No |
A minimal project looks like this:
my-distro/
├── chariot_config.toml
├── chariot.lua
├── .chariot.toml # optional, personal
├── .chariot-cache/ # created by chariot
└── .chariot-rootfs/ # created by chariot
Both directories Chariot creates gitignore themselves, so they are safe to leave inside a repository.
Project root¶
The directory containing chariot_config.toml is the project root. Everything resolved from the
config is resolved against it: the Lua entry file, require paths, patch files and the paths passed
to chariot.read_file and chariot.list_dir.
Those paths can never escape the project root. Leading / and ./ components are ignored when
joining, so /etc/passwd is read as <project root>/etc/passwd.
Chariot does not care what your working directory is as long as it can find the base config, so
--base-config ../my-distro/chariot_config.toml works from anywhere.
chariot_config.toml¶
The base config. Only [rootfs] is required.
lua_root = "chariot.lua"
target_prefix = "/usr"
global_native_packages = ["build-essential"]
[global_environment_variables]
LC_ALL = "C"
[rootfs]
version = "debian/20260901T000000Z"
hash = "7a9147a2fce8ac2bae29fcde0b822ce613ffc73b66acf080c70301f386afee81"
| Key | Type | Default | Description |
|---|---|---|---|
lua_root |
string, a path | chariot.lua |
The Lua file Chariot evaluates first, relative to the project root. |
target_prefix |
string | /usr |
Install prefix for target packages, exposed to their scripts as PREFIX. |
global_native_packages |
array of strings | empty | Native rootfs packages installed into every build environment, on top of each package's own dependencies. |
global_environment_variables |
map of string to string | empty | Environment variables exported into every script. |
rootfs.version |
string | required | Manifest version to use, for example debian/20260901T000000Z. |
rootfs.hash |
string | required | SHA-256 of the manifest. Chariot refuses to use a manifest that does not match. |
rootfs.url |
string | CDN default | Manifest URL template, must contain @ARCH@ and @VERSION@. See Root Filesystem. |
Warning
target_prefix, global_native_packages and global_environment_variables are part of every
package's content hash. Changing any of them invalidates the whole project and rebuilds
everything.
chariot.lua¶
The Lua entry file declares what the project builds. The full API is covered in Sources and Packages; this section covers the environment the script itself runs in.
Splitting the config up¶
require is available and resolves module paths against the project root, so a config can be split
across as many files and directories as you like:
Available Lua standard library¶
The config runs in a restricted Lua interpreter. math, string, table, package and the basic
functions are available. io, os, debug, coroutine and utf8 are not. A config cannot
read the outside world except through the chariot API below, which keeps config evaluation
reproducible.
The chariot table¶
| Member | Description |
|---|---|
chariot.target_arch |
The architecture passed via --arch. |
chariot.target_prefix |
The effective target_prefix. |
chariot.options |
Table of user options passed via -o KEY=VALUE, as strings. |
chariot.read_file(path) |
Read a file from the project root and return its contents as a string. |
chariot.list_dir(path) |
List a directory in the project root, returning { filename = string, is_dir = boolean } entries. |
chariot.concat_paths(a, b) |
Join two path strings. |
chariot.def_source(...) |
Low level source registration. Prefer Source. |
chariot.def_package(...) |
Low level package registration. Prefer Package and Tool. |
Convenience helpers¶
Chariot adds a few helpers on top of stock Lua:
| Helper | Description |
|---|---|
Path(a, b, ...) |
Join any number of path segments. |
string.starts_with(s, prefix) |
Returns true if s starts with prefix. |
string.ends_with(s, suffix) |
Returns true if s ends with suffix. |
string.split(s, separator) |
Split into an array of strings. separator defaults to whitespace. |
table.merge(t1, t2) |
Shallow merge, t2 wins on collisions. |
table.print(t) |
Print key=value for each entry, useful while debugging a config. |
Example of picking up every package directory automatically:
for _, entry in ipairs(chariot.list_dir("packages")) do
if entry.is_dir then
require("packages." .. entry.filename)
end
end
Options and profiles¶
Options are string key/value pairs you pass on the command line and read from the config:
A profile is one permutation of target architecture and options. Because options can change what
the config declares, each profile is a different build. Chariot records the profiles it has seen so
that chariot cache gc knows which results are still reachable.
The first time it encounters a new profile it asks for confirmation:
Detected a new profile (profile describes a specific permutation of architecture and options). Proceed?
This exists to catch mistakes like -o debgu=true, which would otherwise silently build a whole
second distribution. In CI, pass --allow-new-profiles to accept without prompting.
Options are not automatically visible to build scripts. To use one inside a script, pass it through
the package's env:
.chariot.toml¶
The local config holds settings that belong to a developer rather than to the project. It is
optional, read from .chariot.toml in the working directory by default, and should not be
committed.
disable_pruning = false
[pkgs.my-kernel]
enable_build_cache = true
[tools.gcc]
enable_build_cache = true
[source_overrides]
my-kernel = "../my-kernel"
mlibc = { path = "../mlibc", patch = true, prepare = true }
| Key | Type | Default | Description |
|---|---|---|---|
disable_pruning |
bool | false |
Skip the automatic store, ledger and build directory pruning that runs after build and install. |
pkgs.<name>.enable_build_cache |
bool | false |
Keep the build directory of a target package between builds instead of wiping it. See Caching. |
tools.<name>.enable_build_cache |
bool | false |
Same, for a host tool. |
source_overrides.<name> |
string, a path | Replace the source named <name> with a local directory. Shorthand for { path = "..." }. |
|
source_overrides.<name>.path |
string, a path | The local directory to use instead of the declared source. | |
source_overrides.<name>.patch |
bool | false |
Still apply the source's declared patches to the override. |
source_overrides.<name>.prepare |
bool | false |
Still run the source's prepare script on the override. |
Note
Source overrides are the main tool for working on a component: point one at your checkout and Chariot builds from it, hashing the directory contents so edits are picked up automatically. See Sources.
JSON instead of TOML¶
If you generate the local config from a script, JSON may be easier to produce:
This changes the default path to .chariot.json. --local-config <path> overrides the path
regardless of format.