AppImage real?

Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
swurl 2025-04-14 20:45:18 -04:00
parent 807397680a
commit 053d68deef
13 changed files with 402 additions and 2 deletions

View file

@ -1,5 +1,9 @@
#!/bin/bash -ex #!/bin/bash -ex
set -e
declare INSTALLABLES=`find build -type d -exec test -e '{}/cmake_install.cmake' ';' -print`
set +e
GITDATE="$(git show -s --date=short --format='%ad' | sed 's/-//g')" GITDATE="$(git show -s --date=short --format='%ad' | sed 's/-//g')"
GITREV="$(git show -s --format='%h')" GITREV="$(git show -s --format='%h')"
ARTIFACTS_DIR="$PWD/artifacts" ARTIFACTS_DIR="$PWD/artifacts"
@ -44,6 +48,10 @@ create_appimage() {
mkdir -p "${app_dir}/usr/optional/libstdc++" mkdir -p "${app_dir}/usr/optional/libstdc++"
mkdir -p "${app_dir}/usr/optional/libgcc_s" mkdir -p "${app_dir}/usr/optional/libgcc_s"
echo "Copying libraries..."
for i in $INSTALLABLES; do cmake --install $i --prefix ${app_dir}/usr; done
if [ -d "build/bin/Release" ]; then if [ -d "build/bin/Release" ]; then
cp "build/bin/Release/${binary_name}" "${app_dir}/usr/bin/" || echo "${binary_name} not found for AppDir" cp "build/bin/Release/${binary_name}" "${app_dir}/usr/bin/" || echo "${binary_name} not found for AppDir"
else else

View file

@ -164,13 +164,13 @@ jobs:
- name: Package AppImages - name: Package AppImages
run: | run: |
./.ci/package-appimage.sh "${{ github.ref_name }}" ./AppImage-build-local.sh
- name: Upload Linux artifacts - name: Upload Linux artifacts
uses: forgejo/upload-artifact@v4 uses: forgejo/upload-artifact@v4
with: with:
name: linux.zip name: linux.zip
path: artifacts/* path: *.AppImage
android: android:
runs-on: android runs-on: android

83
AppImage-build-debian-inner.sh Executable file
View file

@ -0,0 +1,83 @@
#! /bin/bash
set -e
# Make sure script is called from inside our container
test -e /tmp/torzu-src-ro || (echo "Script MUST NOT be called directly!" ; exit 1)
# Set up environment
export LANG=C.UTF-8
export LC_ALL=C.UTF-8
unset LC_ADDRESS LC_NAME LC_MONETARY LC_PAPER LC_TELEPHONE LC_MEASUREMENT LC_TIME
# Raise max open files count
ulimit -n 50000
# Install dependencies
apt -y install cmake ninja-build build-essential autoconf pkg-config locales wget git file mold libtool lsb-release wget software-properties-common gnupg \
qtbase5-dev qtmultimedia5-dev qtbase5-private-dev glslang-tools libssl-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libpulse-dev libasound2-dev
if [ ! "$BUILD_USE_CPM" = 1 ]; then
apt -y install libfmt-dev libenet-dev liblz4-dev nlohmann-json3-dev zlib1g-dev libopus-dev libsimpleini-dev libstb-dev libzstd-dev libusb-1.0-0-dev libcubeb-dev libcpp-jwt-dev libvulkan-dev gamemode-dev libasound2-dev libglu1-mesa-dev libxext-dev mesa-common-dev libva-dev
if [ ! -f /usr/local/lib/cmake/Boost-1.88.0/BoostConfigVersion.cmake ]; then
# Install Boost
wget https://archives.boost.io/release/1.88.0/source/boost_1_88_0.tar.bz2
echo "Extracting Boost sources..."
tar xf boost_1_88_0.tar.bz2
cd boost_1_88_0
./bootstrap.sh
./b2 install --with-{headers,context,system,fiber,atomic,filesystem} link=static
cd ..
rm -rf boost_1_88_0 boost_1_88_0.tar.bz2
fi
fi
# Install Clang
if ([ "$BUILD_USE_CLANG" = 1 ] && ! clang-19 --version); then
cd /tmp
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
./llvm.sh 19
rm llvm.sh
fi
# Mount Torzu sources with temporary overlay
cd /tmp
mkdir torzu-src-upper torzu-src-work torzu-src
mount -t overlay overlay -olowerdir=torzu-src-ro,upperdir=torzu-src-upper,workdir=torzu-src-work torzu-src
# Get extra configuration/compilation options
EXTRA_COMPILE_FLAGS=""
EXTRA_CMAKE_FLAGS=""
if [ "$BUILD_USE_CLANG" = 1 ]; then
EXTRA_CMAKE_FLAGS="-DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19"
FATLTO_FLAG="-flto=full"
else
FATLTO_FLAG="-flto"
fi
if [ "$BUILD_USE_THIN_LTO" = 1 ]; then
EXTRA_COMPILE_FLAGS="-flto=thin"
fi
if [ "$BUILD_USE_FAT_LTO" = 1 ]; then
EXTRA_COMPILE_FLAGS="$FATLTO_FLAG"
fi
if [ "$BUILD_USE_CPM" = 1 ]; then
EXTRA_CMAKE_FLAGS="$EXTRA_CMAKE_FLAGS -DYUZU_USE_CPM=ON"
fi
# Build Torzu
cd /tmp
mkdir torzu-build
cd torzu-build
cmake /tmp/torzu-src -GNinja -DCMAKE_BUILD_TYPE=Release -DYUZU_TESTS=OFF -DENABLE_QT_TRANSLATION=OFF -DSPIRV_WERROR=OFF -DCMAKE_FIND_LIBRARY_SUFFIXES=".a;.so" -DSPIRV-Headers_SOURCE_DIR=/tmp/torzu-src/externals/SPIRV-Headers -DCMAKE_{C,CXX}_FLAGS="$EXTRA_COMPILE_FLAGS -fdata-sections -ffunction-sections" -DCMAKE_{EXE,SHARED}_LINKER_FLAGS="-Wl,--gc-sections" $EXTRA_CMAKE_FLAGS
ninja || (
echo "Compilation has failed. Dropping you into a shell so you can inspect the situation. Run 'ninja' to retry and exit shell once compilation has finished successfully."
echo "Note that any changes made here will not be reflected to the host environment, but changes made from the host environment will be reflected here."
bash
)
# Generate AppImage
cp -rv /tmp/torzu-src/AppImageBuilder /tmp/AppImageBuilder
cd /tmp/AppImageBuilder
./build.sh /tmp/torzu-build /tmp/torzu.AppImage || echo "This error is known. Using workaround..."
cp /lib/$(uname -m)-linux-gnu/libICE.so.6 build/
mv build /tmp/hosttmp/torzu-debian-appimage-rootfs

73
AppImage-build-debian.sh Executable file
View file

@ -0,0 +1,73 @@
#! /bin/bash
set -e
# Parse options
for i in "$@"
do
case $i in
-l|--clang)
export BUILD_USE_CLANG=1
echo "-> Using Clang for compilation."
;;
-o|--thin-lto)
export BUILD_USE_THIN_LTO=1
echo "-> Thin link time optimization enabled."
;;
-O|--fat-lto)
export BUILD_USE_FAT_LTO=1
echo "-> Fat link time optimization enabled."
;;
-p|--use-cpm)
export BUILD_USE_CPM=1
echo "-> Using CPM to download most dependencies."
;;
-k|--keep-rootfs)
BUILD_KEEP_ROOTFS=1
echo "-> Not deleting rootfs after successful build."
;;
*)
echo "Usage: $0 [--clang/-l] [--thin-lto/-o] [--fat-lto/-O] [--use-cpm/-p] [--keep-rootfs/-k]"
exit 1
;;
esac
done
# Make sure options are valid
if [ "$BUILD_USE_THIN_LTO" = 1 ] && [ "$BUILD_USE_CLANG" != 1 ]; then
echo "Thin LTO can't be used without Clang!"
exit 2
fi
if [ "$BUILD_USE_THIN_LTO" = 1 ] && [ "$BUILD_USE_FAT_LTO" = 1 ]; then
echo "Only either thin or fat LTO can be used!"
exit 2
fi
# Get torzu source dir
TORZU_SOURCE_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
echo "-> Source dir is $TORZU_SOURCE_DIR"
rm -rf "$TORZU_SOURCE_DIR/AppImageBuilder/build"
# Generate debian rootfs
cd /tmp
echo "Cleaning up before build..."
rm -rf torzu-debian-appimage-rootfs
[ -d rootfs-torzu-appimage-build ] ||
debootstrap stable rootfs-torzu-appimage-build http://deb.debian.org/debian/
bwrap --bind rootfs-torzu-appimage-build / \
--unshare-pid \
--dev-bind /dev /dev --proc /proc --tmpfs /tmp --ro-bind /sys /sys --dev-bind /run /run \
--tmpfs /var/tmp \
--chmod 1777 /tmp \
--ro-bind /etc/resolv.conf /etc/resolv.conf \
--ro-bind "$TORZU_SOURCE_DIR" /tmp/torzu-src-ro \
--chdir / \
--tmpfs /home \
--setenv HOME /home \
--bind /tmp /tmp/hosttmp \
/tmp/torzu-src-ro/AppImage-build-debian-inner.sh
appimagetool torzu-debian-appimage-rootfs torzu.AppImage
echo "AppImage generated at /tmp/torzu.AppImage! Cleaning up..."
rm -rf torzu-debian-appimage-rootfs
if [ ! "$BUILD_KEEP_ROOTFS" = 1 ]; then
rm -rf rootfs-torzu-appimage-build
fi

42
AppImage-build-local.sh Executable file
View file

@ -0,0 +1,42 @@
#!/bin/bash
FILE=build/bin/eden
if test -f "$FILE"; then
# remove any previously made AppImage in the base eden git folder
rm ./eden.AppImage
# enter AppImage utility folder
cd AppImageBuilder
# run the build script to create the AppImage
# (usage) ./build.sh [source eden build folder] [destination .AppImage file]
./build.sh ../build ./eden.AppImage
FILE=./eden.AppImage
if test -f "$FILE"; then
# move the AppImage to the main eden folder
mv eden.AppImage ..
# return to main eden folder
cd ..
# show contents of current folder
echo
ls
# show AppImages specifically
echo
ls *.AppImage
echo
echo "'eden.AppImage' is now located in the current folder."
echo
else
cd ..
echo "AppImage was not built."
fi
else
echo
echo "$FILE does not exist."
echo
echo "No eden executable found in the /eden/build/bin folder!"
echo
echo "You must first build a native linux version of eden before running this script!"
echo
fi

Binary file not shown.

11
AppImageBuilder/assets/AppRun Executable file
View file

@ -0,0 +1,11 @@
#! /bin/bash
cd "$APPDIR"
if [ -d /usr/lib/$(uname -m)-linux-gnu/qt5 ] || [ -d /usr/lib/qt ]; then
# System-wide Qt5
exec ./yuzu.sh "$@"
else
# Bundled Qt5
exec ./yuzu-bqt.sh "$@"
fi

View file

@ -0,0 +1,3 @@
#! /bin/sh
LD_LIBRARY_PATH=./qt5:/usr/lib/$(uname -m)-linux-gnu:/usr/lib:. QT_PLUGIN_PATH=./qt5 exec ./yuzu "$@"

3
AppImageBuilder/assets/eden.sh Executable file
View file

@ -0,0 +1,3 @@
#! /bin/sh
LD_LIBRARY_PATH=/usr/lib/$(uname -m)-linux-gnu:/usr/lib:. exec ./yuzu "$@"

View file

Binary file not shown.

View file

@ -0,0 +1 @@
This is a statically compiled bubblewrap 0.9.0 executable.

176
AppImageBuilder/build.sh Executable file
View file

@ -0,0 +1,176 @@
#! /bin/bash
set -e
# Check arguments
if [[ $# != 2 ]]; then
>&2 echo "Bad usage!"
echo "Usage: $0 <build dir> <output file>"
exit 1
fi
# Get paths
ARCH="$(uname -m)"
SYSTEM_LIBS="/usr/lib"
SYSTEM_LIBS64="/usr/lib64"
EDEN_BIN="${1}/bin"
EDEN_BIN_GUI="${EDEN_BIN}/eden"
# Make sure executable exists
if [[ $(file -b --mime-type "$EDEN_BIN_GUI") != application/x-pie-executable ]]; then
>&2 echo "Invalid eden executable!"
fi
# Clean up build dir
rm -rf build
mkdir build
# NOTE: some of these aren't used now, but can be reordered in priority when eden is converted to QT6
# QT5 - /usr/lib/${ARCH}-linux-gnu/qt5 (debian), /usr/lib64/qt5 (fedora), /usr/lib/qt (steam deck)
# QT5 - /usr/lib/${ARCH}-linux-gnu/qt6 (debian), /usr/lib64/qt6 (fedora), /usr/lib/qt6 (steam deck)
QTFOUND="true"
QTDIR="$SYSTEM_LIBS"/${ARCH}-linux-gnu/qt5/plugins
if [ ! -d "$QTDIR" ]; then
# default qt5 folder not found, check for 64-bit qt5 folder
QTDIR="$SYSTEM_LIBS64"/qt5/plugins
if [ ! -d "$QTDIR" ]; then
# 64-bit qt5 folder not found, check for Steam Deck qt (qt5) folder
QTDIR="$SYSTEM_LIBS"/qt/plugins
if [ ! -d "$QTDIR" ]; then
# Steam Deck qt (qt5) folder not found, check for regular qt6 folder
QTDIR="$SYSTEM_LIBS"/${ARCH}-linux-gnu/qt6/plugins
if [ ! -d "$QTDIR" ]; then
# regular qt6 folder not found, check for 64-bit qt6 folder
QTDIR="$SYSTEM_LIBS64"/qt6/plugins
if [ ! -d "$QTDIR" ]; then
# 64-bit qt6 folder not found, check for Steam Deck qt6 folder
QTDIR="$SYSTEM_LIBS"/qt6/plugins
if [ ! -d "$QTDIR" ]; then
QTFOUND="false"
fi
fi
fi
fi
fi
fi
if [ $QTFOUND == "true" ]; then
echo "QT plugins from $QTDIR will be used."
# Copy system dependencies used to build and required by the eden binary
# includes:
# - '/lib64/ld-linux-x86-64.so.2' or `/lib/ld-linux-aarch64.so.1` file per architecture
# - required files from `/usr/lib/x86_64-linux-gnu` or `/usr/lib/aarch64-linux-gnu`
# - different for SteamDeck, but still does it automatically
function copy_libs {
for lib in $(ldd "$1"); do
(cp -vn "$lib" ./build/ 2> /dev/null) || true
done
}
echo "Copying main dependencies..."
copy_libs "$EDEN_BIN_GUI"
# Copy QT dependency folders, path determined above
echo "Copying Qt dependencies..."
mkdir ./build/qt5
cp -rv "$QTDIR"/{imageformats,platforms,platformthemes,xcbglintegrations} ./build/qt5/
# Discover indirect dependencies (mostly from runtime-loaded Qt plugins)
echo "Copying extra dependencies..."
while true; do
LIBS="$(find ./build -name \*.so\*)"
LIB_COUNT=$(echo "$LIBS" | wc -l)
echo "$LIB_COUNT dependency libraries discovered so far..."
if [ $LIB_COUNT == "$PREV_LIB_COUNT" ]; then
break
fi
PREV_LIB_COUNT=$LIB_COUNT
for plib in $LIBS; do
if [ -f "$plib" ]; then
copy_libs "$plib"
fi
done
done
# Copy executable
cp -v "$EDEN_BIN_GUI" ./build/
cat > "build/org.eden_emu.eden.desktop" << EOL
[Desktop Entry]
Type=Application
Name=Eden
Icon=org.eden_emu.eden
Exec=eden
Categories=Game;Emulator;
EOL
cp "../dist/eden.svg" build/org.eden_emu.eden.svg
# Strip all libraries and executables
for file in $(find ./build -type f); do
(strip -v "$file" 2> /dev/null) || true
done
PASSED_CHECKSUM="false"
FILE=appimagetool.AppImage
# total number of times to try downloading if a checksum doesn't match
DL_TRIES=3
while [ $PASSED_CHECKSUM == "false" ] && [ "$DL_TRIES" -gt 0 ]; do
case $ARCH in
x86_64)
# Static copy from the 'ext-linux-bin' repo.
# Checksum will need to be changed when/if this file in the repo is updated.
if ! test -f "$FILE"; then
echo "Downloading appimagetool for architecture '$ARCH'"
wget -O appimagetool.AppImage https://github.com/litucks/ext-linux-bin/raw/refs/heads/main/appimage/appimagetool-x86_64.AppImage
fi
if [ $(shasum -a 256 appimagetool.AppImage | cut -d' ' -f1) = "110751478abece165a18460acbd7fd1398701f74a9405ad8ac053427d937bd5d" ] ; then
PASSED_CHECKSUM="true"
fi
# DISABLED TO USE THE ABOVE
# The current continuous release channel option, until a static copy is put in 'ext-linux-bin'.
# The checksum will pass until the continuous release is updated, then a new one needs to be
# generated to update this script.
#if ! test -f "$FILE"; then
# echo "Downloading appimagetool for architecture '$ARCH'"
# wget -O appimagetool.AppImage https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
#fi
#if [ $(shasum -a 256 appimagetool.AppImage | cut -d' ' -f1) = "46fdd785094c7f6e545b61afcfb0f3d98d8eab243f644b4b17698c01d06083d1" ] ; then
# PASSED_CHECKSUM="true"
#fi
;;
aarch64)
# Currently set to the continuous release channel until a static copy is put in 'ext-linux-bin'.
# The checksum will pass until the continuous release is updated, then a new one needs to be
# generated to update this script.
if ! test -f "$FILE"; then
echo "Downloading appimagetool for architecture '$ARCH'"
wget -O appimagetool.AppImage https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-aarch64.AppImage
fi
if [ $(shasum -a 256 appimagetool.AppImage | cut -d' ' -f1) = "04f45ea45b5aa07bb2b071aed9dbf7a5185d3953b11b47358c1311f11ea94a96" ] ; then
PASSED_CHECKSUM="true"
fi
;;
*)
PASSED_CHECKSUM="invalid_arch"
;;
esac
# delete the appimagetool downloaded if the checksum doesn't match.
if [ ! $PASSED_CHECKSUM == "true" ]; then
rm -f appimagetool.AppImage
fi
((DL_TRIES-=1))
done
if [ $PASSED_CHECKSUM == "true" ]; then
echo "Checksum passed. Proceeding to build image."
# Build AppImage
chmod a+x appimagetool.AppImage
./appimagetool.AppImage ./build "$2"
elif [ $PASSED_CHECKSUM == "invalid_arch" ]; then
echo "No download found for architecture '$ARCH'. Building halted."
else
echo "Checksum for appimagetool does not match. Building halted."
echo "If the file to be downloaded has been changed, a new checksum will need to be generated for this script."
fi
else
echo "QT not found, aborting AppImage build."
fi