[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
This commit is contained in:
parent
6f44fdb572
commit
7ec3d14851
2 changed files with 123 additions and 4 deletions
85
TODO.md
85
TODO.md
|
|
@ -123,6 +123,91 @@ 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.
|
||||
|
||||
### 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.
|
||||
|
||||
---
|
||||
|
||||
## Architectural
|
||||
|
|
|
|||
|
|
@ -125,17 +125,51 @@ for f in "$REPO"/*.pkg.tar.*; do
|
|||
readelf -d "$b" 2>/dev/null | sed -n 's/.*Shared library: \[\(.*\)\].*/\1/p' \
|
||||
| sed "s|^|$_pn |" >> "$_sa/want"
|
||||
done < <(find "$_sa/x" -type f 2>/dev/null)
|
||||
# Shipped FILENAMES count as supplied, not only recorded SONAMEs. ld.so
|
||||
# resolves a DT_NEEDED entry by looking for a file of that name, and a
|
||||
# library is free to record no DT_SONAME at all -- tcl's libtcl9.0.so does
|
||||
# exactly that. Counting only SONAMEs reported it as missing while the file
|
||||
# sat in usr/lib, which would have sent the next reader hunting for a
|
||||
# packaging bug that does not exist. Symlinks count too: they are what
|
||||
# ld.so follows.
|
||||
find "$_sa/x" \( -type f -o -type l \) -name '*.so*' -printf '%f\n' \
|
||||
2>/dev/null >> "$_sa/have"
|
||||
done
|
||||
sort -u "$_sa/have" > "$_sa/have.s"
|
||||
awk '{print $2}' "$_sa/want" | sort -u > "$_sa/want.s"
|
||||
if [ -s "$(comm -13 "$_sa/have.s" "$_sa/want.s" > "$_sa/miss"; echo "$_sa/miss")" ]; then
|
||||
bad "$(wc -l < "$_sa/miss") soname(s) requested and never shipped:"
|
||||
comm -13 "$_sa/have.s" "$_sa/want.s" > "$_sa/miss"
|
||||
# CLASSIFY, because the two kinds need different work and an unclassified list
|
||||
# is just alarming. A missing soname whose library exists in the repository at
|
||||
# a DIFFERENT version is the ordinary stage-1 artefact: the binary linked the
|
||||
# host's copy, and stage 2 dissolves it by rebuilding in the chroot. A missing
|
||||
# soname with no provider at any version is a CLOSURE GAP -- a package that
|
||||
# still has to be built, or a dependency nobody declared.
|
||||
: > "$_sa/drift"; : > "$_sa/gap"
|
||||
while read -r m; do
|
||||
_base=${m%%.so*}
|
||||
if grep -q "^${_base}\.so" "$_sa/have.s"; then
|
||||
echo "$m" >> "$_sa/drift"
|
||||
else
|
||||
echo "$m" >> "$_sa/gap"
|
||||
fi
|
||||
done < "$_sa/miss"
|
||||
_report() {
|
||||
while read -r m; do
|
||||
printf ' %-24s <- %s\n' "$m" \
|
||||
"$(awk -v m="$m" '$2==m {print $1}' "$_sa/want" | sort -u | tr '\n' ' ')"
|
||||
done < "$_sa/miss"
|
||||
done < "$1"
|
||||
}
|
||||
if [ -s "$_sa/gap" ]; then
|
||||
bad "$(wc -l < "$_sa/gap") soname(s) with NO provider at any version:"
|
||||
_report "$_sa/gap"
|
||||
else
|
||||
good "every requested soname is shipped by some package"
|
||||
good "every requested soname has a provider in the repository"
|
||||
fi
|
||||
if [ -s "$_sa/drift" ]; then
|
||||
printf ' note %s soname(s) at the host version, provider present at another\n' \
|
||||
"$(wc -l < "$_sa/drift")"
|
||||
printf ' (stage-1 artefact by construction -- stage 2 rebuilds these)\n'
|
||||
_report "$_sa/drift"
|
||||
fi
|
||||
rm -rf "$_sa"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue