diff --git a/scripts/build-stage2.sh b/scripts/build-stage2.sh index cbcbb70..58f62d8 100755 --- a/scripts/build-stage2.sh +++ b/scripts/build-stage2.sh @@ -84,6 +84,14 @@ CHROOT_PKGS=( # STAGE2_FIRST instead. Listing it here would fail make_rootfs with "target # not found" against a repository that will never contain it. gperf wget patchelf inetutils swig help2man + # scdoc: kmod's meson asks for it by name. + scdoc + # + # The Python packaging set is NOT here. Those six cannot be built on the + # host at all -- see STAGE2_FIRST below -- so they come from repo2 and are + # listed in CHROOT_STAGE2_PKGS. python-flit-core is the exception: it is + # pure data with no install-path logic, so the host builds it correctly. + python-flit-core # libxcrypt-compat, for a reason no declaration expresses. perl declares # `libxcrypt` and `libcrypt.so`, both satisfied by libxcrypt, which ships # libcrypt.so.2. But perl's BINARY was linked on the host against Ubuntu's @@ -452,6 +460,47 @@ in_chroot() { /usr/bin/bash -lc "$*" } +# The CA bundle, which nothing else was going to create. +# +# Four packages -- m4, libtool, groff, libnghttp2 -- failed in prepare() on +# +# Failed to clone 'gl-mod/bootstrap' a second time, aborting +# +# and the first diagnosis was DNS, correctly: the chroot had no resolv.conf. +# Copying it fixed resolution -- `getent hosts github.com` answers -- and the +# clones still failed, now on +# +# fatal: unable to access 'https://...': error adding trust anchors from +# file: /etc/ssl/certs/ca-certificates.crt +# +# Everything needed was already installed: the symlink, the Mozilla trust +# source, update-ca-trust, and p11-kit's trust. What was missing is that the +# bundle those produce is generated by an ALPM HOOK, and `pacman --root` does +# not run hooks -- so /etc/ca-certificates/extracted/tls-ca-bundle.pem, the +# target of that symlink, never existed. A dangling symlink and a complete +# installation look identical in a package list. +# +# Generated from OUR OWN trust source, not copied from the host: this is what +# will be on the target, and copying Ubuntu's bundle would be exactly the kind +# of host artefact the ARTEFACT check exists to find. +generate_ca_bundle() { + log "Generating the CA bundle" + if in_chroot "update-ca-trust" > "$WORK/stage2-ca.txt" 2>&1; then + local n + n=$(sudo grep -c "BEGIN CERTIFICATE" \ + "$ROOT/etc/ca-certificates/extracted/tls-ca-bundle.pem" 2>/dev/null || echo 0) + # A count, because update-ca-trust exits 0 on an empty trust source and + # the failure it hides is an https clone hours later. + if [ "${n:-0}" -lt 50 ]; then + printf ' WARNING: only %s certificates extracted; https will fail\n' "${n:-0}" + else + printf ' %s certificates\n' "$n" + fi + else + printf ' WARNING: update-ca-trust failed, see %s\n' "$WORK/stage2-ca.txt" + fi +} + smoke_test() { log "Smoke test: does the chroot build anything at all?" # NO PIPELINES IN THESE CHECKS. The first version ran `makeinfo --version | @@ -592,7 +641,15 @@ NOTE # a wget that cannot start stops them before they compile a line. Exactly the # bsdtar shape: a stage-1 TOOL linked against the host, which only matters # once it is the tool actually being used. -STAGE2_FIRST=(texinfo libxml2 binutils pkgconf wget libxslt) +# +# the Python packaging set -- brotli, libseccomp and meson build wheels with +# `python -m build`, which did not exist in the chroot. Building it means +# running it, and its dependencies close the same circle. Arch's PKGBUILDs +# carry _bootstrap=1 for exactly this, and it must run in HERE rather than on +# the host, whose python would bake dist-packages into every one of them. +STAGE2_FIRST=(texinfo libxml2 binutils pkgconf wget libxslt + python-packaging python-pyproject-hooks python-build + python-installer python-setuptools python-wheel) # Packages the chroot needs that can only come from repo2. # @@ -612,7 +669,26 @@ STAGE2_FIRST=(texinfo libxml2 binutils pkgconf wget libxslt) # conflicts with the zlib stage 1 chose for this chroot. A list says which # packages are build tools and why; a conflict heuristic would have to be # extended every time a package like that appeared. -CHROOT_STAGE2_PKGS=(libxslt) +CHROOT_STAGE2_PKGS=( + libxslt + # The Python packaging set, for the same reason and a sharper one: their + # package() computes install paths from the RUNNING python. + # + # local site_packages=$(python -c "import site; print(site.getsitepackages()[0])") + # rm "$pkgdir/$site_packages/$_name"/*.exe + # + # On the host that resolves to Debian's dist-packages, so three of them + # failed on `rm` finding nothing -- and the three that SUCCEEDED shipped + # usr/lib/python3/dist-packages, where our python 3.14 never looks. 180 + # paths of unreachable modules, and nothing about them looked wrong. + # + # The failures were protective. That is the useful lesson here: those three + # refused rather than shipping the same fiction, and the ARTEFACT check -- + # which only ever asked about C library directories -- has been taught + # dist-packages so it can say so next time. + python-packaging python-pyproject-hooks python-build + python-installer python-setuptools python-wheel +) STAGE2_SKIP_HOOKS=(libgcrypt git meson libarchive) @@ -681,6 +757,21 @@ stage2_build() { else ( cd "$dir" && bash "$PATCH_DIR/$name.sh" ) || { echo " hook failed" >&2; return 1; } + # A hook can leave a PKGBUILD that no longer parses, and makepkg + # reports that far from its cause: + # + # /build/binutils/PKGBUILD: line 107: --enable-plugins: + # command not found + # + # binutils' hook had commented out one option of a + # backslash-continued ./configure, which does not remove an option + # -- it breaks the continuation, and the next option becomes a + # command. Checking here names the hook that did it. + # + # -O extglob because PKGBUILDs use it (`rm -r !(test)`), and bash -n + # calls a valid file broken without it. + ( cd "$dir" && bash -O extglob -n PKGBUILD ) || { + echo " hook left an unparseable PKGBUILD" >&2; return 1; } fi fi @@ -826,6 +917,7 @@ main() { make_rootfs configure_chroot mount_chroot + generate_ca_bundle smoke_test || die "the chroot cannot build; stage 2 stops here" log "Chroot ready" if [ "$#" -eq 0 ]; then