Files
ww/BOOTSTRAP.md
Hojun-Cho cb57cd795d build: split cstage/wwstage targets, document bootstrap
Phase 10 step 8 (delete the C trees) is deferred to v1.0 — until the
compiler stops churning we keep Cstage as the fresh-checkout entry
point. Split the Makefile so the two stages are named, and add
BOOTSTRAP.md describing the cstage → ww1 → ww2 → ww3 fixed-point
flow. PLAN.md gets a status note pointing at it.
2026-05-11 02:36:46 +09:00

2.6 KiB
Raw Blame History

BOOTSTRAP

How ww builds itself.

ww is self-hosted: the ww-side compiler/assembler/linker/driver live under selfhost/cmd/ and reach a byte-identical fixed point under make bootstrap. But the first ww binary on a fresh checkout has to come from somewhere. Today, that "somewhere" is a small C bootstrap toolchain — the Cstage:

cmd/wwc/   frontend library (lex, parse, check)  → libwwc.a
cmd/6c/    amd64 compiler   .ww → .s
cmd/6a/    amd64 assembler  .s  → .o
cmd/6l/    amd64 linker     .o  → static ELF
cmd/ww/    user-facing driver (orchestrates 6c → 6a → 6l)

Cstage is built with cc. Once it exists, it compiles the ww-rewritten tools (the wwstage) under selfhost/cmd/, which then self-compile to a byte-identical fixed point. After that, no C is involved.

Build flow

cstage     (cc → C tools, one-time)
  │
  ├──→ ww1   wwstage tools, built by Cstage
  │     │
  │     └──→ ww2   wwstage self-compiles
  │            │
  │            └──→ ww3   ww2 self-compiles
  │                   │
  │                   ↓
  │              cmp ww2 ww3   →   fixed point ✓
  ↑
  └ from here on, no C is invoked

Make targets

make             builds cstage + wwstage + libs
make cstage      Cstage only (cc → ww, 6c, 6a, 6l, wwdump, libs)
make wwstage     wwstage only (assumes cstage)
make bootstrap   three-stage build; gates on cmp ww2 == ww3
make test        runs all tests, including the 990993 diffs
                 (ww-side tools vs C-side tools, byte-for-byte)

Status

Phase 10 of PLAN.md is at its first exit criterion: the bootstrap is green and selfhost/cmd/{wwc,6a,6l,ww} are byte-identical to their Cstage counterparts. The second exit criterion — deleting the C trees — is deferred to v1.0: until the compiler stops churning, the Cstage stays as the fresh-checkout entry point. A git clone today still requires cc.

What "no C" looks like

When the compiler stabilises:

  1. Cross-compile or natively build a known-good wwstage on each supported arch.
  2. Ship those binaries under bootstrap/<arch>/{ww,6c,6a,6l} in the tree. They are the new stage 0.
  3. Delete cmd/wwc/, cmd/6c/, cmd/6a/, cmd/6l/, cmd/ww/.
  4. Move selfhost/cmd/* to cmd/*.
  5. Build path: stage-0 binary → ww1 → ww2 → fixed point, same as today, just without cc.

This is the standard self-hosting story (Go, Rust, OCaml all do variants of it). The bootstrap binaries become the new "trusting trust" surface.