From b067d5e7ae855edef7c132842ab58c1d9d928950 Mon Sep 17 00:00:00 2001 From: SRHTNIN Date: Tue, 13 Oct 2026 09:47:15 +0200 Subject: [PATCH] AppImage build script for older glibc Co-Authored-By: Claude Opus 5.5 --- Packaging/BuildAppImage.sh | 31 +++++++++++++++++++++++++++++++ Packaging/RestoreLibraryPath.py | 11 +++++++++++ SaraFem.spec | 5 +++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100755 Packaging/BuildAppImage.sh create mode 100644 Packaging/RestoreLibraryPath.py diff --git a/Packaging/BuildAppImage.sh b/Packaging/BuildAppImage.sh new file mode 100755 index 0000000..a00d421 --- /dev/null +++ b/Packaging/BuildAppImage.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Builds Packaging/appimage/SaraFem-x86_64.AppImage (where Install.sh expects +# it): a PyInstaller one-file build from SaraFem.spec, put into the AppDir +# next to it and wrapped by appimagetool. Needs podman and appimagetool on +# PATH. +set -euo pipefail +cd "$(dirname "$(readlink -f "$0")")/.." + +# PyInstaller runs in a manylinux_2_28 container (glibc 2.28) with uv's +# portable Python, not with Fedora's: PyInstaller bundles libpython, and +# Fedora's needs a newer glibc than many distros have ("GLIBC_ABI_GNU2_TLS +# not found"). The Python, venv and downloads are cached in build/Container. +mkdir -p build/Container +podman run --rm --security-opt label=disable -v "$PWD:/src" -w /src \ + -e UV_CACHE_DIR=/src/build/Container/cache -e UV_PYTHON_INSTALL_DIR=/src/build/Container/python \ + quay.io/pypa/manylinux_2_28_x86_64 bash -euo pipefail -c ' + uv venv --quiet --allow-existing --managed-python --python 3.14 build/Container/venv + uv pip install --quiet --python build/Container/venv -r requirements.txt pyinstaller + build/Container/venv/bin/pyinstaller --noconfirm --clean --log-level WARN \ + --distpath build/PyInstaller/dist --workpath build/PyInstaller/work \ + SaraFem.spec' + +AppDir=Packaging/appimage/AppDir +mkdir -p "$AppDir/usr/bin" +cp build/PyInstaller/dist/SaraFem "$AppDir/usr/bin/SaraFem" + +# Built under a temporary name, then renamed into place: the AppImage can't be +# overwritten while SaraFem is running from it ("Text file busy"). +ARCH=x86_64 appimagetool --no-appstream "$AppDir" Packaging/appimage/SaraFem-x86_64.AppImage.new +mv -f Packaging/appimage/SaraFem-x86_64.AppImage.new Packaging/appimage/SaraFem-x86_64.AppImage +echo "Built Packaging/appimage/SaraFem-x86_64.AppImage" diff --git a/Packaging/RestoreLibraryPath.py b/Packaging/RestoreLibraryPath.py new file mode 100644 index 0000000..446798a --- /dev/null +++ b/Packaging/RestoreLibraryPath.py @@ -0,0 +1,11 @@ +# PyInstaller runtime hook. The frozen app runs with LD_LIBRARY_PATH pointing +# at its bundled libraries, and programs it starts inherit that: Flet's +# desktop client then loads the bundled (older) libstdc++ instead of the +# system's and won't start ("GLIBCXX_3.4.29 not found"). Give them the +# original value back; the app itself has already loaded what it needs. +import os + +if "LD_LIBRARY_PATH_ORIG" in os.environ: + os.environ["LD_LIBRARY_PATH"] = os.environ["LD_LIBRARY_PATH_ORIG"] +else: + os.environ.pop("LD_LIBRARY_PATH", None) diff --git a/SaraFem.spec b/SaraFem.spec index 40a3a9b..42cb083 100644 --- a/SaraFem.spec +++ b/SaraFem.spec @@ -1,15 +1,16 @@ # -*- mode: python ; coding: utf-8 -*- +from PyInstaller.utils.hooks import collect_data_files a = Analysis( ['Main.py'], pathex=[], binaries=[], - datas=[('assets', 'assets')], + datas=[('assets', 'assets')] + collect_data_files('flet'), # without Flet's, ft.Icons crashes when frozen hiddenimports=[], hookspath=[], hooksconfig={}, - runtime_hooks=[], + runtime_hooks=['Packaging/RestoreLibraryPath.py'], excludes=[], noarchive=False, optimize=0,