Skip to content
AOS-ARCH-023 Normative planning baseline

Build Strategy and Developer Experience for the Fuchsia Fork

How we neutralize the heavy Fuchsia full-tree build: a two-tier model where day-to-day product work uses the Bazel SDK against prebuilt platform artifacts (no platform build at all), and only kernel/driver deltas require the full GN/ninja tree; incremental ninja + ccache make the full tree a first-build-only cost; Appl

Build Strategy and Developer Experience for the Fuchsia Fork

The scary sentence — "the Fuchsia build is heavy, you need a dedicated Linux box" — is true only for the full platform tree, and only for the first build. Most of our engineering (the entire product layer) never needs a platform build at all: it compiles in seconds-to-minutes against prebuilt platform artifacts via the SDK. This document makes that split normative.

Table of Contents

Problem Statement

The full Fuchsia tree builds through GN/ninja/fx, officially on x86-64 Linux (Debian-based), and the first build needs serious disk (~200 GB working set), RAM, and cores. Taken naively, that means every engineer needs a build server and every iteration costs a platform build. That would be a real velocity killer. This document exists because the naive reading is wrong: the platform build is a rare, cacheable, CI-owned cost, not the daily loop.

Facts (verified against fuchsia.dev)

  • Full-tree host support: x86-64 Linux (Debian-based) only; Windows unsupported; macOS is not a supported full-tree build host (any CPU).
  • SDK host support is broader: the Bazel-based SDK builds components/drivers natively on macOS arm64 (darwin_arm64 Bazel config, confirmed in the Pigweed Fuchsia SDK workflow); ffx and SDK core are published for macOS via CIPD. This is the key fact that makes an Apple-Silicon workstation viable.
  • ccache is officially supported for the full tree ("enabled automatically if CCACHE_DIR refers to an existing directory") and caches C/C++ artifacts across builds.
  • GN/ninja is incremental by design: after the first build, fx build recompiles only changed targets.
  • The Fuchsia SDK (Bazel-based) exists precisely so components, drivers, and even product assembly happen out-of-tree against prebuilt platform artifacts — the IDK/SDK "can be used to develop Fuchsia components without checking out Fuchsia's source code or using Fuchsia's own build system," and Fuchsia itself converged on Bazel+SDK as the well-lit path (RFC-0139, RFC-0186).
  • Prebuilt product bundles are downloadable (ffx product download) and boot directly in the emulator — trying Fuchsia in FEMU requires no build at all.
  • FEMU supports ARM64 hosts including Apple Silicon; the qemu-arm64 target is documented as "very limited and not recommended", so arm64-target work carries friction; x64 remains the well-lit target.

Two-Tier Build Model (normative)

Tier Who What builds Where Cost
Tier 1 — Product (default) Product-layer engineers (entity/agent, shell, services, apps) Only our components, via Bazel SDK against prebuilt platform Any decent laptop Seconds–minutes
Tier 2 — Platform (exception) Kernel/driver/platform-delta engineers + CI The forked Fuchsia tree via fx/GN/ninja Dedicated x86-64 Linux builder + CI First build: hours; incremental: minutes

Rules:

  1. Product-layer code MUST build with the SDK workflow and MUST NOT require a platform checkout.
  2. The fork pins an upstream revision; CI produces and publishes platform artifacts (IDK/SDK + product bundles) for Tier 1 to consume.
  3. Only changes below the platform contract (kernel deltas, board drivers, platform patches) touch Tier 2.
  4. CI is the canonical Tier-2 builder; local Tier-2 builds are for platform engineers only.

This is the same decoupling as substrate/platform/shell, applied to the build: the contract line is the SDK.

Tier 1: SDK-First Product Development

Bootstrap (per sdk-samples/getting-started):

git clone https://fuchsia.googlesource.com/sdk-samples/getting-started fuchsia-getting-started --recurse-submodules
cd fuchsia-getting-started
scripts/bootstrap.sh          # fetches the Bazel-based SDK toolchain
tools/ffx sdk version         # verify
tools/ffx product download <bundle>   # prebuilt platform image
tools/ffx emu start           # boot the emulator from prebuilts
bazel build //src/...         # build only OUR components

Iteration on a component is a normal Bazel build: seconds-to-minutes, cached, hermetic. Our repo will vendor the same Bazel SDK rules and point them at OUR CI-published platform artifacts once the fork exists; until then, upstream bundles are the substrate for product-layer development — which is exactly the Track-A plan.

Tier 2: Full-Tree Platform Work

curl -s "https://fuchsia.googlesource.com/fuchsia/+/HEAD/scripts/bootstrap?format=TEXT" | base64 --decode | bash
cd fuchsia
export CCACHE_DIR=$HOME/.ccache   # enables ccache automatically
fx set minimal.x64 --release       # or workbench_eng.x64 / our product.board
fx build                           # FIRST build: heavy. After: incremental.
fx ffx emu start --headless        # boot what you built

Sizing the builder: ≥16 modern cores, 64 GB RAM, ≥250 GB NVMe free. On such a box the first minimal.x64 build is on the order of 1–3 hours; a beefier CI machine (32–96 cores) brings it to tens of minutes. These are estimates from community experience, not vendor promises; our own CI will record real numbers as evidence.

Incremental Builds and Caching

  • ninja incrementality: fx build after a small change rebuilds only affected targets — typically seconds to a few minutes, not hours. The "heavy build" is a first-build/clean-build property.
  • ccache: caches C/C++ compilation across builds and checkouts; officially supported.
  • Pinned upstream: the fork pins a revision, so the expensive graph doesn't churn under us; controlled rebases are scheduled, and CI pre-warms caches after each rebase.
  • CI-published artifacts: Tier 1 never pays the platform cost because CI publishes the IDK/SDK and product bundles per pinned revision.

Apple Silicon (M-series) Guidance — Verdict

Short answer: yes, the daily build works natively on an M4 Pro. Only the full platform tree does not. The two questions were conflated; here they are separated with verified facts.

What works natively on macOS arm64 (this is 90% of our work)

The Fuchsia SDK is build-system-agnostic and Bazel-native on Apple Silicon. Bazel auto-detects the host and produces a darwin_arm64 configuration (darwin_arm64-fastbuild for host builds, darwin_arm64-opt-exec for build tools) — confirmed in the Pigweed/Sapphire Fuchsia SDK workflow, which runs on macOS arm64 hosts. The SDK core is published for macOS via CIPD (fuchsia/sdk/core/mac-*), and ffx host tools run on macOS. So on the M4 Pro, natively and fast:

  • Build our components, drivers, and packages against the prebuilt platform (Bazel --config=fuchsia).
  • Run ffx, assemble packages, push to a target, stream logs, debug with zxdb.
  • Boot the emulator from prebuilt product bundles.

This is Tier 1, and it is the entire product-layer effort (entity/agent, shell, services, apps) plus driver work against the SDK. It needs no Linux box.

What does NOT work natively on macOS (the sentence in the source)

The full GN/ninja platform build (fx set / fx build of the whole tree) is supported only on x86-64 Debian-based Linux. The historical macOS SDK-core CIPD path is mac-amd64 (Intel); Apple Silicon runs host tools via Rosetta or native where published, but the platform tree itself is not a supported macOS build on any CPU. So "compile the forked Zircon + full image" is a Linux-only job.

The resolution — a two-machine home setup (no rental)

You do not need to rent anything and you should not try to make the Mac build the whole OS. The clean split uses two machines you already have:

Mac M4 Pro — primary workstation (daily, ~90% of the work). Write the entire product layer (entities, agents, shell, services) and SDK-level drivers; build them natively and fast with the Bazel SDK; run the emulator. This is the everyday loop and it never needs Linux.

Ubuntu laptop (i7 + RTX 3060) — the platform builder (occasional). This is the "dedicated build machine" the spec mentions — but it's a laptop you own, not a cloud rental. It builds the full forked Fuchsia tree (first build a few hours; afterwards incremental minutes with ccache) and publishes the image/artifacts the Mac consumes. The RTX 3060 is a bonus: FEMU has hardware Vulkan acceleration on Linux with Nvidia, so the emulator runs better there too.

Workflow: edit and iterate on the Mac; when a platform change is needed (kernel/driver deltas), the Ubuntu box rebuilds the tree and publishes; the Mac pulls the fresh artifacts. Set it up once and the Ubuntu box just rebuilds on demand.

Why not make the Mac build the whole tree?

Verified and deliberately not attempted: the full tree is supported only on x86-64 Debian Linux; the public build toolchain/SDK exists only for Linux (for macOS you would have to assemble your own platform toolchain by hand). Fuchsia maintainers have stated the Fuchsia build "never really worked on macOS" (closed wont-fix). Forking and repairing Google's build system for macOS is a multi-week, fragile effort that breaks on every upstream update — a poor use of time when a Linux laptop you own does the job. So: Mac for everything daily, Ubuntu laptop for the platform image.

Sizing the Ubuntu laptop (i7 + RTX 3060)

A quad/hex-core i7 with 16 GB RAM builds the tree; more cores and RAM help. Watch two things: disk (need ~200 GB free for a full checkout + build output — an external NVMe SSD is the easy fix if the internal drive is small) and RAM (16 GB works; 32 GB is smoother for linking). Enable ccache so only the first build is slow. The 3060 accelerates the emulator (Vulkan) but is not needed for the build itself. Record real first-build and incremental times as evidence to replace the estimates here.

Try-It-Tonight Path (no build)

Booting Fuchsia in the emulator tonight does not require building anything: fetch the SDK tools, ffx product download a prebuilt bundle, ffx emu start. On Apple Silicon prefer the arm64 bundle if offered, x64 otherwise (slower under emulation). The full-tree first build is what runs overnight — on a Linux builder, via the script in scripts/fuchsia-full-build.sh.

Requirements

  • R01. Product-layer code builds via the SDK workflow with no platform checkout (Tier 1).
  • R02. CI owns the Tier-2 full-tree build on a pinned revision and publishes IDK/SDK + product bundles.
  • R03. ccache is enabled on all Tier-2 builders; incremental build health (time-to-rebuild after a 1-file change) is a tracked CI metric.
  • R04. First-build, incremental-build, and emulator-boot times are recorded as evidence per builder class (CI box, M4 Pro VM) — estimates in this document are replaced by measurements.
  • R05. Apple Silicon engineers default to Tier 1; Tier-2 access is via the remote builder.

Risks and Open Questions

  • The SDK is a moving target (Bazel migration ongoing per RFC-0186); pinning SDK versions alongside the platform revision is mandatory.
  • arm64-host/arm64-target support may lag x64; if VM builds on Apple Silicon prove painful, the remote x86-64 builder is the fallback (budgeted).
  • Out-of-tree product assembly had gaps historically; verify current assembly-out-of-tree status when we vendor the SDK rules.
  • Open-question rule: unanswered high-impact questions become claims/experiments.

Related Documents