From 1175e2b5a978ba97ade07e6f5346f1564e9a5196 Mon Sep 17 00:00:00 2001 From: Douglas Teles Date: Wed, 24 Jun 2026 20:28:04 -0300 Subject: [PATCH] archr: symlink PortMaster compat libs into the default linker path PortMaster runtimes failed to launch: love_11.5's love.aarch64 died with "error while loading shared libraries: libtheoradec.so.1: cannot open shared object file" (caught live over SSH while a port was launched). Root cause: ArchR keeps the ~50 PortMaster compat libraries (older Debian-11-era SONAMEs: libtheoradec.so.1, libavcodec.so.58, libwebp.so.6, libx264.so.160, etc.) under /usr/lib/compat to stay out of the base system, and the image ships NO ld.so.cache. glibc's dynamic linker therefore only searches the hardcoded /usr/lib + /lib plus LD_LIBRARY_PATH, so /usr/lib/compat is invisible to anything that does not explicitly prepend it. control.txt does set LD_LIBRARY_PATH=/usr/lib/compat, but the per-runtime invocation overwrites it, dropping compat for binaries like love.aarch64. docs/PortMaster_CFW.md is explicit on the fix: "add these older .so symlinks alongside [the newer versions]" and "Keep [libtheoradec] at standard versions." So we expose the compat SONAMEs in the default path. New archr-compat-symlinks script + archr-compat-libs.service oneshot (ordered Before=archr-autostart so it runs before any port launches): walks /usr/lib/compat (and /usr/lib32/compat) and symlinks each SONAME into /usr/lib, but ONLY when the base system does not already provide that exact name, so real libraries (libogg.so.0, libvorbis.so.0, ...) are never shadowed. Idempotent via the `[ -e ]` guard; the writable ext4 rootfs keeps the links so later boots are no-ops. Verified live on the R36S: 46 compat-only SONAMEs linked into /usr/lib, libtheoradec.so.1 now resolvable, libogg.so.0 left untouched (still the real /usr/lib/libogg.so.0.8.6). --- projects/ArchR/packages/archr/package.mk | 6 +++ .../sources/scripts/archr-compat-symlinks | 45 +++++++++++++++++++ .../archr/system.d/archr-compat-libs.service | 15 +++++++ 3 files changed, 66 insertions(+) create mode 100644 projects/ArchR/packages/archr/sources/scripts/archr-compat-symlinks create mode 100644 projects/ArchR/packages/archr/system.d/archr-compat-libs.service diff --git a/projects/ArchR/packages/archr/package.mk b/projects/ArchR/packages/archr/package.mk index 07e8883453..0d603a0152 100644 --- a/projects/ArchR/packages/archr/package.mk +++ b/projects/ArchR/packages/archr/package.mk @@ -153,6 +153,12 @@ EOF ### Take a backup of the system configuration on shutdown enable_service save-sysconfig.service + ### Expose PortMaster compat libs (/usr/lib/compat) in the default + ### linker path. No ld.so.cache ships, so love_11.5 et al. fail on + ### libtheoradec.so.1 unless it is symlinked into /usr/lib (see + ### docs/PortMaster_CFW.md and the archr-compat-symlinks script). + enable_service archr-compat-libs.service + ### System locale. glibc/package.mk only generates en_US.UTF-8; without ### this file LANG stays empty and every shell falls back to POSIX, ### which breaks UTF-8 input, pacman messages and emulator menus. diff --git a/projects/ArchR/packages/archr/sources/scripts/archr-compat-symlinks b/projects/ArchR/packages/archr/sources/scripts/archr-compat-symlinks new file mode 100644 index 0000000000..f579c3cb1d --- /dev/null +++ b/projects/ArchR/packages/archr/sources/scripts/archr-compat-symlinks @@ -0,0 +1,45 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# archr-compat-symlinks: expose the PortMaster compat libraries +# (/usr/lib/compat/*.so*, the older Debian-11-era SONAMEs that ports and +# their runtimes link against) in the default linker search path. +# +# ArchR keeps these libs under /usr/lib/compat to stay out of the base +# system, but the image ships no ld.so.cache: the dynamic linker only +# searches the hardcoded /usr/lib + /lib plus LD_LIBRARY_PATH, so +# /usr/lib/compat is invisible to anything that does not explicitly +# prepend it. PortMaster runtimes such as love_11.5 link +# libtheoradec.so.1 as a normal system library and die with +# "cannot open shared object file: libtheoradec.so.1" when it lives only +# under compat. docs/PortMaster_CFW.md is explicit: "add these older .so +# symlinks alongside [the newer versions]" and "Keep [libtheoradec] at +# standard versions." +# +# We therefore symlink each compat lib into /usr/lib, but ONLY when the +# base system does not already provide that exact SONAME, so we never +# shadow a real system library (e.g. libogg.so.0, libvorbis.so.0). +# +# Idempotent: the `[ -e ]` guard skips anything already present, so it is +# safe to run every boot. The rootfs is writable ext4, so the links +# persist and later boots are no-ops. + +link_dir() { + local compat="$1" libdir="$2" n=0 f base + [ -d "${compat}" ] || return 0 + for f in "${compat}"/*.so*; do + [ -e "${f}" ] || continue + base="${f##*/}" + if [ ! -e "${libdir}/${base}" ]; then + ln -sf "compat/${base}" "${libdir}/${base}" && n=$((n + 1)) + fi + done + echo "${n}" +} + +created=$(link_dir /usr/lib/compat /usr/lib) +# armhf / 32-bit ports use the lib32 tree when present. +created32=$(link_dir /usr/lib32/compat /usr/lib32) + +echo "archr-compat-symlinks: linked ${created:-0} (lib) + ${created32:-0} (lib32) compat SONAMEs into the default path" +exit 0 diff --git a/projects/ArchR/packages/archr/system.d/archr-compat-libs.service b/projects/ArchR/packages/archr/system.d/archr-compat-libs.service new file mode 100644 index 0000000000..699c821e3e --- /dev/null +++ b/projects/ArchR/packages/archr/system.d/archr-compat-libs.service @@ -0,0 +1,15 @@ +[Unit] +Description=ArchR PortMaster compat library symlinks +# Ports are launched from EmulationStation, which archr-autostart.service +# brings up; ordering before it guarantees the compat SONAMEs are linked +# into /usr/lib before any port (or its runtime) can dlopen them. +Before=archr-autostart.service +After=systemd-tmpfiles-setup.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/archr-compat-symlinks +RemainAfterExit=yes + +[Install] +WantedBy=archr.target