Packages¶
A package is one buildable unit. Chariot builds it in an isolated container, captures what the
install script writes, and turns that into a binary package other builds can depend on.
Tools vs packages¶
Every declaration says where the software it produces is meant to run:
- A
Toolproduces software that runs on your machine, so that other builds can use it. A cross compiler, an assembler or a code generator are tools. - A
Packageproduces software that runs on the system you are building, and ends up in it.
Both are built the same way, in the same kind of container on your machine. The difference is who
the result is for, which is why a cross compiler is a Tool while the C library it targets is a
Package. Two things follow from that distinction:
- How they are built. A tool is built for the architecture Chariot itself runs on. A package is
built for the
--archarchitecture, usingtarget_prefixas its install prefix. Scripts see both asARCHandPREFIX. - What depending on them means. A tool you depend on becomes available to run during your build. A target package you depend on is installed into the sysroot, so you can compile and link against it.
Names are unique per flavour, so a host gcc and a target gcc can coexist. On the command line,
tools are selected with --tool.
Fields¶
local coreutils = Package {
name = "coreutils",
version = "9.5",
revision = 1,
source = coreutils_source,
dependencies = {
"build-essential",
gcc_tool,
mlibc,
},
runtime_dependencies = { mlibc },
env = {
CFLAGS = "-O2 -pipe",
},
configure = [[
"${SOURCE_DIR}"/configure \
--host="${ARCH}-chariot" \
--prefix="${PREFIX}" \
--with-sysroot="${SYSROOT_DIR}"
]],
build = [[
make -j"${PARALLELISM}"
]],
install = [[
DESTDIR="${INSTALL_DIR}" make install
]],
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Package name. Must not contain whitespace. |
version |
string | yes | Upstream version. Must not contain whitespace, - or _. |
revision |
number | yes | Packaging revision, starting at 1. See below. |
source |
source reference | no | The source to build, available to scripts as SOURCE_DIR. |
dependencies |
array | no | Everything needed at build time. See Dependencies. |
runtime_dependencies |
array of package references | no | Packages required to run this one. See Runtime dependencies. |
env |
map of string to string or number | no | Extra environment variables for all of this package's scripts. |
configure |
string | no | First script. |
build |
string | no | Second script. |
install |
string | yes | Final script. Everything it writes to INSTALL_DIR becomes the package. |
Chariot does not use revision for anything itself. Rebuilds are decided by content hashing, so a
revision bump is not how you force one. It exists because it ends up in the produced package's
metadata, where the target's package manager uses it to order upgrades. That makes it worth keeping
accurate for target packages, and largely irrelevant for host tools.
Package and Tool return a reference that can be used in other declarations' dependencies and
runtime_dependencies. That is the only way to express a relationship between two packages, which
is why configs usually assign them to locals:
local mlibc = Package { name = "mlibc", ... }
local coreutils = Package { name = "coreutils", dependencies = { mlibc }, ... }
Dependencies¶
The dependencies array mixes four kinds of entry, distinguished by what you put in it:
| Entry | Kind | Effect |
|---|---|---|
"build-essential" |
Native package | Installed into the container from the rootfs distribution. |
a Tool reference |
Host tool | Built first, then made available to run during the build. |
a Package reference |
Target package | Built first, then installed into the sysroot at SYSROOT_DIR. |
a Source reference |
Source | Fetched and made available read-only under SOURCES_DIR. |
dependencies = {
"build-essential", "texinfo", -- from the rootfs
binutils_tool, gcc_tool, -- host tools, available to run
mlibc, -- target package, lands in the sysroot
gnulib_source, -- extra source tree
}
Native packages come from the rootfs distribution and are the one dependency kind
Chariot does not build. Declaring them per package, rather than installing them into the rootfs
once, means each build only sees the native tooling it actually asked for. Packages that every
build needs belong in global_native_packages instead.
Runtime dependencies¶
runtime_dependencies are written into the produced package's metadata as
<name> >= <version>_<revision> so the target's package manager can resolve them at install time.
They must be the same flavour as the package declaring them, so a Tool cannot have a target
Package as a runtime dependency.
They are not build inputs, but they do travel with the packages that declare them: when a build depends on package A, A's runtime dependencies are installed into the sysroot alongside it. So if A has a runtime dependency on B, a package depending on A gets both.
A library you both link against and ship a dependency on belongs in both lists:
Build lifecycle¶
Building a package happens in five stages:
- Native package set. The project's
global_native_packagesplus this package's native dependencies are assembled into the environment. - Dependencies. Host tools and target packages are built if needed, then installed: tools so they can run, packages into a fresh sysroot. Sources are made available read-only.
- Build directory. A directory for the build is prepared and exposed as
BUILD_DIR. It starts empty unless build directory caching is enabled for the package. - Scripts.
configure,buildandinstallrun in that order, each starting inBUILD_DIR. A non-zero exit stops the build and prints the captured log. - Packaging. Everything the
installscript wrote toINSTALL_DIRis packaged, with the name, version, revision, architecture and runtime dependencies attached as metadata.
Stages 1 to 4 are keyed on the package's content hash and stage 5 on its metadata hash, so changing
only version or revision repackages without rebuilding. See Caching.
Building and installing¶
$ chariot build --arch x86_64 coreutils # target package
$ chariot build --arch x86_64 --tool nasm # host tool
$ chariot install --arch x86_64 coreutils /mnt # build and install into /mnt
$ chariot lookup --arch x86_64 coreutils # where is the built package?
build stops after producing the package. install additionally unpacks it into a directory of
your choice, which is how a full system image gets assembled. Multiple packages can be given at
once, and --keep-going keeps building unrelated packages after a failure instead of stopping at
the first one.
To debug a build, chariot exec --build-env <package> drops you into the exact environment that
package builds in. See the CLI reference.