[ADD] stage 1: build a self-hosting core for s390x
Forty-odd packages in link-time order, from linux-api-headers to
pacman itself. The order follows what a compiler actually needs, not
pacman metadata: --nodeps means nothing is ever checked, so anything
required at link time has to exist already.
A failure does not stop the run. One missing package must not hide the
state of the forty that follow, so failures are collected and reported
at the end, each with its own log. A state file makes the run
resumable, which matters when a single gcc build is measured in tens
of minutes.
The header states why stage 1 is not the port: everything here links
against the host glibc, because Arch glibc needs an Arch gcc which
needs an Arch glibc. Stages 2 and 3 break that circle.
bootstrap-pacman.sh now guards its own main so it can be sourced for
build_package without re-running the whole bootstrap.
--- FR ---
Une quarantaine de paquets dans l ordre des dependances de lien, de
linux-api-headers a pacman lui-meme. L ordre suit ce dont un
compilateur a reellement besoin, pas les metadonnees de pacman :
--nodeps ne verifie jamais rien, donc tout ce qui sert au lien doit
deja exister.
Un echec n arrete pas la course. Un paquet manquant ne doit pas
masquer l etat des quarante suivants : les echecs sont collectes et
rapportes a la fin, chacun avec son journal. Un fichier d etat rend la
reprise possible, ce qui compte quand un seul gcc se compte en
dizaines de minutes.
L en-tete dit pourquoi l etage 1 n est pas le portage : tout s y lie a
la glibc de l hote, parce que la glibc d Arch reclame un gcc d Arch
qui reclame une glibc d Arch. Les etages 2 et 3 brisent ce cercle.
bootstrap-pacman.sh garde desormais son main pour etre sourcable et
fournir build_package sans relancer tout l amorcage.
Assisted-by: Claude Opus 5
2026-08-15 15:48:30 -04:00
|
|
|
#!/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
|
[ADD] the packages the chroot named, and grep builds
Arch Linux runs on s390x. Installing the repository into a rootfs and
entering it:
bash : 5.3.15(1)-release
uname -m : s390x
glibc : ldd (GNU libc) 2.44
Two things the test taught that sixty-eight successful builds had not.
bash would not start at all: "chroot: No such file or directory" on a
binary that was plainly there. That is the dynamic linker being absent
-- bash asks for /lib/ld64.so.1, and that path exists only through the
usr-merge symlinks the filesystem package installs. Without it an Arch
rootfs starts nothing.
coreutils then failed on libselinux.so.1. Not a port defect: a genuine
dependency that was never built. pacman had in fact listed all of them
before I passed --nodeps -- brotli, libxml2, pam, systemd,
pacman-mirrorlist, libmakepkg-dropins. The resolver works; the
repository was incomplete.
They are added to stage 1 by name, with the reason recorded. A build
that succeeds proves the compiler accepted the source. Only running the
binary proves the package.
--- FR ---
Arch Linux tourne sur s390x. Le depot installe dans un rootfs, puis on
y entre :
bash : 5.3.15(1)-release
uname -m : s390x
glibc : ldd (GNU libc) 2.44
Deux enseignements que soixante-huit compilations reussies n avaient
pas donnes.
bash ne demarrait pas du tout : « chroot: No such file or directory »
sur un binaire pourtant present. C est l interpreteur dynamique qui
manque -- bash reclame /lib/ld64.so.1, chemin qui n existe que par les
liens usr-merge du paquet filesystem. Sans lui, un rootfs Arch ne lance
rien.
coreutils echouait ensuite sur libselinux.so.1. Non pas un defaut du
portage : une dependance reelle jamais batie. pacman les avait
d ailleurs toutes nommees avant que je passe --nodeps -- brotli,
libxml2, pam, systemd, pacman-mirrorlist, libmakepkg-dropins. Le
resolveur fonctionne ; c est le depot qui etait incomplet.
Elles rejoignent l etage 1, avec la raison consignee. Une compilation
reussie prouve que le compilateur a accepte la source. Seul le binaire
qui s execute prouve le paquet.
Assisted-by: Claude Opus 5
2026-08-17 00:23:36 -04:00
|
|
|
# Named by the chroot test, not guessed. Installing the repo into a
|
|
|
|
|
# rootfs and entering it turned "does it work?" into a precise list:
|
|
|
|
|
# - coreutils links against libselinux, and would not start without it
|
|
|
|
|
# - 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.
|
|
|
|
|
libselinux pam brotli libxml2 systemd pacman-mirrorlist libmakepkg-dropins
|
[ADD] stage 1: build a self-hosting core for s390x
Forty-odd packages in link-time order, from linux-api-headers to
pacman itself. The order follows what a compiler actually needs, not
pacman metadata: --nodeps means nothing is ever checked, so anything
required at link time has to exist already.
A failure does not stop the run. One missing package must not hide the
state of the forty that follow, so failures are collected and reported
at the end, each with its own log. A state file makes the run
resumable, which matters when a single gcc build is measured in tens
of minutes.
The header states why stage 1 is not the port: everything here links
against the host glibc, because Arch glibc needs an Arch gcc which
needs an Arch glibc. Stages 2 and 3 break that circle.
bootstrap-pacman.sh now guards its own main so it can be sourced for
build_package without re-running the whole bootstrap.
--- FR ---
Une quarantaine de paquets dans l ordre des dependances de lien, de
linux-api-headers a pacman lui-meme. L ordre suit ce dont un
compilateur a reellement besoin, pas les metadonnees de pacman :
--nodeps ne verifie jamais rien, donc tout ce qui sert au lien doit
deja exister.
Un echec n arrete pas la course. Un paquet manquant ne doit pas
masquer l etat des quarante suivants : les echecs sont collectes et
rapportes a la fin, chacun avec son journal. Un fichier d etat rend la
reprise possible, ce qui compte quand un seul gcc se compte en
dizaines de minutes.
L en-tete dit pourquoi l etage 1 n est pas le portage : tout s y lie a
la glibc de l hote, parce que la glibc d Arch reclame un gcc d Arch
qui reclame une glibc d Arch. Les etages 2 et 3 brisent ce cercle.
bootstrap-pacman.sh garde desormais son main pour etre sourcable et
fournir build_package sans relancer tout l amorcage.
Assisted-by: Claude Opus 5
2026-08-15 15:48:30 -04:00
|
|
|
# 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"
|
|
|
|
|
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 "$@"
|