archlinux-s390x/scripts/build-stage1.sh

129 lines
5.7 KiB
Bash
Raw Permalink Normal View History

[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"
[FIX] stage 2: the build tools the host was providing silently glibc rebuilt inside the chroot; binutils died on `make info-recursive`, and makeinfo said why: its XS module was compiled against the host's perl 5.40 and our perl is 5.42. Stage-1 texinfo cannot run in there. Everything that builds .info documentation needs it, and it sat near the end of the list because that is where its own dependencies are, so stage 2 hoists it. linux-api-headers stopped earlier on `rsync: command not found` -- the kernel's headers_install runs it. apt had put it there and a build that finds its tool says nothing, so stage 1 never mentioned it. Its man pages come from Markdown the git tag does not pre-render, hence --disable-md2man. An inventory of the 110 apt packages against the chroot found 84 more such binaries. Most are documentation; the rest wait until something needs them. --- FR --- glibc a été rebâti dans le chroot ; binutils est mort sur `make info-recursive`, et makeinfo en donne la raison : son module XS a été compilé contre le perl 5.40 de l'hôte, or le nôtre est en 5.42. Le texinfo de l'étage 1 ne peut pas tourner là-dedans. Tout ce qui bâtit de la documentation .info en dépend, et il figurait en fin de liste, là où sont ses propres dépendances : l'étage 2 le remonte. linux-api-headers s'était arrêté avant sur `rsync: command not found` — le headers_install du noyau l'appelle. apt l'avait posé, et une construction qui trouve son outil n'en dit rien : l'étage 1 ne l'a jamais mentionné. Ses pages de manuel viennent d'un Markdown que l'étiquette git ne rend pas, d'où --disable-md2man. Un inventaire des 110 paquets apt face au chroot a trouvé 84 autres binaires du même genre. La plupart sont de la documentation ; le reste attendra qu'un paquet les réclame. Assisted-by: Claude Opus 5
2026-08-20 01:34:41 -04:00
source "$HERE/lib-watch.sh"
[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
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.
[IMP] stage 2: resumable, guarded, driven by the shared list Stage 2 could rebuild one named package. It could not rebuild a hundred and thirty-three, for reasons that were all about the driver. The order is not re-derived: it is the closure stage 1 arrived at over four rounds of resolver output and then confirmed by 179 builds, so it moves to packages.sh and both stages read it. make_rootfs wipes the chroot every run, which is what makes it reproducible and what made stage 2 unresumable -- stage2.state outlived the packages it named. Its output is now put back. The stall guard is shared rather than copied: stage 2 needs it more, since a test suite is the likeliest thing in a build to wait forever. Build trees are removed after a package installs, never after it fails. --- FR --- L'étage 2 savait rebâtir un paquet nommé. Il ne savait pas en rebâtir cent trente-trois, pour des raisons qui tenaient toutes au pilote. L'ordre n'est pas réinventé : c'est la fermeture obtenue à l'étage 1 en quatre tours de sortie du résolveur, puis confirmée par 179 constructions. Il passe donc dans packages.sh, que les deux étages lisent. make_rootfs efface le chroot à chaque passage — ce qui le rend reproductible et rendait l'étage 2 irreprenable, stage2.state survivant aux paquets qu'il nommait. Sa production y est désormais réinstallée. La garde d'immobilité est partagée plutôt que recopiée : l'étage 2 en a plus besoin, une suite de tests étant ce qui attend le plus volontiers pour toujours. Les arbres de compilation sont effacés après installation, jamais après un échec. Assisted-by: Claude Opus 5
2026-08-20 01:16:49 -04:00
# The list and its order live in one file, read by both stages -- see the
# header of packages.sh for why stage 2 must not derive its own.
source "$HERE/packages.sh"
[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
[FIX] driver: kill a build that has stopped producing output python's PKGBUILD hunts for a free X display before running make: export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run is not installed here. It exits 127, `!` inverts that to true, and the loop tries the next number. There is no exit condition for "the command does not exist", and the 2>/dev/null swallows the one line that would have said so. Measured before anyone noticed: ten hours of wall clock, four million PIDs, and a log frozen at `configure: creating Makefile`. Every signal said the build was healthy -- alive, 40% CPU, sitting in a plausible source directory. A process list cannot tell work from spinning. A stalled log next to a live makepkg can, and that is all this guard does. Forty-five minutes of COMPLETE silence, because real builds do go quiet: a long link, a test suite that prints nothing, gcc between bootstrap stages. The case this was written for ran two hundred times longer. EL_STALL_MIN=0 disables it. Tested against a real spin loop: detected, whole process tree killed, rc=2 so STALL reads differently from FAIL in the summary. --- FR --- Le PKGBUILD de python cherche un numéro d'affichage X libre avant make : export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run n'est pas installé ici. Il sort en 127, le `!` inverse, et la boucle essaie le numéro suivant. Il n'existe aucune condition de sortie pour « la commande n'existe pas », et le 2>/dev/null avale la seule ligne qui l'aurait dit. Mesuré avant que quiconque s'en aperçoive : dix heures d'horloge, quatre millions de PID, un journal figé à `configure: creating Makefile`. Tous les signaux disaient que le build allait bien — vivant, 40 % de CPU, dans un répertoire source plausible. Une liste de processus ne distingue pas le travail du sur-place. Un journal figé à côté d'un makepkg vivant, si — et c'est tout ce que fait ce garde-fou. Quarante-cinq minutes de silence COMPLET, car de vrais builds se taisent : une longue édition de liens, une suite de tests muette, gcc entre deux étages. Le cas qui l'a motivé a tourné deux cents fois plus longtemps. EL_STALL_MIN=0 le désactive. Éprouvé contre une vraie boucle infinie : détecté, arbre de processus tué en entier, rc=2 pour que STALL se lise autrement que FAIL dans le bilan. Assisted-by: Claude Opus 5
2026-08-19 19:53:46 -04:00
# Kill a build that has stopped producing output.
#
# WHY THIS EXISTS. python's PKGBUILD contains
#
# while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do
# servernum=$((servernum+1)); done
#
# and xvfb-run is not installed here. It exits 127, `!` inverts that to true,
# and the loop tries the next display number. Forever -- there is no exit
# condition for "the command does not exist", and the 2>/dev/null swallows the
# one line that would have said so.
#
# Measured before anyone noticed: TEN HOURS of wall clock, four million PIDs,
# and a log frozen at `configure: creating Makefile`. Every signal I had said
# the build was healthy -- the process was alive, burning 40% CPU, sitting in
# a plausible source directory. A process list cannot tell work from spinning.
#
# A STALLED LOG NEXT TO A LIVE makepkg CAN. That is the whole idea here.
#
# The threshold is deliberately generous. Real builds do go quiet: a long link,
# a test suite that prints nothing, gcc between bootstrap stages. Forty-five
# minutes of COMPLETE silence is not one of those, and the case this was
# written for ran two hundred times longer. EL_STALL_MIN=0 disables it.
#
# `set -m` rather than setsid or a bare `&`. The whole tree has to die, because
# makepkg forks children that outlive it -- killing the parent alone leaves
# them spinning, which is how ten hours happened. Job control gives the
# background job its own process group, so `kill -- -$pid` reaches all of it.
#
# A subshell, NOT `setsid bash -c "$(declare -f ...)"`. The first attempt here
# re-declared build_package into a fresh shell, which loses $WORK, $REPO,
# $PATCH_DIR and every other function it calls -- a guard that would have
# broken the thing it was guarding.
[IMP] stage 2: resumable, guarded, driven by the shared list Stage 2 could rebuild one named package. It could not rebuild a hundred and thirty-three, for reasons that were all about the driver. The order is not re-derived: it is the closure stage 1 arrived at over four rounds of resolver output and then confirmed by 179 builds, so it moves to packages.sh and both stages read it. make_rootfs wipes the chroot every run, which is what makes it reproducible and what made stage 2 unresumable -- stage2.state outlived the packages it named. Its output is now put back. The stall guard is shared rather than copied: stage 2 needs it more, since a test suite is the likeliest thing in a build to wait forever. Build trees are removed after a package installs, never after it fails. --- FR --- L'étage 2 savait rebâtir un paquet nommé. Il ne savait pas en rebâtir cent trente-trois, pour des raisons qui tenaient toutes au pilote. L'ordre n'est pas réinventé : c'est la fermeture obtenue à l'étage 1 en quatre tours de sortie du résolveur, puis confirmée par 179 constructions. Il passe donc dans packages.sh, que les deux étages lisent. make_rootfs efface le chroot à chaque passage — ce qui le rend reproductible et rendait l'étage 2 irreprenable, stage2.state survivant aux paquets qu'il nommait. Sa production y est désormais réinstallée. La garde d'immobilité est partagée plutôt que recopiée : l'étage 2 en a plus besoin, une suite de tests étant ce qui attend le plus volontiers pour toujours. Les arbres de compilation sont effacés après installation, jamais après un échec. Assisted-by: Claude Opus 5
2026-08-20 01:16:49 -04:00
# The stall guard moved to bootstrap-pacman.sh when stage 2 needed it too.
build_watched() { watched "$2" build_package "$1"; }
[FIX] driver: kill a build that has stopped producing output python's PKGBUILD hunts for a free X display before running make: export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run is not installed here. It exits 127, `!` inverts that to true, and the loop tries the next number. There is no exit condition for "the command does not exist", and the 2>/dev/null swallows the one line that would have said so. Measured before anyone noticed: ten hours of wall clock, four million PIDs, and a log frozen at `configure: creating Makefile`. Every signal said the build was healthy -- alive, 40% CPU, sitting in a plausible source directory. A process list cannot tell work from spinning. A stalled log next to a live makepkg can, and that is all this guard does. Forty-five minutes of COMPLETE silence, because real builds do go quiet: a long link, a test suite that prints nothing, gcc between bootstrap stages. The case this was written for ran two hundred times longer. EL_STALL_MIN=0 disables it. Tested against a real spin loop: detected, whole process tree killed, rc=2 so STALL reads differently from FAIL in the summary. --- FR --- Le PKGBUILD de python cherche un numéro d'affichage X libre avant make : export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run n'est pas installé ici. Il sort en 127, le `!` inverse, et la boucle essaie le numéro suivant. Il n'existe aucune condition de sortie pour « la commande n'existe pas », et le 2>/dev/null avale la seule ligne qui l'aurait dit. Mesuré avant que quiconque s'en aperçoive : dix heures d'horloge, quatre millions de PID, un journal figé à `configure: creating Makefile`. Tous les signaux disaient que le build allait bien — vivant, 40 % de CPU, dans un répertoire source plausible. Une liste de processus ne distingue pas le travail du sur-place. Un journal figé à côté d'un makepkg vivant, si — et c'est tout ce que fait ce garde-fou. Quarante-cinq minutes de silence COMPLET, car de vrais builds se taisent : une longue édition de liens, une suite de tests muette, gcc entre deux étages. Le cas qui l'a motivé a tourné deux cents fois plus longtemps. EL_STALL_MIN=0 le désactive. Éprouvé contre une vraie boucle infinie : détecté, arbre de processus tué en entier, rc=2 pour que STALL se lise autrement que FAIL dans le bilan. Assisted-by: Claude Opus 5
2026-08-19 19:53:46 -04:00
[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
built() { grep -qxF "$1" "$STATE" 2>/dev/null; }
[FIX] stage 2: produce its first package Stage 2 could build and could not deliver. Four obstacles, all in the tail of package(), after a compile that had already succeeded. Our meson ships arch-meson and it passes --auto-features enabled, so each of the nine documentation tools this chroot lacks was a hard error, not a skipped feature. A wrapper appends --auto-features auto; meson honours the last one. Building those tools was the alternative and it is not close -- doxygen alone wants clang, fmt, spdlog, llvm-libs. Then bsdtar would not start: stage-1 libxml2 asks for the host's libicuuc.so.76, our icu ships 78, and bsdtar is what writes the package. The package that would fix it was the one being built. libarchive only links libxml2 for xar, which nothing here reads, so stage 1 drops it. Verified: libxml2 rebuilt against libicuuc.so.78, provides libxml2.so=16-64, zero multiarch paths. --- FR --- L'étage 2 savait bâtir et ne savait pas livrer. Quatre obstacles, tous dans la queue de package(), après une compilation déjà réussie. Notre meson livre arch-meson, qui passe --auto-features enabled : chacun des neuf outils de documentation absents de ce chroot devenait une erreur franche au lieu d'une option écartée. Une enveloppe ajoute --auto-features auto, meson retenant la dernière occurrence. Bâtir ces outils était l'autre voie et l'écart est net -- doxygen seul réclame clang, fmt, spdlog, llvm-libs. Puis bsdtar ne démarrait plus : le libxml2 de l'étage 1 réclame le libicuuc.so.76 de l'hôte, notre icu livre le 78, et bsdtar est ce qui écrit le paquet. Le paquet qui corrigeait cela était celui qu'on bâtissait. libarchive ne lie libxml2 que pour xar, que rien ici ne lit : l'étage 1 l'abandonne. Vérifié : libxml2 rebâti sur libicuuc.so.78, fournit libxml2.so=16-64, aucun chemin multiarch. Assisted-by: Claude Opus 5
2026-08-20 01:12:14 -04:00
# Appended only once: a forced rebuild of an already-built package must not
# leave two identical lines in the state file. built() uses grep -qxF, so a
# duplicate is harmless to the logic and confusing to a reader counting lines.
mark() { built "$1" || echo "$1" >> "$STATE"; }
[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
main() {
mkdir -p "$WORK/pkg" "$REPO"
touch "$STATE"
[FIX] libdir: the Debian host hid the libraries from Arch meson and cmake both ask the HOST where libraries go. On Ubuntu the answer is lib/s390x-linux-gnu, so five packages already in the repository ship theirs where Arch's ld.so and pkgconf never look. Measured: expat 12 lz4 6 pacman 6 pkgconf 6 zstd 12 entries Nothing failed. util-linux is where it finally shouted, and even there the rm was the first victim, not the cause. pacman is the one that matters: libalpm.so.16 landed where pacman's own binary cannot load it, and a target installed from that package has no working package manager left to repair itself with. arch-meson now states the libdir devtools has no need to state, and is reinstalled on every run -- editing the copy here changed nothing while /usr/local/bin held a stale one. Four packages call bare meson or cmake and get their own hook. util-linux's old hook chased lib64, which never existed here; it is deleted. --- FR --- meson et cmake demandent tous deux à l'HÔTE où vont les bibliothèques. Sous Ubuntu la réponse est lib/s390x-linux-gnu : cinq paquets déjà dans le dépôt livrent donc les leurs là où ld.so et pkgconf d'Arch ne regarderont jamais. Mesuré : expat 12 lz4 6 pacman 6 pkgconf 6 zstd 12 entrées Rien n'a échoué. util-linux est l'endroit où cela a fini par crier, et même là le rm était la première victime, pas la cause. pacman est celui qui compte : libalpm.so.16 atterrissait là où le binaire de pacman ne peut pas la charger, et une cible installée depuis ce paquet n'a plus de gestionnaire de paquets pour se réparer. arch-meson énonce désormais le libdir que devtools n'a pas besoin d'énoncer, et se réinstalle à chaque exécution : éditer la copie du dépôt ne changeait rien tant que /usr/local/bin en gardait une périmée. Quatre paquets appellent meson ou cmake nu et reçoivent leur crochet. L'ancien crochet util-linux poursuivait un lib64 qui n'a jamais existé ici : il est supprimé. Assisted-by: Claude Opus 5
2026-08-17 01:33:41 -04:00
# 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
[FIX] stage 2: produce its first package Stage 2 could build and could not deliver. Four obstacles, all in the tail of package(), after a compile that had already succeeded. Our meson ships arch-meson and it passes --auto-features enabled, so each of the nine documentation tools this chroot lacks was a hard error, not a skipped feature. A wrapper appends --auto-features auto; meson honours the last one. Building those tools was the alternative and it is not close -- doxygen alone wants clang, fmt, spdlog, llvm-libs. Then bsdtar would not start: stage-1 libxml2 asks for the host's libicuuc.so.76, our icu ships 78, and bsdtar is what writes the package. The package that would fix it was the one being built. libarchive only links libxml2 for xar, which nothing here reads, so stage 1 drops it. Verified: libxml2 rebuilt against libicuuc.so.78, provides libxml2.so=16-64, zero multiarch paths. --- FR --- L'étage 2 savait bâtir et ne savait pas livrer. Quatre obstacles, tous dans la queue de package(), après une compilation déjà réussie. Notre meson livre arch-meson, qui passe --auto-features enabled : chacun des neuf outils de documentation absents de ce chroot devenait une erreur franche au lieu d'une option écartée. Une enveloppe ajoute --auto-features auto, meson retenant la dernière occurrence. Bâtir ces outils était l'autre voie et l'écart est net -- doxygen seul réclame clang, fmt, spdlog, llvm-libs. Puis bsdtar ne démarrait plus : le libxml2 de l'étage 1 réclame le libicuuc.so.76 de l'hôte, notre icu livre le 78, et bsdtar est ce qui écrit le paquet. Le paquet qui corrigeait cela était celui qu'on bâtissait. libarchive ne lie libxml2 que pour xar, que rien ici ne lit : l'étage 1 l'abandonne. Vérifié : libxml2 rebâti sur libicuuc.so.78, fournit libxml2.so=16-64, aucun chemin multiarch. Assisted-by: Claude Opus 5
2026-08-20 01:12:14 -04:00
# Named packages rebuild on demand, the way stage 2 already works.
#
# Without this, rebuilding one package means deleting its line from
# stage1.state first -- editing the record of what was built in order to
# build something. That file is the port's memory; the opening instruction
# for this work is to regenerate it from what is REALLY in repo/s390x and
# never from a log, and hand-editing it is the same mistake in a smaller
# form. Naming a package is also how a hook gets tested: libarchive's xar
# fix needed exactly one package rebuilt, not a pass over a hundred and
# ninety.
local list=("${STAGE1_PACKAGES[@]}") forced=0
if [ "$#" -gt 0 ]; then
list=("$@")
forced=1
printf '== stage 1: rebuilding on request: %s ==\n' "$*"
fi
[FIX] driver: kill a build that has stopped producing output python's PKGBUILD hunts for a free X display before running make: export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run is not installed here. It exits 127, `!` inverts that to true, and the loop tries the next number. There is no exit condition for "the command does not exist", and the 2>/dev/null swallows the one line that would have said so. Measured before anyone noticed: ten hours of wall clock, four million PIDs, and a log frozen at `configure: creating Makefile`. Every signal said the build was healthy -- alive, 40% CPU, sitting in a plausible source directory. A process list cannot tell work from spinning. A stalled log next to a live makepkg can, and that is all this guard does. Forty-five minutes of COMPLETE silence, because real builds do go quiet: a long link, a test suite that prints nothing, gcc between bootstrap stages. The case this was written for ran two hundred times longer. EL_STALL_MIN=0 disables it. Tested against a real spin loop: detected, whole process tree killed, rc=2 so STALL reads differently from FAIL in the summary. --- FR --- Le PKGBUILD de python cherche un numéro d'affichage X libre avant make : export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run n'est pas installé ici. Il sort en 127, le `!` inverse, et la boucle essaie le numéro suivant. Il n'existe aucune condition de sortie pour « la commande n'existe pas », et le 2>/dev/null avale la seule ligne qui l'aurait dit. Mesuré avant que quiconque s'en aperçoive : dix heures d'horloge, quatre millions de PID, un journal figé à `configure: creating Makefile`. Tous les signaux disaient que le build allait bien — vivant, 40 % de CPU, dans un répertoire source plausible. Une liste de processus ne distingue pas le travail du sur-place. Un journal figé à côté d'un makepkg vivant, si — et c'est tout ce que fait ce garde-fou. Quarante-cinq minutes de silence COMPLET, car de vrais builds se taisent : une longue édition de liens, une suite de tests muette, gcc entre deux étages. Le cas qui l'a motivé a tourné deux cents fois plus longtemps. EL_STALL_MIN=0 le désactive. Éprouvé contre une vraie boucle infinie : détecté, arbre de processus tué en entier, rc=2 pour que STALL se lise autrement que FAIL dans le bilan. Assisted-by: Claude Opus 5
2026-08-19 19:53:46 -04:00
local ok=0 fail=0 rc=0 failed=()
[FIX] stage 2: produce its first package Stage 2 could build and could not deliver. Four obstacles, all in the tail of package(), after a compile that had already succeeded. Our meson ships arch-meson and it passes --auto-features enabled, so each of the nine documentation tools this chroot lacks was a hard error, not a skipped feature. A wrapper appends --auto-features auto; meson honours the last one. Building those tools was the alternative and it is not close -- doxygen alone wants clang, fmt, spdlog, llvm-libs. Then bsdtar would not start: stage-1 libxml2 asks for the host's libicuuc.so.76, our icu ships 78, and bsdtar is what writes the package. The package that would fix it was the one being built. libarchive only links libxml2 for xar, which nothing here reads, so stage 1 drops it. Verified: libxml2 rebuilt against libicuuc.so.78, provides libxml2.so=16-64, zero multiarch paths. --- FR --- L'étage 2 savait bâtir et ne savait pas livrer. Quatre obstacles, tous dans la queue de package(), après une compilation déjà réussie. Notre meson livre arch-meson, qui passe --auto-features enabled : chacun des neuf outils de documentation absents de ce chroot devenait une erreur franche au lieu d'une option écartée. Une enveloppe ajoute --auto-features auto, meson retenant la dernière occurrence. Bâtir ces outils était l'autre voie et l'écart est net -- doxygen seul réclame clang, fmt, spdlog, llvm-libs. Puis bsdtar ne démarrait plus : le libxml2 de l'étage 1 réclame le libicuuc.so.76 de l'hôte, notre icu livre le 78, et bsdtar est ce qui écrit le paquet. Le paquet qui corrigeait cela était celui qu'on bâtissait. libarchive ne lie libxml2 que pour xar, que rien ici ne lit : l'étage 1 l'abandonne. Vérifié : libxml2 rebâti sur libicuuc.so.78, fournit libxml2.so=16-64, aucun chemin multiarch. Assisted-by: Claude Opus 5
2026-08-20 01:12:14 -04:00
for p in "${list[@]}"; do
# An explicit request outranks the state file. Asking for a package
# that is already built and being told it was skipped would make the
# command useless for the one job it exists to do.
if [ "$forced" -eq 0 ] && built "$p"; then
[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
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.
[FIX] driver: kill a build that has stopped producing output python's PKGBUILD hunts for a free X display before running make: export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run is not installed here. It exits 127, `!` inverts that to true, and the loop tries the next number. There is no exit condition for "the command does not exist", and the 2>/dev/null swallows the one line that would have said so. Measured before anyone noticed: ten hours of wall clock, four million PIDs, and a log frozen at `configure: creating Makefile`. Every signal said the build was healthy -- alive, 40% CPU, sitting in a plausible source directory. A process list cannot tell work from spinning. A stalled log next to a live makepkg can, and that is all this guard does. Forty-five minutes of COMPLETE silence, because real builds do go quiet: a long link, a test suite that prints nothing, gcc between bootstrap stages. The case this was written for ran two hundred times longer. EL_STALL_MIN=0 disables it. Tested against a real spin loop: detected, whole process tree killed, rc=2 so STALL reads differently from FAIL in the summary. --- FR --- Le PKGBUILD de python cherche un numéro d'affichage X libre avant make : export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run n'est pas installé ici. Il sort en 127, le `!` inverse, et la boucle essaie le numéro suivant. Il n'existe aucune condition de sortie pour « la commande n'existe pas », et le 2>/dev/null avale la seule ligne qui l'aurait dit. Mesuré avant que quiconque s'en aperçoive : dix heures d'horloge, quatre millions de PID, un journal figé à `configure: creating Makefile`. Tous les signaux disaient que le build allait bien — vivant, 40 % de CPU, dans un répertoire source plausible. Une liste de processus ne distingue pas le travail du sur-place. Un journal figé à côté d'un makepkg vivant, si — et c'est tout ce que fait ce garde-fou. Quarante-cinq minutes de silence COMPLET, car de vrais builds se taisent : une longue édition de liens, une suite de tests muette, gcc entre deux étages. Le cas qui l'a motivé a tourné deux cents fois plus longtemps. EL_STALL_MIN=0 le désactive. Éprouvé contre une vraie boucle infinie : détecté, arbre de processus tué en entier, rc=2 pour que STALL se lise autrement que FAIL dans le bilan. Assisted-by: Claude Opus 5
2026-08-19 19:53:46 -04:00
if build_watched "$p" "$WORK/log-$p.txt"; then
[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
mark "$p"; ok=$((ok + 1))
echo "OK $p"
else
[FIX] driver: kill a build that has stopped producing output python's PKGBUILD hunts for a free X display before running make: export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run is not installed here. It exits 127, `!` inverts that to true, and the loop tries the next number. There is no exit condition for "the command does not exist", and the 2>/dev/null swallows the one line that would have said so. Measured before anyone noticed: ten hours of wall clock, four million PIDs, and a log frozen at `configure: creating Makefile`. Every signal said the build was healthy -- alive, 40% CPU, sitting in a plausible source directory. A process list cannot tell work from spinning. A stalled log next to a live makepkg can, and that is all this guard does. Forty-five minutes of COMPLETE silence, because real builds do go quiet: a long link, a test suite that prints nothing, gcc between bootstrap stages. The case this was written for ran two hundred times longer. EL_STALL_MIN=0 disables it. Tested against a real spin loop: detected, whole process tree killed, rc=2 so STALL reads differently from FAIL in the summary. --- FR --- Le PKGBUILD de python cherche un numéro d'affichage X libre avant make : export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run n'est pas installé ici. Il sort en 127, le `!` inverse, et la boucle essaie le numéro suivant. Il n'existe aucune condition de sortie pour « la commande n'existe pas », et le 2>/dev/null avale la seule ligne qui l'aurait dit. Mesuré avant que quiconque s'en aperçoive : dix heures d'horloge, quatre millions de PID, un journal figé à `configure: creating Makefile`. Tous les signaux disaient que le build allait bien — vivant, 40 % de CPU, dans un répertoire source plausible. Une liste de processus ne distingue pas le travail du sur-place. Un journal figé à côté d'un makepkg vivant, si — et c'est tout ce que fait ce garde-fou. Quarante-cinq minutes de silence COMPLET, car de vrais builds se taisent : une longue édition de liens, une suite de tests muette, gcc entre deux étages. Le cas qui l'a motivé a tourné deux cents fois plus longtemps. EL_STALL_MIN=0 le désactive. Éprouvé contre une vraie boucle infinie : détecté, arbre de processus tué en entier, rc=2 pour que STALL se lise autrement que FAIL dans le bilan. Assisted-by: Claude Opus 5
2026-08-19 19:53:46 -04:00
rc=$?
[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
fail=$((fail + 1)); failed+=("$p")
[FIX] driver: kill a build that has stopped producing output python's PKGBUILD hunts for a free X display before running make: export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run is not installed here. It exits 127, `!` inverts that to true, and the loop tries the next number. There is no exit condition for "the command does not exist", and the 2>/dev/null swallows the one line that would have said so. Measured before anyone noticed: ten hours of wall clock, four million PIDs, and a log frozen at `configure: creating Makefile`. Every signal said the build was healthy -- alive, 40% CPU, sitting in a plausible source directory. A process list cannot tell work from spinning. A stalled log next to a live makepkg can, and that is all this guard does. Forty-five minutes of COMPLETE silence, because real builds do go quiet: a long link, a test suite that prints nothing, gcc between bootstrap stages. The case this was written for ran two hundred times longer. EL_STALL_MIN=0 disables it. Tested against a real spin loop: detected, whole process tree killed, rc=2 so STALL reads differently from FAIL in the summary. --- FR --- Le PKGBUILD de python cherche un numéro d'affichage X libre avant make : export servernum=99 while ! xvfb-run -a -n "$servernum" /bin/true 2>/dev/null; do servernum=$((servernum+1)); done xvfb-run n'est pas installé ici. Il sort en 127, le `!` inverse, et la boucle essaie le numéro suivant. Il n'existe aucune condition de sortie pour « la commande n'existe pas », et le 2>/dev/null avale la seule ligne qui l'aurait dit. Mesuré avant que quiconque s'en aperçoive : dix heures d'horloge, quatre millions de PID, un journal figé à `configure: creating Makefile`. Tous les signaux disaient que le build allait bien — vivant, 40 % de CPU, dans un répertoire source plausible. Une liste de processus ne distingue pas le travail du sur-place. Un journal figé à côté d'un makepkg vivant, si — et c'est tout ce que fait ce garde-fou. Quarante-cinq minutes de silence COMPLET, car de vrais builds se taisent : une longue édition de liens, une suite de tests muette, gcc entre deux étages. Le cas qui l'a motivé a tourné deux cents fois plus longtemps. EL_STALL_MIN=0 le désactive. Éprouvé contre une vraie boucle infinie : détecté, arbre de processus tué en entier, rc=2 pour que STALL se lise autrement que FAIL dans le bilan. Assisted-by: Claude Opus 5
2026-08-19 19:53:46 -04:00
if [ "$rc" -eq 2 ]; then
echo "STALL $p (no output for ${EL_STALL_MIN:-45} min, killed)"
else
echo "FAIL $p (see $WORK/log-$p.txt)"
fi
[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
fi
done
echo
echo "== stage 1: $ok built, $fail failed =="
[ "$fail" -eq 0 ] || printf ' failed: %s\n' "${failed[*]}"
}
main "$@"