[ADD] TODO.md: track every divergence from upstream Arch
A port that does not track what it gave up drifts silently, and the gap
is found years later by whoever needs the missing feature. Every
deliberate difference is now written down, with the hook that
implements it and what it would take to close it.
The document separates two kinds, because the difference matters.
DEFERRED entries were dropped to get the bootstrap moving -- nothing
about s390x prevents them, they cost build time or a host dependency,
and they should come back. ARCHITECTURAL entries drop something that is
x86-specific by nature; there is nothing to restore, and they are
listed so nobody spends an afternoon rediscovering why.
A third section covers what is neither: environment facts, like
dev.gnupg.org being unreachable from this host, which close themselves
elsewhere.
curl joins the deferred list. Arch builds HTTP/3 through nghttp3 and
ngtcp2; Ubuntu packages neither, and building both to reach HTTP/3 is a
detour when pacman and ERPLibre talk to plain HTTPS mirrors. The
dependency declarations and the soname map go with the configure flags:
left in place, the package would claim to need libraries it no longer
links.
--- FR ---
Un portage qui ne trace pas ce qu il a abandonne derive en silence, et
l ecart se decouvre des annees plus tard par celui a qui la
fonctionnalite manque. Chaque difference deliberee est desormais
consignee, avec le crochet qui la met en oeuvre et ce qu il faudrait
pour la refermer.
Le document separe deux natures, parce que la distinction compte. Les
entrees DIFFEREES ont ete abandonnees pour faire avancer l amorcage --
rien dans s390x ne s y oppose, elles coutent du temps de compilation ou
une dependance d hote, et elles doivent revenir. Les entrees
ARCHITECTURALES retirent ce qui est par nature propre a x86 ; il n y a
rien a restaurer, et elles figurent la pour que personne ne passe un
apres-midi a redecouvrir pourquoi.
Une troisieme section couvre ce qui n est ni l un ni l autre : des
faits d environnement, comme dev.gnupg.org injoignable depuis cet hote,
qui se refermeront ailleurs.
curl rejoint la liste des differes. Arch batit HTTP/3 par nghttp3 et
ngtcp2 ; Ubuntu n empaquete ni l un ni l autre, et les batir tous deux
pour atteindre HTTP/3 est un detour quand pacman et ERPLibre parlent a
des miroirs HTTPS ordinaires. Les declarations de dependance et la
table de sonames partent avec les options de configuration : laissees
en place, le paquet pretendrait dependre de bibliotheques qu il ne lie
plus.
Assisted-by: Claude Opus 5
2026-08-16 05:47:47 -04:00
# TODO — divergences from upstream Arch
Every deliberate difference between this port and Arch's own packages, so
that none of them becomes invisible. A port that does not track what it gave
up drifts silently, and the gap is discovered years later by whoever needs
the missing feature.
Two kinds of entry, and the difference matters:
- **Deferred** — dropped to get the bootstrap moving. Nothing about s390x
prevents it; it costs build time, a host dependency, or another package
first. These should come back.
- **Architectural** — the thing being dropped is x86-specific by nature.
There is nothing to restore.
Each entry names the hook that implements it, so the change is one file away.
---
## Deferred
### libgccjit — `patches/pkgbuild/gcc.sh`
Arch configures and compiles the **entire gcc tree a second time** just for
libgccjit, because it needs `--enable-host-shared` and applying that to the
main compiler would slow it down. That pass is about half of gcc's build
time — twenty minutes per attempt on this hardware.
Already re-enablable, no code change needed:
EL_GCC_JIT=1 bash scripts/build-stage1.sh
**To close:** run one build with the switch on and confirm the package
appears. Nothing else is required.
### HTTP/3 in curl — `patches/pkgbuild/curl.sh`
configure: error: nghttp3 enabled without a QUIC library; enable ngtcp2
Ubuntu packages neither ngtcp2 nor nghttp3, so the build host cannot satisfy
them. pacman talks to plain HTTPS mirrors, and so does ERPLibre.
**To close:** build `ngtcp2` and `nghttp3` as Arch packages, add them to the
stage-1 list before curl, then delete the hook.
### gcc front ends: Ada, D, Modula-2, COBOL — `patches/pkgbuild/gcc.sh`
configure: error: GNAT is required to build ada
configure: error: GDC is required to build d
These are written in themselves and need an existing compiler of the same
language. Ubuntu ships `gnat` , but not a version GCC 15 accepts; there is no
D bootstrap compiler here at all.
**To close:** after stage 2, the port's own gcc can bootstrap them. This is
the entry most likely to matter to someone — a mainframe shop with Ada is not
a hypothetical.
### Test suites — `scripts/bootstrap-pacman.sh` (`--nocheck`)
Stage-1 suites run against the **host** libraries, not Arch's, so their
verdict says nothing about the port. `acl` failed its check step on a sound
build. They also cost hours.
**To close:** stage 2 runs inside the chroot, where the suites test what was
actually built. Drop `--nocheck` there.
### Checksums on generated patches — `scripts/bootstrap-pacman.sh`
`--skipchecksums` . GitLab regenerates `.patch` URLs, so their checksums drift
from what the PKGBUILD recorded. Release tarballs still validate — only the
generated patches are skipped.
**To close:** fetch patches from a stable source, or record our own sums.
### PGP signatures — `scripts/bootstrap-pacman.sh`
`--skippgpcheck` , because no keyring exists yet.
**To close:** build `archlinux-keyring` , then verify.
[UPD] TODO: the category the other three did not cover
Deferred, Architectural and Environment all assume someone made a choice.
Four divergences this round were made by nobody: a build option whose
DEFAULT is computed from the build machine, so installing an unrelated
Ubuntu package changes what a PKGBUILD produces.
libdir and python.platlibdir come from meson asking dpkg-architecture.
EXPAT_BUILD_DOCS comes from whichever docbook converter is on PATH.
split-bin comes from whether the builder's /usr/sbin is a symlink. None of
them fail loudly, and one waited twenty-nine hours before it did.
They get their own section because the "To close" is the same for all four
and different from the others: stage 2 builds inside an Arch root, where
every one of these defaults is already right. Until then, pin rather than
hope.
Six entries added elsewhere, including two that are deliberately NOT fixed:
makedb's libselinux and the bare sonames !autodeps leaves behind.
--- FR ---
Deferred, Architectural et Environment supposent tous que quelqu'un a
choisi. Quatre divergences de ce tour n'ont été décidées par personne : une
option dont la valeur PAR DÉFAUT est calculée depuis la machine de build,
si bien qu'installer un paquet Ubuntu sans rapport change ce qu'un PKGBUILD
produit.
libdir et python.platlibdir viennent de meson interrogeant
dpkg-architecture. EXPAT_BUILD_DOCS vient du convertisseur docbook présent
dans le PATH. split-bin vient de savoir si le /usr/sbin du constructeur est
un lien. Aucune n'échoue bruyamment, et l'une a attendu vingt-neuf heures.
Elles ont leur section parce que le « pour clore » est le même pour les
quatre et diffère des autres : l'étage 2 construit dans une racine Arch, où
chacun de ces défauts est déjà le bon. D'ici là, épingler plutôt qu'espérer.
Six entrées ailleurs, dont deux délibérément NON corrigées : le libselinux
de makedb et les sonames sans version que laisse !autodeps.
Assisted-by: Claude Opus 5
2026-08-17 02:37:46 -04:00
### PDF manuals in pam — `patches/pkgbuild/pam.sh`
Arch lists `fop` in makedepends, a Java renderer, to produce three PDFs that
the very next line of `package()` deletes as unreproducible. A JVM on the
build host buys nothing, so without it meson drops the PDF targets silently
and the `rm` is handed an unexpanded glob. The hook makes it `rm -f` .
**To close:** nothing needs closing. Listed because the hook's `-f` would
otherwise look like it is papering over a real absence.
### `libalpm.so` has no version — `/etc/makepkg.conf`
Every package in the repository declares bare sonames — `provides =
libalpm.so`, not `libalpm.so=16-64` — because `OPTIONS` carries `!autodeps` ,
which is makepkg's own default. The soname scan never runs for any package.
Verified across all seventy.
Harmless today: our `depends` are equally unversioned, so the repository is
internally consistent and pacman resolves it. It breaks the moment anything
wants a versioned soname, as Arch's own packages do.
**To close:** enable `autodeps` and rebuild, or accept the divergence
knowingly. Not urgent, but it is a real difference from Arch's repository.
### `makedb` still links libselinux — no hook, deliberately
`glibc` 's `usr/bin/makedb` is the last binary in the repository carrying a
host artefact. It is the only one left of the six the audit found.
It is NOT hooked on purpose: nothing in the bootstrap runs `makedb` , and
rebuilding glibc for it would relink the foundation under every other
package.
**To close:** stage 2 rebuilds glibc in a chroot that has no libselinux, and
it closes itself.
### The python module brotli builds is unusable on the target — `patches/pkgbuild/brotli.sh`
The wheel is built by the host's python 3.13 and is ABI-tagged
`cpython-313` ; Arch ships 3.14. No destination makes it importable. The hook
only moves it out of `/usr/local` , which an Arch package may not ship.
**To close:** stage 2 builds it with the port's own python.
[FIX] test-chroot: an audit that classifies, and one that was wrong
The soname check reported seventeen missing libraries. Four were false: it
built its "shipped" set from DT_SONAME alone, and tcl's libtcl9.0.so records
no SONAME at all. The file sits in usr/lib and ld.so resolves it by name, so
the check was calling a correct package broken -- which would have sent the
next reader hunting for a packaging bug that does not exist. Shipped filenames
and symlinks now count as supplied.
The remaining twelve needed separating, because an unclassified list is only
alarming. A missing soname whose library exists at a DIFFERENT version is
stage 1 working as designed: it linked the host, and stage 2 dissolves it. A
missing soname with no provider at any version is a closure gap. Nine and
three.
The three are each understood: pylibmount's cp313 extension (inert, no python
is shipped), makedb's libselinux (deliberate), and libtcl8.6 against our tcl
9.0 -- which is the honest cost of a decision made an hour before on closure
size without looking at ABI.
TODO.md records all twelve, with the note that stage 2 must install using the
host's pacman, because pacman inside the stage-1 rootfs cannot start.
--- FR ---
La vérification de sonames annonçait dix-sept bibliothèques manquantes. Quatre
étaient fausses : elle construisait son ensemble « livré » à partir du seul
DT_SONAME, et le libtcl9.0.so de tcl n'enregistre aucun SONAME. Le fichier est
dans usr/lib et ld.so le résout par son nom : la vérification déclarait donc
défectueux un paquet correct — de quoi envoyer le lecteur suivant chasser un
défaut d'empaquetage inexistant. Les noms de fichiers et les liens livrés
comptent désormais comme fournis.
Les douze restants demandaient d'être séparés, une liste non classée n'étant
qu'alarmante. Un soname manquant dont la bibliothèque existe à une AUTRE
version, c'est l'étage 1 fonctionnant comme prévu : il a lié l'hôte, et
l'étage 2 le dissout. Un soname sans aucun fournisseur est un trou de
fermeture. Neuf et trois.
Les trois sont compris : l'extension cp313 de pylibmount (inerte, aucun python
livré), le libselinux de makedb (délibéré), et libtcl8.6 contre notre tcl 9.0
— coût honnête d'une décision prise une heure plus tôt sur la taille de la
fermeture, sans regarder l'ABI.
TODO.md consigne les douze, avec la note que l'étage 2 devra installer avec le
pacman de l'hôte, celui du rootfs d'étage 1 ne pouvant pas démarrer.
Assisted-by: Claude Opus 5
2026-08-19 06:40:50 -04:00
### Host sonames the target does not have — `scripts/test-chroot.sh` check 3
Nine libraries are requested by a shipped binary at the HOST's version while
the repository ships the same library at Arch's:
| requested | by | we ship |
|---|---|---|
| `libgpgme.so.11` | pacman (via libalpm) | gpgme 2.x, `.45` |
| `libnettle.so.8` , `libhogweed.so.6` | gnutls, libcurl-gnutls | nettle |
| `libicuuc.so.76` | libxml2 | icu |
| `liblmdb.so.0` | krb5 | lmdb |
| `libnsl.so.2` | pam | libnsl |
| `libsasl2.so.2` | libldap, openldap | libsasl |
| `libsodium.so.23` | openldap | libsodium |
| `libdevmapper.so.1.02.1` | cryptsetup | device-mapper |
This is stage 1 working as designed, not a defect list: stage 1 links the
host, so it records the host's sonames. It is written down because the
consequence is concrete — `pacman` in the stage-1 rootfs does not start:
pacman: error while loading shared libraries: libgpgme.so.11
**To close:** stage 2. Every one of these dissolves when the package is
rebuilt inside the chroot against the repository's own libraries. Nothing here
should be hooked in stage 1; a hook would only hide it.
Note for stage 2's design: because pacman cannot run inside the stage-1
rootfs, stage 2 has to install with the HOST's pacman and `--root` , the way
scripts/test-chroot.sh already does, and use the chroot only for building.
### Three sonames with no provider at all — same check
Distinct from the nine above, and each for its own reason:
- `libpython3.13.so.1.0` ← `util-linux-libs` . It ships
`pylibmount.cpython-313-*.so` , built against the host's python. Inert: this
port ships no python, so nothing imports it. Stage 2 drops it by
construction — the chroot has no python either, so meson will not build it.
Worth naming because `arch-meson` was fixed to put this file in the right
PLACE (site-packages, not dist-packages) and the wrong ABI stayed invisible
until the soname audit.
- `libselinux.so.1` ← `glibc` 's `makedb` . Deliberate, see above.
- `libtcl8.6.so` ← `sqlite-tcl` , `sqlite-analyzer` . We ship tcl **9.0** ;
sqlite's configure found the host's 8.6 tclConfig.sh. An honest admission:
the measurement that chose to BUILD tcl rather than drop these
sub-packages compared closure cost and never looked at the ABI. Stage 2
fixes it — tcl 9.0 is in the repository — but the reasoning had a blind
spot, and it was the same blind spot as the pylibmount one.
### `lvm2` — `patches/pkgbuild/lvm2.sh`
Only `device-mapper` is built. The `lvm2` half declares
`thin-provisioning-tools` , which is Rust now, so a language runtime arrived
through a fourth-order dependency. Nothing in the repository wants `lvm2`
itself; cryptsetup wants device-mapper, which the same source produces.
**To close:** build Rust, restore the sub-package, rebuild. A target that
wants LVM needs this; dm-crypt and systemd do not.
### SQL auxprop in libsasl — `patches/pkgbuild/libsasl.sh`
Disabled. Its two database headers exist on this host, on paths configure does
not try (`/usr/include/postgresql`, `/usr/include/mariadb` ). Arch declares
`depends=(glibc)` for libsasl because the plugins are dlopened, so nothing is
lost.
**To close:** supply the include paths, or leave it — a bootstrap has no SQL
authentication backend to serve.
### fuse2fs — `patches/pkgbuild/e2fsprogs.sh`
Not built: no fuse3 on the host, and none in the closure.
**To close:** add `fuse3` , and both the sub-package and the removal that feeds
it come back on their own.
### kbd without xkb — `patches/pkgbuild/kbd.sh`
`loadkeys` cannot generate keymaps from an XKB database. Arch's kbd cannot
either — it declares libxkbcommon nowhere, so Arch's chroot fails the same
probe. Building it would want libxcb and xkeyboard-config behind it.
**To close:** it is already closed with respect to Arch. Reopen only if a
target grows a graphics stack.
[ADD] TODO.md: track every divergence from upstream Arch
A port that does not track what it gave up drifts silently, and the gap
is found years later by whoever needs the missing feature. Every
deliberate difference is now written down, with the hook that
implements it and what it would take to close it.
The document separates two kinds, because the difference matters.
DEFERRED entries were dropped to get the bootstrap moving -- nothing
about s390x prevents them, they cost build time or a host dependency,
and they should come back. ARCHITECTURAL entries drop something that is
x86-specific by nature; there is nothing to restore, and they are
listed so nobody spends an afternoon rediscovering why.
A third section covers what is neither: environment facts, like
dev.gnupg.org being unreachable from this host, which close themselves
elsewhere.
curl joins the deferred list. Arch builds HTTP/3 through nghttp3 and
ngtcp2; Ubuntu packages neither, and building both to reach HTTP/3 is a
detour when pacman and ERPLibre talk to plain HTTPS mirrors. The
dependency declarations and the soname map go with the configure flags:
left in place, the package would claim to need libraries it no longer
links.
--- FR ---
Un portage qui ne trace pas ce qu il a abandonne derive en silence, et
l ecart se decouvre des annees plus tard par celui a qui la
fonctionnalite manque. Chaque difference deliberee est desormais
consignee, avec le crochet qui la met en oeuvre et ce qu il faudrait
pour la refermer.
Le document separe deux natures, parce que la distinction compte. Les
entrees DIFFEREES ont ete abandonnees pour faire avancer l amorcage --
rien dans s390x ne s y oppose, elles coutent du temps de compilation ou
une dependance d hote, et elles doivent revenir. Les entrees
ARCHITECTURALES retirent ce qui est par nature propre a x86 ; il n y a
rien a restaurer, et elles figurent la pour que personne ne passe un
apres-midi a redecouvrir pourquoi.
Une troisieme section couvre ce qui n est ni l un ni l autre : des
faits d environnement, comme dev.gnupg.org injoignable depuis cet hote,
qui se refermeront ailleurs.
curl rejoint la liste des differes. Arch batit HTTP/3 par nghttp3 et
ngtcp2 ; Ubuntu n empaquete ni l un ni l autre, et les batir tous deux
pour atteindre HTTP/3 est un detour quand pacman et ERPLibre parlent a
des miroirs HTTPS ordinaires. Les declarations de dependance et la
table de sonames partent avec les options de configuration : laissees
en place, le paquet pretendrait dependre de bibliotheques qu il ne lie
plus.
Assisted-by: Claude Opus 5
2026-08-16 05:47:47 -04:00
---
## Architectural
Nothing to restore here. Listed so nobody spends an afternoon rediscovering
why.
| What | Where | Why |
|---|---|---|
| SFrame | `glibc.sh` | `configure: error: the architecture doesn't support SFrame` |
| gold linker | `binutils.sh` | x86-centric, deprecated upstream since 2.44; `ld.bfd` is the linker on Z |
| 32-bit multilib | `glibc.sh` , `gcc.sh` , `libtool.sh` | On x86_64 it means i686. On Z it means the 31-bit ESA/390 ABI that GCC is removing |
| `libhwasan` | `gcc.sh` | Hardware-assisted ASan exists on x86_64 and aarch64 only |
[UPD] TODO: the category the other three did not cover
Deferred, Architectural and Environment all assume someone made a choice.
Four divergences this round were made by nobody: a build option whose
DEFAULT is computed from the build machine, so installing an unrelated
Ubuntu package changes what a PKGBUILD produces.
libdir and python.platlibdir come from meson asking dpkg-architecture.
EXPAT_BUILD_DOCS comes from whichever docbook converter is on PATH.
split-bin comes from whether the builder's /usr/sbin is a symlink. None of
them fail loudly, and one waited twenty-nine hours before it did.
They get their own section because the "To close" is the same for all four
and different from the others: stage 2 builds inside an Arch root, where
every one of these defaults is already right. Until then, pin rather than
hope.
Six entries added elsewhere, including two that are deliberately NOT fixed:
makedb's libselinux and the bare sonames !autodeps leaves behind.
--- FR ---
Deferred, Architectural et Environment supposent tous que quelqu'un a
choisi. Quatre divergences de ce tour n'ont été décidées par personne : une
option dont la valeur PAR DÉFAUT est calculée depuis la machine de build,
si bien qu'installer un paquet Ubuntu sans rapport change ce qu'un PKGBUILD
produit.
libdir et python.platlibdir viennent de meson interrogeant
dpkg-architecture. EXPAT_BUILD_DOCS vient du convertisseur docbook présent
dans le PATH. split-bin vient de savoir si le /usr/sbin du constructeur est
un lien. Aucune n'échoue bruyamment, et l'une a attendu vingt-neuf heures.
Elles ont leur section parce que le « pour clore » est le même pour les
quatre et diffère des autres : l'étage 2 construit dans une racine Arch, où
chacun de ces défauts est déjà le bon. D'ici là, épingler plutôt qu'espérer.
Six entrées ailleurs, dont deux délibérément NON corrigées : le libselinux
de makedb et les sonames sans version que laisse !autodeps.
Assisted-by: Claude Opus 5
2026-08-17 02:37:46 -04:00
| systemd-boot | `systemd.sh` | `meson.build:1627` maps a cpu family to an EFI machine type and s390x is not in the table. Z boots from an IPL record; there is no ESP to write into. `bootctl` is still built |
---
## The host decides what gets built
A category the first three did not cover, and the one that cost this round
the most. These are not choices anyone made. A build option's DEFAULT is
computed from the build machine, so installing an unrelated Ubuntu package
changes what a PKGBUILD produces — usually without failing, sometimes weeks
later.
Four were found, all in one round, all now pinned:
| Option | Where | What the host decides |
|---|---|---|
| `libdir` | `scripts/devtools/arch-meson` | meson asks `dpkg-architecture` and answers `lib/s390x-linux-gnu` . Five packages shipped their libraries where Arch's `ld.so` never looks |
| `python.platlibdir` | `scripts/devtools/arch-meson` | meson's python module uses Debian's `deb_system` scheme, `/usr/lib/python3/dist-packages` |
| `EXPAT_BUILD_DOCS` | `expat.sh` | ON if any of four docbook converters is on `PATH` . `asciidoc` pulled in `docbook-utils` as an automatic dependency, and expat — which had built clean the day before — started failing 29 hours later |
| `split-bin` | `systemd.sh` | probes whether the BUILD machine's `/usr/sbin` is a symlink. Ubuntu's is a real directory, so six binaries went to `/usr/sbin` and `package()` could not find them |
The general lesson: `arch-meson` passes `--auto-features enabled` , which
promotes every `auto` feature to a hard requirement. Installing a tool
therefore switches on code that has never compiled in this port. `util-linux`
was the clearest case — `asciidoctor` was needed for its man3 pages, and its
arrival enabled a translation step that had never once run.
**To close:** stage 2 builds inside an Arch root, where every one of these
defaults is already the right one. Until then, pin rather than hope.
[ADD] TODO.md: track every divergence from upstream Arch
A port that does not track what it gave up drifts silently, and the gap
is found years later by whoever needs the missing feature. Every
deliberate difference is now written down, with the hook that
implements it and what it would take to close it.
The document separates two kinds, because the difference matters.
DEFERRED entries were dropped to get the bootstrap moving -- nothing
about s390x prevents them, they cost build time or a host dependency,
and they should come back. ARCHITECTURAL entries drop something that is
x86-specific by nature; there is nothing to restore, and they are
listed so nobody spends an afternoon rediscovering why.
A third section covers what is neither: environment facts, like
dev.gnupg.org being unreachable from this host, which close themselves
elsewhere.
curl joins the deferred list. Arch builds HTTP/3 through nghttp3 and
ngtcp2; Ubuntu packages neither, and building both to reach HTTP/3 is a
detour when pacman and ERPLibre talk to plain HTTPS mirrors. The
dependency declarations and the soname map go with the configure flags:
left in place, the package would claim to need libraries it no longer
links.
--- FR ---
Un portage qui ne trace pas ce qu il a abandonne derive en silence, et
l ecart se decouvre des annees plus tard par celui a qui la
fonctionnalite manque. Chaque difference deliberee est desormais
consignee, avec le crochet qui la met en oeuvre et ce qu il faudrait
pour la refermer.
Le document separe deux natures, parce que la distinction compte. Les
entrees DIFFEREES ont ete abandonnees pour faire avancer l amorcage --
rien dans s390x ne s y oppose, elles coutent du temps de compilation ou
une dependance d hote, et elles doivent revenir. Les entrees
ARCHITECTURALES retirent ce qui est par nature propre a x86 ; il n y a
rien a restaurer, et elles figurent la pour que personne ne passe un
apres-midi a redecouvrir pourquoi.
Une troisieme section couvre ce qui n est ni l un ni l autre : des
faits d environnement, comme dev.gnupg.org injoignable depuis cet hote,
qui se refermeront ailleurs.
curl rejoint la liste des differes. Arch batit HTTP/3 par nghttp3 et
ngtcp2 ; Ubuntu n empaquete ni l un ni l autre, et les batir tous deux
pour atteindre HTTP/3 est un detour quand pacman et ERPLibre parlent a
des miroirs HTTPS ordinaires. Les declarations de dependance et la
table de sonames partent avec les options de configuration : laissees
en place, le paquet pretendrait dependre de bibliotheques qu il ne lie
plus.
Assisted-by: Claude Opus 5
2026-08-16 05:47:47 -04:00
---
[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
### Documentation is skipped in the stage-2 chroot — `scripts/build-stage2.sh`
Our own meson package ships `/usr/bin/arch-meson` , and it passes
`--auto-features enabled` . That is right on Arch, whose build chroot has every
optional tool installed. Ours has none of them:
doxygen xsltproc asciidoctor itstool convert
fig2dev elinks ducktype yelp-build
With `enabled` , each absent tool is a hard error rather than a skipped
feature. libxml2 stopped on
libxml2/doc/meson.build:3:10: ERROR: Program 'doxygen' not found
The chroot now gets a `/usr/local/bin/arch-meson` wrapper appending
`--auto-features auto` — meson honours the last occurrence, so every other
choice arch-meson makes survives. `/usr/local/bin` comes first on the
chroot's PATH; `/usr/bin/arch-meson` is left exactly as the package shipped it.
**Measured before choosing**, because building the tools was the alternative
and it is not close: doxygen alone wants `clang` , `fmt` , `spdlog` and
`llvm-libs` — a compiler infrastructure for a documentation generator. Behind
the other eight stand Ruby, ImageMagick and a GNOME stack. Several times the
size of everything built so far, for man pages.
To restore at stage 3, once there is somewhere to build them from.
### The docs split assumed the docs exist — `patches/pkgbuild/libxml2.sh`
Consequence of the above, and the **fourth** appearance of one shape: pam's
PDFs, e2fsprogs' `fuse2fs` , cmake's emacs byte-compilation, and now
mv: cannot stat '< pkgdir > /usr/share/doc': No such file or directory
A failure on the last line of `package()` , after a completely successful
compile, naming a path instead of a reason. It has never once been a broken
build. The move is made conditional rather than deleted — on the host the docs
do exist and belong in their own package.
### libarchive drops xar for stage 1 — `patches/pkgbuild/libarchive.sh`
Stage 2 reached its first packaging step and stopped on
bsdtar: error while loading shared libraries: libicuuc.so.76
==> ERROR: Failed to create package file.
The chain: `bsdtar` → `libarchive.so.13` → `libxml2.so.16` → `libicuuc.so.76` .
The libxml2 in the chroot is our stage-1 build, and stage 1 builds against the
HOST, whose ICU is 76; our icu package ships 78. So bsdtar cannot start — and
bsdtar is what makepkg uses to write the package. **The package that would fix
it is the one being built.** Nothing comes out of the chroot until this is
broken from outside it.
Supplying `libicuuc.so.76` from the host is the obvious move and the wrong
one: untracked host binaries in `/usr/lib` are exactly what test-chroot.sh's
ARTEFACT check exists to catch. A symlink to 78 does not work either — ICU
version-suffixes every symbol, so `libicuuc.so.78` does not define
`u_strlen_76` .
The root is that libarchive links libxml2 at all: it wants it for **xar** , an
Apple installer container. Nothing here reads one — makepkg writes
`.pkg.tar.gz` , pacman reads it. `--without-xml2 --without-expat` removes the
whole ICU chain instead of arguing about its version. Stage 1 only;
`STAGE2_SKIP_HOOKS` lists libarchive, so stage 2 builds it as Arch does,
against our own libxml2 and icu, where the versions agree.
### Rebuilding one package at stage 1 — `scripts/build-stage1.sh`
`build-stage1.sh` now takes package names, like stage 2 already did. Without
it, rebuilding one package meant deleting its line from `stage1.state` first —
editing the record of what was built in order to build something. That file is
this port's memory, and the standing instruction is to regenerate it from what
is really in `repo/s390x` , never from a log; hand-editing it is the same
mistake in a smaller form. An explicit name outranks the state file, because
being told "already built, skipping" would make the command useless for the
one job it has.
[UPD] TODO: the 84 host binaries the chroot does not have
Measured once rather than discovered a package at a time: dpkg says what each
of the 110 apt packages ships in /usr/bin, and each of those is tested against
the chroot. Two had already been found the slow way, rsync and makeinfo, and
each cost a full build to surface.
Sorted by what it means: ten are build tools that will each block something,
eleven are documentation already settled by --auto-features auto, and eight are
not gaps at all -- bison.yacc, fakeroot-tcp, automake-1.17, ncurses6-config and
the like are Debian's alternative names for tools that are present under Arch's.
Counting those as missing would have meant building packages that exist.
--- FR ---
Mesuré une fois plutôt que découvert un paquet à la fois : dpkg dit ce que
chacun des 110 paquets apt livre dans /usr/bin, et chacun est testé contre le
chroot. Deux avaient déjà été trouvés par la voie lente, rsync et makeinfo, au
prix d'une construction complète chacun.
Classé par ce que cela signifie : dix sont des outils de construction qui
bloqueront chacun quelque chose, onze sont de la documentation déjà tranchée par
--auto-features auto, et huit ne sont pas des manques -- bison.yacc,
fakeroot-tcp, automake-1.17, ncurses6-config et compagnie sont les noms
alternatifs de Debian pour des outils présents sous ceux d'Arch. Les compter
comme absents aurait fait bâtir des paquets qui existent.
Assisted-by: Claude Opus 5
2026-08-20 01:36:10 -04:00
### 84 host binaries the chroot does not have — measured, not guessed
`install_host_deps` installs 110 apt packages. Asking dpkg what each ships in
`/usr/bin` , then testing every one of those against the stage-2 chroot, gives
84 absent binaries. Worth doing once rather than discovering them a package at
a time over a twenty-hour pass — two were found that way first (`rsync`,
`makeinfo` ) and each cost a full build to surface.
Build tools, which will each block something:
gperf help2man po4a xsltproc scdoc dtrace (systemtap)
cython pyproject-build sphinx-build rst2man (docutils)
Documentation only, and settled by `--auto-features auto` :
doxygen asciidoctor itstool ducktype yelp-build yelp-check
elinks fig2dev transfig rsvg-convert clang (doxygen's)
Not gaps at all, on inspection: `bison.yacc` , `fakeroot-tcp` , `faked-sysv` ,
`automake-1.17` , `aclocal-1.17` , `ncurses6-config` , `nspr-config` ,
`tcltk-depends` are Debian's alternative or versioned names for tools that are
present under Arch's names. Counting them as missing would have sent someone
building packages that already exist.
Each is built when a package actually asks for it, not in advance — several
carry closures much larger than themselves (`dtrace` brings systemtap,
`sphinx-build` a Python stack), and paying for one before knowing it is needed
is how a bootstrap doubles in size.
[ADD] TODO.md: track every divergence from upstream Arch
A port that does not track what it gave up drifts silently, and the gap
is found years later by whoever needs the missing feature. Every
deliberate difference is now written down, with the hook that
implements it and what it would take to close it.
The document separates two kinds, because the difference matters.
DEFERRED entries were dropped to get the bootstrap moving -- nothing
about s390x prevents them, they cost build time or a host dependency,
and they should come back. ARCHITECTURAL entries drop something that is
x86-specific by nature; there is nothing to restore, and they are
listed so nobody spends an afternoon rediscovering why.
A third section covers what is neither: environment facts, like
dev.gnupg.org being unreachable from this host, which close themselves
elsewhere.
curl joins the deferred list. Arch builds HTTP/3 through nghttp3 and
ngtcp2; Ubuntu packages neither, and building both to reach HTTP/3 is a
detour when pacman and ERPLibre talk to plain HTTPS mirrors. The
dependency declarations and the soname map go with the configure flags:
left in place, the package would claim to need libraries it no longer
links.
--- FR ---
Un portage qui ne trace pas ce qu il a abandonne derive en silence, et
l ecart se decouvre des annees plus tard par celui a qui la
fonctionnalite manque. Chaque difference deliberee est desormais
consignee, avec le crochet qui la met en oeuvre et ce qu il faudrait
pour la refermer.
Le document separe deux natures, parce que la distinction compte. Les
entrees DIFFEREES ont ete abandonnees pour faire avancer l amorcage --
rien dans s390x ne s y oppose, elles coutent du temps de compilation ou
une dependance d hote, et elles doivent revenir. Les entrees
ARCHITECTURALES retirent ce qui est par nature propre a x86 ; il n y a
rien a restaurer, et elles figurent la pour que personne ne passe un
apres-midi a redecouvrir pourquoi.
Une troisieme section couvre ce qui n est ni l un ni l autre : des
faits d environnement, comme dev.gnupg.org injoignable depuis cet hote,
qui se refermeront ailleurs.
curl rejoint la liste des differes. Arch batit HTTP/3 par nghttp3 et
ngtcp2 ; Ubuntu n empaquete ni l un ni l autre, et les batir tous deux
pour atteindre HTTP/3 est un detour quand pacman et ERPLibre parlent a
des miroirs HTTPS ordinaires. Les declarations de dependance et la
table de sonames partent avec les options de configuration : laissees
en place, le paquet pretendrait dependre de bibliotheques qu il ne lie
plus.
Assisted-by: Claude Opus 5
2026-08-16 05:47:47 -04:00
## Environment, not the port
[UPD] TODO: the category the other three did not cover
Deferred, Architectural and Environment all assume someone made a choice.
Four divergences this round were made by nobody: a build option whose
DEFAULT is computed from the build machine, so installing an unrelated
Ubuntu package changes what a PKGBUILD produces.
libdir and python.platlibdir come from meson asking dpkg-architecture.
EXPAT_BUILD_DOCS comes from whichever docbook converter is on PATH.
split-bin comes from whether the builder's /usr/sbin is a symlink. None of
them fail loudly, and one waited twenty-nine hours before it did.
They get their own section because the "To close" is the same for all four
and different from the others: stage 2 builds inside an Arch root, where
every one of these defaults is already right. Until then, pin rather than
hope.
Six entries added elsewhere, including two that are deliberately NOT fixed:
makedb's libselinux and the bare sonames !autodeps leaves behind.
--- FR ---
Deferred, Architectural et Environment supposent tous que quelqu'un a
choisi. Quatre divergences de ce tour n'ont été décidées par personne : une
option dont la valeur PAR DÉFAUT est calculée depuis la machine de build,
si bien qu'installer un paquet Ubuntu sans rapport change ce qu'un PKGBUILD
produit.
libdir et python.platlibdir viennent de meson interrogeant
dpkg-architecture. EXPAT_BUILD_DOCS vient du convertisseur docbook présent
dans le PATH. split-bin vient de savoir si le /usr/sbin du constructeur est
un lien. Aucune n'échoue bruyamment, et l'une a attendu vingt-neuf heures.
Elles ont leur section parce que le « pour clore » est le même pour les
quatre et diffère des autres : l'étage 2 construit dans une racine Arch, où
chacun de ces défauts est déjà le bon. D'ici là, épingler plutôt qu'espérer.
Six entrées ailleurs, dont deux délibérément NON corrigées : le libselinux
de makedb et les sonames sans version que laisse !autodeps.
Assisted-by: Claude Opus 5
2026-08-17 02:37:46 -04:00
### Build locale — `scripts/bootstrap-pacman.sh`
`LC_ALL=C.UTF-8` on the `makepkg` line. This host runs `fr_FR.UTF-8` , and
util-linux's `poman-translate.sh` greps po4a's output for the English word
`Discard` . In French po4a says `Rejet de …` , so the skip list came out empty
and the build was handed 852 files po4a had never written.
`C.UTF-8` and not `C` : the Arabic and Ukrainian pages must stay valid UTF-8.
Arch's build chroot runs in this locale, so this is parity, not a workaround.
### `history.pc` — `scripts/bootstrap-pacman.sh`
GNU readline installs both `readline.pc` and `history.pc` ; Debian and Ubuntu
keep the first and drop the second, while `libhistory.so` ships in
`libreadline-dev` regardless. libxml2 asks pkg-config for `history` and stops.
Our own readline package ships a correct `history.pc` — and copying it would
be wrong. Its `libdir` names `/usr/lib` , which on a multiarch host holds no
`libhistory` . The file has to describe the BUILD host, so it is generated.
### gnupg's feature set moved on its own — no hook
`libtss2-dev` was installed for systemd. gnupg's configure found it, turned
`TPM: no` into `TPM: yes` , and shipped `usr/lib/gnupg/tpm2daemon` — code that
had never compiled here. It built cleanly, and Arch's gnupg depends on
`tpm2-tss` too, so this is parity rather than drift.
Recorded because nobody decided it. It is the same mechanism as the table
above, caught on the way past.
**To close:** nothing. Noted so the next unexplained gnupg change has a
precedent to read.
[ADD] TODO.md: track every divergence from upstream Arch
A port that does not track what it gave up drifts silently, and the gap
is found years later by whoever needs the missing feature. Every
deliberate difference is now written down, with the hook that
implements it and what it would take to close it.
The document separates two kinds, because the difference matters.
DEFERRED entries were dropped to get the bootstrap moving -- nothing
about s390x prevents them, they cost build time or a host dependency,
and they should come back. ARCHITECTURAL entries drop something that is
x86-specific by nature; there is nothing to restore, and they are
listed so nobody spends an afternoon rediscovering why.
A third section covers what is neither: environment facts, like
dev.gnupg.org being unreachable from this host, which close themselves
elsewhere.
curl joins the deferred list. Arch builds HTTP/3 through nghttp3 and
ngtcp2; Ubuntu packages neither, and building both to reach HTTP/3 is a
detour when pacman and ERPLibre talk to plain HTTPS mirrors. The
dependency declarations and the soname map go with the configure flags:
left in place, the package would claim to need libraries it no longer
links.
--- FR ---
Un portage qui ne trace pas ce qu il a abandonne derive en silence, et
l ecart se decouvre des annees plus tard par celui a qui la
fonctionnalite manque. Chaque difference deliberee est desormais
consignee, avec le crochet qui la met en oeuvre et ce qu il faudrait
pour la refermer.
Le document separe deux natures, parce que la distinction compte. Les
entrees DIFFEREES ont ete abandonnees pour faire avancer l amorcage --
rien dans s390x ne s y oppose, elles coutent du temps de compilation ou
une dependance d hote, et elles doivent revenir. Les entrees
ARCHITECTURALES retirent ce qui est par nature propre a x86 ; il n y a
rien a restaurer, et elles figurent la pour que personne ne passe un
apres-midi a redecouvrir pourquoi.
Une troisieme section couvre ce qui n est ni l un ni l autre : des
faits d environnement, comme dev.gnupg.org injoignable depuis cet hote,
qui se refermeront ailleurs.
curl rejoint la liste des differes. Arch batit HTTP/3 par nghttp3 et
ngtcp2 ; Ubuntu n empaquete ni l un ni l autre, et les batir tous deux
pour atteindre HTTP/3 est un detour quand pacman et ERPLibre parlent a
des miroirs HTTPS ordinaires. Les declarations de dependance et la
table de sonames partent avec les options de configuration : laissees
en place, le paquet pretendrait dependre de bibliotheques qu il ne lie
plus.
Assisted-by: Claude Opus 5
2026-08-16 05:47:47 -04:00
### libassuan source — `patches/pkgbuild/libassuan.sh`
`dev.gnupg.org` is unreachable from this build host — measured HTTP 000,
while `github.com/gpg/libassuan.git` and `gnupg.org/ftp` both answer. Only
the transport changed; the pinned tag is untouched.
**To close:** it closes itself on a host with wider outbound access.
### `arch-meson` / `arch-cmake` — `scripts/devtools/`
Several PKGBUILDs call them, they ship in `devtools` , and `devtools` is
itself an Arch package — during a bootstrap they cannot exist yet.
**To close:** build `devtools` in stage 2 and drop the stand-ins.
### Host include layout — `scripts/bootstrap-pacman.sh`
Ubuntu multiarch puts `asm/` , `bits/` , `gnu/` and `sys/sdt.h` under
`/usr/include/s390x-linux-gnu` , while glibc builds with `-nostdinc` and
expects the classic layout. Symlinks bridge it.
**To close:** stage 2 builds inside an Arch root, where the layout is
already right.