Python Programm als AppImage deployen

  Prof.P   Lesezeit: 18 Minuten  🗪 1 Kommentar

Anhand des Programms "YouPlay" wird exemplarisch gezeigt wie ein AppImage auf GNU/Linux Distributionen erstellt werden kann.

python programm als appimage deployen

Wenn es darum geht als Entwickler sein fertiges Python-Programm zu verteilen, gibt es viele Möglichkeiten (PIP-Paket, natives Paketformat, git download, git clone, Binaries, Flatpak, Snap ...) In diesem Artikel soll anhand des Beispiels des Python-Programms "YouPlay" von Ralf Hersel gezeigt werden, wie der Python Code als AppImage ausgeliefert werden kann.

Disclaimer: YouPlay hat "harte" Abhängigkeiten von externen Programmen wie "yt-dlp", "ffmpeg" und "mpv". Außerdem werden auf Nicht-GNOME-Desktop-Umgebungen die runtimes "gtk4" und "libadwaita" für den GUI-part benötigt. Die Integration dieser Abhängigkeiten sind nicht Bestandteil dieses Artikels, sondern nur die Erstellung des YouPlay-Programms an sich als AppImage.

AppImage ist ein System zur einfachen Nutzung von Software auf GNU/Linux-Umgebungen. Es stellt eine distributionsübergreifende Alternative zu den zentral verwalteten Paketmanagersystemen der jeweiligen Linux-Distribution dar. AppImages kommen ohne Installation auf dem System aus, da sie alle verwendeten Programmbibliotheken mitführen und laufen in der Regel auf allen gängigen Desktop-Distributionen wie Ubuntu, openSUSE, Fedora, Debian, Arch Linux oder Red Hat Linux. Für jede Anwendung wird nur eine einzige Datei (meistens mit der Endung .AppImage) benötigt. Da sie nicht im klassischen Sinne installiert werden, wird am Zielsystem auch keinerlei Änderung vorgenommen (z.B. systeminterne Bibliotheken überschrieben etc.)

Das Nutzen von AppImages erfordert keine root-Rechte. Es reicht aus, die entsprechende Datei ausführbar zu machen und zu starten. Es ist zum Transport auch praktisch, da nur eine Datei, die AppImage-Datei an sich zu kopieren ist.

AppImages werden beim Starten des Programm zur Laufzeit vom System selbständig extrahiert und ausgeführt - für die Benutzer:In ist dies ein intransparenter Prozess, der die Ausführungsgeschwindigkeit nur minimal, kaum merkbar verzögert.

AppImages lassen sich prinzipiell auch manuell extrahieren, falls der Entwickler dies beim Build Prozess berücksichtigt, respektive freigeschaltet hat.

Vorgehensweise

Um sein Python Programm als AppImage zu verteilen gibt es im Prinzip zwei Möglichkeiten:

a.) Einen vorhandenen, offiziellen Python-AppImage Container zu verwenden und seinen eigenen Code zu integrieren - der Code wird dann vom Python Compiler im AppImage-Container zur Laufzeit interpretiert (Bsp. YouPlay-AppImage ca. 32 MB)

b.) Den Python Code vorher als Binary erstellen und diese als eigenständiges AppImages zu erstellen - in dem Fall wird gar kein Python mehr im AppImage benötigt.

Nachteil bei dieser Option im Vgl. zu a.): man muss erst mal das Binary mit Hilfe von externen Tools erstellen (z.B. PyInstaller), es ist also ein zusätzlicher build-Prozess notwendig und das AppImage wird wesentlicher grösser sein, da alle Abhängigkeiten ebenfalls als Binaries inkludiert sind (Bsp. YouPlay-bin-AppImage ca. 160 MB)

Vorteil könnte eine gewisse Obskurität sein wenn man das so sehen will, da der Quellcode an sich nicht mehr lesbar ist, falls sich jemand die Mühe machen sollte das AppImage zu extrahieren. (Dieses ist aber nur eine trügerische Sicherheit, da der Python Binärcode wohl mit recht einfachen Mitteln wieder de-kompilierbar ist).

In beiden Fällen wird das Tool AppImageKit zum erstellen des AppImages verwendet, welches unter der MIT Lizenz steht.

In diesem Artikel verwenden wir Option a.)

Voraussetzungen für das System, auf dem das AppImage erstellt werden soll

  • YouPlay ist aktuell und ausführbar (quasi python3 youplay.py läuft), siehe Manual Installation
  • Der Python Paketmanager PIP ist installiert
  • Auf non-GNOME Desktop Environments werden zusätzlich die Pakete gtk4und libadwaita gebraucht.

Manuelle Anleitung in 9 Schritten

  1. Python AppImage herunterladen und ausführbar machen

(Ich empfehle das Python 3.10 Image, da dies, Stand heute, noch recht aktuell ist und etwas kleiner als das Python 3.11 Image.)

Als Ort bietet sich ein Verzeichnis an, aus welchem bequem per Eintrag in der $PATH Umgebungsvariablen zugegriffen werden kann, z.B. ~\local\.bin

  1. AppImageKit herunterladen und ausführbar machen (analog zum 1. Schritt nach~\.local\bin oder ähnliches)

Es gibt Releases pro Architektur; in unserem Fall bietet sich die 64bit Version an.

  1. Python AppImage extrahieren

Das zuvor geholte Python AppImage per CLI extrahieren -> erzeugt Verzeichnisstruktur "squashfs-root" im Dateisystem; diese nach "AppDir" umbenennen (=Standard Name beim AppImage Format)

In der Shell in das youplay Verzeichnis (siehe Voraussetzungen) wechseln

    cd youplay

Die nachfolgenden Schritte können nun alle aus dem youplay Verzeichnis heraus durchgeführt werden.

    python3.10.11-cp310-cp310-manylinux_2_28_x86_64.AppImage --appimage-extract
    mv squashfs-root AppDir
  1. Aus dem Python AppImage nicht mehr benötigte Dateien entfernen

    rm AppDir/python*
  2. YouPlay in die "AppDir"-Struktur kopieren

    cp youplay.py AppDir/
    cp youplay.svg AppDir/
    cp youplay.desktop AppDir/
  3. Von YouPlay benötigte PIP-Pakete ins AppImage installieren

Die notwendigen PIP-Pakete werden direkt in das Dateisystem von "AppDir" installiert. Dazu wird eine alternative site-packages Lokation mittels Schalter target verwendet:

    mkdir AppDir/packages
    AppDir/opt/python3.10/bin/python3.10 -m pip install -r requirements.txt --target=AppDir/packages
  1. Anpassen der Datei "AppDir/AppRun"

Nun muss das interne launcher-Script "AppRun" auf unsere Bedürfnisse angepasst werden. Wir starten darin Python und übergeben den Namen des Python Programms als ersten Übergabeparameter und hängen weitere Übergabeparameter hinten dran. Dazu folgende Datei in dem Verzeichnis "AppDir" in dem Editor der Wahl modifizieren; z.B. für den CLI-Editor in der shell via

    "${EDITOR:-vi}" AppDir/AppRun

oder analog für den Aufruf des voreingestellten GUI-Editors:

    xdg-open AppDir/AppRun

Dazu genügt es die letzte Zeile auszukommentieren, die bisher nur Python startet und unser Programm zusätzlich an den Python-Interpreter zu übergeben. Da AppImages meistens im GUI Kontext verwendet werden, starten wir YouPlay entsprechend mit dem youplay-spezifischen Schalter gui. Da wir die benötigten Python-Pakete zuvor in eine alternative site-packages Lokation installiert haben müssen wir entsprechend die Umgebungsvariable PYTHONPATH setzen um dies mitzuteilen:

    [...]
    # "$APPDIR/opt/python3.10/bin/python3.10" "$@"  

    export PYTHONPATH="${APPDIR}/packages"
    cd $APPDIR
    "$APPDIR/opt/python3.10/bin/python3.10" "youplay.py" "--gui"

Falls wir die youplay-spezifischen Kommandozeilenparamater erhalten wollen, können wir das Ganze etwas komplexer gestalten; falls kein Schalter verwendet wird, starte immer im GUI Modus, anonsten gebe den Schalten entsprechend weiter:

    [...]
    # "$APPDIR/opt/python3.10/bin/python3.10" "$@"

    export PYTHONPATH="${APPDIR}/packages"
    cd $APPDIR

    if [ -z "$@" ]
    then # if no command line argument was passed, assume GUI mode
          "$APPDIR/opt/python3.10/bin/python3.10" "youplay.py" "--gui"
    else # launch youplay with command line args
          "$APPDIR/opt/python3.10/bin/python3.10" "youplay.py" "$@"
    fi

Da das AppImage System beim späteren Ausführen eben dieses launcher script "AppRun" aufruft, können (und sollten) wir das korrekte Ausführen nun Testen in dem wir manuell starten:

    ./AppDir/AppRun

Eventuelle Fehler, wie fehlende Dateien, sollten nun korrigiert werden, bis AppRun problemlos ausgeführt werden kann. Das Ergebnis sollte nun in etwa so aussehen:

  1. Anpassungen an der Datei "AppDir/youplay.desktop"

Das AppImageToolkit besteht auf eine vorhandene Desktop-Datei. Hieraus wird die Information über das zu verwendete Icon bei der Erstellung ausgelesen, daher muss diese entsprechend angepasst werden. Dazu die Datei youplay.desktop in dem Verzeichnis "AppDir" in dem Editor der Wahl modifizieren. Bei "Icon" einfach nur den Dateinamen ohne Pfad und Extension verwenden.

    [...]
    Icon=youplay
    [...]
  1. AppImage mit Hilfe des AppImageTool erstellen

Nun ist der große Moment gekommen auf den die vorherigen Schritte hin gearbeitet haben. Zur Erinnerung: das AppImageTool muss sich im Pfad befinden und ausführbar sein; eventuelle Fehlermeldungen beachten. Die Syntax lautet ./appimagetool <Name des AppDir> <Name des Ziel AppImages>, konkret in unserem Beispiel:

    ./appimagetool-x86_64.AppImage AppDir youplay_0.43_x86_64.AppImage

Ein erfolgreicher Lauf sollte dann in etwa so aussehen:

Anschließend kann das fertige AppImage getestet werden, dazu einfach im Dateimanager ausführen oder in der Shell launchen:

    ./youplay_0.43_x86_64.AppImage

Die programmspezifischen Kommandozeilenparameter bleiben erhalten, man kann also auch beispielsweise den Hilfe Schalter verwenden:

    ./youplay_0.43_x86_64.AppImage --help

oder

    ./youplay_0.43_x86_64.AppImage --version

AppImages sind übrigens von Haus aus komprimiert und sollten daher nicht weiter mit externen Tools vor dem Versenden/Bereitstellen komprimiert werden.

Troubleshooting

Sollte dieses (oder jedes beliebige andere) AppImage nicht ausgeführt werden können, empfiehlt es sich auf mögliche Fehlermeldungen zu achten in dem man das AppImage in der Shell ausführt. Darüber hinaus kann in der Regel jedes AppImage mit dem Kommandozeilen-Schalter appimage-extract extrahiert werden. Dann lässt sich die Struktur inspizieren und eventuell fehlende Dateien ausmachen.

Die Syntax lautet ./Programm.AppImage --appimage-extract

Innerhalb des damit erzeugten Verzeichnisses "squashfs-root" kann dann der bereits bekannte launcher gestartet werden

    cd squashfs-root
    ./AppRun

Mögliche Fehlermeldungen

  • Fehlermeldung in der shell: ValueError: Namespace Adw not available

    • Fehlerursache: Programmbibliothek "Libadwaita" fehlt
    • Lösung: Paket "Libadwaita" via Paketmanager installieren
      • Name bei Arch/Manjaro/Fedora: 'libadwaita'
      • Name bei Debian/Mint/Ubuntu: 'libadwaita-1-dev'
  • Fehlermeldung in der shell: ValueError: Namespace Gtk not available for version 4.0

    • Fehlerursache: Programmbibliothek "GTK4" fehlt
    • Lösung: Paket "GTK4" via Paketmanager installieren
      • Name bei Arch/Manjaro/Fedora: 'gtk4'
      • Name bei Debian/Mint/Ubuntu: 'libgtk-4-dev'
  • Fehlermeldung in der shell: Please wait /bin/sh: 1: yt-dlp: not found

    • Fehlerursache: Programm "yt-dlp" fehlt
    • Lösung: Paket 'yt-dlp' via Paketmanager installieren
  • Fehlermeldung in der shell: OSError: Cannot find libmpv in the usual places.

    • Fehlerursache: Programmbibliothek "libmpv" fehlt
    • Lösung: Paket "libmpv" via Paketmanager installieren
      • Name bei Manjaro/Arch: 'mpv'
      • Name bei Fedora: 'mpv-libs'
      • Name bei Debian/Mint/Ubuntu: 'libmpv-dev'

Automatisierte AppImage Generierung via shell-script

Das shell-script Make_AppImage.sh erstellt das AppImage namens youplay_0.43_x86_64.AppImage im Verzeichnis dist (für "distribute") unterhalb vom youplay-Verzeichnis. Es wird außerdem für jeden Lauf ein log namens Make_AppImage.log in dist mitgeschrieben. Das shell-script Make_AppImage.sh muss sich zum Zeitpunkt des Ausführens in einem Unterverzeichnis unterhalb vom youplay-Verzeichnis befinden. Es wird ohne weitere Kommandozeilenparamter gestartet und kann direkt, ohne weitere Anpassungen ausgeführt werden (denkbar ist natürlich einen zusätzlichen Parameter für den gewünschten AppImage-Namen zu übergeben etc.)

Dazu werden die benötigten Tools selbständig via wget (als AppImages) in ein temporäres Verzeichnis heruntergeladen und ausführbar gemacht. Anschließend wird das Python-AppImage extrahiert und die notwendigen PIP-Pakete in die alternative site-packages Lokation installiert. Danach wird der youplay-code hineinkopiert und der AppRun-launcher erzeugt. Zum Schluß wird das AppImage mit dem AppImageTool generiert.

Das Shell-script ist hier verfügbar.

Anmerkungen

  • "youplay_0.43_x86_64.AppImage" wurde erfolgreich generiert unter Manjaro Plasma

  • "youplay_0.43_x86_64.AppImage" wurde erfolgreich ausgeführt auf

    • Manjaro Plasma
    • Manjaro LXQt
    • Arch Plasma
    • Arch LXQt
    • Fedora 38 Plasma
    • Fedora 38 GNOME
    • Debian Bookworm
    • Linux Mint 21.1 Cinnamon
    • Ubuntu 23.04 MATE

  • Es gibt zwei fertige 64bit AppImages für YouPlay:

Über Hilfe der Community bei der Integration der Abhängigkeiten mpv, yt-dlp, ffmpeg, gtk4 und libadwaita via PRs (Pull Request) oder Mails an das youplay-Team sind willkommen. :)

Git: https://codeberg.org/ralfhersel/youplay

E-Mail: ralf.hersel[at]gmx.net oder p.salajean[at]gmx.de

Weitere Links

Artikel AppImage bei der Wikipedia
AppImage Doc - Manual Packaging
Python AppImages

Tags

Python, AppImage, Deployment, Verteilung, Paketformat, Development, Entwicklung

Torsten
Geschrieben von Torsten am 8. Mai 2023 um 17:25

Ich habe das Gtk4 AppImage auf meiner Distro (Pop!_OS 22.04 LTS) ausprobiert. Das AppImage läuft astrein. Youplay hatte ich ja vorher schon als Python Programm im Einsatz. Vielen, vielen Dank für dieses geniale Tool an Ralf und alle Beteiligten, die ihre Energie in die Weiterentwicklung / Containerisierung des Tools stecken! :-)