Build AppImage #8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build AppImage | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| # APPIMAGE_EXTRACT_AND_RUN=1 is required because GitHub Actions runners | |
| # do not have FUSE available, which AppImage tools need to self-mount. | |
| env: | |
| APPIMAGE_EXTRACT_AND_RUN: "1" | |
| jobs: | |
| appimage: | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Install Qt 6.7 via the official Qt online installer. | |
| # jurplel/install-qt-action sets QT_ROOT_DIR in the environment, | |
| # which we later pass to linuxdeploy-plugin-qt via QMAKE. | |
| - name: Install Qt 6 | |
| uses: jurplel/install-qt-action@v4 | |
| with: | |
| version: '6.7.*' | |
| host: 'linux' | |
| target: 'desktop' | |
| arch: 'linux_gcc_64' | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libgraphicsmagick++-dev libomp-dev \ | |
| libfftw3-dev libcurl4-openssl-dev | |
| # Build the application and stage it into appdir/ using the | |
| # standard qmake INSTALL_ROOT mechanism. The .pro already has | |
| # correct INSTALLS targets for binary, icons, .desktop, and appstream. | |
| - name: Build and stage | |
| run: | | |
| qmake CONFIG+=release PREFIX=/usr | |
| make -j$(nproc) | |
| make install INSTALL_ROOT=$PWD/appdir | |
| # AppImages are relocatable and don't inherit the host's XDG_DATA_DIRS, | |
| # so MainWindow::loadTranslator() can't find the .qm files installed | |
| # under usr/share/photoflare/languages/ (that lookup only works for | |
| # .deb installs because /usr/share happens to be a host XDG_DATA_DIR). | |
| # Mirror the .qm files next to the binary so the applicationDirPath() | |
| # lookup in loadTranslator() finds them. | |
| - name: Stage translations next to binary | |
| run: | | |
| mkdir -p appdir/usr/bin/languages | |
| cp appdir/usr/share/photoflare/languages/*.qm appdir/usr/bin/languages/ | |
| # Clone gmic-qt and the matching G'MIC source tree, build the standalone | |
| # gmic_qt binary, and stage it into appdir/usr/bin/ alongside photoflare. | |
| - name: Build and stage gmic-qt | |
| run: | | |
| git clone --depth 1 --branch v.3.4.2 https://github.com/c-koi/gmic-qt.git gmic-qt-src | |
| # Pin GMIC core to v.3.7.6: it's the last release where gmic::init_rc() | |
| # still returns bool. gmic-qt v.3.4.2 (last tagged gmic-qt release, and | |
| # its current master branch too) calls it as `create && gmic::init_rc()`, | |
| # which fails to compile against gmic >= v.4.0.0, where init_rc() was | |
| # changed to return void. Bumping GMIC core past v.4.0.0 (as previously | |
| # tried) breaks this API compatibility, even though it fixes the stdlib | |
| # header 404 below. | |
| git clone --depth 1 --branch v.3.7.6 https://github.com/GreycLab/gmic.git gmic-qt-src/gmic | |
| GMIC_SRC="$PWD/gmic-qt-src/gmic/src" | |
| GMIC_VER=$(grep -oP '(?<=gmic_version )\d+' "$GMIC_SRC/gmic.h") | |
| CIMG_TAG="v.${GMIC_VER:0:1}.${GMIC_VER:1:1}.${GMIC_VER:2:1}" | |
| wget --no-check-certificate --quiet -O "$GMIC_SRC/CImg.h" \ | |
| "https://github.com/GreycLab/CImg/raw/${CIMG_TAG}/CImg.h" | |
| # gmic.eu only hosts gmic_stdlib_community<VERSION>.h for whatever the | |
| # CURRENT GMIC release is (older pinned versions 404 there), but the | |
| # header's compressed G'MIC-script content isn't version-locked at | |
| # compile time -- it's just a `data_gmic`/`size_data_gmic` byte array, | |
| # and CMake's GMIC_PATH build only checks gmic.h vs CImg.h consistency, | |
| # not the stdlib header's version. So resolve whatever the latest GMIC | |
| # release actually is and fetch that header, decoupled from the core | |
| # version pinned above for API compatibility. | |
| LATEST_GMIC_TAG=$(curl -fsSL https://api.github.com/repos/GreycLab/gmic/releases/latest \ | |
| | grep -oP '"tag_name":\s*"\K[^"]+') \ | |
| || { echo "Failed to resolve latest GMIC release tag"; exit 1; } | |
| LATEST_GMIC_VER="${LATEST_GMIC_TAG#v.}" | |
| LATEST_GMIC_VER="${LATEST_GMIC_VER//./}" | |
| wget --quiet -O "$GMIC_SRC/gmic_stdlib_community.h" \ | |
| "https://gmic.eu/gmic_stdlib_community${LATEST_GMIC_VER}.h" \ | |
| || { echo "Failed to download gmic_stdlib_community.h"; exit 1; } | |
| # Sanity check: this header must define the data_gmic/size_data_gmic | |
| # symbols that gmic.cpp's decompress_stdlib() expects, otherwise fail | |
| # fast here instead of with a confusing compile error later. | |
| if ! grep -q 'data_gmic' "$GMIC_SRC/gmic_stdlib_community.h"; then | |
| echo "gmic_stdlib_community.h does not define data_gmic; aborting" | |
| exit 1 | |
| fi | |
| cmake gmic-qt-src -B build-gmic-qt \ | |
| -DCMAKE_PREFIX_PATH="${QT_ROOT_DIR}" \ | |
| -DBUILD_WITH_QT6=ON \ | |
| -DGMIC_QT_HOST=none \ | |
| -DENABLE_SYSTEM_GMIC=OFF \ | |
| -DGMIC_PATH="$PWD/gmic-qt-src/gmic/src" \ | |
| -DENABLE_FFTW3=ON \ | |
| -DENABLE_CURL=ON \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_EXE_LINKER_FLAGS="-no-pie" | |
| cmake --build build-gmic-qt --parallel | |
| cp build-gmic-qt/gmic_qt appdir/usr/bin/gmic_photoflare_qt | |
| # Download linuxdeploy and its Qt plugin into a tools/ subdirectory | |
| # so they do not match the *.AppImage upload glob later. | |
| - name: Download linuxdeploy | |
| run: | | |
| mkdir tools | |
| wget -nv -P tools \ | |
| https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \ | |
| https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage | |
| chmod +x tools/*.AppImage | |
| # linuxdeploy-plugin-qt needs QMAKE to point at the correct Qt 6 qmake | |
| # so it can discover Qt plugins and translations. | |
| # VERSION is used by linuxdeploy to name the output file. | |
| - name: Build AppImage | |
| env: | |
| QMAKE: ${{ env.QT_ROOT_DIR }}/bin/qmake | |
| VERSION: ${{ github.ref_name }} | |
| run: | | |
| export PATH="$PWD/tools:$PATH" | |
| ./tools/linuxdeploy-x86_64.AppImage \ | |
| --appdir appdir \ | |
| --plugin qt \ | |
| --output appimage | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: photoflare-appimage | |
| path: '*.AppImage' | |
| if-no-files-found: error | |
| # Attach the AppImage to the GitHub Release when triggered by a tag push. | |
| - name: Upload to release | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: '*.AppImage' |