8000 bootstrap pins -> gen-13: every root, ladder top and userland cycle breaker from one generation by bryan-minimal · Pull Request #1242 · gominimal/pkgs · GitHub
[go: up one dir, main page]

Skip to content

bootstrap pins -> gen-13: every root, ladder top and userland cycle breaker from one generation - #1242

Open
bryan-minimal wants to merge 84 commits into
mainfrom
bryan/gen11-flip
Open

bryan-minimal wants to merge 84 commits into
mainfrom
bryan/gen11-flip

Conversation

@bryan-minimal
@bryan-minimal bryan-minimal commented Nov 1, 2026 •
Copy link
Copy Markdown
Member

Every bootstrap pin in pkgs now comes from one generation: gen-13 of gominimal/bootstrap (gs://minimal-bootstrap/gen-13/, 118 objects, generations/gen-13/manifest.json).

This branch is five of the six draft pin PRs merged (#983 toolchain roots, #1147 go, #774 ghc, #1210 rust, #1212 ocaml) plus the tools/pkgs-flip.py commits that rewrite each pin's url and sha256 from the generation manifests (gen-11, gen-12, then gen-13). It supersedes those drafts. The sixth, #913 (jdk-21/25/27 built from source instead of Temurin), is split out after review: jdk-21, jdk-25 and jdk-27 here are main's Temurin recipes, unchanged, with the CVE-2026-111943 step and jdk-27 at 27.0.1.0.2.

Scope

Beyond the pins, this PR:

  • Deletes 39 packages: the JVM ladder (jikes through openjdk-24, except the pinned tops), the Go ladder (go-1.4 to go-1.22.6) and the Rust ladder (mrustc to rustc-1.97.1). They now live in gominimal/bootstrap; pkgs keeps only the published tops as prebuilts. Nothing left in the tree imports a deleted package.
  • Moves ghc's boot compiler from the upstream 9.8.1 bindist (ghc-bootstrap) to ghc-9.6.7, the top of the source-only GHC ladder. The Hadrian plan changes with it (9.10.3 publishes bootstrap sources only for 9.6.4 and 9.8.1). alex and happy are still built by ghc-bootstrap; moving them is a follow-up.
  • Adds a standalone test to each bootstrap prebuilt (openjdk-21/25/26, ghc-9.6.7, ocaml-5.5.2, go-1.24.9, rustc-1.98.1): a version check run from the package's own runtime closure, outside any build sandbox.
  • Declares llvm at runtime for arm64 ghc-9.6.7, whose settings name ld.lld.

Coordination with #1339: the pinned rustc-1.98.1 loads libLLVM.so.21.1 through the live llvm. Whichever of the two lands second points rustc-1.98.1 at llvm-21 and makes libLLVM findable under its prefix.

What gen-13 is

gen-11 was the full rebuild of every ladder on the rebuilt userland; gen-12 rebuilt the same packages from the polished tree with mip --no-fetch (113 of 117 byte-identical to gen-11); gen-13 repoints every gen0-* slot at gen-12 and makes the amd64 gcc seed self-contained: gcc-15.2.0-glibc is installed stripped with PT_INTERP /usr/lib/ld-linux-x86-64.so.2 and no RUNPATH, so a sandbox needs no bedrock sysroot tree to run the compiler. 113 of gen-13's 118 objects are byte-identical to gen-12; the five that moved are the amd64 gcc seed, the new amd64 stage0-patchelf, and arm64's three OpenJDKs (now built with the rebuilt gcc the slots point at). Every ladder (hex0 → C toolchain, userland, JVM, Go, GHC, Rust, OCaml, zig) built on two independent machines per arch (amd64: an AMD c4d and an Intel c3; arm64: two Axions) and every published package agreed byte for byte on both machines of its arch.

gen-14 (published since) adds only node 26.12.1; every object this PR pins is byte-identical between gen-13 and gen-14. Node's pin is a separate PR on top of #817.

Pins

75 pins in 39 packages, relative to main:

  • 57 flip (new sha): the 25 userland cycle breakers on both arches (acl, attr, bash-bootstrap, bison, bzip2, coreutils, diffutils, file, findutils, gawk-bootstrap, gmp, grep, gzip, libcap, lz4, m4, make, mpc, mpfr, pcre2, sed, tar, xz, zlib, zstd), previously bedrock prebuilts from gs://minimal-staging-archives/prebuilts/bedrock/; amd64 and arm64 gcc; arm64 ghc-9.6.7, ocaml-5.5.2, openjdk-21/25/26, rustc-1.98.1.
  • 18 relist (same sha, new url): amd64 binutils, glibc, linux_headers and their versioned aliases, amd64 ghc-9.6.7, go-1.24.9, ocaml-5.5.2, openjdk-21/25/26, rustc-1.98.1; arm64 binutils, glibc, linux_headers, go-1.24.9.

Nothing pkgs pins is in gen-13's unreproduced list. The four-line "BEDROCK ROOT" comments beside each pin become one line naming the generation.

The self-contained gcc seed retires the bedrock-loader workarounds: gcc (prebuilt) drops its glibc-bedrock-2.42-sysroot runtime dep, glibc (prebuilt) drops the bedrock_sysroot_lib output, and go-1.24.9's runtime_deps are [glibc] on both arches. glibc-bedrock-2.42-sysroot stays on amd64 for openjdk-21/25/26, ghc-9.6.7 and ghc, whose published binaries were linked against the bedrock loader (bootstrap#8 tracks moving them to the plain loader).

Cost

Every spec hash in the tree moves (the toolchain roots move). One world rebuild on both arches. Not included: #1145 (staging mirrors; gcc's libzstd runtime dep), which is orthogonal and should land on its own.

🤖 Generated with Claude Code

bryan-minimal and others added 30 commits September 28, 2026 10:51
…on amd64)

Clean re-cut of bryan/ghc-ladder onto main d0b0026: only the ladder package
directories, none of the stale pre-#667 chain that branch carried.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
8000
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
microhs-0.16 -> ghc-4.08.2 -> ghc-5.04.3 -> ghc-6.6.1 -> ghc-6.10.4 -> ghc-7.0.4 -> ghc-7.6.3.
MicroHs ships its compiled form as portable C, so gcc alone yields a Haskell compiler; GHC 4.08.2's
compiler runs on it (first-party overlay: desugared modules, shims, patches, tests), compiles itself
to C, and each later GHC is booted by the one before. ghc-7.6.3 is now built from source by 7.0.4
(registerised) and keeps the install layout 7.8.4 consumes; the .hc bundle Source is gone.

All rungs use the bedrock gcc/binutils/glibc through a sysroot gcc wrapper; every Source is in
gs://minimal-staging-archives. Rehearsed on a lab VM: the lineage and the unchanged 7.8.4..9.6.7
rungs on top of it all build and pass their gates. arm64 sides remain stubs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…64 only like the other rungs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
x86_64 rungs keep the bedrock sysroot wrapper; aarch64 rungs compile with the
toolchain gcc. microhs..7.0.4 gain aarch64 configure/driver patches, the
hand-passed triple for pre-2010 config.guess, and libffi 3.5.2 where the
bundled one has no aarch64 port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Platform tables and checkArch, libffi, gold via --with-ld.gold, unregisterised
builds through 8.10.7, the boot compiler's RTS headers first, lld for the
registerised 9.2.8 link, and genapply built against the target's registers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ghc-bootstrap leaves the closure; hadrian bootstraps from
hadrian-bootstrap-sources-9.6.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MicroHs invokes cc; the aarch64 toolchain ships gcc only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The happy-generated parsers and Lex collect garbage constantly in the
default 50M-cell heap. 600M cells gives byte-identical .hc about 3x faster.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dagbuild.py starts a module once its imports have compiled, largest remaining
work first, instead of the overlay's retry rounds (std and lang ran one module
at a time; gen1 serialized Parser and ParseIface behind a round barrier). The
per-module commands are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…364)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bare build root

In the sandbox the build root is /build, so grepping for it matched GHC's
foldr/build rewrite rule in sources, interfaces and docs. 4.08.2, 5.04.3,
6.6.1 and 6.10.4 now look for their own tree and bin paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The overlay was packed on macOS, so every member carried a
com.apple.provenance pax header and GNU tar warned once per file. v2 holds the
same tree (contents, modes, links), packed deterministically with GNU tar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…L-separated

In the sandbox the build root is /build, so selecting files by a bare build-root
grep matched far more than the tree's paths, including 5.04.3's
"ghc/InstallShield/Setup Files/...", which xargs split at the spaces. Select by
the tree, bin and boot paths with grep -F, and pass names with -Z / xargs -0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.6.1 deletes compiler/stage1, so compiler/ghc-inplace -> stage1/ghc-inplace
dangled and the sandbox rejected the output (link outside the output dir).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he sandbox's rules

- 6.10.4 (aarch64): libffi 3.5.2 builds in a per-subdir build/ tree, so
  build/*/ expanded to several dirs and the sandbox's bash cd rejected them
  (Debian's dash took the first). Name the host dir; fail if cd fails.
- 9.6.7 (aarch64): the ghc-9.2.8 boot's settings link with ld.lld; add llvm to
  the arm build closure (the lab had lld from apt).
- ghc (aarch64): the same for its 9.6.7 boot, configured with
  --disable-ld-override so the shipped settings do not need lld, and checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
buildbot keeps only the last ~4 KiB of stderr, and the bootstrapping.conf
failure's message matched none of the grep patterns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bootstrapping Cabal needs hsc2hs for hpc and looks it up on PATH;
the sandbox has none. Use the 6.6.1 rung's in-tree hsc2hs-inplace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r libffi's libtool

aarch64: libffi 3.5.2 builds in build/<host>/, but rts/Makefile adds
-I../libffi/build/include; copy ffi.h and ffitarget.h there too.
x86_64: libffi 3.0.8's libtool sanity-checks a C++ preprocessor; bare
g++ -E lacks the sysroot and the sandbox has no /lib/cpp. Use the gcc
wrapper with -x c++.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
These configures probe bfd.h, libiberty and libbfd unconditionally.
The sandbox closure has binutils' bfd.h, which then breaks the debug
rts (bfd.h insists on config.h first), and the lib probes would add
-lbfd -liberty to every link. Pin the three results to no. 7.10.3+
probe only under --enable-bfd-debug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build.sh's error grep misses the compiler's message for ghctags, and the
sandbox returns only ~4 KiB of stderr. Wrap build.sh on x86_64 only and
print the 22 lines before make's first "] Error". aarch64's spec is
unchanged, so its built rungs stay cached.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…install

hadrian install runs the bindist's configure without our flags, and it
picked ld.lld from the build closure. Export enable_ld_override=no (the
environment form of --disable-ld-override) so both configures see it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…roduction binutils

Same fix as the jvm ladder (pkgs#775): with the amd64 bedrock roots
sealed and production glibc 2.44 in /usr/lib, the bedrock gcc (no
RUNPATH) cannot start. On x86_64 each rung starts every bedrock program
through the sysroot's ld.so with --library-path (per process; the
drivers find the wrapped cc1/collect2 via -B), and assembles and links
with production binutils 2.47 instead of the sealed 2.46.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bedrock sysroot's libm.so is a linker script naming
/usr/lib/libm.so.6, which in the sandbox is production glibc 2.44's.
-lm therefore bound 2.44 symbol versions (mhs: GLIBC_2.43 not found at
run time against the 2.42 sysroot). Rewrite it into fixlib next to
libc.so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bryan-minimal and others added 2 commits November 2, 2026 09:25
…eed's loader lives there

The amd64 seed gcc's interpreter and RUNPATH name /usr/lib/glibc-bedrock-2.42/lib. In a cycle
pass that pairs the seed with a from-source glibc (nginx), nothing else supplies that tree and
gcc cannot exec: "C compiler gcc is not found". The glibc seed ships the tree as its
bedrock_sysroot_lib output; the gcc seed now depends on exactly that subset, so nothing at
top-level /usr/lib collides.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bryan-minimal
Copy link
Copy Markdown
Member Author

amd64 nginx failure root-caused from the kept sandbox: nginx's cycle pass paired the gen-11 gcc seed (interpreter and RUNPATH at /usr/lib/glibc-bedrock-2.42/lib) with the from-source glibc, and nothing in the seed's closure supplied that tree, so gcc could not exec. 963e440: the gcc seed's replace_on_cycle runtime_deps now carry subsetOf glibc ["bedrock_sysroot_lib"] (the tree #1211 made glibc's seed export), and only that subset, so top-level /usr/lib does not collide. The generation objects are unchanged.

bryan-minimal and others added 2 commits November 2, 2026 11:52
…oot package

In the cycle pass `glibc` resolves to whichever glibc that pass holds, and the from-source one
has no bedrock_sysroot_lib output, so the subset could name nothing. The glibc-bedrock-2.42-sysroot
package is the pinned tree itself, with no cycle through gcc, as go-1.24.9 and the JDKs use it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
113 of 117 objects are the same bytes as gen-11, so most pins change url only; go-1.24.9 (amd64)
moves to a new sha (its BUILDINFO text changed).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bryan-minimal bryan-minimal changed the title bootstrap pins -> gen-11: every root, ladder top and userland cycle breaker from one generation bootstrap pins -> gen-12: every root, ladder top and userland cycle breaker from one generation Nov 2, 2026
@bryan-minimal
Copy link
Copy Markdown
Member Author

Repointed at gen-12 (gominimal/bootstrap d26d026), the validation rebuild of the polished tree: 113 of 117 objects are byte-identical to gen-11, so most pins change url only; amd64 go-1.24.9 moves to a new sha (BUILDINFO wording). The gcc seed carries glibc-bedrock-2.42-sysroot at runtime (75050e9) for the amd64 loader.

bryan-minimal and others added 2 commits November 2, 2026 14:46
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…f-contained gcc seed retires

Every gominimal/bootstrap pin moves from gen-12 to gen-13. gen-13's amd64
gcc-15.2.0-glibc seed is installed with PT_INTERP /usr/lib/ld-linux-x86-64.so.2
and no RUNPATH (bootstrap a6bef0c), so it no longer needs
/usr/lib/glibc-bedrock-2.42/lib at run time.

Removed:
- gcc (prebuilt): the glibc-bedrock-2.42-sysroot runtime dep, its comment
  and import.
- glibc (prebuilt): the bedrock_sysroot_lib output and its comment; outputs
  are all_outputs again.
- go-1.24.9: runtime_deps are [glibc] on both arches. The amd64 go is built
  with cgo off and has no interpreter.

Kept: glibc-bedrock-2.42-sysroot on amd64 for openjdk-21/25/26, ghc-9.6.7
and ghc. Their published amd64 binaries are byte-identical to the earlier
generations and were linked with --dynamic-linker set to the bedrock loader
and an rpath into the sysroot, and ghc-9.6.7's ghc-cc compiles against that
sysroot. The JDK recipes now say so in a comment.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bryan-minimal
Copy link
Copy Markdown
Member Author

Repointed at gen-13 (gominimal/bootstrap 563820b). The gen-13 amd64 gcc seed is installed with the plain /usr/lib loader and no RUNPATH, so the sysroot runtime dep on the gcc seed, the sysroot dep on go-1.24.9 and #1211's bedrock export on the glibc seed are gone (4b7c23e). The amd64 openjdk-21/25/26 and ghc-9.6.7 objects still name the bedrock loader themselves (their bootstrap rungs link with an explicit --dynamic-linker), so their sysroot dep stays until those rungs are rebuilt with the plain loader in the next generation.

@bryan-minimal bryan-minimal changed the title bootstrap pins -> gen-12: every root, ladder top and userland cycle breaker from one generation bootstrap pins -> gen-13: every root, ladder top and userland cycle breaker from one generation Nov 4, 2026
bryan-minimal and others added 2 commits November 4, 2026 08:39
…ervers#292); every package built

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@bryan-minimal
Copy link
Copy Markdown
Member Author

The gnupg smoke-test failure here (create directory I/O error at path …/rootfs/usr/lib64: File exists → failed setup for test smoke, run 42112308631) is a latent path collision that's already on main, not a regression from the gen-13 pins.

  • Cause: gnupg's artifact ships a dangling usr/lib64 -> lib symlink. libgpg-error, libgcrypt, libassuan, libksba and npth ship usr/lib64 as a real directory. Both are leaks of the sandbox's seeded $OUTPUT_DIR/usr/lib64 through their usr/** output globs.
  • Why it fails only here: the sandbox lays packages down in spec-hash order. On main the directories go first and gnupg's symlink is only a WARN. The pins in this PR flip that order.

Fix: #1341. It drops the symlink in all nine usr/** packages, and only those nine rebuild. When it lands on main, a rebase of this PR should clear the gnupg test.

@msample msample left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at dd19d82. Thanks for consolidating the six drafts. The pin mechanics check out (details at the bottom). There are two blockers on the JDK side, though, both security regressions, and one change fixes both.

Blockers

1. The CVE-2026-111943 mitigation (#949) is gone from jdk-21, jdk-25 and jdk-27

445288a merged main into bryan/jdk-from-source and carried over main's Temurin bumps (#1137, #1138) but not #949. Merge 98e130b then brought that branch in cleanly, and every later merge of main (dd19d82 included) kept the deletion. All three JDKs have lost the following, and so has jdk, because it points at jdk-25:

  • the import of ../jdk/cve-2026-111943.ncl and its four build inputs
  • the cve-2026-111943.sh step
  • the cve_2026_111943 test

packages/jdk/cve-2026-111943.{sh,ncl} and JdkDistrust.java are still in the tree, but nothing uses them now. AGENTS.md:447 still says the patch is "used by jdk-21, jdk-25 and jdk-27".

#949's description anticipated exactly this: "#913 (jdk-21/25/27 from source) … will ship OpenJDK's store with both roots, so it needs the same sh ./cve-2026-111943.sh step." At the three tags this PR builds (jdk-21.0.13-ga, jdk-25.0.5-ga, jdk-27-ga):

  • src/java.base/share/data/cacerts/ contains both distrusted anchors: comodoaaaca (AAA Certificate Services, which none of the Temurin builds we've shipped carried) and emsigneccrootcag3.
  • src/java.base/share/data/blockedcertsconverter/blocked.certs.pem lists 19 certificates, none of them one of the 16 compromised intermediates (0 of the 48 fingerprints in cve-2026-111943-blocked-sha256.txt).

build.sh passes no --with-cacerts-* option, so as built these JDKs ship both anchors and block none of the intermediates. That is worse than before #949.

2. jdk-27 goes back from 27.0.1.0.2 to 27 GA

dd19d82 resolved the jdk-27/build.ncl conflict by keeping version = "27". That takes jdk-27 back from 27.0.1.0.2 (#1302: the October CPU 27.0.1, plus upstream's eMudhra blocked-certs update) to 27 GA, losing both. Temurin 27.0.1.0.2, which main ships today, has neither anchor and blocks all 48 fingerprints. This branch's jdk-27 has both anchors and blocks none.

One fix for both

Upstream has already fixed both halves on all three lines. The .0.3-ga tags (jdk-21.0.13.0.3-ga, jdk-25.0.5.0.3-ga, jdk-27.0.1.0.3-ga) drop both anchors from cacerts (107 roots) and add the 16 intermediates to blocked.certs.pem. Suggested fix:

  • Move each recipe to its .0.3-ga tag. That also gives jdk-27 its CPU back.
  • Restore the import, the four build inputs, the test, and the sh ./cve-2026-111943.sh "${DST}" step after the cd "${BUILDROOT}" that follows the image copy, so the harness gates the result.

The harness already accepts a JDK that blocks the intermediates upstream (#1304, which came in with dd19d82) and anchors that are already absent. It also writes cacerts with no salt or MAC, so reproducibility is unaffected.

Longer term, AGENTS.md asks for the system store where upstream allows it, and otherwise for the denylist plus a note in build.ncl. Configure takes --with-cacerts-file / --with-cacerts-src at all three tags, so building against ca-certificates is the policy-preferred end state. As it stands, the PR does neither.

Worth addressing before merge

The description doesn't cover the full scope. It names the six drafts (#913 and #774 included), but doesn't say that this PR also:

  • deletes 39 packages (the JVM, Go and Rust ladders)
  • replaces the Temurin binaries for jdk-21/25/27 with from-source builds
  • moves ghc's boot compiler from the upstream 9.8.1 bindist (ghc-bootstrap) to ghc-9.6.7

Users will notice the JDK switch:

  • the vendor string becomes minimal
  • there are no CDS archives, so the JVM starts more slowly
  • there is no src.zip
  • the trust store is OpenJDK's rather than a Mozilla-derived one
  • there are 13 runtime deps instead of 3
  • build_cost_multiple is 12

The JDK switch would be easier to review as its own PR, and blocker 1 would have been easier to spot there. At minimum, the description should cover it.

The prebuilts have no tests. The smoke-test-coverage report marks ghc-9.6.7, ocaml-5.5.2, openjdk-21/25/26, go-1.24.9 and rustc-1.98.1 as MISSING. These are bucket prebuilts with hand-curated runtime deps. That's the same kind of package as the amd64 gcc seed, whose missing loader broke #1162's build (#1211) and nginx's cycle pass earlier in this thread.

The packages that build on them do exercise them, but only inside build sandboxes. A build sandbox holds more than the runtime closure, so a missing loader or library doesn't show up there. A one-line standalone test for each would catch it. Nothing lands on /usr/bin, so use full paths:

  • /usr/lib/openjdk-{21,25,26}/bin/java -version
  • /usr/lib/ghc-9.6.7/bin/ghc --numeric-version
  • /usr/lib/ocaml-5.5.2/bin/ocamlc.byte -version
  • /usr/lib/go-1.24.9/bin/go version
  • /usr/lib/rustc-1.98.1/bin/rustc -vV

For the JDKs, restoring the trust-store test and adding a headless AWT/font test would cover the larger runtime closure.

This needs coordinating with #1339. In both gen-13 rustc-1.98.1 tarballs, librustc_driver NEEDS libLLVM.so.21.1. Its only RUNPATH (amd64) / RPATH (arm64) is $ORIGIN/../lib, and the tarball doesn't bundle libLLVM, so today it resolves through the live llvm in /usr/lib. #1339 moves the default llvm to 23.1.5, freezes 21 under /usr/lib/llvm-21, and edits the rustc-1.91.1…1.98.1 rungs, which gives modify/delete conflicts with this PR. Whichever PR lands second has two jobs:

  • point rustc-1.98.1 at llvm-21
  • make libLLVM findable under the prefix, for example through LD_LIBRARY_PATH in rust/build.sh or a regenerated tarball

On arm64, ghc-9.6.7 needs ld.lld but doesn't declare it. In the arm64 tarball, lib/settings has -fuse-ld=lld in the C compiler link flags and ld.lld as both the ld command and the merge-objects command. Its runtime deps, though, are only [glibc, gmp, ncurses]. ghc works around this by adding all of llvm to its arm64 build deps (ghc/build.ncl:69). Please declare the dependency on ghc-9.6.7 itself, or at least note it there.

What I verified
  • All 75 gs://minimal-bootstrap pins (72 distinct URLs). Each is in the public gen-13 listing. The sha in the path, the sha256 field and gen-13's MANIFEST.txt agree. Each object's arch matches its match arm. I couldn't check the unreproduced list, because manifest.json isn't public.
  • No dangling imports. At dd19d82, which already contains main, nothing references any of the 39 removed packages.
  • JDK source mirrors.
    • jdk-21 and jdk-25 are byte-identical to the GitHub tag archives.
    • jdk-27 is byte-identical to the GitHub API tarball of jdk27u@jdk-27-ga (commit 815ff4d). The archive/refs/tags URL in the comment at jdk-27/build.ncl:58 produces different bytes, so the comment should name the tarball endpoint instead.
  • glibc's bedrock_sysroot_lib output. Nothing uses it any more, so dropping it is safe.
  • ghc. The Hadrian plan rewrite is justified: 9.10.3 only publishes bootstrap sources for 9.6.4 and 9.8.1. The checks in ghc/build.sh that fail the build if the output references the amd64 sysroot or arm64 lld are good.
Nits
  • go/build.sh:11. The comment says the old ./go and bindist paths are kept "so the script fails shut on anything but the rung". On amd64, though, the bindist branch (line 47) still builds. With go-1.24.9 always staged, both fallbacks can go.
  • Stale comments.
    • hex0/amd64-ladder.ncl still describes the go/mrustc/rustc rungs ("38 packages").
    • gcc-15.2.0-glibc still says "(the jvm ladder roots)" import it.
  • Orphaned packages.
    • Nothing imports gcc-15.2.0-glibc or fastjar now.
    • binutils-2.46-glibc's only importer is gcc-15.2.0-glibc.
    • Related question: is the stage0/hex0 chain meant to stay in pkgs now that the ladders have moved out?
  • Duplicated JDK scripts. The three jdk-*/build.sh scripts are 123 lines each and differ by about 8 lines per pair. One shared script under packages/jdk/ would mean the next fix, the CVE step included, lands in one place.
  • A way around the source-only chain. alex and happy are build deps of ghc, and they are still built by ghc-bootstrap (the upstream 9.8.1 binary). That's a side door into the "source-only chain" that ghc/build.sh:66 guards.
  • History. 81 commits, including four empty ci: commits. Squash on merge?

…or the bootstrap prebuilts

- jdk-21, jdk-25, jdk-27: back to main's recipes (Temurin with the CVE-2026-111943 step and
  test, jdk-27 at 27.0.1.0.2). The from-source builds move to their own PR.
- openjdk-21/25/26, ghc-9.6.7, ocaml-5.5.2, go-1.24.9, rustc-1.98.1: a standalone version test
  each, run from the package's own runtime closure.
- ghc-9.6.7: arm64 declares llvm at runtime; its settings name ld.lld.
- go: bootstrap only from the go-1.24.9 rung; the ./go and bindist fallbacks are gone.
- gcc-15.2.0-glibc: drop a stale reference to the JVM ladder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bryan-minimal
Copy link
Copy Markdown
Member Author

Thanks, this is a careful review. Addressed in 7db96d5:

Blockers 1 and 2: the from-source JDKs are split out of this PR, as you suggested. jdk-21, jdk-25 and jdk-27 are back to main's recipes, byte for byte: Temurin, the CVE-2026-111943 step and test, and jdk-27 at 27.0.1.0.2. The from-source work continues on br D907 yan/jdk-from-source-v2 and will come back as its own PR on the .0.3-ga tags with the CVE step restored and one shared build script, and it will say how it differs from Temurin to users. Thanks for catching the #949 loss; that merge was mine.

Description: now covers the 39 deleted packages, the ghc boot compiler move, and the #1339 coordination.

Tests: each bootstrap prebuilt has a standalone version test with your paths. ghc-9.6.7's bin/ghc is a #!/bin/sh wrapper, so that test takes bash as its only test dep. ocamlc.byte runs through an absolute-path ocamlrun and needs nothing.

arm64 ghc-9.6.7 and lld: declared, llvm is an arm64 runtime dep now. I left ghc's own arm64 llvm build dep in place.

#1339: agreed, whichever lands second points rustc-1.98.1 at llvm-21 and makes libLLVM findable under its prefix. It's in the description.

Nits:

  • go/build.sh: the ./go and bindist fallbacks are gone; it bootstraps only from go-1.24.9 and checks the version.
  • gcc-15.2.0-glibc's stale JVM ladder comment is fixed. I left hex0/amd64-ladder.ncl alone: this PR doesn't otherwise touch it, and a comment edit there moves the hex0 spec and forces a cold rebuild of the stage0 chain. It will go with the decision below.
  • Orphans and the stage0 chain: you're right that nothing imports gcc-15.2.0-glibc, binutils-2.46-glibc or fastjar now. The ladders' home is gominimal/bootstrap, so I'd remove the stage0 chain from pkgs in a follow-up rather than grow this one.
  • The jdk-27 mirror comment and duplicated JDK scripts go with the JDK PR.
  • alex/happy still built by ghc-bootstrap: agreed it's a side door. A follow-up will build them with ghc-9.6.7 so ghc-bootstrap can go.
  • History: squash on merge, yes.

🤖 Generated with Claude Code

@bryan-minimal
bryan-minimal requested a review from msample November 6, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0