[ADD] host deps: the tools six packages needed and nobody declared
--nodeps means every makedepend must be named here by hand. Seven builds stopped on one, each naming a different tool: itstool, convert, fig2dev, asciidoctor, libnsl, python -m build, libbpf, history. The list was also a lie by omission. libreadline-dev, libncurses-dev, zlib1g-dev, python3-dev, doxygen, xsltproc, docbook-xsl, elinks and libcap2-bin were on this VM by hand and never declared. They made the builds pass here and would fail on a fresh Ubuntu, for reasons that have nothing to do with s390x. history.pc is generated rather than copied: our own readline package ships a correct one, but its libdir names /usr/lib, which on a multiarch host holds no libhistory. The .pc has to describe THIS host. Three hooks for what apt cannot buy. systemd asks for an EFI arch s390x does not have -- and says "python3 is missing modules: elftools", which sends you to apt for four lines before admitting the real reason. --- FR --- --nodeps veut dire que chaque makedepend doit être nommé ici à la main. Sept compilations se sont arrêtées sur l'une d'elles, chacune désignant un outil différent : itstool, convert, fig2dev, asciidoctor, libnsl, python -m build, libbpf, history. La liste mentait aussi par omission. libreadline-dev, libncurses-dev, zlib1g-dev, python3-dev, doxygen, xsltproc, docbook-xsl, elinks et libcap2-bin étaient posés à la main sur cette VM, jamais déclarés. Ils faisaient passer les compilations ici et auraient échoué sur un Ubuntu neuf, pour des raisons étrangères à s390x. history.pc est généré et non copié : notre propre paquet readline en livre un correct, mais son libdir nomme /usr/lib, qui sur un hôte multiarch ne contient aucun libhistory. Le .pc doit décrire CET hôte-ci. Trois crochets pour ce qu'apt n'achète pas. systemd réclame une architecture EFI que s390x n'a pas — et annonce « python3 is missing modules: elftools », ce qui envoie chez apt pour quatre lignes avant d'avouer la vraie raison. Assisted-by: Claude Opus 5
This commit is contained in:
parent
04ee9be5cc
commit
dcaa55b19a
4 changed files with 282 additions and 1 deletions
85
patches/pkgbuild/brotli.sh
Executable file
85
patches/pkgbuild/brotli.sh
Executable file
|
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env bash
|
||||
# brotli: two Debian defaults, and both of them ship silently.
|
||||
#
|
||||
# Neither produces an error. makepkg exits 0 both times and the repository
|
||||
# gains a package whose files are in places nothing on the target will look.
|
||||
# This is the case "an exit code proves nothing, only the artefact proves"
|
||||
# was written for -- the symptom arrives months later, far from the cause.
|
||||
set -euo pipefail
|
||||
|
||||
# 1. The C library, and the one that actually matters.
|
||||
#
|
||||
# brotli's PKGBUILD calls plain `cmake`, not the arch-cmake stand-in, so it
|
||||
# never sees the -DCMAKE_INSTALL_LIBDIR=lib that stand-in passes. CMake's
|
||||
# GNUInstallDirs then picks its branch by sniffing the host: no
|
||||
# /etc/arch-release, /etc/debian_version present, so
|
||||
#
|
||||
# CMAKE_INSTALL_LIBDIR = lib/s390x-linux-gnu
|
||||
#
|
||||
# Measured on a DESTDIR install of a real build: libbrotlicommon.so.1,
|
||||
# libbrotlidec.so.1, libbrotlienc.so.1 and their .pc files all under
|
||||
# /usr/lib/s390x-linux-gnu. brotli is in stage 1 only because the chroot said
|
||||
# openssl and curl need libbrotli*.so -- and the filesystem package's
|
||||
# /etc/ld.so.conf reads only ld.so.conf.d, so the target would never find
|
||||
# them. A no-op in stage 2, where CMake takes the /etc/arch-release branch.
|
||||
python3 - <<'PY'
|
||||
import io
|
||||
s = io.open("PKGBUILD", encoding="utf-8").read()
|
||||
old = ' -DCMAKE_INSTALL_PREFIX=/usr \\\n'
|
||||
assert s.count(old) == 1, "expected exactly one cmake configure, found %d" % s.count(old)
|
||||
s = s.replace(old, old + ' -DCMAKE_INSTALL_LIBDIR=lib \\\n', 1)
|
||||
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
|
||||
PY
|
||||
grep -q 'DCMAKE_INSTALL_LIBDIR=lib' PKGBUILD || {
|
||||
echo "brotli: libdir not pinned" >&2; exit 1; }
|
||||
echo "brotli: cmake libdir pinned to lib (host GNUInstallDirs says multiarch)"
|
||||
|
||||
# 2. The python wheel, and an honest account of what this buys.
|
||||
#
|
||||
# package_python-brotli() runs
|
||||
#
|
||||
# python -m installer --destdir="$pkgdir" dist/*.whl
|
||||
#
|
||||
# and `installer` asks sysconfig where a wheel belongs. Debian and Ubuntu
|
||||
# patch sysconfig to prefer the "posix_local" scheme, so the answer here is
|
||||
# /usr/local/lib/python3.13/dist-packages. Verified by running the real wheel
|
||||
# through the real installer into a scratch pkgdir.
|
||||
#
|
||||
# BE CLEAR ABOUT WHAT THIS FIXES. It does NOT make the module importable on
|
||||
# Arch. Arch ships python 3.14 and this wheel is cp313 with an ABI-tagged
|
||||
# _brotli.cpython-313-*.so, so no destination makes a stage-1 wheel work on
|
||||
# the target; stage 2 is what produces a usable one. What the move buys is
|
||||
# that an Arch package must not ship files under /usr/local, which Arch
|
||||
# reserves for the administrator. That is the whole justification, and
|
||||
# writing a bigger one here would mislead the next reader.
|
||||
#
|
||||
# `installer --prefix=/usr` does NOT help: posix_local is literally
|
||||
# "{base}/local/lib/pythonX.Y/dist-packages", so overriding base with /usr
|
||||
# still lands in /usr/local. The SCHEME would have to change, and the only
|
||||
# supported way to change it is to be a different interpreter.
|
||||
#
|
||||
# Guarded on the directory, not the host name: under an Arch python the
|
||||
# directory is absent and the block does nothing. Only purelib moves -- the
|
||||
# wheel declares py_modules=["brotli"] plus the extension, no scripts and no
|
||||
# data files, so nothing else of it ever leaves /usr/local.
|
||||
python3 - <<'PY'
|
||||
import io
|
||||
s = io.open("PKGBUILD", encoding="utf-8").read()
|
||||
old = ' python -m installer --destdir="$pkgdir" dist/*.whl\n'
|
||||
assert old in s, "installer invocation not found"
|
||||
new = old + """ # Ubuntu's python installs to /usr/local/lib/pythonX.Y/dist-packages
|
||||
# (sysconfig's posix_local scheme). An Arch package may not ship /usr/local.
|
||||
local _pyver=$(python -c 'import sys; print("%d.%d" % sys.version_info[:2])')
|
||||
if [ -d "$pkgdir/usr/local/lib/python$_pyver/dist-packages" ]; then
|
||||
install -dm 755 "$pkgdir/usr/lib/python$_pyver"
|
||||
mv "$pkgdir/usr/local/lib/python$_pyver/dist-packages" \\
|
||||
"$pkgdir/usr/lib/python$_pyver/site-packages"
|
||||
rm -rf "$pkgdir/usr/local"
|
||||
fi
|
||||
"""
|
||||
s = s.replace(old, new, 1)
|
||||
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
|
||||
PY
|
||||
grep -q "posix_local scheme" PKGBUILD || {
|
||||
echo "brotli: wheel relocation not inserted" >&2; exit 1; }
|
||||
echo "brotli: python wheel moved out of /usr/local"
|
||||
44
patches/pkgbuild/pam.sh
Executable file
44
patches/pkgbuild/pam.sh
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env bash
|
||||
# pam: the PDF removal assumes fop, which the Ubuntu host does not have.
|
||||
#
|
||||
# rm: cannot remove
|
||||
# '.../pkg/pam/usr/share/doc/Linux-PAM/*.pdf': No such file or directory
|
||||
#
|
||||
# package() ends on
|
||||
#
|
||||
# # remove unreproducible pdf files
|
||||
# rm "${pkgdir}"/usr/share/doc/Linux-PAM/*.pdf
|
||||
#
|
||||
# and that line only works because Arch lists fop in makedepends. fop is a
|
||||
# Java renderer; putting a JVM on the build host to produce three PDFs that
|
||||
# the very next line deletes buys nothing, so the host stays without it.
|
||||
#
|
||||
# Without fop meson drops every PDF target in silence -- doc/adg, doc/mwg and
|
||||
# doc/sag each guard theirs with `if prog_fop.found()`, and the configured
|
||||
# build.ninja then holds zero .pdf rules. The DIRECTORY still exists, because
|
||||
# the HTML and text manuals install beside them, so the glob is never
|
||||
# expanded and rm is handed the literal string `*.pdf`. Same shape as the
|
||||
# util-linux glob that started the libdir hunt: the message names a path that
|
||||
# was never going to exist, and it aborts package() AFTER a successful
|
||||
# compile -- so the build looks like it failed at the very last step for no
|
||||
# reason at all.
|
||||
#
|
||||
# -f is the whole fix. With fop the PDFs are still removed; without it the
|
||||
# empty glob stops being an error.
|
||||
#
|
||||
# Not a hook, but the other half of pam and worth finding here: libnsl and
|
||||
# libtirpc are NOT optional on this host even though upstream marks NIS
|
||||
# `auto`, because arch-meson passes --auto-features enabled, which promotes
|
||||
# every auto feature to a hard requirement. Same mechanism turns pam's `docs`
|
||||
# feature into five fatal xmlcatalog probes. All of it is host packages, and
|
||||
# they are declared in install_host_deps.
|
||||
set -euo pipefail
|
||||
# Exactly one removal, and it must be the pdf one. Never a blanket rewrite:
|
||||
# package() also runs `install` and `chmod +s` on paths under the same tree,
|
||||
# and meson install itself writes there.
|
||||
n=$(grep -cF 'rm "${pkgdir}"/usr/share/doc/Linux-PAM/' PKGBUILD || true)
|
||||
[ "$n" = "1" ] || { echo "pam: expected 1 pdf removal, found $n" >&2; exit 1; }
|
||||
sed -i 's|rm "${pkgdir}"/usr/share/doc/Linux-PAM/|rm -f "${pkgdir}"/usr/share/doc/Linux-PAM/|' PKGBUILD
|
||||
grep -qF 'rm -f "${pkgdir}"/usr/share/doc/Linux-PAM/*.pdf' PKGBUILD || {
|
||||
echo "pam: pdf removal not made tolerant" >&2; exit 1; }
|
||||
echo "pam: pdf removal tolerates the empty glob (host has no fop)"
|
||||
83
patches/pkgbuild/systemd.sh
Executable file
83
patches/pkgbuild/systemd.sh
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env bash
|
||||
# systemd: two build options Arch can hold and s390x cannot.
|
||||
#
|
||||
# Neither is a missing host package -- both are hard errors raised by meson
|
||||
# because the PKGBUILD ASKS for something that does not exist on this
|
||||
# architecture, so no amount of apt-get makes them go away. The libraries
|
||||
# systemd wants (libbpf, clang, libfdisk, libkmod, ...) ARE host packages and
|
||||
# belong in install_host_deps, not here.
|
||||
set -euo pipefail
|
||||
|
||||
# 1. -Dbootloader=enabled: systemd-boot is EFI, and s390x has no EFI.
|
||||
#
|
||||
# The message you get is NOT about EFI:
|
||||
#
|
||||
# systemd/meson.build:1638:19: ERROR: python3 is missing modules: elftools
|
||||
#
|
||||
# because meson.build:1638 asks for pyelftools with
|
||||
# `required : get_option('bootloader')`, and the PKGBUILD set that to enabled.
|
||||
#
|
||||
# THE TRAP is that this reads like a missing host package, and
|
||||
# `apt install python3-pyelftools` looks like the fix. It is not. It buys four
|
||||
# lines, and then meson.build:1642 says what is really wrong:
|
||||
#
|
||||
# ERROR: Feature bootloader cannot be enabled: unsupported EFI arch or
|
||||
# EFI support is disabled
|
||||
#
|
||||
# (verified by planting a stub elftools module on PYTHONPATH; without it the
|
||||
# EFI message is unreachable, which is why nobody ever sees it first.)
|
||||
#
|
||||
# meson.build:1627 maps a cpu family to an EFI machine type name -- aa64, arm,
|
||||
# loongarch32/64, riscv32/64, x64, ia32 -- and s390x is not in that table, so
|
||||
# efi_arch is ''. -Defi is still true; the architecture simply has no EFI.
|
||||
# IBM Z boots from an IPL record, there is no ESP for systemd-boot to write
|
||||
# into, and no configuration invents one.
|
||||
#
|
||||
# The cost is the systemd-boot artefacts. bootctl itself is still built and
|
||||
# installed -- checked in the install plan -- package_systemd() names neither,
|
||||
# and the arch.conf/loader.conf/splash-arch.bmp it ships are `install`ed from
|
||||
# $srcdir rather than built. Packaging is untouched. Disabling also drops the
|
||||
# pyelftools requirement in the same line.
|
||||
sed -i 's/-Dbootloader=enabled/-Dbootloader=disabled/' PKGBUILD
|
||||
grep -q -- '-Dbootloader=disabled' PKGBUILD || {
|
||||
echo "systemd: bootloader option not rewritten" >&2; exit 1; }
|
||||
echo "systemd: bootloader disabled (s390x has no EFI machine type)"
|
||||
|
||||
# 2. -Dvmlinux-h=provided: the file Arch points at is an Arch file.
|
||||
#
|
||||
# src/bpf/meson.build: error('Path to provided vmlinux.h does not exist.')
|
||||
#
|
||||
# Arch's linux-headers ships /usr/src/linux/vmlinux.h, the path hard-coded in
|
||||
# the PKGBUILD. Ubuntu's linux-headers-* ship no vmlinux.h anywhere. This
|
||||
# failure only appears AFTER libbpf and clang are installed, because the whole
|
||||
# block is skipped while BPF_FRAMEWORK is off -- fixing libbpf uncovers it.
|
||||
#
|
||||
# systemd's own fallback dumps the header out of the running kernel's BTF,
|
||||
# which is what 'generated' selects:
|
||||
#
|
||||
# bpftool btf dump file /sys/kernel/btf/vmlinux format c
|
||||
#
|
||||
# Checked on this host: exit 0, 122471 lines, and enum lsm_integrity_type is
|
||||
# there at line 15931, so restrict-fsaccess.bpf.c builds rather than being
|
||||
# quietly dropped.
|
||||
#
|
||||
# THE TRAP is that 'auto' would NOT have done this for us. The auto branch
|
||||
# generates only when `host_machine.cpu_family() in ['x86_64', 'aarch64']`; on
|
||||
# s390x it falls through to "neither provided nor generated" and silently
|
||||
# drops the BPF programs that need the header. s390x has to say it out loud.
|
||||
#
|
||||
# Note the asymmetry this buys: on the 'provided' branch systemd probes the
|
||||
# header with cc.compiles() before deciding what to build. On 'generated' it
|
||||
# sets have_lsm_integrity_type = true outright. So the build now depends on
|
||||
# the BTF of the kernel RUNNING when it starts -- fine on 6.17.0-41, and on an
|
||||
# older kernel it turns into a compile error with no fallback.
|
||||
#
|
||||
# -Dvmlinux-h-path goes with it: 'generated' ignores the value, and leaving a
|
||||
# path that resolves to nothing invites the next reader to "repair" it.
|
||||
sed -i 's/-Dvmlinux-h=provided/-Dvmlinux-h=generated/' PKGBUILD
|
||||
sed -i '/-Dvmlinux-h-path=/d' PKGBUILD
|
||||
grep -q -- '-Dvmlinux-h=generated' PKGBUILD || {
|
||||
echo "systemd: vmlinux.h still read from a provided path" >&2; exit 1; }
|
||||
grep -q -- '-Dvmlinux-h-path' PKGBUILD && {
|
||||
echo "systemd: stale vmlinux-h-path left in place" >&2; exit 1; }
|
||||
echo "systemd: vmlinux.h generated from /sys/kernel/btf/vmlinux"
|
||||
|
|
@ -37,6 +37,30 @@ install_host_deps() {
|
|||
# systemtap-sdt-dev and gmp/mpfr/mpc for glibc and gcc, autopoint and
|
||||
# gperf for coreutils, asciidoc for pacman, po4a for xz, gnat for gcc's
|
||||
# Ada front end, debuginfod and jansson for binutils.
|
||||
#
|
||||
# THE LIST WAS ALSO A LIE BY OMISSION. An audit of the six packages that
|
||||
# follow found libreadline-dev, libncurses-dev, zlib1g-dev, python3-dev,
|
||||
# doxygen, xsltproc, docbook-xsl, elinks and libcap2-bin already present
|
||||
# on the build VM but installed BY HAND, never declared here. On this
|
||||
# host they made the builds pass; on a fresh Ubuntu they would have
|
||||
# failed at readline, at libxml2 and inside shadow's `make install`, for
|
||||
# reasons that have nothing to do with s390x. They are named below now.
|
||||
# The rest is per-package, and each group says which package needs it.
|
||||
#
|
||||
# gnupg imagemagick + fig2dev render doc/*.svg and doc/*.fig, which
|
||||
# a git checkout must generate; librsvg2-bin guarantees the
|
||||
# SVG coder even under --no-install-recommends.
|
||||
# shadow itstool builds the translated man pages; libcap2-bin gives
|
||||
# the bare `setcap` its install rule calls.
|
||||
# util-linux asciidoctor -- Ruby, and NOT the `asciidoc` above, which
|
||||
# is a different program added for pacman. Easy to mistake
|
||||
# for coverage.
|
||||
# pam libnsl/libtirpc for NIS, the DocBook 5 catalog, and elinks,
|
||||
# which meson uses to dump the HTML manuals to text.
|
||||
# brotli cmake, and the PEP 517 chain its python bindings build with.
|
||||
# libxml2 ICU, readline, and the doc toolchain.
|
||||
# systemd the widest surface of anything in stage 1; every one of
|
||||
# these was checked against a real meson configure.
|
||||
sudo apt-get -o DPkg::Lock::Timeout=600 install -y -qq \
|
||||
meson ninja-build pkg-config gettext \
|
||||
libarchive-dev libcurl4-openssl-dev libgpgme-dev libssl-dev \
|
||||
|
|
@ -46,7 +70,19 @@ install_host_deps() {
|
|||
systemtap-sdt-dev asciidoc autopoint gperf help2man rsync \
|
||||
libgmp-dev libmpfr-dev libmpc-dev python3-docutils \
|
||||
libseccomp-dev libpcre2-dev \
|
||||
po4a gnat libdebuginfod-dev libjansson-dev
|
||||
po4a gnat libdebuginfod-dev libjansson-dev \
|
||||
libreadline-dev libncurses-dev zlib1g-dev python3-dev \
|
||||
doxygen xsltproc docbook-xsl libcap2-bin \
|
||||
imagemagick fig2dev librsvg2-bin \
|
||||
itstool asciidoctor \
|
||||
libtirpc-dev libnsl-dev docbook5-xml docbook-xsl-ns elinks \
|
||||
cmake python3-build python3-installer python3-pkgconfig \
|
||||
python3-setuptools python3-wheel \
|
||||
libicu-dev \
|
||||
libbpf-dev clang libapparmor-dev libfdisk-dev libkmod-dev libdw-dev \
|
||||
libpwquality-dev libxkbcommon-dev libdbus-1-dev libqrencode-dev \
|
||||
libfido2-dev libtss2-dev libmicrohttpd-dev libaudit-dev \
|
||||
libcryptsetup-dev libgcrypt20-dev libgnutls28-dev libpam0g-dev
|
||||
install_host_shims
|
||||
}
|
||||
|
||||
|
|
@ -62,6 +98,39 @@ install_host_shims() {
|
|||
log "Host shims"
|
||||
local d="$HERE_DIR/devtools"
|
||||
sudo install -m755 "$d/arch-meson" "$d/arch-cmake" /usr/local/bin/
|
||||
# history.pc, which Ubuntu drops and Arch ships.
|
||||
#
|
||||
# GNU readline generates and installs BOTH readline.pc and history.pc;
|
||||
# Debian and Ubuntu keep the first and delete the second, while the
|
||||
# library, libhistory.so, is right there in libreadline-dev. libxml2 asks
|
||||
# pkg-config for `history` and stops:
|
||||
#
|
||||
# libxml2/meson.build:353:18: ERROR: Dependency "history" not found
|
||||
#
|
||||
# THE TRAP: our own readline package in repo/s390x DOES ship a correct
|
||||
# history.pc, so copying that one looks like the tidy answer. It is not.
|
||||
# Its libdir is ${exec_prefix}/lib -- right for the target rootfs, wrong
|
||||
# for a multiarch host where /usr/lib holds no libhistory. The .pc has to
|
||||
# describe THIS host, so it is generated from the host's own readline.pc.
|
||||
local multiarch version
|
||||
multiarch="$(dpkg-architecture -qDEB_HOST_MULTIARCH)"
|
||||
version="$(pkg-config --modversion readline)"
|
||||
sudo mkdir -p /usr/local/lib/pkgconfig
|
||||
printf '%s\n' \
|
||||
"prefix=/usr" \
|
||||
"exec_prefix=\${prefix}" \
|
||||
"libdir=/usr/lib/$multiarch" \
|
||||
"includedir=\${prefix}/include" \
|
||||
"" \
|
||||
"Name: History" \
|
||||
"Description: GNU History library" \
|
||||
"Version: $version" \
|
||||
"Requires.private: tinfo" \
|
||||
"Libs: -L\${libdir} -lhistory" \
|
||||
"Cflags: -I\${includedir}" \
|
||||
| sudo tee /usr/local/lib/pkgconfig/history.pc > /dev/null
|
||||
pkg-config --exists history || {
|
||||
echo "history.pc still not visible to pkg-config" >&2; return 1; }
|
||||
}
|
||||
|
||||
build_pacman() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue