archlinux-s390x/patches/pkgbuild/systemd.sh

371 lines
18 KiB
Bash
Raw Normal View History

[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
2026-08-17 01:33:41 -04:00
#!/usr/bin/env bash
[REM] sub-packages: four that cost more closure than they carry pacman's resolver named 70 unresolved dependencies. Excluding python-brotli alone took that to 47 and removed `python` outright, with libffi, mpdecimal and gdbm behind it. python-libseccomp would have re-admitted the same tree, and nothing across 135 packages depends on either. Both wheels are unusable on the target anyway: built by the host's python 3.13, ABI-tagged cpython-313, while Arch ships 3.14. Stage 2 produces real ones. systemd-ukify is different -- it is architectural. ukify assembles a PE binary and its EFI_ARCH_MAP has no s390x entry, so guess_efi_arch() raises ValueError on this machine. Shipping it would put a program in the repository that cannot start. systemd-tests followed it out: a test suite behind --nocheck, and the only reason five more python packages were wanted. The dropped artefacts were still indexed in core.db afterwards. repo-add only adds, so a sub-package removed from pkgname leaves its last build installable forever. Removed by hand; TODO.md records the gap. --- FR --- Le résolveur de pacman nommait 70 dépendances non résolues. Écarter le seul python-brotli a ramené le compte à 47 et retiré `python` d'un coup, avec libffi, mpdecimal et gdbm derrière. python-libseccomp aurait réadmis le même arbre, et rien parmi 135 paquets ne dépend de l'un ou de l'autre. Les deux roues sont de toute façon inutilisables sur la cible : bâties par le python 3.13 de l'hôte, marquées cpython-313, quand Arch livre la 3.14. L'étage 2 en produira de vraies. systemd-ukify est d'une autre nature — architectural. ukify assemble un binaire PE et son EFI_ARCH_MAP n'a pas d'entrée s390x : guess_efi_arch() lève donc ValueError sur cette machine. Le livrer mettrait au dépôt un programme incapable de démarrer. systemd-tests l'a suivi : une suite de tests derrière --nocheck, et la seule raison de réclamer cinq paquets python de plus. Les artefacts écartés restaient indexés dans core.db. repo-add n'ajoute que : un sous-paquet retiré de pkgname laisse sa dernière compilation installable à jamais. Retirés à la main ; TODO.md consigne le manque. Assisted-by: Claude Opus 5
2026-08-19 05:28:32 -04:00
# systemd: four defaults Arch can hold and s390x cannot.
[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
2026-08-17 01:33:41 -04:00
#
[REM] sub-packages: four that cost more closure than they carry pacman's resolver named 70 unresolved dependencies. Excluding python-brotli alone took that to 47 and removed `python` outright, with libffi, mpdecimal and gdbm behind it. python-libseccomp would have re-admitted the same tree, and nothing across 135 packages depends on either. Both wheels are unusable on the target anyway: built by the host's python 3.13, ABI-tagged cpython-313, while Arch ships 3.14. Stage 2 produces real ones. systemd-ukify is different -- it is architectural. ukify assembles a PE binary and its EFI_ARCH_MAP has no s390x entry, so guess_efi_arch() raises ValueError on this machine. Shipping it would put a program in the repository that cannot start. systemd-tests followed it out: a test suite behind --nocheck, and the only reason five more python packages were wanted. The dropped artefacts were still indexed in core.db afterwards. repo-add only adds, so a sub-package removed from pkgname leaves its last build installable forever. Removed by hand; TODO.md records the gap. --- FR --- Le résolveur de pacman nommait 70 dépendances non résolues. Écarter le seul python-brotli a ramené le compte à 47 et retiré `python` d'un coup, avec libffi, mpdecimal et gdbm derrière. python-libseccomp aurait réadmis le même arbre, et rien parmi 135 paquets ne dépend de l'un ou de l'autre. Les deux roues sont de toute façon inutilisables sur la cible : bâties par le python 3.13 de l'hôte, marquées cpython-313, quand Arch livre la 3.14. L'étage 2 en produira de vraies. systemd-ukify est d'une autre nature — architectural. ukify assemble un binaire PE et son EFI_ARCH_MAP n'a pas d'entrée s390x : guess_efi_arch() lève donc ValueError sur cette machine. Le livrer mettrait au dépôt un programme incapable de démarrer. systemd-tests l'a suivi : une suite de tests derrière --nocheck, et la seule raison de réclamer cinq paquets python de plus. Les artefacts écartés restaient indexés dans core.db. repo-add n'ajoute que : un sous-paquet retiré de pkgname laisse sa dernière compilation installable à jamais. Retirés à la main ; TODO.md consigne le manque. Assisted-by: Claude Opus 5
2026-08-19 05:28:32 -04:00
# None of them is a missing host package. Two are hard errors raised by meson
# because the PKGBUILD ASKS for something this architecture does not have; two
# are defaults computed from the BUILD MACHINE rather than the target. No
# amount of apt-get fixes any of them. The libraries systemd wants (libbpf,
# clang, libfdisk, libkmod, ...) ARE host packages and belong in
# install_host_deps, not here.
#
# Three of the four fail with a message that names something else entirely.
# Each section says which, because that is the part worth reading twice.
[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
2026-08-17 01:33:41 -04:00
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"
[FIX] host defaults: apt was deciding what got built --auto-features enabled turns every auto feature into a requirement, so installing a tool switches on code that never compiled here. Three of the fifty host packages did exactly that, and only one failed for the reason it named. expat had built clean the day before. asciidoc pulled docbook-utils in as an automatic dependency; it owns docbook2man, the third name in expat's find_program list, so docs defaulted ON twenty-nine hours before anything rebuilt. That tool is the SGML pipeline: on DocBook XML it writes nothing and still exits 0, and the mv it feeds is what reported the failure. Arch ships no xmlwf.1 either, so OFF is parity. systemd's split-bin probes the BUILD host's /usr/sbin. Ubuntu's is a real directory, so six binaries went where package() does not look -- and arch-meson's --sbindir is ignored, systemd computes its own. util-linux needed no option: poman-translate.sh greps po4a for the English "Discard" and this host answers "Rejet de". The locale belongs to the host, so it is pinned once on the makepkg line. --- FR --- --auto-features enabled fait de chaque fonction « auto » une exigence : installer un outil active donc du code jamais compilé ici. Trois des cinquante paquets hôte l'ont fait, et un seul a échoué pour la raison qu'il annonçait. expat compilait proprement la veille. asciidoc avait tiré docbook-utils en dépendance automatique ; il fournit docbook2man, troisième nom de la liste find_program d'expat, et la doc est passée à ON vingt-neuf heures avant toute reconstruction. Cet outil est le pipeline SGML : sur du DocBook XML il n'écrit rien et sort quand même 0, et le mv qu'il alimente est ce qui a signalé la panne. Arch ne livre pas xmlwf.1 non plus : OFF, c'est la parité. Le split-bin de systemd sonde le /usr/sbin de la machine de BUILD. Celui d'Ubuntu est un vrai répertoire, donc six binaires sont partis là où package() ne regarde pas — et le --sbindir d'arch-meson est ignoré, systemd calcule le sien. util-linux n'avait besoin d'aucune option : poman-translate.sh cherche le « Discard » anglais de po4a, et cet hôte répond « Rejet de ». La locale appartient à l'hôte : elle est épinglée une fois, sur la ligne makepkg. Assisted-by: Claude Opus 5
2026-08-17 02:37:46 -04:00
# 3. -Dsplit-bin=auto: the question is answered by the HOST, not the target.
#
# systemd/meson.build:123
# sbindir = prefixdir / (split_bin ? 'sbin' : 'bin')
#
# split-bin is a combo defaulting to 'auto', and 'auto' probes whether
# /usr/sbin on the BUILD MACHINE is a symlink to bin. On Arch it is, so
# split_bin is false and everything lands in /usr/bin. Here /usr/sbin is a
# real directory, and meson-log.txt says so:
#
# split bin-sbin : true
#
# THE TRAP is that arch-meson ALREADY passes --sbindir bin, and
# `meson configure` dutifully reports sbindir = bin. It is ignored: systemd
# computes its own sbindir from split_bin and never reads meson's builtin. The
# option that looks like the fix is not the fix, and the one that is mentions
# neither sbin nor a directory in its name.
#
# Nothing fails in build(). It fails much later, in package_systemd(), on the
# first line that names a path:
#
# rm: cannot remove '<pkgdir>/usr/bin/halt': No such file or directory
#
# because halt, init, poweroff, reboot, shutdown and resolvconf all went to
# /usr/sbin -- along with mount.ddi, mount.mstack and mount.storage, which the
# PKGBUILD never mentions at all. The rm is only the first victim. Suppress it
# and the package ships /usr/sbin as a DIRECTORY, which collides on the target
# with the ["usr/sbin"]="bin" SYMLINK our own filesystem package declares.
#
# Measured on a configured copy: with split-bin=false there is no /usr/sbin in
# the install tree at all, and all six paths are where package() looks.
#
# Same species as arch-meson's --libdir -- an Ubuntu default standing in for
# an Arch one -- but it cannot live in arch-meson: split-bin is systemd's own
# option, not a meson builtin. --auto-features does not reach it either; it is
# a combo, not a feature.
test "$(grep -c -- '-Dcompat-sysv-interfaces=false' PKGBUILD)" -eq 1 || {
echo "systemd: expected exactly one _meson_options array" >&2; exit 1; }
test "$(grep -c -- '-Dsplit-bin' PKGBUILD)" -eq 0 || {
echo "systemd: PKGBUILD already sets split-bin, re-read it" >&2; exit 1; }
sed -i 's/^\( *\)-Dcompat-sysv-interfaces=false/\1-Dsplit-bin=false\n\1-Dcompat-sysv-interfaces=false/' PKGBUILD
grep -q -- '-Dsplit-bin=false' PKGBUILD || {
echo "systemd: split-bin still auto (would install into /usr/sbin)" >&2; exit 1; }
echo "systemd: split-bin=false (Ubuntu's /usr/sbin is not Arch's)"
[REM] sub-packages: four that cost more closure than they carry pacman's resolver named 70 unresolved dependencies. Excluding python-brotli alone took that to 47 and removed `python` outright, with libffi, mpdecimal and gdbm behind it. python-libseccomp would have re-admitted the same tree, and nothing across 135 packages depends on either. Both wheels are unusable on the target anyway: built by the host's python 3.13, ABI-tagged cpython-313, while Arch ships 3.14. Stage 2 produces real ones. systemd-ukify is different -- it is architectural. ukify assembles a PE binary and its EFI_ARCH_MAP has no s390x entry, so guess_efi_arch() raises ValueError on this machine. Shipping it would put a program in the repository that cannot start. systemd-tests followed it out: a test suite behind --nocheck, and the only reason five more python packages were wanted. The dropped artefacts were still indexed in core.db afterwards. repo-add only adds, so a sub-package removed from pkgname leaves its last build installable forever. Removed by hand; TODO.md records the gap. --- FR --- Le résolveur de pacman nommait 70 dépendances non résolues. Écarter le seul python-brotli a ramené le compte à 47 et retiré `python` d'un coup, avec libffi, mpdecimal et gdbm derrière. python-libseccomp aurait réadmis le même arbre, et rien parmi 135 paquets ne dépend de l'un ou de l'autre. Les deux roues sont de toute façon inutilisables sur la cible : bâties par le python 3.13 de l'hôte, marquées cpython-313, quand Arch livre la 3.14. L'étage 2 en produira de vraies. systemd-ukify est d'une autre nature — architectural. ukify assemble un binaire PE et son EFI_ARCH_MAP n'a pas d'entrée s390x : guess_efi_arch() lève donc ValueError sur cette machine. Le livrer mettrait au dépôt un programme incapable de démarrer. systemd-tests l'a suivi : une suite de tests derrière --nocheck, et la seule raison de réclamer cinq paquets python de plus. Les artefacts écartés restaient indexés dans core.db. repo-add n'ajoute que : un sous-paquet retiré de pkgname laisse sa dernière compilation installable à jamais. Retirés à la main ; TODO.md consigne le manque. Assisted-by: Claude Opus 5
2026-08-19 05:28:32 -04:00
# 4. -Dukify=auto: the tool cannot run on this architecture at all.
#
# ukify assembles a Unified Kernel Image, and a UKI is a PE binary -- ukify.py
# imports pefile at module level and drives it directly (pefile.PE,
# SectionStructure, IMAGE_SCN_*). It is EFI tooling, so the same reasoning as
# section 1 applies. But it is stronger than "pointless on Z", and the source
# says so out loud:
#
# EFI_ARCH_MAP = {
# 'x86_64': ['x64','ia32'], 'i[3456]86': ['ia32'], 'aarch64': ['aa64'],
# 'armv[45678]*l': ['arm'], 'loongarch32': ..., 'riscv64': ...
# }
#
# def guess_efi_arch() -> str:
# ...
# else:
# raise ValueError(f'Unsupported architecture {arch}')
#
# s390x is not in that table, so ukify RAISES on this machine. Shipping it
# would put a program in the repository that cannot start.
#
# THE TRAP is that ukify does not announce itself as EFI-only anywhere the
# build stops. meson_options.txt:560 declares it a plain feature with no
# value -- 'auto' -- and meson.build:1659 is get_option('ukify').allowed(),
# which is true for 'auto'. So it is on by default, and what it broke was
# nowhere near ukify:
#
# FAILED: src/boot/test-hwids-section.c
# ModuleNotFoundError: No module named 'pefile'
#
# That looked like a missing host package, and `apt install python3-pefile`
# made it build. It was the wrong fix: the target at src/boot/meson.build:31
# is gated on ENABLE_UKIFY, not on ENABLE_BOOTLOADER, which is why disabling
# systemd-boot did not reach it. Disabling ukify does, and python3-pefile is
# then unnecessary -- nothing else in the tree needs it, since the only other
# importer, tools/check-efi-alignment.py, is reached from
# src/boot/meson.build:495, far below the ENABLE_BOOTLOADER subdir_done()
# guard.
#
# systemd-tests goes with it, for a different reason. It is a test suite --
# stage 1 runs --nocheck -- and it is the sole reason five python packages
# (colorama, packaging, pexpect, psutil, pytest) would enter the closure.
# Deferred, not architectural: TODO.md records it.
#
# The two subpackages leave in three places, and the pkgname array is the
# awkward one: its LAST entry carries the closing paren, so deleting a line
# would delete the ')' with it. The array is rebuilt rather than edited.
python3 - <<'PY'
import io, re
s = io.open("PKGBUILD", encoding="utf-8").read()
# (a) the option, next to the other EFI one so they read together
anchor = " -Dbootloader=disabled\n"
assert s.count(anchor) == 1, "expected section 1 to have set bootloader=disabled"
s = s.replace(anchor, anchor + " -Dukify=disabled\n", 1)
# (b) the pkgname array, rebuilt to keep its syntax intact
m = re.search(r"pkgname=\((.*?)\)\n", s, re.S)
assert m, "pkgname array not found"
names = re.findall(r"'([^']+)'", m.group(1))
drop = {"systemd-ukify", "systemd-tests"}
assert drop <= set(names), "expected both subpackages in pkgname, found %s" % names
kept = [n for n in names if n not in drop]
s = s[:m.start()] + "pkgname=(" + ("\n" + " " * 9).join("'%s'" % n for n in kept) + ")\n" + s[m.end():]
# (c) package_systemd() moves four ukify paths out. With ukify disabled none
# of them exists, and mv fails -- after a successful compile, which is the
# expensive way to find out.
blk = re.search(
r"\n # ukify shipped in separate package\n"
r"(?:.*\n)*?"
r" mv \"\$pkgdir\"/usr/lib/kernel/install\.d/60-ukify\.install systemd-ukify/install\.d\n",
s)
assert blk, "ukify mv block not found"
s = s[:blk.start()] + "\n" + s[blk.end():]
# (d) an optdepends on a package we no longer produce
s = re.sub(r"^.*'systemd-ukify: .*\n", "", s, flags=re.M)
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
PY
# The guard checks what MATTERS, which is not "no mention of ukify remains".
# package_systemd-ukify() still sits in the file and still names four paths --
# harmless, because makepkg never calls a function whose name is absent from
# pkgname, exactly as with package_libquadmath() in gcc.sh. Counting mentions
# instead of checking the two real conditions made this hook exit 1 on a
# correctly patched PKGBUILD, and build_package reads that as a failed
# package: systemd would have been skipped entirely, with every edit applied.
grep -q -- '-Dukify=disabled' PKGBUILD || {
echo "systemd: ukify still enabled" >&2; exit 1; }
grep -q '# ukify shipped in separate package' PKGBUILD && {
echo "systemd: package_systemd() still moves ukify paths that cannot exist" >&2
exit 1; }
python3 - <<'PYGUARD'
import io, re, sys
s = io.open("PKGBUILD", encoding="utf-8").read()
m = re.search(r"pkgname=\((.*?)\)\n", s, re.S)
if not m:
sys.exit("systemd: pkgname array unreadable after patching")
names = re.findall(r"'([^']+)'", m.group(1))
left = sorted({"systemd-ukify", "systemd-tests"} & set(names))
if left:
sys.exit("systemd: still declared in pkgname: %s" % left)
print("systemd: pkgname -> %s" % " ".join(names))
PYGUARD
echo "systemd: ukify disabled (guess_efi_arch raises on s390x), tests dropped"
# --- no BPF framework ---------------------------------------------------------
#
# meson.build:1052:9: ERROR: Dependency "libbpf" not found (tried pkgconfig)
#
# libbpf is not in this port's package list, and adding it is not a small step:
# systemd's BPF programs are compiled with clang and llvm, so the dependency is
# an entire second compiler toolchain for a feature that only matters to
# systemd's own resource-control and socket-binding units.
#
# -Dbpf-framework=disabled is systemd's own switch for building without it,
# which is what every distribution that does not ship BPF-based unit features
# uses. Revisit if something on the target actually needs IPAddressAllow= or
# RestrictNetworkInterfaces=.
set -euo pipefail
python3 - <<'ZZPY'
import io
s = io.open("PKGBUILD", encoding="utf-8").read()
old = "-Dbpf-framework=enabled"
assert s.count(old) == 1, "systemd: expected one bpf-framework option, got %d" % s.count(old)
s = s.replace(old, "-Dbpf-framework=disabled", 1)
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
ZZPY
grep -q -- "-Dbpf-framework=disabled" PKGBUILD || {
echo "systemd: bpf-framework was not disabled" >&2; exit 1; }
echo "systemd: BPF framework disabled (no libbpf, no clang)"
[FIX] systemd without AppArmor, gpgme without its test harness, groff without a logo gpgme is the one worth reading. It failed while BUILDING, not testing: make[3]: Entering directory '.../gpgme/tests/gpg' gpgconf: error running '/usr/bin/gpg-connect-agent': exit status 1 EL_NOCHECK skips check(), but `make all` still descends into tests/gpg and sets up a throwaway GNUPGHOME, which means starting an agent -- and the chroot has no dbus, no session and no tty. Third time this port has found that "no tests" and "no test harness" are different requests. groff needs xpmtoppm from netpbm to draw the GNU logo for its own manual. There is no configure switch: groff has neither --without-doc nor --disable-doc, so inventing a flag would have failed identically while the hook's check passed -- autoconf only warns about options it does not know. The generated Makefile's DOC_GNU_EPS is emptied instead, and the verification runs inside build(), where the generated file actually exists. --- FR --- gpgme mérite lecture. Il échouait en CONSTRUISANT, pas en testant : make[3]: Entering directory '.../gpgme/tests/gpg' gpgconf: error running '/usr/bin/gpg-connect-agent': exit status 1 EL_NOCHECK saute check(), mais `make all` descend quand même dans tests/gpg et met en place un GNUPGHOME jetable, donc démarre un agent — or le chroot n'a ni dbus, ni session, ni terminal. Troisième fois que ce portage constate que « pas de tests » et « pas de harnais de test » sont deux demandes différentes. groff a besoin de xpmtoppm, de netpbm, pour dessiner le logo GNU de son propre manuel. Aucun interrupteur n'existe : ni --without-doc ni --disable-doc, donc inventer un drapeau aurait échoué à l'identique pendant que le contrôle du hook passait — autoconf ne fait qu'avertir des options qu'il ignore. La variable DOC_GNU_EPS du Makefile généré est vidée, et la vérification tourne dans build(), là où le fichier généré existe. Assisted-by: Claude Opus 5
2026-08-22 22:02:56 -04:00
# --- no AppArmor ---------------------------------------------------------------
#
# meson.build:1098:14: ERROR: Dependency "libapparmor" not found (tried pkgconfig)
#
# The second dependency systemd asked for that this port does not package, after
# libbpf. AppArmor is a Debian/Ubuntu security module; Arch ships it but nothing
# in this bootstrap uses it, and systemd's support for it is a set of unit
# directives (AppArmorProfile=) rather than anything the system needs to boot.
#
# -Dapparmor=disabled is systemd's own switch. Revisit if the target ever runs
# an AppArmor policy.
set -euo pipefail
python3 - <<'ZZPY'
import io
s = io.open("PKGBUILD", encoding="utf-8").read()
old = "-Dapparmor=enabled"
assert s.count(old) == 1, "systemd: expected one apparmor option, got %d" % s.count(old)
s = s.replace(old, "-Dapparmor=disabled", 1)
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
ZZPY
grep -q -- "-Dapparmor=disabled" PKGBUILD || { echo "systemd: apparmor not disabled" >&2; exit 1; }
echo "systemd: AppArmor disabled"
[FIX] groff's remaining lists, systemd man pages, git without libsecret groff was the third round on the same package: DOC_GNU_EPS, then PROCESSEDEXAMPLEFILES_PS, then HDTBL -- and mom's examples were waiting behind those. groff renders its own manuals and every contrib package's examples with the groff being built, each list a separate variable. Finding them one failure at a time cost three passes; all seven are emptied together now. systemd is the fourth package to stop on missing DocBook DATA rather than a missing tool -- xsltproc exists, our libxslt supplies it: compilation error: file ../systemd/man/custom-man.xsl line 12 element import It has the largest man page set here, which is the strongest argument in this port for shipping docbook-xsl eventually. git's libsecret helper needed THREE places, one spanning two lines. The first version asserted "expected one _make, got 2" and stopped -- the guard working. Replacing the install's first line alone would have left its continuation as a command of its own, which is the binutils trap again. --- FR --- groff en était au troisième tour sur le même paquet : DOC_GNU_EPS, puis PROCESSEDEXAMPLEFILES_PS, puis HDTBL — et les exemples de mom attendaient derrière. groff rend ses propres manuels et les exemples de chaque contrib avec le groff en cours de construction, chaque liste étant une variable distincte. Les trouver un échec à la fois a coûté trois passes ; les sept sont vidées ensemble. systemd est le quatrième paquet à s'arrêter sur des DONNÉES DocBook absentes et non sur un outil manquant — xsltproc existe, notre libxslt le fournit : compilation error: file ../systemd/man/custom-man.xsl line 12 element import Il porte le plus grand ensemble de pages de manuel du portage : c'est le meilleur argument pour livrer docbook-xsl à terme. L'aide libsecret de git demandait TROIS endroits, dont un sur deux lignes. La première version a affirmé « expected one _make, got 2 » et s'est arrêtée — le garde faisant son travail. Remplacer la première ligne de l'installation aurait laissé sa continuation comme commande à part, soit le piège de binutils à nouveau. Assisted-by: Claude Opus 5
2026-08-23 23:58:32 -04:00
# --- no man pages -------------------------------------------------------------
#
# compilation error: file ../systemd/man/custom-man.xsl line 12 element import
#
# An XSLT import that cannot resolve: systemd renders its man pages from DocBook,
# and the stylesheets its own custom-man.xsl imports are not installed. xsltproc
# exists -- our libxslt supplies it -- so this is the FOURTH package to stop on
# missing DocBook DATA rather than a missing tool, after pam, shadow and p11-kit.
#
# systemd has by far the largest man page set of any package here, which is the
# strongest argument in the port for shipping docbook-xsl eventually. Not now.
set -euo pipefail
python3 - <<'ZZPY'
import io
s = io.open("PKGBUILD", encoding="utf-8").read()
old = "-Dman=enabled"
assert s.count(old) == 1, "systemd: expected one man option, got %d" % s.count(old)
s = s.replace(old, "-Dman=disabled", 1)
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
ZZPY
grep -q -- "-Dman=disabled" PKGBUILD || { echo "systemd: man not disabled" >&2; exit 1; }
echo "systemd: man pages disabled (DocBook stylesheets absent, not xsltproc)"
[FIX] systemd: every man page operation at once, not one per pass mv: cannot stat '<pkgdir>/usr/share/man/man3': No such file or directory Fifteenth instance, and the first where the whole class was handled before the failures arrived. -Dman=disabled means NO man pages exist, and package() touches them six times -- three moves into split packages, three removals of pages Arch does not ship. Treated by kind rather than by name: the moves are neutralised, because with no pages there is nothing to move; the removals get -f, because their intent still holds on a machine that HAS the DocBook stack, and one of them also removes a binary that must still go. Five moves, three removals, counted and reported by the hook. This is the procedure written into jsoncpp's hook one commit earlier, applied forwards: after disabling documentation, grep package() for the output paths. Chasing man3 alone would have cost five more passes. The first guard for it matched any `rm` without a dash and condemned correct code -- systemd removes plenty that is not documentation. Same mistake as the blanket `grep tcl8.6` in sqlite's hook, and caught the same way. --- FR --- mv: cannot stat '<pkgdir>/usr/share/man/man3': No such file or directory Quinzième occurrence, et la première où toute la classe est traitée avant que les échecs n'arrivent. -Dman=disabled signifie qu'AUCUNE page n'existe, et package() y touche six fois — trois déplacements vers des sous-paquets, trois suppressions de pages qu'Arch ne livre pas. Traitées par nature et non par nom : les déplacements sont neutralisés, puisqu'il n'y a rien à déplacer ; les suppressions reçoivent -f, car leur intention tient toujours sur une machine dotée de la pile DocBook, et l'une retire aussi un binaire qui doit bien partir. Cinq déplacements, trois suppressions, comptés et rapportés par le hook. C'est la procédure inscrite dans le hook de jsoncpp un commit plus tôt, appliquée à l'endroit : après avoir désactivé une documentation, chercher dans package() les chemins de sortie. Poursuivre man3 seul aurait coûté cinq passes de plus. Le premier garde écrit pour cela attrapait tout `rm` sans tiret et condamnait du code juste — systemd supprime beaucoup qui n'est pas de la documentation. Même erreur que le `grep tcl8.6` global du hook sqlite, attrapée de la même façon. Assisted-by: Claude Opus 5
2026-08-24 00:21:48 -04:00
# --- and every man page operation in package() --------------------------------
#
# mv: cannot stat '<pkgdir>/usr/share/man/man3': No such file or directory
#
# FIFTEENTH time, and the first where the whole class was handled at once instead
# of one path per pass. -Dman=disabled means NO man pages exist, and package()
# touches them six times:
#
# mv .../man/man3 systemd-libs/man3
# mv .../man/man8/*nss* systemd-libs/man8/
# mv .../man/man1/ukify.1 systemd-ukify/man1/
# rm .../man/man1/init.1
# rm .../man/man8/{halt,poweroff,reboot,shutdown}.8
# rm .../usr/{bin/resolvconf,share/man/man1/resolvconf.1}
#
# Treated by KIND rather than by name:
#
# mv -- neutralised. These move pages into split packages, and with no pages
# there is nothing to move and the split simply has no man section.
# rm -- made tolerant with -f. These delete pages Arch does not want shipped,
# and that intent still holds on a machine that HAS the DocBook stack.
# The last one also removes a binary, which must still go.
#
# This is the procedure written in jsoncpp's hook, applied before the failures
# arrive rather than after: grep package() for the output paths, not the tool.
set -euo pipefail
python3 - <<'ZZPY'
import io, re
lines = io.open("PKGBUILD", encoding="utf-8").read().split("\n")
mv_n = rm_n = 0
for i in range(len(lines) - 1, -1, -1):
l = lines[i]
if "share/man" not in l and not re.search(r"\bman[0-9]\b", l):
continue
if re.match(r"^[ \t]*mv ", l):
j = i
while lines[j].rstrip().endswith("\\"):
j += 1
ind = re.match(r"^[ \t]*", l).group(0)
lines[i:j + 1] = [ind + ": # no man pages are built: -Dman=disabled above."]
mv_n += 1
elif re.match(r"^[ \t]*rm ", l) and not re.match(r"^[ \t]*rm -[a-z]*f", l):
lines[i] = re.sub(r"^([ \t]*)rm ", r"\1rm -f ", l)
rm_n += 1
assert mv_n >= 1, "systemd: no man page moves found"
assert rm_n >= 1, "systemd: no man page removals found"
io.open("PKGBUILD", "w", encoding="utf-8").write("\n".join(lines))
print(" %d move(s) neutralised, %d removal(s) made tolerant" % (mv_n, rm_n))
ZZPY
grep -qE "^[[:space:]]*mv .*(share/man|\bman[0-9]\b)" PKGBUILD && {
echo "systemd: a man page move survived" >&2; exit 1; }
# Scoped to man paths. The first version of this guard matched any `rm` without
# a dash and condemned correct code -- systemd's package() removes plenty of
# things that have nothing to do with documentation. Same mistake as the blanket
# `grep tcl8.6` in sqlite's hook: a check must ask about what it changed.
grep -qE "^[[:space:]]*rm [^-].*(share/man|\bman[0-9]\b)" PKGBUILD && {
echo "systemd: an intolerant rm of a man path survived" >&2; exit 1; }
echo "systemd: all man page operations handled"