build: add AppImage packaging script

This commit is contained in:
tri committed 2026-11-02 20:18:07 +07:00
1 parent be658edeec
commit 5b1c1a75be
3 files changed
+136

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
# Start the real binary by its path inside the AppImage. A symlinked AppRun makes Qt take
# the AppImage root as the application dir, so it misses usr/bin/qt.conf and finds no
# platform plugins.
HERE="$(dirname "$(readlink -f "$0")")"
# The Plasma platform theme's own file dialog lists folders through KIO workers, which are
# not bundled (it would show every folder as empty). Use the host's dialog via the
# xdg-desktop-portal instead.
export PLASMA_INTEGRATION_USE_PORTAL=1
export XDG_DATA_DIRS="$HERE/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
exec "$HERE/usr/bin/qtpotato" "$@"
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env bash
# Build a QtPotato AppImage from the host's Qt/KF6/mpv libraries.
#
# The result only runs on distros whose glibc is at least as new as the build host's,
# so build on the oldest distro you want to support.
#
# Usage: packaging/appimage/build-appimage.sh [build-dir]
set -euo pipefail
SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
BUILD_DIR="$(realpath -m "${1:-$SRC_DIR/build-appimage}")"
TOOLS_DIR="${TOOLS_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/qtpotato-appimage-tools}"
APPDIR="$BUILD_DIR/AppDir"
QT_PLUGINS="$(qmake6 -query QT_INSTALL_PLUGINS)"
export APPIMAGE_EXTRACT_AND_RUN=1 # works without FUSE
# The strip bundled with linuxdeploy is too old for binaries from current distros
# (e.g. DT_RELR sections) and aborts the deployment.
export NO_STRIP=1
fetch_tool() {
local repo=$1 file=$2
if [[ ! -x "$TOOLS_DIR/$file" ]]; then
curl -fL --create-dirs -o "$TOOLS_DIR/$file" \
"https://github.com/linuxdeploy/$repo/releases/download/continuous/$file"
chmod +x "$TOOLS_DIR/$file"
fi
}
fetch_tool linuxdeploy linuxdeploy-x86_64.AppImage
fetch_tool linuxdeploy-plugin-qt linuxdeploy-plugin-qt-x86_64.AppImage
fetch_tool linuxdeploy-plugin-appimage linuxdeploy-plugin-appimage-x86_64.AppImage
export PATH="$TOOLS_DIR:$PATH"
cmake -S "$SRC_DIR" -B "$BUILD_DIR" -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_TESTING=OFF
cmake --build "$BUILD_DIR"
rm -rf "$APPDIR"
DESTDIR="$APPDIR" cmake --install "$BUILD_DIR"
# Plugins that are loaded at runtime by name, so linuxdeploy-plugin-qt cannot find them:
# Kirigami's style plugins, the Plasma platform theme (colors, fonts, icon theme and the
# QtQuick style from the user's Plasma settings) and the Breeze/Union widget styles.
copy_plugins() {
local subdir=$1; shift
mkdir -p "$APPDIR/usr/plugins/$subdir"
for pattern in "$@"; do
for f in "$QT_PLUGINS/$subdir"/$pattern; do
if [[ -e "$f" ]]; then cp "$f" "$APPDIR/usr/plugins/$subdir/"; fi
done
done
}
copy_plugins kf6/kirigami/platform '*.so'
copy_plugins platformthemes KDEPlasmaPlatformTheme6.so
copy_plugins styles breeze6.so UnionWidgetsStyle.so
copy_plugins union '*.so'
copy_plugins kf6 FrameworkIntegrationPlugin.so
# EGL integration for Wayland; without it Qt Quick cannot create an OpenGL context.
copy_plugins wayland-graphics-integration-client '*.so'
# QtQuick styles and their private modules are also picked at runtime; list them in a
# dummy QML file so qmlimportscanner deploys them.
EXTRA_QML="$BUILD_DIR/appimage-extra-qml"
mkdir -p "$EXTRA_QML"
cat > "$EXTRA_QML/Styles.qml" <<'EOF'
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Fusion
import QtQuick.Templates
import org.kde.kirigami
import org.kde.kirigami.platform
import org.kde.desktop
import org.kde.qqc2desktopstyle.private
import org.kde.breeze
import org.kde.union
Item {}
EOF
deps_only=()
while IFS= read -r -d '' f; do
deps_only+=(--deploy-deps-only="$f")
done < <(find "$APPDIR/usr/plugins" -name '*.so' -print0)
# linuxdeploy-plugin-qt deploys every image format plugin and fails on any with a missing
# dependency (e.g. kimg_jxr without libjpegxr). Hand it a filtered view of the plugin dir
# through a qmake wrapper.
FILTERED_PLUGINS="$BUILD_DIR/appimage-qt-plugins"
rm -rf "$FILTERED_PLUGINS"
mkdir -p "$FILTERED_PLUGINS/imageformats"
for d in "$QT_PLUGINS"/*; do
[[ "$(basename "$d")" == imageformats ]] || ln -s "$d" "$FILTERED_PLUGINS/"
done
for f in "$QT_PLUGINS"/imageformats/*.so; do
if ldd "$f" | grep -q 'not found'; then
echo "Skipping $(basename "$f"): missing dependencies"
else
ln -s "$f" "$FILTERED_PLUGINS/imageformats/"
fi
done
cat > "$BUILD_DIR/qmake-wrapper" <<EOF
#!/bin/sh
if [ "\$1" = -query ] && [ "\$2" = QT_INSTALL_PLUGINS ]; then echo "$FILTERED_PLUGINS"; exit 0; fi
out=\$(qmake6 "\$@") || exit
printf '%s\n' "\$out" | sed "s|^QT_INSTALL_PLUGINS:.*|QT_INSTALL_PLUGINS:$FILTERED_PLUGINS|"
EOF
chmod +x "$BUILD_DIR/qmake-wrapper"
export QMAKE="$BUILD_DIR/qmake-wrapper"
export QML_SOURCES_PATHS="$SRC_DIR/src/qml:$EXTRA_QML"
export EXTRA_QT_MODULES="svg"
export EXTRA_PLATFORM_PLUGINS="libqwayland.so"
export LDAI_OUTPUT="${LDAI_OUTPUT:-$BUILD_DIR/QtPotato-$(git -C "$SRC_DIR" describe --tags --always --dirty 2>/dev/null || echo dev)-x86_64.AppImage}"
cd "$BUILD_DIR"
linuxdeploy-x86_64.AppImage \
--appdir "$APPDIR" \
--executable "$APPDIR/usr/bin/qtpotato" \
--desktop-file "$APPDIR/usr/share/applications/dev.trivk.qtpotato.desktop" \
--icon-file "$APPDIR/usr/share/icons/hicolor/scalable/apps/dev.trivk.qtpotato.svg" \
--custom-apprun "$SRC_DIR/packaging/appimage/AppRun" \
"${deps_only[@]}" \
--plugin qt \
--output appimage
echo "AppImage: $LDAI_OUTPUT"