Build for Linux desktop

Compile OctoMY natively on Debian/Ubuntu

Build for Linux desktop

Compile OctoMY natively on a Debian/Ubuntu workstation. This is the primary development target — toolchain support is most mature here.

Target: Debian 13 (trixie) amd64. Ubuntu 24.04 LTS also works without changes; older releases need a newer Qt from the Qt installer or aqtinstall.


Status

Item State Notes
Build infrastructure ✅ Mature Native qbs + Qt6 from apt or Qt installer
Source portability ✅ Full This is the development reference platform
Packaging (.deb) ✅ Working qbs build -p octomy-deb, all apps, plus a -dbgsym package

Prerequisites

This list is derived from building the project on a vanilla Debian 13 (trixie) amd64 install — everything below is something a clean machine was missing. Items are split into mandatory (the build fails without them) and optional (feature- or variant-specific).

Mandatory — build toolchain

Component Version Debian package(s) Notes
Qt 6.10.0+ see Qt module set below Declared in integration/toolchain-requirements.json and read by project.qbs as minimumQtVersion. Required for xdg_toplevel_icon_v1 (window icons on KDE Wayland), QRhiTexture::R32UI (construct GBuffer) and Q_STATIC_LOGGING_CATEGORY. Debian 13 ships 6.8.2, which is below the floor — use the Qt online installer.
Qbs 3.3.1+ none — build from source The floor is declared in integration/toolchain-requirements.json and enforced by project.qbs. No distro ships it, and Debian 13's 2.6.1 is on the knownBad list. See Qbs from source.
Compiler GCC 12+ build-essential C++20
mold any mold Required for the default (debug) build — project.useMoldLinker defaults to true, so debug links pass -fuse-ld=mold. Either install mold or build with project.useMoldLinker:false.

Mandatory — system libraries

These are linked unconditionally on Linux and are the ones most often missing when Qt itself was installed from the Qt online installer (the apt Qt -dev packages pull most of them in transitively; a hand-installed ~/Qt does not — see the tip below).

Library Debian package Why it's needed
libudev libudev-dev libserial includes <libudev.h> and links udev for serial-port enumeration on Linux (non-Android). Build fails at Udev_p.hpp without it.
OpenGL libgl1-mesa-dev Qt's OpenGL module and several tools link -lGL; the runtime libGL.so.1 is not enough — the -dev package provides the libGL.so linker symlink.
GLU libglu1-mesa-dev -lGLU for legacy GL utility entry points pulled in by the GL stack.

Optional — variant / feature specific

Component Debian package When you need it
lld lld Release builds only — config:release with project.enableLto:true (the default) links with -fuse-ld=lld for LTO. Not used by debug builds.
Vulkan libvulkan-dev Qt RHI Vulkan backend.
clang clang Only if you switch the toolchain to clang. GCC is the configured/default toolchain; clang is not required to build.

Qbs from source

qbs resolve on a stock Debian box stops immediately with qbs 2.6.1 is below the minimum 3.3.1 this build definition requires. That is the check working: 2.6.1's parallel scheduler SIGSEGVs on the android multi-arch graph, and the knownBad entry records which jobs it killed.

Two build dependencies fail configure in ways that do not obviously name themselves:

sudo apt install cmake ninja-build qt6-base-private-dev qt6-5compat-dev
# without qt6-base-private-dev:  Imported target "Qt6::CorePrivate" includes non-existent path
# without qt6-5compat-dev:       Could NOT find Qt6Core5Compat
curl -sLO https://download.qt.io/official_releases/qbs/3.3.1/qbs-src-3.3.1.tar.gz
tar xf qbs-src-3.3.1.tar.gz
cmake -S qbs-src-3.3.1 -B b -GNinja -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_PREFIX_PATH=/usr -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_TESTS=OFF
cmake --build b -j"$(nproc)" && sudo cmake --install b
which -a qbs && qbs --version      # /usr/local/bin/qbs must come first

Building against the distro Qt (-DCMAKE_PREFIX_PATH=/usr, as above) keeps qbs independent of what you install or remove under ~/Qt later, and needs no rpath flags. If you build it against a ~/Qt tree instead, add -DCMAKE_INSTALL_RPATH=<QtDir>/lib -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON or the installed binary picks up the distro Qt at runtime and dies with version 'Qt_6.10' not found.

Installing the apt Qt -dev packages is the simplest way to get a working build, because they drag in the mandatory system libraries (libgl1-mesa-dev, libudev-dev, etc.) as transitive dependencies:

sudo apt install \
    qt6-base-dev qt6-base-dev-tools \
    qt6-svg-dev qt6-tools-dev qt6-tools-dev-tools \
    qt6-shadertools-dev qt6-declarative-dev \
    libqt6opengl6-dev libqt6openglwidgets6 \
    libqt6sql6-sqlite libqt6printsupport6 libqt6dbus6 \
    qbs build-essential mold libvulkan-dev \
    libudev-dev libgl1-mesa-dev libglu1-mesa-dev
# Optional: release/LTO linker
sudo apt install lld

Tip — using Qt from the Qt online installer (~/Qt)? The installer ships Qt itself but not the system -dev libraries the link step needs. Install at least the mandatory system libraries with apt even when you build against ~/Qt:

sudo apt install build-essential mold libudev-dev libgl1-mesa-dev libglu1-mesa-dev libvulkan-dev

A convenient shortcut is to apt install the apt Qt -dev packages anyway (above) purely to pull in the transitive system libraries — you can still point the qbs profile at your ~/Qt qmake.


One-time profile setup

qbs setup-toolchains --detect
qbs setup-qt /usr/lib/qt6/bin/qmake qt6      # or <QtDir>/bin/qmake6 for a ~/Qt tree
qbs config profiles.qt6.baseProfile x86_64-linux-gnu-gcc-14
qbs config defaultProfile qt6

Point the profile at the Qt the project actually resolves against. If you have both an apt Qt and a ~/Qt installer tree, the project's own probe may pick one while this profile names the other. The failure is loud but misleading: hundreds of lines of product '<lib>' is disabled and Dependency 'Qt.bluetooth' not found, because the apt Qt carries fewer optional modules. qbs resolve prints the Qt it chose on its third line — check it against this profile, and re-run setup-qt if they disagree.

baseProfile is not optional either: setup-qt creates a Qt-only profile and says so in a message that is easy to scroll past. Without a toolchain base profile the build has no compiler.

Verify:

qbs config --list profiles.qt6 | head -5

Build and run

Use the helper script for the common case:

# Build everything in the default profile
qbs build -f project.qbs

# Build a single product
qbs build -p hub
qbs build -p agent
qbs build -p construct

Output lands under default/install-root/usr/local/bin/.

Release build

qbs build -f project.qbs config:release

Build parameter overrides

Parameter Default Description
project.enableLto true Link-time optimization (GCC/Clang/MSVC)
project.useMoldLinker true Use mold instead of ld (Linux only)
project.securityHardening true Stack protector, FORTIFY_SOURCE, PIE
project.treatWarningsAsErrors true -Werror

Feature gating via oc_use.json

Drop an oc_use.json file in the project root to disable expensive features. Templates live in integration/oc_use_examples/. Useful when iterating on unrelated code:

cp integration/oc_use_examples/oc_use_minimal.json oc_use.json
qbs build -p hub

Packaging (.deb)

qbs build -p octomy-deb turns the built apps into two Debian packages (integration/qbs/packaging.qbs, text helpers in integration/qbs/imports/debian.js):

File Contents
<base>_<version>_<arch>.deb Stripped executables in /usr/lib/<base>/bin, <base>-<app> commands, one launcher, icon and AppStream metainfo per GUI app, copyright, changelog.gz, md5sums
<base>-dbgsym_<version>_<arch>.deb Split debug info under /usr/lib/debug/.build-id/, which gdb finds with no configuration
qbs resolve config:release project.packageVersion:0.1.4-rc.1
qbs build config:release -p octomy-deb
sudo apt install ./default/octomy-deb.*/octomy_0.1.4-rc.1_amd64.deb

Install the -dbgsym package too when you want symbols for an installed build. Install the main package with apt install ./file.deb rather than dpkg -i, because apt resolves the dependencies and the conflicts described below.

What the package declares

  • Version. A SemVer pre-release is written with a tilde: 0.1.4-rc.1 becomes 0.1.4~rc.1. dpkg reads a hyphen as the start of the Debian revision, so 0.1.4-rc.1 would sort above the final 0.1.4 and the release would count as a downgrade. The file name keeps the version as given.

  • Depends. dpkg-shlibdeps works this out from the shipped binaries. Packaging.fallbackDepends is used only when shlibdeps names no Qt package.

  • Editions install side by side. OctoMY and Korall builds of the same app can be installed at once. On Windows, each edition gets its own Program Files\<Organization> folder; on Linux, each package keeps to its own paths:

    Path Example
    Binaries, under their own names /usr/lib/korall/bin/construct
    The unambiguous command /usr/bin/korall-construct
    Launcher, icon, AppStream id, Wayland app id io.korall.construct
    Settings and data ~/.config/Korall/…, from the edition's organization

    The bare construct command is an update-alternatives link. The edition installed first owns it, and sudo update-alternatives --config construct switches it. Hub finds agent and remote next to its own binary, which is why the binaries keep their unprefixed names.

    Edition packages from before this layout owned /usr/bin/<app> as real files, which update-alternatives will not replace. New packages therefore declare Breaks: <other edition> (<< 0.1.4~), and apt upgrades or removes the old package first.

  • Icons come from the edition's branding qrc (logo.svg, window/<app>.svg), not from a fixed file.

  • AppStream ids are project.androidPackagePrefix + app name, for example org.octomy.construct.

  • Maintainer scripts only manage the alternatives. The desktop-file-utils and hicolor-icon-theme triggers refresh the menu and icon caches.

The build validates the metainfo with appstreamcli and the launchers with desktop-file-validate, and fails on an error. If either tool is missing, it prints a warning. lintian runs when installed; it reports problems but never fails the build.

Warnings that mean "not distributable"

octomy-deb: WARNING: construct loads Qt from /home/you/Qt/6.11.1/gcc_64/lib/libQt6Core.so.6,
which no Debian package owns. This .deb runs only where that tree exists; it is not distributable.

This is expected when you build against a Qt installer tree and install the package on the same machine. shlibdeps still maps the sonames to the distribution's Qt packages, so Depends names a Qt the binary was not built against. For a package meant for other machines, build against the distribution Qt (qt6-*-dev).

What a software centre shows

Discover and GNOME Software get an app's long description, license and screenshots from AppStream metadata. Where they find it depends on how the package reaches the user:

Situation Source What is shown
A downloaded .deb opened in Discover PackageKit's GetDetailsLocal The control Description, the homepage and the size. License shows as unknown, because apt packages carry no license field. The package's metainfo is not read at this stage.
The app after installation /usr/share/metainfo/*.metainfo.xml Name, summary, description, license, screenshots, releases
An apt repository DEP-11 data from appstream-generator Everything, before installation

The complete page before installation therefore needs an apt repository published with DEP-11 metadata. Screenshots need public, stable URLs in Packaging.screenshots.

Headless verification

The packaged binary must work without a display server:

construct --version -platform offscreen

Troubleshooting

qbs: command not found

Install qbs (Debian 13) or use the bundled binary from a Qt installer (~/Qt/Tools/QtCreator/bin/qbs).

Module 'Qt.<name>' not found

A Qt component is missing. Match the module name to its -dev package — e.g. Qt.svgwidgets → qt6-svg-dev.

Confirm mold is in use:

qbs build -p hub --command-echo-mode command-line 2>&1 | grep fuse-ld

If not, install mold and set project.useMoldLinker:true.

glsl shader compilation failed

qt6-shadertools-dev is missing or the wrong version. The project requires QShaderTools matching the runtime Qt version.


Remaining work

Tracked tasks for a production-quality Linux build:

  • [ ] apt repository with DEP-11: needed for Discover to show the description, license and screenshots before installation.
  • [ ] AppImage / Flatpak: No portable distribution format is supported.
  • [ ] Reproducible builds: the package stamps file times, the changelog and the AppStream release with the commit date, but the binaries themselves are not yet checked for bit-for-bit reproducibility.
  • [ ] A second .deb path: integration/cicd/targets/linux-deb still packages construct through integration/cicd/libs/make_deb.sh, installing into /usr/local/bin, which a Debian package must not use. Release packages come from octomy-deb; retire that target or make it call qbs build -p octomy-deb.

Builds run at low priority

Every process this build starts — compiler, linker, shader baker, help generator — is launched through nice -n 19, so compiling does not make the machine unusable while you work. Priority is inherited, so the whole process tree is covered.

A contended build therefore takes longer; on an idle machine there is no difference. It covers the processor only — a heavy link can still make the disk busy, and ionice does nothing on an NVMe device using the none scheduler.

To turn it off for an unattended batch build, or to make it stronger, see Build priority. The mechanism is one line.

A build through the kiln queue gets the same effect without the prefix: the broker lowers the priority of every job it starts, and of everything that job starts.

See also

Topics
howto linux debian build packaging
See also