Path: blob/master/scripts/packaging/appimage/make-cross-appimage.sh
4251 views
#!/usr/bin/env bash12# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>3# SPDX-License-Identifier: CC-BY-NC-ND-4.045SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")67function retry_command {8# Package servers tend to be unreliable at times..9# Retry a bunch of times.10local RETRIES=101112for i in $(seq 1 "$RETRIES"); do13"$@" && break14if [ "$i" == "$RETRIES" ]; then15echo "Command \"$@\" failed after ${RETRIES} retries."16exit 117fi18done19}2021if [ "$1" == "-inject-libc" ]; then22echo "Injecting libc/libstdc++"23INJECT_LIBC=true24shift25fi2627if [ "$#" -ne 5 ]; then28echo "Syntax: $0 [-inject-libc] <duckstation-qt|duckstation-mini> <target arch> <path to build directory> <deps prefix> <chroot dir>"29exit 130fi3132BINARY=$133ARCH=$234BUILDDIR=$335DEPSDIR=$436CHROOTDIR=$53738STRIP=llvm-strip3940if [ "$ARCH" == "arm64" ]; then41DEBARCH="arm64"42RUNTIMEARCH="aarch64"43TRIPLE="aarch64-linux-gnu"44elif [ "$ARCH" == "armhf" ]; then45DEBARCH="armhf"46RUNTIMEARCH="armhf"47TRIPLE="arm-linux-gnueabihf"48else49echo "Unknown arch ${ARCH}."50exit 151fi5253if [ "$BINARY" == "duckstation-qt" ]; then54echo "Building Qt AppImage."55ADD_QT_LIBS=true56APPIMAGENAME="DuckStation-${ARCH}"57elif [ "$BINARY" == "duckstation-mini" ]; then58echo "Building Mini AppImage."59ADD_QT_LIBS=false60APPIMAGENAME="DuckStation-Mini-${ARCH}"61else62echo "Unknown binary $BINARY"63exit 164fi6566APPDIRNAME="${APPIMAGENAME}.AppDir"6768declare -a SYSLIBS=(69"libbrotlicommon.so.1"70"libbrotlidec.so.1"71"libbsd.so.0"72"libcom_err.so.2"73"libcrypto.so.3"74"libcurl.so.4"75"libffi.so.8"76"libgnutls.so.30"77"libgssapi_krb5.so.2"78"libhogweed.so.6"79"libidn2.so.0"80"libk5crypto.so.3"81"libkeyutils.so.1"82"libkrb5.so.3"83"libkrb5support.so.0"84"liblber-2.5.so.0"85"libldap-2.5.so.0"86"libnettle.so.8"87"libnghttp2.so.14"88"libp11-kit.so.0"89"libpsl.so.5"90"librtmp.so.1"91"libsasl2.so.2"92"libssh.so.4"93"libssl.so.3"94"libtasn1.so.6"95"libudev.so.1"96"libunistring.so.2"97)9899declare -a DEPLIBS=(100"libbacktrace.so.0"101"libfreetype.so.6"102"libharfbuzz.so"103"libjpeg.so.62"104"libpng16.so.16"105"libSDL3.so.0"106"libsharpyuv.so.0"107"libwebpdemux.so.2"108"libwebpmux.so.3"109"libwebp.so.7"110"libzip.so.5"111"libzstd.so.1"112113"libcpuinfo.so"114"libdiscord-rpc.so"115"libplutosvg.so.0"116"libshaderc_ds.so"117"libsoundtouch.so.2"118"libspirv-cross-c-shared.so.0"119120#"libavcodec.so.61"121#"libavformat.so.61"122#"libavutil.so.59"123#"libswscale.so.8"124#"libswresample.so.5"125#"libva-drm.so.2"126#"libva.so.2"127)128129if [ "${ADD_QT_LIBS}" == true ]; then130SYSLIBS+=(131"libatk-1.0.so.0"132"libatk-bridge-2.0.so.0"133"libatspi.so.0"134"libblkid.so.1"135"libcairo-gobject.so.2"136"libcairo.so.2"137"libcap.so.2"138"libdatrie.so.1"139"libdeflate.so.0"140"libdbus-1.so.3"141"libepoxy.so.0"142"libgcrypt.so.20"143"libgdk-3.so.0"144"libgdk_pixbuf-2.0.so.0"145"libgio-2.0.so.0"146"libglib-2.0.so.0"147"libgmodule-2.0.so.0"148"libgobject-2.0.so.0"149"libgraphite2.so.3"150"libgtk-3.so.0"151"libjbig.so.0"152"liblz4.so.1"153"liblzma.so.5"154"libmd.so.0"155"libmount.so.1"156"libpango-1.0.so.0"157"libpangocairo-1.0.so.0"158"libpangoft2-1.0.so.0"159"libpcre2-16.so.0"160"libpcre2-8.so.0"161"libpcre.so.3"162"libpixman-1.so.0"163"libselinux.so.1"164"libsystemd.so.0"165"libtiff.so.5"166"libXau.so.6"167"libxcb-cursor.so.0"168"libxcb-glx.so.0"169"libxcb-icccm.so.4"170"libxcb-image.so.0"171"libxcb-keysyms.so.1"172"libxcb-randr.so.0"173"libxcb-render.so.0"174"libxcb-render-util.so.0"175"libxcb-shape.so.0"176"libxcb-shm.so.0"177"libxcb-sync.so.1"178"libxcb-util.so.1"179"libxcb-xfixes.so.0"180"libxcb-xkb.so.1"181"libXcomposite.so.1"182"libXcursor.so.1"183"libXdamage.so.1"184"libXdmcp.so.6"185"libXext.so.6"186"libXfixes.so.3"187"libXinerama.so.1"188"libXi.so.6"189"libxkbcommon.so.0"190"libxkbcommon-x11.so.0"191"libXrandr.so.2"192"libXrender.so.1"193)194195declare -a QTLIBS=(196"libQt6Core.so.6"197"libQt6DBus.so.6"198"libQt6Gui.so.6"199"libQt6OpenGL.so.6"200"libQt6Svg.so.6"201"libQt6WaylandClient.so.6"202"libQt6WaylandEglClientHwIntegration.so.6"203"libQt6Widgets.so.6"204"libQt6XcbQpa.so.6"205)206207declare -a QTPLUGINS=(208"plugins/iconengines"209"plugins/imageformats"210"plugins/platforminputcontexts"211"plugins/platforms"212"plugins/platformthemes"213"plugins/wayland-decoration-client"214"plugins/wayland-graphics-integration-client"215"plugins/wayland-shell-integration"216"plugins/xcbglintegrations"217)218fi219220set -e221IFS="222"223224APPIMAGETOOL=./appimagetool-x86_64225APPIMAGERUNTIME=./runtime-${RUNTIMEARCH}226PATCHELF=patchelf227228if [ ! -f "$APPIMAGETOOL" ]; then229retry_command wget -O "$APPIMAGETOOL" https://github.com/stenzek/duckstation-ext-qt-minimal/releases/download/linux/appimagetool-x86_64.AppImage230chmod +x "$APPIMAGETOOL"231fi232233if [ ! -f "$APPIMAGERUNTIME" ]; then234retry_command wget -O "$APPIMAGERUNTIME" https://github.com/stenzek/type2-runtime/releases/download/continuous/runtime-${RUNTIMEARCH}235fi236237OUTDIR=$(realpath "./$APPDIRNAME")238rm -fr "$OUTDIR"239mkdir "$OUTDIR"240mkdir -p "$OUTDIR/usr/bin" "$OUTDIR/usr/lib"241242echo "Copying binary and resources..."243cp -a "$BUILDDIR/bin/$BINARY" "$BUILDDIR/bin/resources" "$BUILDDIR/bin/translations" "$OUTDIR/usr/bin"244245# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system.246echo "Patching RPATH in ${BINARY}..."247patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY"248249# Libraries we pull in from the system.250echo "Copying system libraries..."251for lib in "${SYSLIBS[@]}"; do252blib=$(basename "$lib")253echo "$CHROOTDIR/lib/$TRIPLE/$lib"254if [ -f "$CHROOTDIR/lib/$TRIPLE/$lib" ]; then255cp "$CHROOTDIR/lib/$TRIPLE/$lib" "$OUTDIR/usr/lib/$blib"256elif [ -f "$CHROOTDIR/usr/lib/$TRIPLE/$lib" ]; then257cp "$CHROOTDIR/usr/lib/$TRIPLE/$lib" "$OUTDIR/usr/lib/$blib"258elif [ -f "$CHROOTDIR/lib/$lib" ]; then259cp "$CHROOTDIR/lib/$lib" "$OUTDIR/usr/lib/$blib"260elif [ -f "$CHROOTDIR/usr/lib/$lib" ]; then261cp "$CHROOTDIR/usr/lib/$lib" "$OUTDIR/usr/lib/$blib"262else263echo "*** Failed to find '$blib'"264exit 1265fi266267"$STRIP" $OUTDIR/usr/lib/$blib268done269270echo "Copying local libraries..."271for lib in "${DEPLIBS[@]}"; do272blib=$(basename "$lib")273echo "$DEPSDIR/lib/$lib"274if [ -f "$DEPSDIR/lib/$lib" ]; then275cp "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib/$blib"276else277echo "*** Failed to find '$blib'"278exit 1279fi280281"$STRIP" "$OUTDIR/usr/lib/$blib"282done283284if [ "${ADD_QT_LIBS}" == true ]; then285echo "Copying Qt libraries..."286for lib in "${QTLIBS[@]}"; do287cp -avL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib"288"$STRIP" "$OUTDIR/usr/lib/$lib"289done290291echo "Copying Qt plugins..."292mkdir -p $OUTDIR/usr/lib/plugins293for plugin in "${QTPLUGINS[@]}"; do294mkdir -p "$OUTDIR/usr/lib/$plugin"295cp -avL "$DEPSDIR/$plugin/"*.so "$OUTDIR/usr/lib/$plugin/"296done297298for so in $(find $OUTDIR/usr/lib/plugins -iname '*.so'); do299# This is ../../ because it's usually plugins/group/name.so300echo "Patching RPATH in ${so}..."301patchelf --set-rpath '$ORIGIN/../..' "$so"302"$STRIP" "$so"303done304305echo "Creating qt.conf..."306cat > "$OUTDIR/usr/bin/qt.conf" << EOF307[Paths]308Plugins = ../lib/plugins309EOF310311fi312313for so in $(find $OUTDIR/usr/lib -maxdepth 1); do314if [ -f "$so" ]; then315echo "Patching RPATH in ${so}"316patchelf --set-rpath '$ORIGIN' "$so"317fi318done319320# Copy desktop/icon321echo "Copying desktop/icon..."322mkdir -p "$OUTDIR/usr/share/applications"323mkdir -p "$OUTDIR/usr/share/icons/hicolor/512x512/apps"324cp -v "$SCRIPTDIR/../org.duckstation.DuckStation.desktop" "$OUTDIR/usr/share/applications"325cp -v "$SCRIPTDIR/../org.duckstation.DuckStation.png" "$OUTDIR/usr/share/icons/hicolor/512x512/apps"326ln -s "usr/share/applications/org.duckstation.DuckStation.desktop" "$OUTDIR"327ln -s "usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png" "$OUTDIR"328329# Generate AppStream meta-info.330echo "Generating AppStream metainfo..."331mkdir -p "$OUTDIR/usr/share/metainfo"332"$SCRIPTDIR/../generate-metainfo.sh" "$OUTDIR/usr/share/metainfo"333334# Copy AppRun335cp "$SCRIPTDIR/apprun-cross.sh" "$OUTDIR/AppRun"336chmod +x "$OUTDIR/AppRun"337ln -s "usr/bin/$BINARY" "$OUTDIR/AppRun.wrapped"338339# Optionally inject libc340if [ "$INJECT_LIBC" == true ]; then341echo "Injecting libc/libc++..."342"$SCRIPTDIR/inject-libc.sh" "$OUTDIR" "$DEBARCH" "$TRIPLE" "$BINARY"343fi344345echo "Generating AppImage..."346rm -f "$APPIMAGENAME.AppImage"347348# Can't run the appimage in a docker container because no fuse, so extract it first.349"$APPIMAGETOOL" --appimage-extract350"$PWD/squashfs-root/AppRun" -v --runtime-file "$APPIMAGERUNTIME" "$OUTDIR" "$APPIMAGENAME.AppImage"351352353