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.
Install — apt (recommended)
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-devlibraries 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-devA convenient shortcut is to
apt installthe apt Qt-devpackages anyway (above) purely to pull in the transitive system libraries — you can still point the qbs profile at your~/Qtqmake.
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
~/Qtinstaller tree, the project's own probe may pick one while this profile names the other. The failure is loud but misleading: hundreds of lines ofproduct '<lib>' is disabledandDependency 'Qt.bluetooth' not found, because the apt Qt carries fewer optional modules.qbs resolveprints the Qt it chose on its third line — check it against this profile, and re-runsetup-qtif they disagree.
baseProfileis not optional either:setup-qtcreates 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.1becomes0.1.4~rc.1. dpkg reads a hyphen as the start of the Debian revision, so0.1.4-rc.1would sort above the final0.1.4and the release would count as a downgrade. The file name keeps the version as given. -
Depends.
dpkg-shlibdepsworks this out from the shipped binaries.Packaging.fallbackDependsis 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/constructThe unambiguous command /usr/bin/korall-constructLauncher, icon, AppStream id, Wayland app id io.korall.constructSettings and data ~/.config/Korall/…, from the edition's organizationThe bare
constructcommand is anupdate-alternativeslink. The edition installed first owns it, andsudo update-alternatives --config constructswitches it. Hub findsagentandremotenext 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, whichupdate-alternativeswill not replace. New packages therefore declareBreaks: <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 exampleorg.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.
Slow link
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-debstill packagesconstructthroughintegration/cicd/libs/make_deb.sh, installing into/usr/local/bin, which a Debian package must not use. Release packages come fromoctomy-deb; retire that target or make it callqbs 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
- Build for Android — Cross-compile to Android targets
- Build for Windows (MSVC) — Native MSVC build
- Qbs Build System — Build system internals