Add AppImage support

Add a Dockerfile having all needed tooling. Using a container also means
those are the libs that will end up being used in the AppImage.

Then add a script for building pyrogenesis either form git or from
extracted source tarballs and for assembling the AppImage and finally
creating the AppImage.

Add building the AppImage to the "bundles" pipeline.

Also add a wrapper script to use podman to drive the whole process
for convenience for local builds.

Ref: #7577
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
This commit is contained in:
Ralph Sennhauser 2025-06-25 10:06:38 +02:00
parent 199f4cb666
commit 788708ed8c
No known key found for this signature in database
6 changed files with 197 additions and 5 deletions

2
.gitignore vendored
View file

@ -25,6 +25,7 @@ libraries/source/spirv-reflect/*
!libraries/source/**/patches/
# Tools
appimage-build/
archives/
build/bin/
source/tools/spirv/rules.*.json
@ -68,6 +69,7 @@ binaries/data/mods/public/gui/credits/texts/translators.json
*.pot
# Packaged mods and tarballs
*.AppImage
*.pyromod
*.zip
*.tar

View file

@ -0,0 +1,40 @@
FROM debian-12
# minisign only needed for signing in pipeline
RUN apt-get -qqy update \
&& apt-get upgrade -qqy \
&& apt-get install -qqy --no-install-recommends \
cimg-dev \
desktop-file-utils \
file \
git \
libgcrypt20-dev \
libgpgme-dev \
libjpeg-dev \
minisign \
patchelf \
squashfs-tools \
wget \
&& apt-get clean
RUN \
git clone --depth 1 --branch 1-alpha-20250213-2 https://github.com/linuxdeploy/linuxdeploy --recurse-submodules && \
cd linuxdeploy && cp src/core/copyright/copyright.h src/core && \
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DBUILD_TESTING=OFF \
-DUSE_CCACHE=OFF \
&& cmake --build build --target install && \
cd .. && \
rm -rf linuxdeploy
RUN \
git clone --depth 1 --branch continuous https://github.com/AppImage/appimagetool.git && \
cd appimagetool && \
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
&& cmake --build build --target install && \
cd .. && \
rm -rf appimagetool

View file

@ -140,24 +140,67 @@ pipeline {
stage('Create Windows Installer & Tarballs') {
steps {
sh "BUNDLE_VERSION=${params.BUNDLE_VERSION} DO_GZIP=${params.DO_GZIP} source/tools/dist/build-unix-win32.sh"
stash(name: 'unix-sources', includes: '*.tar.gz')
}
}
stage('Create AppImage') {
stages {
stage('Docker Setup') {
agent {
node {
label 'LinuxAgent'
customWorkspace 'workspace/appimage'
}
}
steps {
checkout scm
sh 'git clean -dxf'
sh 'docker build -t debian-12 -f build/jenkins/dockerfiles/debian-12.Dockerfile .'
}
}
stage('Build AppImage') {
agent {
dockerfile {
label 'LinuxAgent'
customWorkspace 'workspace/appimage'
dir 'build/jenkins/dockerfiles'
filename 'debian-12-appimage.Dockerfile'
// Prevent Jenkins from running commands with the UID of the host's jenkins user
// https://stackoverflow.com/a/42822143
args '-u root'
}
}
steps {
unstash('unix-sources')
untar(dir: 'appimage-build', file: "0ad-${params.BUNDLE_VERSION}-unix-build.tar.gz", keepPermissions: true)
untar(dir: 'appimage-build', file: "0ad-${params.BUNDLE_VERSION}-unix-data.tar.gz", keepPermissions: true)
sh "source/tools/dist/build-appimage.sh --version ${params.BUNDLE_VERSION} --root appimage-build/0ad-${params.BUNDLE_VERSION}"
stash(name: 'appimage', includes: '*AppImage')
}
}
}
}
stage('Generate Signatures and Checksums') {
steps {
unstash('appimage')
withCredentials([sshUserPrivateKey(credentialsId: 'minisign-releases-key', keyFileVariable: 'MINISIGN_KEY', passphraseVariable: 'MINISIGN_PASS')]) {
sh 'echo ${MINISIGN_PASS} | minisign -s ${MINISIGN_KEY} -Sm *.{dmg,exe,tar.gz,tar.xz}'
sh 'echo ${MINISIGN_PASS} | minisign -s ${MINISIGN_KEY} -Sm *.{AppImage,dmg,exe,tar.gz,tar.xz}'
}
sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do md5sum "${file}" > "${file}".md5sum; done'
sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do sha1sum "${file}" > "${file}".sha1sum; done'
sh 'for file in *.{dmg,exe,tar.gz,tar.xz}; do sha256sum "${file}" > "${file}".sha256sum; done'
sh 'for file in *.{AppImage,dmg,exe,tar.gz,tar.xz}; do md5sum "${file}" > "${file}".md5sum; done'
sh 'for file in *.{AppImage,dmg,exe,tar.gz,tar.xz}; do sha1sum "${file}" > "${file}".sha1sum; done'
sh 'for file in *.{AppImage,dmg,exe,tar.gz,tar.xz}; do sha256sum "${file}" > "${file}".sha256sum; done'
}
}
}
post {
success {
archiveArtifacts '*.dmg,*.exe,*.tar.gz,*.tar.xz,*.minisig,*.md5sum,*.sha1sum,*.sha256sum'
archiveArtifacts '*AppImage,*.dmg,*.exe,*.tar.gz,*.tar.xz,*.minisig,*.md5sum,*.sha1sum,*.sha256sum'
}
cleanup {
sh 'svn revert -R .'

View file

@ -15,6 +15,7 @@ in particular, let us know and we can try to clarify it.
MIT
dist
GPL-2.0-or-later
MIT
zlib/libpng (FileAssociation.nsh)

7
source/tools/dist/build-appimage-podman.sh vendored Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
podman build -t 0ad-debian-12 -f build/jenkins/dockerfiles/debian-12.Dockerfile
podman build -t 0ad-debian-12-appimage --build-context debian-12=container-image://0ad-debian-12 -f build/jenkins/dockerfiles/debian-12-appimage.Dockerfile
podman run --mount=type=bind,source=.,destination=/mnt --workdir /mnt 0ad-debian-12-appimage source/tools/dist/build-appimage.sh "$@"

99
source/tools/dist/build-appimage.sh vendored Executable file
View file

@ -0,0 +1,99 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later
# shellcheck disable=SC2120
die()
{
[ $# -ne 0 ] && echo ERROR: "$*"
exit 1
}
doins()
{
mkdir -p "$2"
cp -a "$1" "$2" || die
}
JOBS=${JOBS#-j}
njobs=${JOBS:-1}
arch=$(uname -m)
version=9999
while [ "$#" -gt 0 ]; do
case "$1" in
--jobs)
njobs=$2
shift
;;
--root)
root=$2
shift
;;
--skip-prepacking)
skip_prepacking="yes"
;;
--version)
version=$2
shift
;;
*)
printf "Unknown option: %s\n\n" "$1"
exit 1
;;
esac
shift
done
TOP_SRC_DIR=$(realpath .)
APPDIR="${TOP_SRC_DIR}/appimage-build/AppDir"
APPIMAGE="${TOP_SRC_DIR}/0ad-${version}-${arch}.AppImage"
ROOT="${TOP_SRC_DIR}"
if [ -n "${root}" ]; then
ROOT=$(realpath "${root}")
fi
cd "${ROOT}" || die
./libraries/build-source-libs.sh "-j${njobs}" || die
./build/workspaces/update-workspaces.sh || die
make -C build/workspaces/gcc "-j${njobs}" || die
if [ -z "${root}" ] && [ -z "${skip_prepacking}" ]; then
./source/tools/i18n/get-nightly-translations.sh || die
./source/tools/spirv/get-nightly-shaders.sh || die
# TODO: Fails at check for root user currently when generating mods archives
#./source/tools/dist/build-archives.sh
fi
rm -rf "${APPDIR}" "${APPIMAGE}"
doins binaries/system/pyrogenesis "${APPDIR}/usr/bin"
ln -rs "${APPDIR}/usr/bin/pyrogenesis" "${APPDIR}/usr/bin/0ad" || die
for lib in \
libmozjs*-release.so \
libnvcore.so \
libnvimage.so \
libnvmath.so \
libnvtt.so; do
patchelf --set-rpath "${lib}:${ROOT}/binaries/system" "${APPDIR}/usr/bin/pyrogenesis" || die
done
# dlopen lib
doins binaries/system/libCollada.so "${APPDIR}/usr/lib"
doins binaries/data/config/default.cfg "${APPDIR}/usr/data/config"
doins binaries/data/l10n "${APPDIR}/usr/data"
doins binaries/data/tools "${APPDIR}/usr/data"
doins binaries/data/mods/mod "${APPDIR}/usr/data/mods"
doins binaries/data/mods/public "${APPDIR}/usr/data/mods"
doins build/resources/0ad.appdata.xml "${APPDIR}/usr/share/metainfo"
doins build/resources/0ad.png "${APPDIR}/usr/share/pixmaps"
linuxdeploy \
--appdir "${APPDIR}" \
--executable "${APPDIR}/usr/bin/pyrogenesis" \
--desktop-file "${ROOT}/build/resources/0ad.desktop" \
--icon-file "${ROOT}/build/resources/0ad.png" \
--icon-filename 0ad || die
appimagetool --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 20 "${APPDIR}" "${APPIMAGE}" || die