Files
ww/BOOTSTRAP.md
Hojun-Cho edfc4273f6 nocc: stage-0 bootstrap path (binaries gitignored)
Sets up the cc-free fresh-checkout flow without yet committing the
stage-0 binaries. The pieces are in place; flipping the switch is
one `git add -f` away when the compiler is judged stable.

  bootstrap/<arch>/{ww,6c,6a,6l}   stage-0 binaries (gitignored)
  bootstrap/README.md              layout + workflow

Two new targets:

  make bootstrap-snapshot   populates bootstrap/$(ARCH)/ from the
                            currently-built wwstage
  make nocc                 starts from bootstrap/$(ARCH)/, rebuilds
                            the wwstage from source, gates on
                            stage-0 == rebuilt byte-for-byte. Lands
                            in $(OUT)/nocc/ so $(OUT)/ stays
                            untouched. cc is never invoked.

The fixed-point gate has the same shape as `make bootstrap`, just
the entry point flipped: that target trusts cstage; nocc trusts
the checked-in (or local-snapshot) stage-0 binaries.

Implementation notes:

- libwwrt.a is assembled with stage-0 6a, members ordered to match
  $(RT_OBJ) so the embedded symbol table reproduces the cstage
  build byte-for-byte.
- The driver's default lib path is $self_dir/../../lib, which under
  $(NOCC_BIN) resolves to $(NOCC_OUT)/lib (libwwrt only). Each
  ww-build invocation passes -I $(CURDIR)/lib so `use os` etc.
  resolve to source.
- Stage-0 binaries are duplicated under both natural names (ww/6c/
  6a/6l) and _ww-suffixed names so the wwstage driver's
  hard-coded join_path_lit(self_dir, "6c_ww") still finds them.
  When cmd/wwc/ gets deleted at v1.0, that duplication and the
  _ww suffix in the driver both go away.
2026-05-11 11:51:34 +09:00

95 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 990995 (ww-side
tools vs C-side tools, byte-for-byte, plus
the wwstage rebuilding itself in 995)
Without cc:
make bootstrap-snapshot populate bootstrap/$(ARCH)/ from the
currently-built wwstage (gitignored
by default)
make nocc cold-start from bootstrap/$(ARCH)/,
rebuild the wwstage from source, gate
on `stage-0 == rebuilt` byte-for-byte.
cc is never invoked.
## Status
Phase 10 of `PLAN.md` is at its first exit criterion: the bootstrap is
green and `selfhost/cmd/{wwc,6c,6a,6l,ww}` are byte-identical to their
Cstage counterparts. Test 995 pins the stronger property — the
wwstage rebuilds every one of its own tools through `ww_ww + 6c_ww +
6a_ww + 6l_ww`, byte-for-byte.
`make nocc` is wired and verifies stage-0 self-reproduction locally;
the stage-0 binaries under `bootstrap/$(ARCH)/` are gitignored until
ready to commit. The second exit criterion — deleting the C trees —
is **still deferred to v1.0**: shipping the stage-0 binaries is a
one-way door (they become the project's new trust surface), and the
compiler is still churning. A `git clone` today still requires `cc`
unless the local working copy has already done `make
bootstrap-snapshot` once.
## What "no C" looks like
The pieces are already wired; only the binary commit is held back.
When the compiler stabilises:
1. On each supported arch, run `make wwstage && make bootstrap-snapshot`
to populate `bootstrap/<arch>/{ww,6c,6a,6l}` from the current
wwstage. Verify with `make nocc`.
2. `git add -f bootstrap/<arch>/{ww,6c,6a,6l}` — explicit because
the dir is gitignored. The binary SHAs become the new trust
surface.
3. Delete `cmd/wwc/`, `cmd/6c/`, `cmd/6a/`, `cmd/6l/`, `cmd/ww/`.
Drop `CC`/`AR` C-tool dependencies from the top-level Makefile.
4. Move `selfhost/cmd/*` to `cmd/*` and `make nocc` becomes the
default `make`.
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.