This guide walks through building darwinOS end-to-end on a fresh Linux or macOS host. When you’re done you’ll have a bootable kernel image and a minimal root filesystem under build/. A companion guide covers running the output in QEMU.
The build is driven by a top-level Makefile that orchestrates the per-component builds (XNU, launchd, dyld, libSystem, userland). You don’t need to understand the internals to follow this guide.
Host requirements
You need a modern Unix-like host. Both Linux and macOS are supported; Windows works through WSL2 with the Linux instructions.
Tooling:
clang17 or newermake,ninja, andcmakegit2.40+python33.10+- A working C++ toolchain (libstdc++ or libc++)
Disk space: about 8 GB for a full build, plus 4 GB for the source checkout.
RAM: 8 GB minimum; 16 GB recommended if you want to build in parallel.
On Debian/Ubuntu
sudo apt install -y \
build-essential clang lld ninja-build cmake \
git python3 python3-pip \
qemu-system-aarch64 qemu-system-x86On Fedora
sudo dnf install -y \
clang lld ninja-build cmake make \
git python3 python3-pip \
qemu-system-aarch64 qemu-system-x86On macOS
Install the Xcode command-line tools:
xcode-select --installThen install the rest via Homebrew:
brew install cmake ninja qemuCheck out the monorepo
git clone https://github.com/darwinos-io/darwinos.git
cd darwinos
git submodule update --init --recursiveThe checkout bundles every component darwinOS builds — XNU, launchd, dyld, libSystem, userland — plus the build system under glue/. Submodules track upstream Apple Open Source drops where relevant.
Configure your build
Pick a target architecture and build profile:
./configure --arch=arm64 --profile=debugSupported architectures: arm64, x86_64. Supported profiles: debug (default), release, release-with-debug.
Configure writes build/config.mk. Re-run with different flags to switch targets; the output directory is keyed on the combination so multiple configs can coexist.
Build
make -j$(nproc) worldOn a modern 8-core machine a clean debug build takes 40–60 minutes. Incremental rebuilds after small changes finish in seconds.
make world builds every component in dependency order. If you only need the kernel, make xnu is faster; make userland builds userland without the kernel.
What gets built
When the build finishes, you’ll have:
build/arm64-debug/kernel.img— the XNU kernel imagebuild/arm64-debug/initrd.img— a minimal initial ramdiskbuild/arm64-debug/rootfs.img— the root filesystembuild/arm64-debug/boot.efi— a UEFI boot stub (used by QEMU and real hardware)
Run the tests
Before you push a change, run the host-side test suite:
make testThis runs unit tests for the components that have them — today that’s launchd, dyld, and the build system itself. Integration tests that require a booted VM are covered by make vm-test (which internally uses the image you just built).
Next steps
- Run darwinOS in QEMU — boot the image you just built.
- Your first darwinOS program — compile and run a user program against the image.
- Debug the kernel — wire up KDP over serial for kernel debugging.
If the build fails, grab the tail of build/<target>/build.log and open a discussion on GitHub. Include your ./configure arguments and the host OS.