Building Generic Qt Apps for Linux in AppImage Format with GitLab CI


For one of my projects I had the need of building a Qt app based on Qt 6.4 with a universal distro-agnostic format. In the past, I used snap packages for this purpose. Unfortunately, it is my understanding that building an application with a version of Qt different from the one in Ubuntu may be difficult. So I thought I could try to learn a different tool and build an AppImage instead.

My target is: building the AppImage in a GitLab CI environment with an arbitrary self-built version of Qt for both, at least, x64 and aarch64.

Tools

I found a good tool to build a Qt app: linuxdeployqt. The problem here is this sentence quoted from the GitHub project:

To produce binaries that are compatible with many target systems, build on the oldest still-supported build system. The oldest still-supported release of Ubuntu is currently targeted, tested and supported by the team.
We recommend to target the oldest still-supported Ubuntu LTS release and build your applications on that. If you do this, the resulting binaries should be able to run on newer (but not older) systems (Ubuntu and other distributions).
We do not support linuxdeployqt on systems newer than the oldest Ubuntu LTS release, because we want to encourage developers to build applications in a way that makes them possible to run on all still-supported distribution releases.

https://github.com/probonopd/linuxdeployqt

I don’t like this too much. I would like to build on very recent versions of the libraries, Qt in particular. In my project I used the Qt HTTP module, which requires Qt 6.4. Building Qt 6.4 on an old Ubuntu version may be done or not, but old Ubuntu versions are not supported by Qt itself (the oldest currently is Ubuntu 20.04: https://doc.qt.io/qt-6/supported-platforms.html). In general, I do not like this approach much.

I then searched a bit more and I found this project: appimage-builder. This one is a bit different:

appimage-builder uses a new approach for creating AppImages which is based on:

  • bundling almost every dependency inside the AppImage (including glibc and family)
  • selecting at runtime the newer glibc version to be used while running the bundled app using a custom AppRun
  • excluding by default drivers and using the system ones at runtime
  • restoring the environment variables while calling external binaries using function hooks
  • patching paths on function calls at runtime using function hooks

This allows creating backward and forward compatible bundles with little effort if compared to other existent solutions where the developer has to setup or tweak a build environment and finding/making backports of their app dependencies.

But this approach also has drawbacks, bundling everything means:

  • AppImage will be at least 30Mb bigger
  • critical software such as libssl will be frozen into the bundle
https://appimage-builder.readthedocs.io/en/latest/faq.html

This one feels better, so I tried with this tool.

Example

The tool seemed to do what I need, but next point is doing it in a container. For an example, I used my Qt test app here: https://github.com/carlonluca/Fall. It is a simple QtQuick app with some animations.

Setting up the Env

I’d prefer to do everything inside a container, so I do not have to bother to setup my machine. To do this, I used my docker image for Qt development. That image also includes appimage-builder. The version of the included appimage-builder version is one taken from my fork here. The reason why that fork is used is simply because it includes a patch I applied for aarch64 AppImage’s (the PR was merged already).

To know how appimage-builder works, please refer to official docs. What I did here is executing the app inside the container (through X11 or xwayland) to create the recipe. This means that the container must be started like this:

docker run --name fall -ti -e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix carlonluca/qt-dev:6.5.2 bash

This is using Qt 6.5.2, but you could use whatever other version. Refer to this page for the available options.

Building the App

Now, it is time to build the app in the container. For Fall, this is pretty simple, but there are some issues to fix in the image first.

First of all you’ll need to remove this symlink, to avoid confusion in the paths to use:

rm /opt/Qt-amd64-6.5.2

Now, you’ll need to replace the dir /opt/Qt-amd64-6.5.2 in the ldconfig in /etc/ld.so.conf.d/x86_64-linux-gnu.conf and then run ldconfig. I’ll have to take care of this in future images. Then:

git clone https://github.com/carlonluca/Fall.git
git submodule update --init --recursive
cd Fall
mkdir build
cd build
/opt/qt/6.5.2/gcc_64/bin/qt-cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
cmake --build .

At this point note that we will want to install the app, so we need the install target. Add this with this line in cmake:

install(TARGETS ${CUR_TARGET} DESTINATION bin)

Once the app is built, install it by using the DESTDIR option:

make install DESTDIR=AppDir

Now, you can have a look at the result and see if all the libs are properly found. If you see something like this:

ldd AppDir/usr/local/bin/Fall
        linux-vdso.so.1 (0x00007fff373e8000)
        libQt6Quick.so.6 => not found
        libQt6Qml.so.6 => not found
        libQt6Network.so.6 => not found
        libQt6StateMachine.so.6 => not found
        libQt6Gui.so.6 => not found
        libQt6Core.so.6 => not found
        libGLX.so.0 => /lib/x86_64-linux-gnu/libGLX.so.0 (0x00007fa04e528000)
        libOpenGL.so.0 => /lib/x86_64-linux-gnu/libOpenGL.so.0 (0x00007fa04e4fc000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fa04e2d2000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa04e2b2000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa04e08a000)
        libGLdispatch.so.0 => /lib/x86_64-linux-gnu/libGLdispatch.so.0 (0x00007fa04dfd0000)
        libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007fa04de90000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa04dda9000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa04e936000)
        libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007fa04dd7f000)
        libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 (0x00007fa04dd79000)
        libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007fa04dd6f000)
        libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007fa04dd57000)
        libmd.so.0 => /lib/x86_64-linux-gnu/libmd.so.0 (0x00007fa04dd4a000)

check you ldconfig. If everything is ok, you should see something like this:

ldconfig
        linux-vdso.so.1 (0x00007ffc6d746000)
        libQt6Quick.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6Quick.so.6 (0x00007f68fcf75000)
        libQt6Qml.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6Qml.so.6 (0x00007f68fc9df000)
        libQt6Network.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6Network.so.6 (0x00007f68fc836000)
        libQt6StateMachine.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6StateMachine.so.6 (0x00007f68fc7d6000)
        libQt6Gui.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6Gui.so.6 (0x00007f68fbe0f000)
        libQt6Core.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6Core.so.6 (0x00007f68fb782000)
        libGLX.so.0 => /lib/x86_64-linux-gnu/libGLX.so.0 (0x00007f68fb74e000)
        libOpenGL.so.0 => /lib/x86_64-linux-gnu/libOpenGL.so.0 (0x00007f68fb722000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f68fb4f8000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f68fb4d8000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f68fb2b0000)
        libQt6QmlModels.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6QmlModels.so.6 (0x00007f68fb1e0000)
        libxkbcommon.so.0 => /lib/x86_64-linux-gnu/libxkbcommon.so.0 (0x00007f68fb199000)
        libQt6OpenGL.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6OpenGL.so.6 (0x00007f68fb0f8000)
        libGL.so.1 => /lib/x86_64-linux-gnu/libGL.so.1 (0x00007f68fb071000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f68faf8a000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f68faf85000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f68faf7e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f68fd9e1000)
        libgssapi_krb5.so.2 => /lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007f68faf2a000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f68faf0e000)
        libEGL.so.1 => /lib/x86_64-linux-gnu/libEGL.so.1 (0x00007f68faefb000)
        libfontconfig.so.1 => /lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f68faeb1000)
        libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x00007f68fad6f000)
        libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f68fac35000)
        libQt6DBus.so.6 => /opt/qt/6.5.2/gcc_64/lib/libQt6DBus.so.6 (0x00007f68fab70000)
        libfreetype.so.6 => /lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f68faaa8000)
        libgthread-2.0.so.0 => /lib/x86_64-linux-gnu/libgthread-2.0.so.0 (0x00007f68faaa3000)
        libicui18n.so.56 => /opt/qt/6.5.2/gcc_64/lib/libicui18n.so.56 (0x00007f68fa600000)
        libicuuc.so.56 => /opt/qt/6.5.2/gcc_64/lib/libicuuc.so.56 (0x00007f68fa200000)
        libicudata.so.56 => /opt/qt/6.5.2/gcc_64/lib/libicudata.so.56 (0x00007f68f8800000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f68faa9c000)
        libGLdispatch.so.0 => /lib/x86_64-linux-gnu/libGLdispatch.so.0 (0x00007f68f8748000)
        libkrb5.so.3 => /lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007f68f867d000)
        libk5crypto.so.3 => /lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007f68fa5d1000)
        libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007f68fa5cb000)
        libkrb5support.so.0 => /lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007f68fa5bd000)
        libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f68f864c000)
        libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007f68fa1f7000)
        libxcb.so.1 => /lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f68f8622000)
        libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f68f85ac000)
        libdbus-1.so.3 => /lib/x86_64-linux-gnu/libdbus-1.so.3 (0x00007f68f855e000)
        libpng16.so.16 => /lib/x86_64-linux-gnu/libpng16.so.16 (0x00007f68f8523000)
        libbrotlidec.so.1 => /lib/x86_64-linux-gnu/libbrotlidec.so.1 (0x00007f68fa1e9000)
        libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007f68f851c000)
        libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f68f8508000)
        libXau.so.6 => /lib/x86_64-linux-gnu/libXau.so.6 (0x00007f68fa1e3000)
        libXdmcp.so.6 => /lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f68f8500000)
        libsystemd.so.0 => /lib/x86_64-linux-gnu/libsystemd.so.0 (0x00007f68f8439000)
        libbrotlicommon.so.1 => /lib/x86_64-linux-gnu/libbrotlicommon.so.1 (0x00007f68f8416000)
        libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007f68f83fc000)
        liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f68f83d1000)
        libzstd.so.1 => /lib/x86_64-linux-gnu/libzstd.so.1 (0x00007f68f8302000)
        liblz4.so.1 => /lib/x86_64-linux-gnu/liblz4.so.1 (0x00007f68f82e2000)
        libcap.so.2 => /lib/x86_64-linux-gnu/libcap.so.2 (0x00007f68f82d7000)
        libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007f68f8199000)
        libmd.so.0 => /lib/x86_64-linux-gnu/libmd.so.0 (0x00007f68f818a000)
        libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f68f8164000)

Generating the Recipe

First, let’s generate the recipe as the docs suggest:

appimage-builder --generate
INFO:Generator:Searching AppDir
? ID [Eg: com.example.app]: com.luke.fall
? Application Name: Fall
? Icon: icon.png
? Executable path relative to AppDir [usr/bin/app]: usr/bin/Fall
? Arguments [Default: $@]: $@
? Version [Eg: 1.0.0]: 1.0.0
? Update Information [Default: guess]: guess
? Architecture: x86_64

The app should also start now and the recipe should be generated:

# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
version: 1
AppDir:
  path: /root/Fall/build/AppDir
  app_info:
    id: com.luke.fall
    name: Fall
    icon: icon.png
    version: latest
    exec: usr/bin/Fall
    exec_args: $@
  apt:
    arch:
    - amd64
    allow_unauthenticated: true
    sources:
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy main restricted
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy universe
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates universe
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy multiverse
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted
        universe multiverse
    - sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted
    - sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security universe
    - sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security multiverse
    include:
    - adwaita-icon-theme
    - fonts-dejavu-core
    - hicolor-icon-theme
    - libc-bin
    - libcap2:amd64
    - libcom-err2:amd64
    - libdbus-1-3:amd64
    - libgpg-error0:amd64
    - libkeyutils1:amd64
    - liblzma5:amd64
    - libpcre3:amd64
    - libtinfo6:amd64
  files:
    include:
    - /lib/x86_64-linux-gnu/libLLVM-15.so.1
    - /lib/x86_64-linux-gnu/libOpenGL.so.0
    - /lib/x86_64-linux-gnu/libelf.so.1
    - /lib/x86_64-linux-gnu/libsensors.so.5
    - /opt/qt/6.5.2/gcc_64/*/*
    - /opt/qt/6.5.2/gcc_64/lib/libQt6Quick.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6StateMachine.so.6
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqgif.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqicns.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqico.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqjpeg.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqpdf.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqsvg.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqtga.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqtiff.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqwbmp.so
    - /opt/qt/6.5.2/gcc_64/plugins/imageformats/libqwebp.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforminputcontexts/libcomposeplatforminputcontextplugin.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforminputcontexts/libibusplatforminputcontextplugin.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforminputcontexts/libqtvirtualkeyboardplugin.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqeglfs.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqlinuxfb.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqminimal.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqminimalegl.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqoffscreen.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqvkkhrdisplay.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqvnc.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqwayland-egl.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqwayland-generic.so
    - /opt/qt/6.5.2/gcc_64/plugins/platforms/libqxcb.so
    - /opt/qt/6.5.2/gcc_64/plugins/platformthemes/libqgtk3.so
    - /opt/qt/6.5.2/gcc_64/plugins/platformthemes/libqxdgdesktopportal.so
    - /opt/qt/6.5.2/gcc_64/plugins/xcbglintegrations/libqxcb-egl-integration.so
    - /opt/qt/6.5.2/gcc_64/plugins/xcbglintegrations/libqxcb-glx-integration.so
    - /opt/qt/6.5.2/gcc_64/plugins/*/*
    - /opt/qt/6.5.2/gcc_64/qml/*/*
    - /opt/qt/6.5.2/gcc_64/qml/QtQml/*/*
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/*/*
    - /opt/qt/6.5.2/gcc_64/qml/QtQml/WorkerScript/libworkerscriptplugin.so
    - /opt/qt/6.5.2/gcc_64/qml/QtQml/WorkerScript/qmldir
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/Basic/libqtquickcontrols2basicstyleplugin.so
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/Basic/qmldir
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/Fusion/impl/libqtquickcontrols2fusionstyleimplplugin.so
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/Fusion/impl/qmldir
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/Fusion/libqtquickcontrols2fusionstyleplugin.so
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/Fusion/qmldir
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/libqtquickcontrols2plugin.so
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Controls/qmldir
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Templates/libqtquicktemplates2plugin.so
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Templates/qmldir
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Window/libquickwindowplugin.so
    - /opt/qt/6.5.2/gcc_64/qml/QtQuick/Window/qmldir
    - /usr/share/icons/default/index.theme
    exclude:
    - usr/share/man
    - usr/share/doc/*/README.*
    - usr/share/doc/*/changelog.*
    - usr/share/doc/*/NEWS.*
    - usr/share/doc/*/TODO.*
AppImage:
  arch: x86_64
  update-information: guess

Unfortunately the list of files to include may not be complete. You’ll have to patiently find those that are missing and add those to the list. For the moment, I temporarily solved by simply adding entire subdirectories from the Qt installation dir:

version: 1
script:
- mkdir -p AppDir/opt/qt/6.5.2/gcc_64/
- cp -r /opt/qt/6.5.2/gcc_64/plugins AppDir/opt/qt/6.5.2/gcc_64/
- cp -r /opt/qt/6.5.2/gcc_64/qml AppDir/opt/qt/6.5.2/gcc_64/
- cp -r /opt/qt/6.5.2/gcc_64/resources AppDir/opt/qt/6.5.2/gcc_64/
AppDir:
  path: /root/Fall/build/AppDir
  app_info:
    id: com.luke.fall
    name: Fall
    icon: icon.png
    version: latest
    exec: usr/bin/Fall
    exec_args: $@
  apt:
    arch:
    - amd64
    allow_unauthenticated: true
    sources:
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy main restricted
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy universe
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates universe
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy multiverse
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates multiverse
    - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted
        universe multiverse
    - sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted
    - sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security universe
    - sourceline: deb http://security.ubuntu.com/ubuntu/ jammy-security multiverse
    include:
    - adwaita-icon-theme
    - fonts-dejavu-core
    - hicolor-icon-theme
    - libc-bin
    - libcap2:amd64
    - libcom-err2:amd64
    - libdbus-1-3:amd64
    - libgpg-error0:amd64
    - libkeyutils1:amd64
    - liblzma5:amd64
    - libpcre3:amd64
    - libtinfo6:amd64
  files:
    include:
    - /lib/x86_64-linux-gnu/libLLVM-15.so.1
    - /lib/x86_64-linux-gnu/libOpenGL.so.0
    - /lib/x86_64-linux-gnu/libelf.so.1
    - /lib/x86_64-linux-gnu/libsensors.so.5
    - /opt/qt/6.5.2/gcc_64/lib/libQt6Core5Compat.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6QuickControls2.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6StateMachine.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6WebView.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6Xml.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6Svg.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6DBus.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6WaylandClient.so.6
    - /opt/qt/6.5.2/gcc_64/lib/libQt6WaylandEglClientHwIntegration.so.6
    - /usr/share/icons/default/index.theme
    exclude:
    - usr/share/man
    - usr/share/doc/*/README.*
    - usr/share/doc/*/changelog.*
    - usr/share/doc/*/NEWS.*
    - usr/share/doc/*/TODO.*
AppImage:
  arch: x86_64
  update-information: guess

I do not need the icon at the moment:

mkdir -p AppDir/usr/share/icons
touch AppDir/usr/share/icons/icon.png

Now you can generate the AppImage:

appimage-builder --recipe AppImageBuilder.yml

The resulting AppImage is pretty large, as expected. There are many things that can clearly be stripped from it.

GitLab CI

Making the process automatic is pretty simple. This is the GitLab CI yml I wrote:

Appimage:
  stage: appimage
  image:
    name: "carlonluca/qt-dev:6.5.2"
    entrypoint: [""]
  script:
    - /opt/qt/6.5.2/gcc_64/bin/qt-cmake . -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
    - cmake --build .
    - make install DESTDIR=AppDir
    - mkdir -p AppDir/usr/share/icons
    - touch AppDir/usr/share/icons/icon.png
    - appimage-builder --recipe appimage/AppImageBuilder.yml
  artifacts:
    paths:
      - Fall-latest-x86_64.AppImage

Recent images in the qt-dev repo already include appimage-builder, but check the table to know which include it.

Test

The interesting part of this experiment was to be able to build packages that are both forward compatible and backward compatible. I tested the resulting AppImage in a Manjaro system on Wayland, updated to 2023.09 and an old Fedora 22 XFCE on X11 (from 2015). In both cases the package worked properly. As I ran the app in Fedora in a VirtualBox environment, I also had to disable acceleration with:

QT_QUICK_BACKEND=software

But Manjaro was on a physical machine, and the GPU could be used properly.

I failed to run the same AppImage on Ubuntu 13 instead. This is an issue I still have to investigate.

Have fun! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *