The previous commit read the chroot's "coreutils needs libselinux.so.1" as a missing package. It is not one. Arch has no libselinux at all -- the clone 404s -- and Arch's coreutils declares no selinux dependency, because its build chroot has no selinux/selinux.h to find. Ours found one. Ubuntu carries libselinux1-dev, gnulib probes for the header unconditionally, and the audit names every victim: coreutils 13 binaries findutils find sed tar glibc makedb --without-selinux per package, which is what Arch gets for free. Arch ships neither chcon nor runcon either, so this converges with Arch rather than diverging. tar and find matter most: stage 2 runs makepkg inside this rootfs, and makepkg calls both. glibc is deliberately left alone. Nothing runs makedb, and rebuilding glibc would relink the foundation under sixty-nine other packages; stage 2 does it in a chroot where the header cannot be found. --- FR --- Le commit précédent a lu le « coreutils réclame libselinux.so.1 » du chroot comme un paquet manquant. Ce n'en est pas un. Arch n'a aucun libselinux — le clone rend un 404 — et son coreutils ne déclare aucune dépendance selinux, faute de selinux/selinux.h dans son chroot de construction. Le nôtre en a trouvé un. Ubuntu embarque libselinux1-dev, gnulib sonde l'en-tête sans condition, et l'audit nomme chaque victime : coreutils 13 binaires findutils find sed tar glibc makedb --without-selinux par paquet, ce qu'Arch obtient gratuitement. Arch ne livre ni chcon ni runcon non plus : on converge donc vers Arch au lieu de s'en écarter. tar et find sont les plus critiques — l'étage 2 lance makepkg dans ce rootfs, et makepkg les appelle tous deux. glibc est laissé tel quel, délibérément. Rien n'exécute makedb, et le reconstruire relierait la fondation sous soixante-neuf autres paquets ; l'étage 2 s'en charge dans un chroot où l'en-tête est introuvable. Assisted-by: Claude Opus 5
99 lines
4.3 KiB
Bash
Executable file
99 lines
4.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Stage 1 of the port: build a self-hosting Arch `core` for s390x.
|
|
#
|
|
# THE THREE-STAGE DISCIPLINE, AND WHY IT IS NOT OPTIONAL
|
|
#
|
|
# Stage 1 builds with the HOST toolchain (Ubuntu gcc/glibc). Every package it
|
|
# produces is therefore linked against the host's glibc, not Arch's. That is
|
|
# acceptable -- and unavoidable, since Arch's glibc needs an Arch gcc which
|
|
# needs an Arch glibc -- but it is not a port yet.
|
|
#
|
|
# Stage 2 chroots into the stage-1 result and rebuilds everything with the
|
|
# stage-1 toolchain. Stage 3 repeats it, and a port is self-hosting once
|
|
# stage 3 reproduces stage 2. Skipping this leaves host artefacts baked into
|
|
# packages that will fail months later, far from their cause.
|
|
#
|
|
# This script is stage 1 only.
|
|
set -uo pipefail
|
|
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
source "$HERE/bootstrap-pacman.sh"
|
|
|
|
WORK="${WORK:-$HOME/work/arch-s390x}"
|
|
REPO="${REPO:-$WORK/repo/s390x}"
|
|
STATE="$WORK/stage1.state"
|
|
|
|
# Build order. It follows link-time dependencies, not pacman metadata:
|
|
# --nodeps means pacman never checks, so anything a compiler actually needs
|
|
# must already exist. Within a group the order is free.
|
|
STAGE1_PACKAGES=(
|
|
# Foundation: headers, then the C library, then the compiler chain.
|
|
linux-api-headers glibc binutils gcc
|
|
# Compression and crypto, needed by libarchive and curl further down.
|
|
zlib bzip2 xz zstd lz4 openssl
|
|
# Terminal handling: bash links against readline, readline against ncurses.
|
|
ncurses readline
|
|
# The shell, and the coreutils prerequisites Arch declares.
|
|
attr acl gmp mpfr libcap bash coreutils
|
|
# Text and file tools the build systems themselves call.
|
|
sed grep gawk findutils diffutils file which patch
|
|
# Archivers, then the library pacman reads packages with.
|
|
tar gzip expat libarchive
|
|
# Build systems.
|
|
m4 autoconf automake libtool make pkgconf
|
|
# pacman's network and signature stack.
|
|
libnghttp2 libpsl curl libgpg-error libassuan gnupg gpgme
|
|
# System skeleton: without these a rootfs has no /etc/passwd, no zones,
|
|
# no /etc/services -- and nothing boots to a usable shell.
|
|
filesystem iana-etc tzdata licenses shadow util-linux
|
|
# Named by the chroot test, not guessed. Installing the repo into a
|
|
# rootfs and entering it turned "does it work?" into a precise list:
|
|
# - libcap needs pam; openssl needs brotli; libarchive needs libxml2
|
|
# - pacman itself asks for systemd, pacman-mirrorlist and
|
|
# libmakepkg-dropins
|
|
# Sixty-eight successful builds proved none of this. One chroot did.
|
|
#
|
|
# The chroot also named libselinux, and libselinux is NOT on this line,
|
|
# because that reading of it was wrong. Arch has no libselinux package at
|
|
# all -- the clone 404s. What the chroot saw was a HOST artefact: Ubuntu
|
|
# carries libselinux1-dev, coreutils probes for selinux/selinux.h
|
|
# unconditionally, and ours came out linked to a library the target will
|
|
# never contain. The answer is --without-selinux per package, which is
|
|
# what Arch's own build chroot gets for free by not having the header.
|
|
pam brotli libxml2 systemd pacman-mirrorlist libmakepkg-dropins
|
|
# And finally the package manager itself, built as an Arch package.
|
|
pacman
|
|
)
|
|
|
|
built() { grep -qxF "$1" "$STATE" 2>/dev/null; }
|
|
mark() { echo "$1" >> "$STATE"; }
|
|
|
|
main() {
|
|
mkdir -p "$WORK/pkg" "$REPO"
|
|
touch "$STATE"
|
|
# The stand-ins are read from /usr/local/bin, so a stage-1 run that never
|
|
# reinstalls them silently builds with whatever was deployed weeks ago.
|
|
# Cheap, idempotent, and it makes this repository the source of truth.
|
|
install_host_shims
|
|
local ok=0 fail=0 failed=()
|
|
for p in "${STAGE1_PACKAGES[@]}"; do
|
|
if built "$p"; then
|
|
echo "== $p already built, skipping =="
|
|
continue
|
|
fi
|
|
# A failure must not stop the run: one missing package should not hide
|
|
# the state of the forty that follow. They are collected and reported.
|
|
if build_package "$p" > "$WORK/log-$p.txt" 2>&1; then
|
|
mark "$p"; ok=$((ok + 1))
|
|
echo "OK $p"
|
|
else
|
|
fail=$((fail + 1)); failed+=("$p")
|
|
echo "FAIL $p (see $WORK/log-$p.txt)"
|
|
fi
|
|
done
|
|
echo
|
|
echo "== stage 1: $ok built, $fail failed =="
|
|
[ "$fail" -eq 0 ] || printf ' failed: %s\n' "${failed[*]}"
|
|
}
|
|
|
|
main "$@"
|