Two more documentation-and-toolchain cuts, both using the project's own switch. systemd asked for libbpf, which this port does not package -- and packaging it means clang and llvm, an entire second compiler toolchain for unit features nothing here uses yet. pacman asked for asciidoc, the same Python documentation stack already declined for doxygen, asciidoctor and a2x. pacman is worth naming out loud: it is the package manager, so its man pages are the ones a user reaches for first. This is the most visible of the documentation cuts and the strongest single argument for restoring them at stage 3. --- FR --- Deux coupes de plus, documentation et chaîne d'outils, chacune par l'interrupteur prévu par le projet lui-même. systemd réclamait libbpf, que ce portage ne paquette pas — et le paqueter suppose clang et llvm, soit une seconde chaîne de compilation entière pour des fonctions d'unité dont rien ici ne se sert encore. pacman réclamait asciidoc, la même pile Python déjà écartée pour doxygen, asciidoctor et a2x. pacman mérite d'être nommé : c'est le gestionnaire de paquets, donc ses pages de manuel sont les premières qu'un utilisateur cherche. C'est la plus visible de ces coupes, et le meilleur argument pour les restaurer à l'étage 3. Assisted-by: Claude Opus 5
265 lines
13 KiB
Bash
Executable file
265 lines
13 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# systemd: four defaults Arch can hold and s390x cannot.
|
|
#
|
|
# 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.
|
|
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"
|
|
|
|
# 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)"
|
|
|
|
# 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)"
|