Requirements

External tools the build, the OS image, and the test suites depend on.

Build (./make_os.sh)

Always required:

  • nasm — assembles boot.bin, kernel.bin, the libbboeos .asm files, every cc.py-emitted .asm, and the user programs.
  • POSIX shell utilitiescat, dd, dirname, find, mkdir, printf, rm, sed, sort, tr, wc. All are part of the macOS and Linux base systems.
  • python3 (3.13+) — runs cc.py (the C-subset compiler) and add_file.py (the host-side image writer). Standard library only — no pip install step needed.

Required only when building with --ext2:

  • debugfsadd_file.py shells out to it to write files, set inode flags, and create directories inside the ext2 image.
  • mke2fsmake_os.sh invokes it directly to format the ext2 partition inside the disk image.

Both ship together in the e2fsprogs package.

Running the OS

  • qemu-system-i386 — the primary target. qemu-system-x86_64 -machine pc also works.

Audio caveats

  • OPL music is silent in QEMU. QEMU 8.x’s sb16 device emulates only the DSP for PCM playback; writes to the chip’s OPL register ports (0x388 / 0x38A) are accepted but no FM audio is synthesized. To hear Doom’s music, run on real SB16 hardware (or an emulator that includes OPL FM synthesis, e.g. DOSBox via passthrough). Doom’s SFX (PCM through /dev/audio) is unaffected and works in QEMU.

Tests

All test runners are bare-Python QEMU drivers; they need every build dependency above plus qemu-system-i386.

Tests under tests/unit/ use pytest (pip install pytest).

Development

The repository uses pre-commit for lint and format hooks; install it via pip install pre-commit then pre-commit install. Formatting C sources is handled by clang-format (configured by .clang-format) — pre-commit pulls the pinned wheel automatically, so no separate install is required for the hook. To run clang-format outside of pre-commit, pip install clang-format gets the same binary the hook uses.

The libbboeos unit tests need clang:

  • tests/unit/test_libbboeos.py runs clang in its host-native default mode to compile each unit test’s tiny C program and compare its behaviour against the system libc.

Note: the libbboeos C sources themselves are compiled by cc.py + nasm (no clang needed). Clang is only required for the unit-test harness programs and the Doom port.

Doom port (ports/doom/build.py)

The Doom build needs clang (for its own .c files), make, ar, plus a GNU-compatible linker + objcopy. build.py auto-picks the first one it finds on $PATH, in order:

  • x86_64-elf-ld / x86_64-elf-objcopy (GNU cross-binutils — typical macOS install)
  • i686-elf-ld / i686-elf-objcopy (32-bit GNU cross-binutils)
  • ld.lld / llvm-objcopy (LLVM toolchain — both platforms)
  • ld / objcopy (system binutils — Linux default)

Apple’s /usr/bin/ld (mach-o) doesn’t speak GNU options like -T or -Map=, so installing one of the above is required on macOS.

Install commands

Ubuntu / Debian:

sudo apt-get install -y e2fsprogs nasm qemu-system-x86
# Plus, for the libbboeos unit test (clang) and the Doom port (binutils + make):
sudo apt-get install -y binutils clang make
# Plus, for the Doom port (lld is one option; binutils above also works):
sudo apt-get install -y lld llvm

macOS (Homebrew):

brew install e2fsprogs nasm qemu
# Plus, for the libbboeos unit test and Doom port (clang + make ship with Xcode CLT):
xcode-select --install
# Plus, for the Doom port — pick one of:
brew install x86_64-elf-binutils    # GNU cross-binutils, simplest
# OR
brew install lld llvm               # LLVM toolchain, also works

macOS gotcha: e2fsprogs is keg-only

Homebrew installs e2fsprogs keg-only on macOS, so mke2fs and debugfs are not on $PATH by default. Either symlink them or add the keg’s sbin/ to your shell’s PATH:

export PATH="$(brew --prefix e2fsprogs)/sbin:$PATH"

This only matters for --ext2 builds — the default bbfs build never touches either tool.


This site uses Just the Docs, a documentation theme for Jekyll.