Building and Running
This page gets you from a clean clone to a running SaltyOS instance.
SaltyOS requires a custom-patched toolchain (LLVM/Clang/LLD + Rust) that knows the x86_64-unknown-saltyos and aarch64-unknown-saltyos target triples. Vanilla Rust and Clang from your package manager will not work for userland. The kernel itself uses Rust nightly with custom JSON target specs, but userland programs need the patched rustc with the SaltyOS targets built in.
|
Prerequisites
| Tool | Why |
|---|---|
Rust nightly + |
Kernel cross-compiles |
Clang |
C code (bootloader, basaltc). GCC will not work — the build system enforces Clang. |
NASM |
x86_64 bootloader assembly. |
Meson (>= 1.1) + Ninja |
Build system. SaltyOS does not use Cargo. |
Python 3 |
Build scripts ( |
CMake |
Required for building the LLVM/Clang toolchain from source. |
QEMU or UTM |
|
Quick Start: just bootstrap
The fastest path from zero to a fully working system is the 4-stage bootstrap:
# Clone with submodules (includes patched LLVM and Rust sources)
git clone --recursive https://github.com/SaltyOS/saltyos.git
cd saltyos
# Full 4-stage bootstrap (builds EVERYTHING from scratch)
just bootstrap
This takes approximately 2 hours and builds:
| Stage | Time | What it does |
|---|---|---|
0 |
~50 min |
Build the custom toolchain: patched LLVM/Clang/LLD + patched |
1 |
~15 min |
Build the OS for both x86_64 and aarch64 (kernel, userland, initrd, disk image). |
2 |
~15 min |
Build host Rust stdlib + cargo, then cross-compile std for SaltyOS targets. |
3 |
~30 min |
Rebuild with ports enabled (bash, FreeBSD utilities, nano, etc.). |
If a stage fails, you can resume from that stage:
just bootstrap --from=2 # Skip stages 0-1, resume from stage 2
After bootstrap completes:
just run # Boot x86_64 in QEMU
just arch=aarch64 run # Boot aarch64 in QEMU
just run --utm # Boot in UTM on macOS
Custom Toolchain
Why a Custom Toolchain?
Vanilla Rust and Clang do not know about the SaltyOS target triples (x86_64-unknown-saltyos, aarch64-unknown-saltyos).
The custom toolchain adds:
-
Target triple definitions for SaltyOS in both LLVM and Rust.
-
Compiler-RT builtins for SaltyOS targets.
-
Knowledge of the SaltyOS C library (basaltc) for linking.
Toolchain Sources
The patched sources live in git submodules:
-
toolchain/llvm-project/— patched LLVM, Clang, LLD -
toolchain/rust/— patched Rust compiler
Manual Toolchain Build
If you want to build just the toolchain without the full bootstrap:
just tc setup # Create build directories
just tc build host llvm # Build Clang/LLD (~30 min)
just tc build host rust # Build rustc (~20 min)
just tc doctor # Validate the installation
# Or all at once:
just tc all # setup → llvm → rust → doctor
Activate the Toolchain
eval "$(just toolchain-env)"
# Or:
source tools/toolchain/env.sh
This puts the custom clang, rustc, lld, etc. on your PATH.
Toolchain Output
Everything goes into build-toolchain/prefix/bin/:
build-toolchain/prefix/bin/ clang # Patched Clang (knows SaltyOS targets) clang++ rustc # Patched rustc (stage1, knows SaltyOS targets) lld # Linker llvm-ar # Archiver llvm-strip # Strip tool llvm-objcopy # Object copy cargo # (after stage 2)
Build Commands
| Command | What it does |
|---|---|
|
Full 4-stage build from scratch (toolchain + OS + std + ports). |
|
Resume bootstrap from stage N (0=toolchain, 1=OS, 2=std, 3=ports). |
|
Build only the host toolchain (LLVM + Rust + validation). |
|
Configure the Meson build for x86_64 (run once, or after adding new source files). |
|
Build kernel, userland, initrd, and disk image. |
|
Build + launch QEMU. |
|
Quick rebuild + run. |
|
Remove all build directories. Required before re-setup. |
|
Format Rust and C code. |
|
Check formatting without modifying files. |
Running in QEMU
just run # x86_64, BIOS, 1 CPU
just run --smp 2 # 2 CPU cores (test SMP)
just run --smp 4 # 4 CPU cores (stress test)
just run --uefi # x86_64 with UEFI firmware
just run --gdb # QEMU with GDB server (-s -S)
just run --debug # Interrupt/reset logging → qemu.log
just run --headless # Serial only, no GUI window
# Combine flags:
just run --smp 4 --uefi --headless --debug
Running in UTM (macOS)
If you are on macOS and prefer UTM over QEMU, SaltyOS has built-in UTM integration:
just run --utm # Build + create UTM VM + boot
just arch=aarch64 run --utm # aarch64 in UTM
This:
-
Finds
UTM.app(in/Applications/or~/Applications/). -
Creates a
.utmbundle in the build directory with a generatedconfig.plist. -
Registers the VM with UTM via AppleScript.
-
Starts the VM and connects your terminal to the serial console.
UTM Options
just run --utm --smp 4 # Multi-core
just run --utm --no-hvf # Disable Hypervisor.framework (use TCG emulation)
UTM uses Hypervisor.framework (HVF) by default for near-native performance on Apple Silicon.
Use --no-hvf if you encounter HVF-related issues.
Manual UTM Setup
If you prefer to configure UTM manually:
-
Build the disk image:
just build -
Open UTM and create a new VM.
-
Set architecture to x86_64 or aarch64.
-
Add a VirtIO block device pointing to
build-x86_64/saltyos.img(orbuild-aarch64/saltyos-uefi.img). -
For aarch64: set UEFI firmware to the AAVMF image.
-
Add a serial port (TCP or Pty) and connect your terminal to it.
Building for aarch64
The arch variable controls the target for all recipes:
just arch=aarch64 setup
just arch=aarch64 build
just arch=aarch64 run # aarch64 forces UEFI automatically
just arch=aarch64 run --utm # aarch64 in UTM
Build directories are architecture-qualified (build-x86_64, build-aarch64), so both can coexist on disk.
aarch64 is UEFI-only. There is no BIOS bootloader for aarch64. QEMU uses virt,gic-version=3 machine with Cortex-A72 CPU.
|
Self-Hosting Toolchain (Advanced)
SaltyOS can cross-compile its own toolchain to run ON SaltyOS:
just sysroot # Generate cross-compilation sysroot
just tc build cross llvm # Cross-compile Clang/LLD for SaltyOS
just tc build cross rust # Cross-compile rustc for SaltyOS
just tc package # Package for inclusion in rootfs
# Or all at once:
just self-host # Full pipeline
What Happens When You Run
-
QEMU (or UTM) loads the disk image containing the 3-stage bootloader, kernel, and initrd.
-
The bootloader loads
kernel.elfandinitrd.cpio, builds a boot info block, and jumps to the kernel. -
The kernel initializes: paging, capabilities, IPC, scheduler.
-
The init task is created from the initrd and dispatched.
-
Init reads
.servicefiles and starts servers in dependency order: mmsrv, procmgr, namesrv, vfs, console, etc. -
The test runner (or shell) starts.
Reading Serial Output
All kernel and userland output goes to the serial port (QEMU: stdio, UTM: TCP connection).
Key prefixes:
-
[FRAME]— PMM initialization (frame count, free count). -
[CAP]— Capability system initialization (slot count). -
[SCHED]— Scheduler bringing CPUs online. -
[INIT]— Init task loading servers. -
PASS/FAIL— Test runner results. -
KERNEL PANIC— Something went wrong. Includes source file and line number.
No Cargo
SaltyOS does not use Cargo for building. All Rust code is compiled via Meson with direct rustc invocation.
-
No
Cargo.tomlfiles.cargo buildandcargo testdo not work. -
Rust compiler flags live in
meson.buildfiles. -
Adding new
.rssource files requiresjust distclean && just setup && just build(Meson discovers files at setup time).
Troubleshooting
"unknown target triple 'x86_64-unknown-saltyos'"
You are using vanilla Rust or Clang instead of the custom toolchain. Build the toolchain first:
just tc all
eval "$(just toolchain-env)"
Build fails with "gcc" error
SaltyOS requires Clang:
export CC=clang
just distclean && just setup && just build
QEMU hangs at boot
just run --debug # Creates qemu.log with interrupt/reset trace
just run --gdb # Then: gdb -ex "target remote :1234"
What to Read Next
-
First Contribution — make your first change to the kernel.
-
What Is a Microkernel? — if you have not read the conceptual guides yet.
-
Architecture — the full technical module map.