| ContactBlogMusicSupport

Setup OSDev Environment on macOS

Why OSDev on macOS works (if you stop fighting defaults)

The failure mode is always the same: you follow an OSDev tutorial, hit make, and end up with a binary that either won’t boot, won’t link, or isn’t even in the format your bootloader expects.

macOS is a great editor and workflow environment. But it is a terrible default build target for classic OSDev.

This guide builds a layered mental model for the “why”, then gives three setups (from lightest to heaviest) that I’ve used successfully: a cross-toolchain on macOS, a Docker build container, and a Linux VM via Lima.


The two hard constraints (the stack you can’t ignore)

1) CPU architecture: aarch64 vs x86

Modern Macs (M1/M2/M3/M4) are aarch64 (ARM64) machines. Most OSDev examples, bootloaders, and “hello kernel” walkthroughs targets i686/x86_64.

If you are targeting ARM on purpose, you still have the second constraint.

2) Executable format: Mach-O vs ELF

macOS uses Mach-O. Most OSDev toolchains and boot flows assume ELF.


Three working setups (from native → isolated → maximum compatibility)

Option 1: Cross-compiler on macOS (fastest feedback loop)

This is the “keep everything local” setup:

Path A: Homebrew (the quick start)

If all you need is a usable cross toolchain, Homebrew is the shortest path.

brew install i686-elf-binutils i686-elf-gcc

Path B: Build from source (the “I want it correct” path)

This is the common OSDev approach: build binutils first, then build GCC against it.

Why this order matters

Binutils example (i686-elf)

# Native compiler toolchain for building tools
xcode-select --install

# Fetch sources
wget https://ftp.gnu.org/gnu/binutils/binutils-2.45.tar.gz
tar -xvf binutils-2.45.tar.gz

# Out-of-tree build keeps your source directory clean
mkdir -p binutils-2.45/build
cd binutils-2.45/build

# Key flags:
# --target=i686-elf    => produce tools that emit i686 code and ELF output
# --prefix=...         => install into an isolated directory
# --disable-nls        => disables Native Language Support (fewer deps, faster build)
# --disable-werror     => warnings won't fail the build on strict compilers
../configure \
  --target=i686-elf \
  --prefix=/usr/local/cross \
  --disable-nls \
  --disable-werror

# macOS doesn't ship `nproc` by default
make -j"$(sysctl -n hw.ncpu)"
make install

Repeat the same pattern for GCC, pointing it at the same --target and --prefix.


Option 2: Docker (portable + reproducible)

Docker gives you a clean Linux build environment while keeping your source on the host.

Minimal Dockerfile skeleton

FROM --platform=linux/amd64 ubuntu:latest

RUN apt-get update && apt-get install -y \
    build-essential \
    wget \
    nasm \
    qemu-system-x86

# Toolchain install/build goes here:
# - install prebuilt x86_64-elf toolchain packages, OR
# - build binutils+gcc from source inside the image

WORKDIR /osdev
CMD ["/bin/bash"]

Build + run

docker build -t osdev-env .

# -v maps your current folder into the container
docker run --rm -it -v "$(pwd)":/osdev osdev-env make

Why --platform=linux/amd64 matters On Apple Silicon, this forces an x86_64 userland. That can increase compatibility with prebuilt toolchains, but it may run slower due to emulation.


Option 3: Linux VM via Lima (maximum compatibility)

If you want the least “mystery meat” behavior, stop fighting macOS and build inside Linux.

Install Lima

brew install lima

Create and enter a VM

limactl start --name osdev template://ubuntu
limactl shell osdev

Mount your source directory (host ↔ guest)

Edit the instance config:

limactl edit osdev

Add a writable mount:

mounts:
  - location: /path/to/your/os/source/code
    writable: true

VS Code integration

Add to your SSH config so your editor can see Lima hosts:

Include ~/.lima/*/ssh.config

Run QEMU inside the VM

sudo apt-get update
sudo apt-get install -y qemu-system-x86

# Example: adjust to your boot flow / image layout
qemu-system-x86_64 -m 512M -net none -kernel /path/to/your/os/kernel

Conclusion

Pick the lightest setup that gives you deterministic results:

If you want a full Linux host on Apple Silicon without virtualization, Asahi Linux is the endgame.


Support the Research

Follow Me on GitHub

I spend about 6 hours a week outside of my main work to write these deep-dives into C, Java, and systems performance. If my work adds value to your engineering toolkit, there are two ways to support the project:

One-Time Support

Simple way to say thanks for a specific fix or tutorial. Donate via Crypto (Any Amount)

Other ways to support

You can visting the Support for more ways to support me and sustain the blog community.

The Blogs