Cross-package tooling notes
A single generic pacman.conf doesn’t cover both x86_64 and the 32-bit arches – the
[core]/[extra]mirrorlist differs, not just$archinside it. Built 2026-08-13, wiringarchlinuxaba-<arch>-buildup for i486/i686/pentium4 (previously x86_64-only, seememory/REPO_PUBLISH_DESIGN.md). The existingarch/config/pacman.conf.d/archlinuxaba.confis a copy of devtools’ genericextra.conf:Architecture = auto,Include = /etc/pacman.d/mirrorlist(the plain 64-bit Arch mirror). Assumed this would “just work” for every arch since pacman substitutes$archinServer =lines at read time – wrong assumption: devtools32 ships separateextra-i486.conf/extra-i686.conf/extra-pentium4.conffiles (/usr/share/devtools/pacman.conf.d/) with an explicitArchitecture = <arch>and, critically,Include = /etc/pacman.d/mirrorlist32(mirror.archlinux32.org) instead – 32-bit packages live on an entirely different mirror network, not just a different$archsubdirectory of the same one. Buildingarchlinuxaba-i486-buildetc. with the generic config failed immediately at fresh chroot creation (error: failed retrieving file 'core.db'– 404 against the 64-bit mirror, which has no i486/i686/pentium4 trees at all). Fix: addedarchlinuxaba-i486.conf/archlinuxaba-i686.conf/archlinuxaba-pentium4.conf, each the corresponding stockextra-<arch>.confwith our[archlinuxaba]section spliced in ahead of[core](same pattern as the originalarchlinuxaba.confvs.extra.conf).archlinuxaba-archbuild’s existing per-arch config resolution (prefers${repo}-${arch}.confover${repo}.conf, see the script’s own header comment) picked these up with no code change. Lesson for wiring up any new arch here in the future: check whether devtools ships an arch-specific base config before assuming the generic one is arch-agnostic – it usually isn’t for anything outside the “one real mirror network” x86_64 case.A build/publish/rebuild cycle for the same pkgver-pkgrel within one session can poison the local pacman package cache for the next build. Same 2026-08-13 session: rebuilt+republished
libstroke0.5.1-11 twice in a row while iterating on the fix above (each build gets a freshSOURCE_DATE_EPOCH, so the two builds are not byte-identical even though the version string is). A laterfvwmx86_64 build then failed installinglibstrokeas a dependency –pacman: “file … is corrupted (invalid or corrupted package (checksum))” – because a stale copy from the first libstroke build was sitting in the build chroot’s package cache and no longer matched the checksum of what got published second. Not specific to archlinuxaba/fvwm/libstroke; any same-version rebuild-and-republish during a single working session can leave this trap for the next package that depends on it. Fix is just a bare retry of the affected arch (the stale cache entry doesn’t survive a fresh chroot sync) – no need to hunt down and manually clear the cache file.A report script that only prints “what’s new since last run” must never be invoked with
>truncation, and ideally shouldn’t let the caller choose. Built 2026-07-22 (scripts/check_aur_feedback.sh): first run redirected with> ../FEEDBACK.txt, correctly printed all 429 then-current AUR comments across every maintained package. Second run (after fixing an unrelated pkgname-resolution bug) was invoked the same way,>again — its own dedup logic correctly suppressed re-printing the 396 comments already marked “seen” from run 1, which is exactly what dedup is supposed to do, but since>truncated the file first and nothing else on disk held a copy of run 1’s text, that entire history was gone with no way to reconstruct it (the comments still exist on AUR, but re-fetching them would just re-trigger the same dedup and print nothing). Any script with this “print only the diff since last time” shape needs the report file itself to be append-only across runs, not just the in-memory dedup state – otherwise dedup working correctly is exactly what destroys the history. Fix applied: the script now takes the output path itself (default../FEEDBACK.txt) and appends a dated## <timestamp>section internally, skipping the write entirely if there’s nothing new to report – there is no>-redirect invocation path left for a caller to get wrong.AUR RPC maintainer checks must include co-maintainers, not just primary maintainer.
scripts/compare_packages.shqueriesrpc/v5/search/<user>?by=maintainer, which only returns packages where<user>is the primary maintainer — packages held as co-maintainer are silently excluded, and show up as false “local dir not on AUR” diffs. Confirmed 2026-07-20:nagircbot,pacman-static, andtrojitaall looked like AUR-maintainer mismatches from theby=maintainersearch alone, butby=comaintainers(same endpoint, differentbyvalue) showed all three are legitimately co-maintained by this account (primary maintainers are other people) — not orphan or drift situations at all. Any future “is this package actually ours on AUR” check needs bothby=maintainerandby=comaintainersunioned before concluding something’s missing/mismatched.rpc/v5/info/<pkgname>also exposes this per-package via theCoMaintainersarray field (absent entirely if there are none).Dependency-resolution checks need
pacman -Si+ a real Provides scan, notpacman -T. Built 2026-07-26 (scripts/check_dependencies.sh, after findingmaintained/lxappearance-obconf-gtk3depended onlxappearance-gtk3, which never existed anywhere – seememory/lxappearance-obconf-gtk3.md). Three separate bugs surfaced while building the checker, in order:pacman -T(deptest) only checks installed packages, not the sync databases –dkms(real package in[extra], just not installed on this build host) came back “unsatisfied” even thoughpacman -Si dkmsfinds it immediately. Use-Sifor an install-state-independent existence check.pacman -Sialone still doesn’t seeProvides– virtual/group deps (sh,pkgconfig,java-runtime,ttf-font,initramfs,fuse,atk) and soname deps (libobrender.so, fromopenbox) are essentially never named after the package that actually provides them, so a plain-Silookup flagged nearly all of them as broken. There’s nopacman -S*query that does a provides-only lookup without an actual transaction; the fix wastar -xOfon every configured repo’s sync db (pacman-conf --repo-list,$(pacman-conf DBPath)sync/<repo>.db) parsed for raw%PROVIDES%fields directly.commneedsLC_ALL=Cto match aLC_ALL=C sort-ed input – this host’s locale isen_US.UTF-8, and a locale-defaultcommagainst C-locale-sorted files silently mis-diffs (“input is not in sorted order” printed to stderr, but the command still exits 0 and produces wrong output that looks plausible). Net effect for any future resolution primitive: verify it against both a known-installed-and-real name and a known-not-installed-but- real name before trusting its output, and assumeProvidesneeds handling explicitly – pacman’s own name-lookup commands don’t do it for you outside a real transaction. As of 2026-07-26 (right after the lxappearance-obconf-gtk3 fix), a full run across all 544 unique dependency entries in arch/ resolves cleanly – 0 BROKEN.
Policy notes, split out since they apply broadly rather than to one package:
HOST_INSTALL_POLICY.md(never install packages on this host to fix a build — chroots exist for that; GPG key imports for source verification are the one exception),PKGREL_VS_PKGVER.md(packaging- only fixes bumppkgrel, notpkgver),ARCHIVE_APPEND_ONLY.md(never remove/move anything out of the private repo’sarchive/dir).This machine can currently only build packages for x86_64, pentium4, i686, and i486 — it has local
extra-<arch>-buildarchbuild chroots for exactly these four. Any other arch that shows up in a PKGBUILD’sarch=()— notably aarch64, arm, armv6h, armv7h, riscv64 — cannot be built here yet; that would need either QEMU user-mode emulation (to run a foreign-arch chroot on this x86_64 host) or SSH access to a real build machine of that architecture, neither of which is set up. Therepo_build.shscript (seeREPO_PUBLISH_DESIGN.md) already treats this as expected: it skips and reports any arch with no localextra-<arch>-buildinstead of failing the whole build.Some existing PKGBUILDs contain pre-existing invalid-UTF-8 byte sequences in comments (e.g. libarchive-static’s
# Tomáš Mrázmaintainer-key comment, which is already mojibake’d to a raw Latin-1 0xE1 byte in git history). My Edit tool and any full-file rewrite (Perl scripts likeupdpkgsums,makepkg --printsrcinfo, etc.) treat the file as UTF-8 text and silently replace such invalid bytes with U+FFFD on save, corrupting them further even in lines I didn’t intend to touch.- After editing a PKGBUILD, diff the full file content against the last
git revision (
git -C <pkg> show HEAD:PKGBUILD) to catch unintended byte-level drift outside the lines you meant to change, not just the lines you meant to change. - Use
LC_ALL=C grep -a/ byte-level tools when inspecting such lines; UTF-8-locale grep can silently fail to match corrupted byte sequences.
- After editing a PKGBUILD, diff the full file content against the last
git revision (
archbuildscripts (extra-<arch>-build) pass args after--straight into their internalmakechrootpkg_argsarray without inserting a separator — so to get args through tomakepkginside the chroot you need a double--:sudo extra-i686-build -- -- --nobuild --skippgpcheck. A single--makesmakechrootpkgitself choke on the makepkg flags (“illegal option – -”).--nobuildis the cheap way to run justprepare()(extract + patch + any config/version reconciliation) inside a chroot without doing the full compile — much faster than a full build when you only need to check/update generated files like kernel configs.- The chroot’s working-copy build tree lives at
/var/lib/archbuild/<repo>-<arch>/<local-copy-user>/build/<pkgname>/src/...(default local-copy name is your own username) — files placed there byprepare()(e.g. a reconciled.config) can besudo cp’d back out andchown’d to your user. namcapinside these chroots is broken (ImportError: libalpm.so.14: cannot open shared object file) andcheckpkgalways says “target not found” since there’s no local repo — both are known-harmless environment issues, not build failures.
Intra-tree dependency ordering — fixed 2026-07-07 for x86_64.
extra-<arch>-buildchroots resolvedepends/makedependsonly against the official Arch mirrors (whateverpacman.confin the chroot points at) — never against other packages built earlier in the samerepo_release_all.shrun, and never in build-order at all (packages are processed in plain alphabetical order). Any package here whosedepends/makedependsnames another custom package from this tree (not an official Arch package — e.g. the Qt5/KDE5 rebuild stack, orarduino-builderneedingarduino-ctags) used to fail witherror: target not found: <pkg>regardless of run order. Seememory/kdstatemachineeditor.mdfor the original diagnosis.- Fix:
scripts/archlinuxaba-archbuild(symlinked asscripts/archlinuxaba-x86_64-build) is a copy of the system/usr/bin/archbuild(devtools32), changed in exactly one place: it resolvespacman_configfrom this project’s ownarch/config/pacman.conf.d/first (falling back to the system location), andarch/config/pacman.conf.d/archlinuxaba.confis a copy of the stockextra.confwith our own private repo (archlinuxaba,SigLevel = Optional TrustAll) added ahead of[core]/[extra]. This mirrors devtools32’s own*-with-build-supportconfig pattern (bootstrap/staging repos layered on top of the base config the same way). It uses its own separate chroot (/var/lib/archbuild/archlinuxaba-x86_64), so the stockextra-x86_64chroot is untouched. Never modifies anything under/usr— everything new lives underarch/. repo_build.shnow resolves the build command per-arch via a_build_cmdhelper:archlinuxaba-x86_64-buildfor x86_64, plainextra-<arch>-buildfor everything else (only x86_64 is wired up so far, per explicit scope).- Verified against a real case:
arduino-builderneedsarduino-ctags(a package in this tree, already published) — failed under plainextra-x86_64-build, succeeded underarchlinuxaba-x86_64-buildonce retried. - Caveat: this only helps once a dependency has actually been
built+published before the package that needs it is attempted —
repo_release_all.shstill processes the tree in plain alphabetical order with no dependency-graph awareness, so a package needing an alphabetically-*later* custom dependency will still fail on a single top-to-bottom pass and needs a manual retry afterward (seememory/gcc-ia16.md,memory/fvwm.mdfor pending examples).
- Fix:
This build box’s GPG keyring is missing some upstream signing keys referenced by
validpgpkeysin various PKGBUILDs, causing--skippgpcheck-less real builds (asrepo_build.shdoes, unlikebuild_all_archs.sh’s own test-build convenience flag) to fail source verification withunknown public key <ID>regardless of anything about the package’s own PKGBUILD/source correctness. First seen 2026-07-07 for key95FA6F43E21188C4acrossmaintained/arduinoandmaintained/arduino-builder. Unlike installing a package on the host (never do that — seememory/feedback_no_host_installs.md’s original, narrower rule), importing a signing key needed purely for source verification is a normal, expected part of doing the build and is fine to do on the host:gpg --recv-keys <ID>(fromhkps://keys.openpgp.orgorkeyserver.ubuntu.comif the PKGBUILD doesn’t specify one). Done for95FA6F43E21188C4on 2026-07-07 — both packages should be retried.A third missing-dependency class, distinct from environment drift and intra-tree ordering: real AUR-only dependencies this tree doesn’t maintain at all (e.g.
dbmodel-qt4needingqt4,adtpro-git/p2c- style needingcc65/gcc14). Unlike the KDE5/Qt5 stack (custom packages that live in this tree, just not resolvable mid-run — fixed byarchlinuxaba-x86_64-build, see above), these depend on packages that were never part ofarch/maintained/private/adapted/ownedin the first place. Building them would mean also building/vendoring a package this tree doesn’t own. Per the user (2026-07-07): note these and move on, don’t try to resolve them now — revisit once there’s an actual plan for out-of-tree AUR dependencies.CMake in this build environment refuses
cmake_minimum_requiredversions below 3.5 (Compatibility with CMake < 3.5 has been removed from CMake.), which will hit any older/unmaintained CMake-based package whoseCMakeLists.txtstill declares an ancient minimum version. First seen 2026-07-07 onkdiagram5(seememory/kdiagram5.md). CMake’s own suggested workaround is-DCMAKE_POLICY_VERSION_MINIMUM=3.5passed to thecmakeinvocation in the PKGBUILD’sbuild()— not applied yet to any package as part of this pass; expect this to recur across other older CMake-based packages in the tree.Modern GCC’s default warnings-as-errors trip older/unmaintained C/C++ sources on genuinely harmless issues like an unused-but-set variable (
error: variable 'X' set but not used [-Werror=unused-but-set-variable=]). Seen 2026-07-07 onmodest(memory/modest.md) andnewsboat-og(memory/newsboat-og.md). Not fixed for either; would need a source fix or relaxing that specific-Werrorin the PKGBUILD’s CFLAGS. Expect this to recur on other old C/C++ packages in the tree.Long-running builds (e.g. kernel compiles via
archbuild) started as a plain backgrounded Bash tool call die with the session (SIGHUP) if the session is closed early. To survive session termination, launch them in a detachedscreensession instead:screen -dmS <name> bash <script>.sh(or-e^Xyfor a custom escape sequence). Check on it later withscreen -r <name>or by tailing the chroot’s own build log at/var/lib/archbuild/<repo>-<arch>/<user>/logdest/<pkg>-<ver>-<arch>-build.log.Danger: manually replicating
repo_build.sh’s git-status-driven post-build cleanup (git status --porcelain -- .→rm -rfevery??entry not matching*.pkg.tar.*/.sig) can delete a brand-new source file you just added, not just real build byproducts. That cleanup’s own assumption is “an untracked file after a successful build is either a release artifact or something makepkg generated” — true when running it via the real pipeline on an already-committed package tree, but this project’s own standing rule is nevergit commit(seeCLAUDE.md). So a genuinely new file you add to amaintained/package (a new local patch, a new config) — something you fully intend to keep — will always show as??untracked, indistinguishable from a downloaded tarball or a.logfile, for as long as this session lives. Hit this for real 2026-07-16 onakonadi-notes: a newly-writtenakonadi-notes-24.08.3-kmime-26.04-api.patchgot deleted by exactly this cleanup snippet run by hand right after a successful publish. Recovered only because a scratch copy of the diff still existed to regenerate it from.- How to apply: before running (or hand-replicating) this cleanup
after a build, check
git status --porcelain -- .yourself first and make sure every??entry it’s about to remove is something you actually expect to be disposable (a downloaded source tarball, a*.logfile, a VCS clone dir) — not a patch/config file you just added as the actual fix. When in doubt, copy the new file somewhere safe (or note its content) before letting any cleanup step run near it. - Confirmed 2026-07-31 that this isn’t just a manual-replication
risk — the real, automated
repo_release.sh→repo_build.shpipeline does this too, every time, to every new uncommitted patch file. Onkdiagram5: wrotekdiagram-2.8.0-ecm-project-version.patch, wired it intoprepare(), ran the normalrepo_release.sh maintained/kdiagram5(not a hand-replicated cleanup), build succeeded, and the patch (plus the unrelated pre-existingPKGBUILD~backup) was silentlyrm -rf’d by this exact cleanup step since neither was git-tracked. Recovered only because the patch content was still in this session’s own context to rewrite verbatim (checksum matched, confirming an exact recreation) — a fresh session with no memory of the patch’s content would have lost it for good. Since this project’s assistant never runsgit commit(seeCLAUDE.md), every single new patch file written in any session is on a countdown to deletion the moment the next successfulrepo_release.sh/repo_build.shrun touches that package directory — there is no “safe” window. Until/unless this cleanup step gets a*.patchexception (not done as of this note — would need explicit user sign-off, since a stray downloaded.patchsource file some PKGBUILDs also legitimately fetch viasource=()complicates a blanket exclusion), treat any newly-written patch as needing the user togit commitit (or add it to.gitignore’s inverse / otherwise mark it tracked) before the first build, not after.
- How to apply: before running (or hand-replicating) this cleanup
after a build, check
repo_publish.sh’s filename-derived arch/pkgname parsing had no validation, and it silently corrupted the remote repo layout twice. Found 2026-07-26 while investigating a user-reported bogus directoryos/x86_64pkg.tar.zst/on the repo host. Root cause:_pkg_arch()/_pkg_name()stripped an expected.pkg.tar.<ext>suffix and then took “whatever’s after the last-” as arch/pkgname, with no check that the strip actually matched anything. Two real incidents from this: (1)m68k-elf-gcc, built via a separate ad-hoc/data/INSTALL/-based flow (not this repo’sarch/tree) with a misconfiguredPKGEXTmissing its leading dot, produced...x86_64pkg.tar.zst– the unguarded strip left it untouched, and${_base##*-}grabbed the wholex86_64pkg.tar.zsttail as “arch”, publishing into a bogus top-level dir with its own orphanedrepo-adddatabase. (2)zoom, built by a separate concurrent session, produced a filename missing its-<pkgrel>-segment (zoom-7.1.5.4332_orig_x86_64.pkg.tar.xz), so the only hyphen left after the (successful, this time) extension strip put7.1.5.4332_orig_x86_64in as “arch”. Both bogus dirs sat unnoticed on the repo host for over a week (m68k-elf-gcc: 2026-07-16 to 2026-07-26; zoom: 2026-07-22 to 2026-07-26) since nothing about publishing failed loudly –mkdir -p/repo-addhappily created a whole new “repo” at the bogus path. Fixed:_pkg_stripped_base()now aborts (non-zero exit,ERROR:to stderr) if the.pkg.tar.*strip didn’t change anything, and_pkg_arch()additionally rejects any result containing a.(real arch names never have one; both incidents above did). Both stale directories were removed from the repo host after confirming a correct copy of m68k-elf-gcc already existed inos/x86_64/(zoom had no other copy – removing its bogus dir removed the package from the repo entirely, done with explicit user confirmation). Lesson for any future filename-parsing helper: validate that an expected-pattern strip actually matched before trusting what’s left over, don’t just chain more stripping operations on a possibly-untouched string.archive/reorganized to be per-arch, 2026-07-26. Was previously one flat directory shared across all archs (deliberate original design – filenames embed pkgver+arch so they can’t collide there either way). User asked for it to mirroros/’s per-arch layout instead._archive_old()inrepo_publish.shalready received the package’s arch as_pkgarch; changed it to create/move into${ARCHIVE_DIR}/${_pkgarch}/instead of flat${ARCHIVE_DIR}/. The existing 73 files were migrated in place on the repo host with a one-off script that reused the same_pkg_arch()parsing logic (not a second implementation) to classify each file, thenmkdir -p+mvper arch – verified file count (73) and total byte size (830534379) matched exactly before and after, nothing lost. Result:archive/{any,i686,pentium4,x86_64}/.**Routine per-package publishes go through
repo_diff_local_remote.shrepo_release_changed.sh, not a hand-chainedextra-x86_64-build->repo_sign.sh->repo_publish.shsequence – even for just one or two UPD-flagged packages.** Went off this rail 2026-07-27 while updatingi686-elf-binutils/x86_64-elf-binutils(2.45/2.46.0 -> 2.47): after editing both PKGBUILDs, ranextra-x86_64-builddirectly to test-build, thenrepo_sign.shandrepo_publish.shby hand for each. That produced a correct result (both published fine, verified against the remote repo and site afterward), but skipped the actual sanctioned tooling:repo_diff_local_remote.shwould have confirmed both read as CHANGED once the PKGBUILDs were bumped, andrepo_release_changed.shbuilds+signs+publishes exactly that detected set (also handles the “already up to date, skip” and multi-package cases uniformly, and keeps theREPO_BUILD_ONLY_ARCHconvention and per-package logfiles underrepo_release_logs/consistent with every other routine cycle).repo_release.sh <pkgdir>(single-package build->sign->publish) is the right manual escape hatch when a package needs individual attention outside the diff-driven flow (e.g. re-testing after a build fix) – reaching for the three lower-level scripts directly should be rarer still, reserved for cases where evenrepo_release.sh’s ordering doesn’t fit (e.g. republishing an already-built artifact without rebuilding it).
Recovering an in-place build into the
/data/INSTALLstaging layout, after building directly insidearch/<category>/<pkgname>by mistake (e.g. viabuild_all_archs.shrun there instead ofrepo_release.sh/repo_build_staged.shfrom the start – don’t do this; see the entry above and the “build staged by default” habit note). If the build already ran and especially if it was expensive (a kernel compile across 4 archs, hours of chroot time), don’t throw the work away and restart staged – migrate the result into the layoutrepo_build_staged.shwould have produced:- If
/data/INSTALL/<pkgname>already exists (a previous release’s staged build), move it aside first – never overwrite/delete it. Follow the existing rotation convention already in use forlinux-lts510(-old,-older,-oldestas each new one bumps the previous aside):mv /data/INSTALL/<pkgname> /data/INSTALL/<pkgname>-old(or-older/-oldestif-oldis already taken). rsync -a --exclude=.git -- arch/<category>/<pkgname>/ /data/INSTALL/<pkgname>/– same invocationrepo_build_staged.shitself uses, just run after the build instead of before. This carries the tracked PKGBUILD/patches/etc and the untracked build byproducts (downloaded sources, produced*.pkg.tar.*, logs) into the staged location together in one shot.git clean -fdinsidearch/<category>/<pkgname>to drop every untracked byproduct from the tracked tree, restoring it to exactly the pre-build state (verify withgit status --short– must be empty). This is the actual goal of staging:arch/never carries build output.- Sign + publish from the
/data/INSTALL/<pkgname>copy directly (repo_sign.sh/repo_publish.shthere) rather than copying package files back intoarch/first – no need, they’re not needed there. - Leave everything else in
/data/INSTALL/<pkgname>as-is afterward (downloaded tarball, per-arch build/package/namcap logs, the package files themselves) – don’t try to replicaterepo_build.sh’s own post-build cleanup (which deletes everything untracked except the release artifacts) by hand here. That cleanup is driven bygit status --porcelaininsidebuild_dir, butrsync --exclude=.gitmeans these staged copies have no working.git(confirmed against the existinglinux-lts515-oldstaged dir:git statusthere fails with “fatal: not a git repository”), sorepo_build.shitself silently skips that cleanup step too when running the normal way – leaving the full build state in/data/INSTALL/<pkgname>permanently is the actual established behavior, not an oversight to fix. First done 2026-08-21 forlinux-lts5155.15.216 (see its own memory file for the specific run) – generalize this same five-step recovery to any other package caught mid-build in place.
- If