#!/usr/bin/env bash # This is free and unencumbered software released into the public domain. # # Anyone is free to copy, modify, publish, use, compile, sell, or # distribute this software, either in source code form or as a compiled # binary, for any purpose, commercial or non-commercial, and by any # means. # # In jurisdictions that recognize copyright laws, the author or authors # of this software dedicate any and all copyright interest in the # software to the public domain. We make this dedication for the benefit # of the public at large and to the detriment of our heirs and # successors. We intend this dedication to be an overt act of # relinquishment in perpetuity of all present and future rights to this # software under copyright law. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # For more information, please refer to if [ "$#" -ne 4 ]; then echo "Syntax: $0 " exit 1 fi BUILDDIR=$1 ROOTDIR=$2 DEPSDIR=$3 NAME=$4 BINDIR="$DSDIR/bin" BINARY=duckstation-qt APPDIRNAME=DuckStation.AppDir STRIP=llvm-strip-12 declare -a SYSLIBS=( "libz.so.1" "libuuid.so.1" "libapparmor.so.1" "libblkid.so.1" "libbsd.so.0" "libdbus-1.so.3" "libgcrypt.so.20" "liblzma.so.5" "libmount.so.1" "libnsl.so.1" "libpcre.so.3" "libselinux.so.1" "libsystemd.so.0" "libudev.so.1" "libwrap.so.0" "libharfbuzz.so.0" "libFLAC.so.8" "libX11.so.6" "libX11-xcb.so.1" "libXau.so.6" "libXcomposite.so.1" "libXcursor.so.1" "libXdamage.so.1" "libXdmcp.so.6" "libXext.so.6" "libXfixes.so.3" "libXi.so.6" "libXinerama.so.1" "libXrandr.so.2" "libXrender.so.1" "libXxf86vm.so.1" "libasyncns.so.0" "libcrypto.so.1.1" "liblz4.so.1" "libpulse.so.0" "libxcb.so.1" "libxcb-render.so.0" "libxcb-shm.so.0" "libxkbcommon.so.0" "libxkbcommon-x11.so.0" "pulseaudio/libpulsecommon-13.99.so" "libfreetype.so.6" "libpcre2-16.so.0" "libexpat.so.1" "libffi.so.7" "libgraphite2.so.3" "libresolv.so.2" "libgpg-error.so.0" "libpcre2-16.so.0" "libxcb-icccm.so.4" "libxcb-image.so.0" "libxcb-keysyms.so.1" "libxcb-randr.so.0" "libxcb-render.so.0" "libxcb-render-util.so.0" "libxcb-shape.so.0" "libxcb-sync.so.1" "libxcb-util.so.1" "libxcb-xfixes.so.0" "libxcb-xkb.so.1" "libevdev.so.2" "libgudev-1.0.so.0" "libinput.so.10" "libjpeg.so.8" "libmtdev.so.1" "libpng16.so.16" "libuuid.so.1" "libSM.so.6" "libICE.so.6" "libfontconfig.so.1" "libglib-2.0.so.0" "libcurl-gnutls.so.4" "libnghttp2.so.14" "libidn2.so.0" "librtmp.so.1" "libssh.so.4" "libpsl.so.5" "libnettle.so.7" "libgnutls.so.30" "libgssapi_krb5.so.2" "libldap_r-2.4.so.2" "liblber-2.4.so.2" "libbrotlidec.so.1" "libunistring.so.2" "libhogweed.so.5" "libgmp.so.10" "libp11-kit.so.0" "libtasn1.so.6" "libkrb5.so.3" "libk5crypto.so.3" "libcom_err.so.2" "libkrb5support.so.0" "libsasl2.so.2" "libgssapi.so.3" "libbrotlicommon.so.1" "libkeyutils.so.1" "libheimntlm.so.0" "libkrb5.so.26" "libasn1.so.8" "libhcrypto.so.4" "libroken.so.18" "libwind.so.0" "libheimbase.so.1" "libhx509.so.5" "libsqlite3.so.0" "libcrypt.so.1" ) declare -a DEPLIBS=( "libSDL2-2.0.so.0" ) declare -a QTLIBS=( "libQt6Core.so.6" "libQt6Gui.so.6" "libQt6Network.so.6" "libQt6OpenGL.so.6" "libQt6Svg.so.6" "libQt6WaylandClient.so.6" "libQt6WaylandCompositor.so.6" "libQt6WaylandEglClientHwIntegration.so.6" "libQt6WaylandEglCompositorHwIntegration.so.6" "libQt6Widgets.so.6" "libQt6XcbQpa.so.6" ) declare -a QTPLUGINS=( "plugins/iconengines" "plugins/imageformats" "plugins/platforms" #"plugins/platformthemes" # Enable this if we want to ship GTK+ themes at any point. "plugins/wayland-decoration-client" "plugins/wayland-graphics-integration-client" "plugins/wayland-graphics-integration-server" "plugins/wayland-shell-integration" "plugins/xcbglintegrations" ) set -e if [ ! -f appimagetool-x86_64.AppImage ]; then wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage chmod +x appimagetool-x86_64.AppImage fi OUTDIR=$(realpath "./$APPDIRNAME") SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}") rm -fr "$OUTDIR" mkdir "$OUTDIR" mkdir -p "$OUTDIR/usr/bin" "$OUTDIR/usr/lib" "$OUTDIR/usr/lib/pulseaudio" echo "Copying binary and resources..." cp -a "$BUILDDIR/bin"/* "$OUTDIR/usr/bin" # We don't need tests rm -f "$OUTDIR"/usr/bin/*-tests # Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system. echo "Patching RPATH in ${BINARY}..." patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY" # Currently we leave the main binary unstripped, uncomment if this is not desired. #$STRIP "$OUTDIR/usr/bin/$BINARY" # Libraries we pull in from the system. echo "Copying system libraries..." for lib in "${SYSLIBS[@]}"; do blib=$(basename "$lib") if [ -f "/lib/x86_64-linux-gnu/$lib" ]; then cp "/lib/x86_64-linux-gnu/$lib" "$OUTDIR/usr/lib/$blib" elif [ -f "$CHROOT/usr/lib/x86_64-linux-gnu/$lib" ]; then cp "$CHROOT/usr/lib/x86_64-linux-gnu/$lib" "$OUTDIR/usr/lib/$blib" elif [ -f "$CHROOT/lib/$lib" ]; then cp "$CHROOT/lib/$lib" "$OUTDIR/usr/lib/$blib" elif [ -f "$CHROOT/usr/lib/$lib" ]; then cp "$CHROOT/usr/lib/$lib" "$OUTDIR/usr/lib/$blib" else echo "*** Failed to find '$blib'" exit 1 fi $STRIP "$OUTDIR/usr/lib/$blib" done # Dependencies we built, at this point it's just SDL. echo "Copying dependency libraries..." for lib in "${DEPLIBS[@]}"; do blib=$(basename "$lib") if [ -f "$DEPSDIR/lib/$lib" ]; then cp "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib/$blib" else echo "*** Failed to find '$blib'" exit 1 fi $STRIP "$OUTDIR/usr/lib/$blib" done echo "Copying Qt libraries..." for lib in "${QTLIBS[@]}"; do cp -aL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib" $STRIP "$OUTDIR/usr/lib/$lib" done echo "Copying Qt plugins..." mkdir -p "$OUTDIR/usr/lib/plugins" for plugin in "${QTPLUGINS[@]}"; do mkdir -p "$OUTDIR/usr/lib/$plugin" cp -aL "$DEPSDIR/$plugin"/*.so "$OUTDIR/usr/lib/$plugin/" done for so in $(find "$OUTDIR/usr/lib/plugins" -iname '*.so'); do # This is ../../ because it's usually plugins/group/name.so echo "Patching RPATH in ${so}..." patchelf --set-rpath '$ORIGIN/../..' "$so" $STRIP "$so" done for so in $(find "$OUTDIR/usr/lib" -maxdepth 1); do if [ -f "$so" ]; then echo "Patching RPATH in ${so}" patchelf --set-rpath '$ORIGIN' "$so" fi done echo "Creating qt.conf..." cat > "$OUTDIR/usr/bin/qt.conf" << EOF [Paths] Plugins = ../lib/plugins EOF echo "Creating desktop..." cat > "$OUTDIR/duckstation-qt.desktop" << EOF [Desktop Entry] Type=Application Name=DuckStation GenericName=PlayStation 1 Emulator Comment=Fast PlayStation 1 emulator Icon=duckstation-qt TryExec=duckstation-qt Exec=duckstation-qt %f Categories=Game;Emulator;Qt; EOF cp "$ROOTDIR/data/resources/images/duck.png" "$OUTDIR/duckstation-qt.png" echo "Creating AppRun..." cat > "$OUTDIR/AppRun" << EOF #!/bin/sh APPDIR=\$(dirname "\$0") exec "\$APPDIR/usr/bin/$BINARY" "\$@" EOF chmod +x "$OUTDIR/AppRun" echo "Generate AppImage" ./appimagetool-x86_64.AppImage -v "$OUTDIR" "$NAME.AppImage"