Getting started

Building and testing

How the build is put together, how to run the tests, and every recipe in the justfile.

This page shows you how to build SlopOS, where the results go, and how to run the test suite and read what it tells you. It ends with every recipe the repository has. It assumes you have run just setup from the Quickstart.

How the build fits together

Every command goes through just, a command runner. The file justfile at the root of the repository defines named recipes, and just <recipe> runs one. just --list prints them all with a line on each.

A bootable SlopOS is made of three things, built in this order:

  1. The programs. The shell, the desktop, the coreutils and everything else that runs on SlopOS, compiled for SlopOS with the slopos Rust toolchain.
  2. A disk image holding those programs: a file containing an ext4 filesystem, the same format Linux uses, which QEMU presents to the virtual machine as a disk.
  3. The kernel, one ELF file.

The boot recipes then wrap the kernel and its programs into something firmware can start: a CD image (ISO) for the live system, or a boot disk for the development machine. You rarely run the steps by hand, because each boot and test recipe builds what it needs first.

CommandWhat it produces
just buildThe programs, the disk image fs/assets/ext2.img and the kernel builddir/kernel-dev.elf
just isoThe live ISO builddir/slop.iso: kernel plus a RAM disk of programs (builddir/initramfs.cpio)
just boot-liveBuilds the ISO, then boots it
just bootThe optimised kernel builddir/kernel-release.elf, the boot disk builddir/boot-disk.img and the persistent root fs/assets/ext2-persist.img, then boots them
just testThe tests kernel builddir/kernel-tests.elf, builddir/slop-tests.iso and the test root fs/assets/ext2-tests.img, then runs them

Image files are still called ext2 for historical reasons; every image the build makes is ext4. Compiler output goes under builddir/target, and downloaded inputs (the Limine bootloader, the OVMF firmware, LLVM sources) are cached under third_party/.

Every kernel build ends by running checks on the finished ELF (for example, that no function's stack frame is too large), so a build can still fail after the compiler has succeeded. Safety gates lists them.

Optimised and debug kernels

The dev kernel is built quickly, with symbols, and is what just build, just boot-live and the debugger recipes use. The release kernel is optimised, and just boot uses it because the development machine runs a compiler. KERNEL_RELEASE=1 selects the release kernel for any recipe, and KERNEL_RELEASE=0 just boot boots the dev kernel instead.

Passing options to a recipe

Settings such as ROULETTE=0 (skip the Wheel of Fate), DEBUG=1 (more kernel logging) and VIDEO=0 (no window) are environment variables, so they go before just:

ROULETTE=0 DEBUG=1 just boot

A recipe's own arguments go after its name and are positional. Write just test 'slopos_mm::*', not just test FILTER='slopos_mm::*': the second form passes the text FILTER=slopos_mm::* as the filter, which matches nothing. One setting, ports, is a justfile variable and goes between just and the recipe:

just ports=7777,8080 boot

QEMU options lists every environment variable the boot recipes read.

Run the tests

1. Run the whole suite

just test

This builds a kernel with the test harness compiled in, boots it in QEMU with no window, and runs every kernel test and then every userland test. A progress bar shows how far it is. When QEMU exits, the runner prints a summary and exits 0 if every test passed and 1 otherwise. Each run starts from a freshly built test disk, so no run depends on what the last one wrote.

2. Read a failure

For each failing test the runner prints its name (<module>::<test>) and the kernel log lines the test produced while it ran, which is usually where the reason is. Passing tests' logs are hidden; just test-verbose shows them too.

After every run that finished, the names of the failed tests are in builddir/last-fail.list, and this reruns only those:

just test-rerun-failed

If the summary looks wrong, just test-raw prints exactly what came out of the virtual machine's serial port: the test results in KTAP, the plain-text format Linux's kernel tests use, mixed with the kernel log. Test output format describes it.

3. Run some of the tests

Pass a glob, a pattern where * matches anything, as the first argument. It is matched against each test's <module>::<test> name. Separate several globs with commas:

just test 'slopos_mm::*'
just test '*ext2_aaa*,slopos_fs::*'

A filtered run whose tests create files must include '*ext2_aaa*'. That test mounts the test disk, and tests run in alphabetical order, so it is what makes the disk available to the tests after it.

just test-verbose and just test-quiet take the same glob.

Tests that run on your machine

just test-host

This runs the unit tests of the parts of SlopOS that are plain logic (the filesystem, network and TLS cores, the terminal, the shell and others) as ordinary programs on your machine, with no QEMU. It is the fastest way to check a change to one of those parts. Write tests explains where a new test belongs.

What usually goes wrong

  • just test stops before booting with a message about LLVM: the test image includes a C++ runtime built with LLVM 18 or later, and your machine has none it can use. See Troubleshooting.
  • A filtered run fails on file operations: add '*ext2_aaa*' to the filter.
  • just check or a framekernel gate complains that the kernel ELF is missing: run just build first.

All recipes

The justfile is the authoritative list; just --list prints it with each recipe's own description.

Setup and build

RecipeWhat it does
just setupInstall the pinned Rust nightly, build the slopos toolchain, check Go 1.22 or later, fetch the Go modules, validate the workspace
just buildBuild the programs, fs/assets/ext2.img and builddir/kernel-dev.elf
just build-kernel-onlyBuild the kernel ELF without the programs or the image
just isoBuild builddir/slop.iso with BOOT_CMDLINE as its kernel command line
just cleanRemove compiler output under builddir/target and the builddir/kernel-*.elf files
just distcleanclean, then remove builddir/, the ISOs, fs/assets/ext2.img, fs/assets/ext2-tests.img, test_output.log and the extracted rustc, llvm-project and vendored-crate trees under third_party/. Leaves the persistent root alone

Boot

RecipeWhat it does
just bootThe development machine: release kernel on an A/B boot disk, persistent root, 4 GB of memory, Wheel of Fate first
just boot-fastjust boot with ROULETTE=0
just boot-debugjust boot-fast on the dev kernel with QEMU's GDB stub on port 1234 and a monitor socket
just boot-liveThe live ISO from memory, no disk; Wheel of Fate unless ROULETTE=0
just boot-logThe live ISO with no window for BOOT_LOG_TIMEOUT seconds (default 15), log in test_output.log; fails unless /sbin/init started
just show-qemu-resolutionPrint the screen size the QEMU wrapper would detect

boot-fast and boot-debug start just boot again inside themselves, and a ports= setting does not reach that inner run. To forward ports without the wheel, use ROULETTE=0 just ports=7777 boot.

Persistent root

RecipeWhat it does
just reset rootDelete fs/assets/ext2-persist.img and its side files, so the next just boot builds a fresh root with a new clone of HEAD. What the guest wrote and did not push is lost; fs/assets/guest-push.git is kept
just export-file PATH=<guest path> OUT=<host path> [IMAGE=<image>]Copy one file off the persistent root (or another image) after the guest has shut down

just boot rebuilds builddir/boot-disk.img on every run, so a kernel the guest installed survives guest reboots but not the next just boot. Installing a system covers boot slots.

Tests

RecipeWhat it does
just test ['glob']Build and run the QEMU test suite, or the tests matching the glob
just test-rerun-failedRerun the tests listed in builddir/last-fail.list
just test-verbose ['glob']Also print the kernel log of every passing test
just test-quiet ['glob']Print only failures and the summary
just test-rawPass QEMU's output through unchanged, KTAP and kernel log mixed
just test-json <path>Also append one JSON event per line to <path>
just test-userland-onlySkip the kernel tests; run only the userland tests
just test-elf [ELF=]<kernel> [BASE=<base.cpio>] ['glob']Run the suite on a tests kernel built elsewhere, such as inside the guest
just test-hostUnit tests of the pure-logic crates and of slopos-ostd, on the host, no QEMU
just check-tests-hostUnit tests of the Go test runner
just check-test-countFail if just test plans fewer tests than TEST_COUNT_BASELINE
just test-persistTwo boots of one image: write and fsync, power off, boot again and read it back
just test-rude-exitA boot commits a file to the root's journal and dies holding it; the host's e2fsck must replay it
just test-capacityMount and write a 16 GiB volume (built once, then kept), and grade the cost
just test-installOn one disk laid out as on a real machine: register SlopOS's firmware boot entry, install a kernel into a boot slot, try it, commit it, roll back a slot that panics, and check the EFI system partition was left unchanged
just test-install-guestThe guest builds a kernel from HEAD, installs it into slot b and boots it, then commits the slot and rolls back a slot that panics
just test-toolchainRun the toolchain checks on the self-hosting root
just test-selfhostThe guest builds the dev and tests systems; the host checks the result and runs the suite on the guest's kernel
just bench-selfhostTime the guest's kernel build and summarise it in builddir/bench-selfhost.log

Filesystem and boot-log checks

RecipeWhat it does
just check-fs-image [image]Hold an image to e2fsck -fn and to being at rest: clean, nothing to replay
just check-fs-throughputFail if a write costs more transactions or device requests per MiB than recorded
just check-quota-headroomFail if a resource account nears its cap or anything was denied
just check-lockdep-headroomFail unless the lock-order checker booted active with room in its pools
just check-sched-spreadFail unless every online CPU can be given tasks

Verification and code rules

RecipeWhat it does
just fmtCheck formatting (cargo fmt --all -- --check)
just checkAllocation and stack-frame checks on builddir/kernel-dev.elf
just check-return-typesSlow audit of kernel functions that return large values; not part of check
just stack-auditList kernel functions whose stack frame exceeds the 32 KiB task-stack budget
just check-framekernel-gatesThe framekernel gate scripts alone (needs just build)
just check-framekernelEvery gate plus fmt, Miri and Verus (needs just build)
just check-no-kernel-asyncFail on any async fn in a kernel crate
just check-miriRun the slopos-ostd tests under Miri, with Stacked and Tree Borrows
just ensure-verusDownload the pinned Verus toolchain into third_party/verus
just verify ['stem']Check every proof under verification/proofs/, or the one named
just tcb-ratioPrint unsafe lines in slopos-ostd over all kernel Rust lines
just check-toolchain-coverageCheck every codegen backend and linker against what the target needs

The framekernel explains what the gates protect.

Debugging

RecipeWhat it does
just debug-gdbInteractive GDB attached to a kernel started by just boot-debug
just debug-btBacktraces of every CPU into builddir/freeze-gdb.log
just debug-monitorConnect to the QEMU monitor socket
just rr-recordRecord a deterministic test run to builddir/replay.bin (one CPU, no KVM)
just rr-replayReplay the recording under interactive GDB
just rr-gdb [<address>]Run the replay to the fault; with an address, find the instruction that last wrote it

Debugging with GDB shows how to use them.

Toolchain for SlopOS

RecipeWhat it does
just vendorDownload every crates.io package the build needs into third_party/vendor
just check-offline-buildCheck that the tree builds with no registry access
just rustc-srcUnpack the pinned rustc sources with the SlopOS target patch
just llvm-srcUnpack the pinned llvm-project sources with the SlopOS port
just toolchain [--pgo]Cross-build the Rust toolchain that runs on SlopOS (hours of CPU)
just toolchain-profileGather the profiles just toolchain --pgo uses
just recipes [names]Build zlib, curl, git and the other C libraries and tools for SlopOS
just check-bootstrap-configCheck the cross-build plan against the toolchain it claims to produce
just check-rustc-targetCheck rustc's built-in SlopOS target against targets/x86_64-unknown-slopos.json
just check-llvm-portCompile LLVM's Support library for SlopOS
just check-clang-driverCheck the port's clang link line against the userland build's

Toolchain explains how these fit together.

On this page