From f41ae5a044db44e99bf404604129fc0e436afcf3 Mon Sep 17 00:00:00 2001 From: cheezwiz7899 Date: Thu, 2 Jul 2026 13:23:53 +1000 Subject: [PATCH] build(linux): fix packaging bugs, deps, and aarch64 regressions package-citron-linux.sh: - Guard patchelf with || true so readelf fallback is reachable under set -e - Check for zstd binary before tar --zstd, fail with a clear message if missing - Fix qt.conf Translations path to match actual AppDir layout (lib/qt6/translations) build-citron-linux.sh: - Split optional linux-tools packages out of the required apt install block - Add zstd CLI to all distro setup functions - Add libXext-devel to zypper X11 block (required by SDL2 CheckX11) - Always apply patchelf --force-rpath to ensure DT_RUNPATH is never left in place - Fix Qt translations find to drop hardcoded gcc_64, works for aarch64 now - Fail fast when CITRON_QT_PATH is empty rather than silently using system Qt --- AppImageBuilder/package-citron-linux.sh | 9 +++-- build-citron-linux.sh | 44 ++++++++++++++++--------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/AppImageBuilder/package-citron-linux.sh b/AppImageBuilder/package-citron-linux.sh index 52622e20c6..d1bbfc5d45 100644 --- a/AppImageBuilder/package-citron-linux.sh +++ b/AppImageBuilder/package-citron-linux.sh @@ -252,7 +252,7 @@ _appdir="${PWD}/AppDir" # section that encodes PT_INTERP, causing sharun -g to find no interpreter and # skip the copy. We do it here from the original install-root binary (never # touched by sed) so it is guaranteed present regardless of sharun -g's outcome. -_interp=$(patchelf --print-interpreter "${DESTDIR}/usr/bin/citron" 2>/dev/null) +_interp=$(patchelf --print-interpreter "${DESTDIR}/usr/bin/citron" 2>/dev/null || true) if [ -z "${_interp}" ]; then # patchelf fallback: parse readelf output _interp=$(readelf -l "${DESTDIR}/usr/bin/citron" 2>/dev/null \ @@ -342,7 +342,7 @@ Prefix = .. Plugins = lib Imports = lib/qt6/qml Qml2Imports = lib/qt6/qml -Translations = ../usr/share/qt6/translations +Translations = lib/qt6/translations QTCONF_EOF # Rename app in desktop file if building a devel/nightly AppImage @@ -383,6 +383,11 @@ mv -v ./*.AppImage.* "${OUTPATH}/" 2>/dev/null || true # (e.g. a CI artifact upload step) drags along every loose unpacked library a # second time alongside the AppImage that already contains them compressed. if [ -d ./AppDir ]; then + if ! command -v zstd >/dev/null 2>&1; then + printf 'ERROR: zstd is not installed — cannot produce %s.tar.zst\n' "${OUTNAME_BASE}" >&2 + printf 'Install zstd (e.g. apt-get install zstd) and re-run.\n' >&2 + exit 1 + fi tar -c --zstd -f "${OUTPATH}/${OUTNAME_BASE}.tar.zst" -C ./AppDir . rm -rf ./AppDir fi diff --git a/build-citron-linux.sh b/build-citron-linux.sh index 64f2fb0aab..d81450d975 100755 --- a/build-citron-linux.sh +++ b/build-citron-linux.sh @@ -382,10 +382,15 @@ _setup_apt() { glslang-tools \ patchelf \ lsb-release software-properties-common gnupg \ - libelf-dev libssl-dev libzstd-dev libudev-dev \ + libelf-dev libssl-dev libzstd-dev libudev-dev zstd \ libgl-dev libopengl-dev \ - libxkbcommon-dev \ - linux-tools-common linux-tools-generic 2>/dev/null || true + libxkbcommon-dev + # linux-tools-common/generic are best-effort: the versioned + # linux-tools-$(uname -r) package frequently doesn't exist on the runner's + # kernel and is intentionally optional. Keeping them in a separate call + # (not grouped with the mandatory packages above) ensures a missing + # perf/tools package never masks a failure in the required deps. + sudo apt-get install -y linux-tools-common linux-tools-generic 2>/dev/null || true sudo apt-get install -y "linux-tools-$(uname -r)" 2>/dev/null || true # NOTE: libgl-dev and libopengl-dev are MANDATORY even though citron is # Vulkan-only and never calls any OpenGL API at runtime. The aqt-downloaded @@ -497,7 +502,7 @@ _setup_pacman() { python python-pip curl wget \ nasm yasm perl \ autoconf automake make \ - glslang clang lld llvm \ + glslang clang lld llvm zstd \ patchelf perf 2>/dev/null || true # Hardware video acceleration for bundled FFmpeg (VAAPI / VDPAU) @@ -543,7 +548,7 @@ _setup_dnf() { nasm yasm perl \ autoconf automake make \ glslang clang lld patchelf \ - elfutils-libelf-devel openssl-devel libudev-devel \ + elfutils-libelf-devel openssl-devel libudev-devel zstd \ perf 2>/dev/null || true sudo dnf install -y "clang${CLANG_VERSION}" "llvm${CLANG_VERSION}" 2>/dev/null \ || warn "Versioned LLVM ${CLANG_VERSION} not in repos — using default clang." @@ -582,7 +587,7 @@ _setup_yum() { nasm yasm perl \ autoconf automake make \ clang lld patchelf \ - elfutils-libelf-devel openssl-devel libudev-devel \ + elfutils-libelf-devel openssl-devel libudev-devel zstd \ perf 2>/dev/null || true warn "yum/CentOS: LLVM ${CLANG_VERSION} may not be in repos. Check SCL or llvm.org." @@ -603,7 +608,7 @@ _setup_zypper() { nasm yasm perl \ autoconf automake make \ glslang clang lld llvm patchelf \ - libelf-devel libopenssl-devel libudev-devel \ + libelf-devel libopenssl-devel libudev-devel zstd \ perf 2>/dev/null || true # Hardware video acceleration for bundled FFmpeg (VAAPI / VDPAU) @@ -611,7 +616,8 @@ _setup_zypper() { libva-devel \ libdrm-devel \ libvdpau-devel \ - libX11-devel 2>/dev/null || warn "Hardware acceleration libraries unavailable — FFmpeg will be software-decode only" + libX11-devel \ + libXext-devel 2>/dev/null || warn "Hardware acceleration libraries unavailable — FFmpeg will be software-decode only" # Optional: bundled into the AppImage by package-citron-linux.sh if present. sudo zypper install -y --no-recommends gamemode 2>/dev/null || true @@ -631,7 +637,7 @@ _setup_emerge() { dev-build/autoconf dev-build/automake \ media-libs/glslang \ dev-util/patchelf \ - dev-libs/elfutils dev-libs/openssl sys-apps/util-linux 2>/dev/null || true + dev-libs/elfutils dev-libs/openssl sys-apps/util-linux app-arch/zstd 2>/dev/null || true # Optional: bundled into the AppImage by package-citron-linux.sh if present. sudo emerge --ask=n games-util/gamemode 2>/dev/null || true @@ -1057,11 +1063,16 @@ _patch_binary_rpaths() { # LD_LIBRARY_PATH. for bin in "citron" "citron-cmd" "citron-room"; do if [[ -f "${bin_dir}/${bin}" ]]; then - # We prepend the custom RPATH to any existing one + # Always re-apply --force-rpath to convert any DT_RUNPATH tag to + # DT_RPATH. Even when existing_rpath already contains our path, a + # DT_RUNPATH tag would still be searched AFTER LD_LIBRARY_PATH, + # letting a system Qt shadow the CPM-built one. --force-rpath + # ensures we always end up with DT_RPATH regardless of the linker's + # default tag choice. local existing_rpath; existing_rpath="$(patchelf --print-rpath "${bin_dir}/${bin}" 2>/dev/null || echo "")" - if [[ -z "${existing_rpath}" ]]; then - patchelf --force-rpath --set-rpath "${rpath}" "${bin_dir}/${bin}" - elif [[ "${existing_rpath}" != *"${rpath}"* ]]; then + if [[ -z "${existing_rpath}" ]] || [[ "${existing_rpath}" == *"${rpath}"* ]]; then + patchelf --force-rpath --set-rpath "${rpath}${existing_rpath:+:${existing_rpath}}" "${bin_dir}/${bin}" + else patchelf --force-rpath --set-rpath "${rpath}:${existing_rpath}" "${bin_dir}/${bin}" fi fi @@ -1181,8 +1192,8 @@ build_appimage_stage() { # directly from the aqt-downloaded Qt under CPM_SOURCE_CACHE/qt-bin # (see CMakeModules/qt_download.cmake) if present. local qt_translations - qt_translations="$(find "${CPM_SOURCE_CACHE}/qt-bin" -maxdepth 3 -type d \ - -path '*/gcc_64/translations' 2>/dev/null | head -1)" + qt_translations="$(find "${CPM_SOURCE_CACHE}/qt-bin" -maxdepth 4 -type d \ + -name 'translations' 2>/dev/null | head -1)" if [[ -n "${qt_translations}" ]]; then mkdir -p "${install_root}/usr/share/qt6" cp -r "${qt_translations}" "${install_root}/usr/share/qt6/translations" @@ -1217,6 +1228,9 @@ build_appimage_stage() { if [[ -f "${config_file}" ]]; then qt_path="$(grep -oP '(?<=export CITRON_QT_PATH=")[^"]+' "${config_file}" || true)" fi + if [[ -z "${qt_path}" ]]; then + error "CITRON_QT_PATH not found in ${config_file} — cannot package AppImage with correct Qt plugins. Ensure the build completed successfully and config.sh was written." + fi APP_VERSION="${version}" \ ARCH_SUFFIX="${arch_suffix}" \