Files
takana/scripts/rust-frontier
Sergio 476168bb07 takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4
250 líneas de comentario en 151 scripts. Control verificado: el diff no toca
NI UNA línea que no empiece por #, y la sintaxis de los 151 pasa.

El barrido saltea heredocs y cadenas triples, y el guardián DISPARÓ 3 veces:
las tres eran el MOTD que el script escribe DENTRO de la imagen construida —
texto del producto, no comentario del script. Se cambiaron aparte y a
propósito, que es rebranding, no limpieza.

Y el hallazgo caro:  casaba contra ,
que es el TARGET de tracing — o sea el module_path!, o sea el nombre del crate.
La etapa 4 lo movió a  y el script quedó casando NADA. No fallaba:
imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado
con el binario (RUST_LOG=info sobre zlib), no deducido. Ahora acepta las dos, y
tiene que seguir aceptándolas porque los logs viejos en disco dicen la vieja.

Además 14 rutas de módulo  en docs, que el barrido anterior no tocó
porque  no es frontera de palabra.
2026-09-09 19:28:48 +00:00
..

rust-frontier — self-hosting the builder's rust toolchain

The last frontier of selfhost-verify variante (b): replace the Alpine rustc/cargo 1.91.1 in /toolchain with a hammer-built rust, via the purist mrustc chain (no prebuilt rustc binary). Path:

mrustc → rustc 1.90.0 (builds bundled LLVM) → 1.91.0 → 1.91.1

These scripts + patch are the working artifacts. The mrustc tree itself lives in .scratch/mrustc (gitignored — it's a large third-party clone, upstream master be69c74); only our deltas are tracked here.

Files

  • run_rustc.patch — patch against mrustc be69c74 for run_rustc/Makefile and run_rustc/rustc_proxy.sh. Apply from the mrustc root: git -C .scratch/mrustc apply /path/to/run_rustc.patch
  • build-stage0-musl.sh — rebuild the mrustc stage0 rustc+cargo with a musl host triple (output-1.90.0-x86_64-unknown-linux-musl/). Run inside the Alpine devfs sandbox (gcc, MRUSTC_TARGET_VER=1.90). Reuses the already-built LLVM and bin/mrustc.
  • run-runrustc.sh — run a run_rustc make target inside the devfs sandbox, pointed at the musl-host stage0.
  • bootstrap.toml — rust's own bootstrap config for hop 1 (1.90.0 → 1.91.0): build/host/target = x86_64-unknown-linux-musl, stage0 rustc/cargo = the run_rustc musl-host 1.90.0 prefix, external LLVM 20.1.8 reused via llvm-config (clears bootstrap's >=19 gate, no LLVM rebuild), crt-static = false (dynamic link against the devfs system musl, like Alpine and the run_rustc toolchain), rpath = true. Copy it into the rust source root.
  • bootstrap-1.91.1.toml — config for hop 2 (1.91.0 → 1.91.1). Same as hop 1 except: stage0 rustc = /stage0/bin/rustc (the installed hop-1 toolchain, bound read-only via STAGE0), stage0 cargo = the run_rustc 1.90.0 cargo (1.90 satisfies bootstrap's "minor-1" check for a 1.91.x source), extended = true + tools = ["cargo"] so the install yields a hammer-built cargo, and cargo-native-static = true — the hermetic devfs has no system OpenSSL/curl/libgit2, so this makes bootstrap build cargo with the all-static feature set (vendored openssl/libgit2 + static curl/libz, compiled from the vendored C sources via gcc). Without it the cargo tool fails on openssl-sys.
  • swap-rust-into-toolchain.sh — overlay the hammer-built rust 1.91.1 (.scratch/rust-1.91.1-prefix) onto a toolchain dir (default .dev-fs/alpine) so hammer build / bootstrap stage1 compile the 4/4 rust inputs (arje-zero, hammerd) with hammer-rust. Additive + reversible: hammer's x86_64-unknown-linux-musl rustlib and hash-suffixed .sos don't collide with Alpine's x86_64-alpine-linux-musl, so only /usr/bin/{rustc,cargo} are replaced (Alpine backed up to *.alpine). --restore undoes it. Wired into selfhost-verify.sh as SWAP_RUST=1 (applies before the stage1 build, restores on exit via trap). This swap changes of_tree (rustc emits the binaries), so the criterion is auto-consistency against a NEW RUST_EXPECT_REF, not the Alpine 9adefb82.
  • run-xpy.sh — run rust's x.py inside the devfs sandbox, binding the source at /src, the install prefix at /out, and the mrustc tree at /mrustc (so the stage0 + llvm-config paths in bootstrap.toml resolve). Set the STAGE0 env var to also bind a prior hop's installed prefix read-only at /stage0. Usage: run-xpy.sh <SRCDIR> <PREFIXDIR> -- build --stage 2 compiler/rustc library/std.

The runners hardcode /home/sergio/hammer and assume the prepared devfs at .dev-fs/alpine (256-TLS-key musl loader + g++; see the bootstrap-devfs notes).

Why the patches exist (the snags)

The lab is musl-only (Alpine devfs); the 4/4 inputs (arje-zero/hammerd) are built --target x86_64-unknown-linux-musl. Three coupled problems had to be fixed to bootstrap a usable rust there:

  1. stage-1 std built for gnu (mmap64/open64 undefined at link). minicargo was invoked without --target, so it used mrustc's default gnu triple — and gnu std references glibc's LFS64 symbols that musl 1.2.5 doesn't export. Fix: pass --target $(RUSTC_TARGET) to minicargo (Makefile:162) and to the stage-1 smoke-test (Makefile:172). A correct musl std uses the base libc symbols (open/mmap/…), matching Alpine's reference std.

  2. self-contained CRT absent. musl's default link is -static-pie against a lib/rustlib/<t>/lib/self-contained/ CRT dir that the mrustc sysroot never populates (also needs static -lunwind). Fix: -C target-feature=-crt-static -C link-self-contained=no so the Alpine gcc supplies crt1/crti/crtn + crtbeginS/crtendS and links dynamically against the system musl (RUSTFLAGS in Makefile:111, plus both hello_world smoke-test rules: the stage-1 one at Makefile:172 and the final fully-bootstrapped one at Makefile:262 — the latter only surfaces once stage-2/3 actually completes, i.e. after snag #3 is fixed).

  3. host-triple = gnu on a musl system (the deep one). cargo compiles build-scripts and proc-macros for the host; mrustc's stage0 rustc has its host triple baked as x86_64-unknown-linux-gnu (not runtime-overridable). A proxy --target musl inject fixes build-script bins, but proc-macros are dlopen'd and must match the host triple structurally — injection makes them target artifacts that rustc rejects. Aliasing musl rlibs as gnu also fails: rustc reads the triple from rlib metadata (E0461), not the path.

    The only fix is a stage0 rustc whose host triple is musl — that's what build-stage0-musl.sh produces (CFG_COMPILER_HOST_TRIPLE via RUSTC_TARGET, --target via MRUSTC_TARGET). Then host==target==musl: cargo doesn't cross-compile, proc-macros load natively, and rustc_proxy.sh only needs the CRT flags (no --target inject).

    Gotcha: do not pass OUTDIR_SUF on make's command line — a command-line var can't be reassigned by the makefile, so the -musl suffix append is skipped and the build contaminates the gnu output dir. Let it default.

  4. final cargo needs vendored OpenSSL. The fully-bootstrapped prefix/bin/cargo rule (Makefile:235) builds cargo with default features, so openssl-sys looks for a system OpenSSL via pkg-config and fails (the hermetic musl devfs has none, and no openssl.pc). Fix: add --features vendored-openssl to that cargo build so openssl-src compiles OpenSSL from source — same approach the stage0 cargo build uses. Real cargo (unlike minicargo) handles the OUT_DIR fine, so snag #4 doesn't recur here. Only surfaces after the final hello_world (snag #2/262) passes.

  5. minicargo OUT_DIR host/target split (only when building the musl stage0's cargo). With RUSTC_TARGET set, minicargo runs each cargo build-script under cargo-build/host/build_X/, but the target crate's include! / include_bytes!(concat!(env!("OUT_DIR"), "/..")) resolves OUT_DIR to cargo-build/build_X/ (no host/, empty) → mrustc aborts with signal 6. Hit libsqlite3-sys (bindgen.rs) and the cargo binary (man.tgz). The gnu build never split (single triple → single dir). Since host==target the script outputs are bit-identical, so build-stage0-musl.sh symlinks the target dir to the host dir (symlink_outdirs). Late sys-crates (cargo, curl, openssl, libgit2-sys, libssh2-sys) run their scripts near the end, so it's applied in a retry loop around the incremental cargo build.

Workflow

# 1. apply the run_rustc patch into the mrustc clone
git -C .scratch/mrustc apply scripts/rust-frontier/run_rustc.patch

# 2. rebuild stage0 rustc+cargo with a musl host triple (~hours, reuses LLVM)
.scratch/build-stage0-musl.sh            # -> output-1.90.0-x86_64-unknown-linux-musl/

# 3. build the optimised rustc + cargo via run_rustc (stage 1/2/3)
.scratch/run-runrustc.sh all

# 4. climb hop 1 — 1.90.0 -> 1.91.0 (stage0 = the run_rustc musl-host 1.90.0)
cp scripts/rust-frontier/bootstrap.toml .scratch/rustc-1.91.0-src/bootstrap.toml
.scratch/run-xpy.sh .scratch/rustc-1.91.0-src .scratch/rust-1.91.0-prefix -- \
    build --stage 2 compiler/rustc library/std
.scratch/run-xpy.sh .scratch/rustc-1.91.0-src .scratch/rust-1.91.0-prefix -- \
    install --stage 2 rustc library/std        # -> relocatable 1.91.0 (rpath)

# 5. climb hop 2 — 1.91.0 -> 1.91.1 (stage0 rustc = the installed 1.91.0)
cp scripts/rust-frontier/bootstrap-1.91.1.toml .scratch/rustc-1.91.1-src/bootstrap.toml
STAGE0=.scratch/rust-1.91.0-prefix .scratch/run-xpy.sh \
    .scratch/rustc-1.91.1-src .scratch/rust-1.91.1-prefix -- \
    build --stage 2 compiler/rustc library/std src/tools/cargo
STAGE0=.scratch/rust-1.91.0-prefix .scratch/run-xpy.sh \
    .scratch/rustc-1.91.1-src .scratch/rust-1.91.1-prefix -- \
    install --stage 2 rustc library/std cargo  # -> hammer rustc+cargo 1.91.1

# 6. swap rust 1.91.1 into /toolchain + auto-consistency verify (in-VM)
#    PRESEED=hammerd es OBLIGATORIO con SWAP_RUST: arje-zero (monorepo tawasuyu) vendorea
#    ~1973 crates; en un rebuild in-VM completo (PRESEED=all) ese vendor desborda el
#    rootfs en RAM de la VM → ENOSPC. Con PRESEED=hammerd se preseedea el arje-zero
#    host-built (takana-rust, locked) y sólo hammerd se reconstruye in-VM.
SWAP_RUST=1 KVM=1 MEM=16384 PRESEED=hammerd ./scripts/selfhost-verify.sh

DONE (2026-06-16): both hops built. rust-1.91.1-prefix/bin/{rustc,cargo} run standalone (rpath), rustc 1.91.1 (ed61e7d7e) host x86_64-unknown-linux-musl LLVM 20.1.8, cargo 1.91.1. Alpine's exact rust version, fully self-hosted from the mrustc chain (mrustc → 1.90.0 → 1.91.0 → 1.91.1). Each hop ≈45 min compile (LLVM reused throughout); hop 2's cargo needed the cargo-native-static fix.

✓ AUTO-CONSISTENCY VERIFICADA IN-VM (2026-06-18): SWAP_RUST=1 … PRESEED=hammerd → el host construye stage1 con hammer-rust (of_tree 7fa6cb4e), la VM lo reconstruye con hammer-rust y reproduce 7fa6cb4e bit a bit (stage1' == stage1, DRIVER_RC=0). RUST_EXPECT_REF=7fa6cb4e (≠ el 9adefb82 de Alpine — rustc emite los bytes). El drift de arje-zero quedó cerrado fijando su Cargo.lock en tawasuyu (recipes/arje-zero.toml → commit 9967b02c): build --locked ⇒ bit-reproducible (lock1 == lock2).

Full diagnostic history is in the selfhost-verify-rust-frontier memory.