Linux Packaging
A release's Linux package is a tarball holding one relocatable tag_tools
directory, built by CI on Ubuntu 24.04 x86_64 against aqt Qt 6.10.3 and
vcpkg's static libraries -- the same configuration as the linux-vcpkg
preset -- and tested in clean Ubuntu 24.04 and Debian 13 containers before it
is uploaded. Why this form and not a .deb, an AppImage or a Flatpak is in
decision 0029.
What is in it
UltralightTags-X.Y-linux-x86_64/
tag_tools/
bin/ every shipped executable, and qt.conf
lib/ the Qt libraries and the ICU Qt ships
plugins/ the Qt plugins listed in cmake/DeployQtLinux.cmake
qml/ the QML modules the applications import
udev/ 70-ultralight-tags.rules
docs/ the user guide (when built with BUILD_HOST_DOCS, as CI does)
licenses/ build-report.json build-report.txt
Every executable has an RPATH of $ORIGIN/../lib, and bin/qt.conf points
Qt at ../plugins and ../qml. The tree mirrors a Qt installation's own
layout, so the RUNPATHs Qt's libraries and plugins carry ($ORIGIN,
$ORIGIN/../../lib) resolve inside it unchanged. Nothing in it names the
build machine; the package test fails any RUNPATH that does.
The command line tools, dataprocessing included, link no Qt; vcpkg links
libusb, protobuf, SQLite and Abseil into every executable.
The package relies on the system for glibc 2.39 or newer (the build runner's;
Qt's own libraries need 2.34), the C++ runtime, GLib, libudev, the display
stack (Wayland client libraries, libxkbcommon, and for X11 libxcb and
libxcb-cursor), OpenGL and EGL, fontconfig, D-Bus, CUPS, OpenSSL 3
(libssl.so.3, loaded by Qt's TLS plugin) and the CA certificates. A desktop
installation has all of them, except sometimes libxcb-cursor0, which the
README names.
How the install is made relocatable
host/CMakeLists.txt installs on Linux to tag_tools,
sets INSTALL_RPATH and leaves CMAKE_INSTALL_RPATH_USE_LINK_PATH off, so
the build machine's library directories never reach an installed binary. An
install-time step then runs
cmake/DeployQtLinux.cmake, Qt having no
Linux counterpart of windeployqt or macdeployqt. It
- asks
qmlimportscannerwhich QML modules the applications' QML imports, and copies each module's own files -- stopping at any subdirectory that is a module in its own right, so the GPL-only modules a full Qt keeps underQtQuickare never copied and nothing needs pruning afterwards; - copies a fixed list of plugins: the
waylandandxcbplatforms; the Wayland client decorations (GNOME leaves decorations to the client), thewayland-eglintegration the 3D view needs, andxdg-shell; the xcb GL integrations; compose and IBus input; the desktop-portal platform theme; CUPS print support; image formats and icon engines; and the TLS backends qtprogram's HTTPS release listing needs (the OpenSSL one loads the system'slibsslat run time). Nothing links a plugin, so they are named rather than discovered; - copies every library the executables, plugins and QML plugins need that is
not under
/libor/usr/lib, resolved against Qt's library directory, failing the install if a Qt or ICU library cannot be found; - writes
qt.conf.
Qt's directories come from the layout it records for itself
(host_find_qt_layout()), so a distribution Qt, which splits its tree, is
found as reliably as an installer one. When Qt is a distribution's -- its
libraries under /usr -- the install does not deploy it: the applications use
the system Qt in place, keeping the plugins the distribution adds. Only an
install against an installer or aqt Qt carries its own.
How it is built
cmake --preset linux-vcpkg configures it: vcpkg at ~/Software/vcpkg with
the x64-linux triplet, Qt at ~/Qt/6.10.3/gcc_64. HOST_QT_VERSION
(6.10.3) is compared with the Qt found; a difference warns, and is an error
under REPRODUCIBLE_BUILD, which the release workflow sets. CPack's TGZ
generator makes the tarball (cmake --build --preset linux-vcpkg-package).
release.yml builds the same
configuration on ubuntu-24.04, attests the tarball's provenance, and
attaches it to the draft release beside the Windows ZIP. Linux packages are
not signed.
How it is tested
host/tools/linux-package-test.sh runs in
a clean container holding only what a desktop has, and
- fails any ELF file in the package with a library
lddcannot find (which catches a too-old glibc as well) or aRUNPATHoutside the package, and a package without the OpenSSL TLS plugin, whichlddcannot catch; - runs each command line tool's
--help,tag-infowith no base (it must exit 1), anddataprocessingderiving streams from a fixture log; - runs each Qt application's documentation capture against
host/docs/fixtures-- everyqtmonitorfake tag, a recordedqtcalibratesession including its 3D orientation view,sensorvizlogs -- under Wayland (mutter --headless, GNOME's compositor) and X11 (Xvfb). Each must exit 0, write screenshots that are not blank, and print no plugin, library or QML loading failure.btvizandqtprogramhave no capture mode and must start and stay up.
linux-build-check.sh --package starts it in
a container of a chosen image; CI runs it on ubuntu:24.04 and debian:13
for every package and uploads only one that passes. From a Mac, OrbStack runs
the x86_64 containers under Rosetta.
Under Wayland the captures grab the application's own widgets, since compositors let no client read the screen, so the screenshots do not show window decorations; the test proves the decoration plugins load, not how they look. USB access through the udev rule cannot be tested in a container either. Both are checked once on a Linux desktop with a base attached.
The udev rule
host/linux/70-ultralight-tags.rules
gives the user at the seat access to the tag base and the other ST-LINK
probes isSTlink() accepts, with TAG+="uaccess". The number matters: the
tag is applied by systemd's 73-seat-late.rules, so the file must sort before
it. The package carries it in udev/; the README's install section and a
source build both point to it.