Skip to content

Building from source

Full prerequisites and first-time setup live on the installation page. This page covers the parts you need once you’re actually developing.

Six, from CMakePresets.json:

PresetBuild typeSanitizers
macos-debugDebugASan + UBSan
macos-releaseReleasenone
linux-debugDebugASan + UBSan
linux-releaseReleasenone
windows-debugDebugnone
windows-releaseReleasenone
Terminal window
cmake --preset macos-debug
cmake --build --preset macos-debug

Debug presets enable AddressSanitizer and UndefinedBehaviorSanitizer, which makes binaries noticeably slower but catches memory and UB bugs at the point they happen. Develop on debug; benchmark on release.

Terminal window
# Everything
ctest --test-dir build/macos-debug --output-on-failure
# In parallel
ctest --test-dir build/macos-debug -j $(sysctl -n hw.ncpu) --output-on-failure
# Engine only — fastest feedback loop
ctest --test-dir build/macos-debug --label-regex engine
# One test by name
ctest --test-dir build/macos-debug -R DependencyResolver

852 tests currently pass. A red suite on a clean checkout is a bug — please report it with your platform and compiler version.

build/macos-debug/
├── cli/reqloom the CLI
├── desktop/Reqloom.app the desktop app (macOS)
├── engine/ static library + object libraries
└── vcpkg_installed/ dependencies
Terminal window
./build/macos-debug/cli/reqloom --help
./build/macos-debug/desktop/Reqloom.app/Contents/MacOS/Reqloom

The engine must not acquire a Qt UI dependency. Two guards will stop you, and it’s worth knowing which one you’ve hit:

At configure time. cmake/ReqloomBoundaryGuards.cmake fails if the engine, CLI, or engine tests link Qt6::Widgets, Qt6::Gui, Qt6::Quick, Qt6::QuickWidgets, or QScintilla. You’ll see it as a CMake error before any compilation.

In CI. A grep job rejects #include <QWidget>, <QApplication>, or <Qsci…> under engine/ or cli/.

If you need to surface engine state in the UI, do it through engine/include/reqloom/engine/Events.h callbacks or by extending PublicApi.h. Don’t add a shared target that imports both worlds — see architecture.

When adding a new engine sub-target, add it to the reqloom_forbid_dependencies(...) loop in engine/CMakeLists.txt so the new target is covered too.

Source lists are explicit — there is no file(GLOB ...) anywhere, deliberately, so a new file can’t silently fail to build.

  1. Add the path to the right add_library(reqloom-engine-<layer> OBJECT ...) block in engine/CMakeLists.txt
  2. Add a unit test under engine/tests/unit/
  3. If it pulls in a new third-party, add it to vcpkg.json
Terminal window
tools/format.sh # clang-format over the tree

clang-tidy runs per .clang-tidy. Warnings are -Wall -Wextra -Wpedantic -Wconversion; -Werror is on in CI but not locally, so your build won’t break on a warning while you’re mid-change — CI will.

Wire it up once:

Terminal window
git config core.hooksPath tools/git-hooks

It runs tools/pre-push-check.sh — configure, build, tests, boundary check — which is roughly what CI does. Catching a failure locally is much faster than waiting for a CI round trip.

Terminal window
./tools/pre-push-check.sh # run it manually any time
git push --no-verify # skip it, when you have a reason

Qt comes from aqtinstall via tools/setup-qt.sh, not vcpkg. Building Qt from source through vcpkg added 45–90 minutes to a cold CI run and blew past job time limits, so the project doesn’t do it.

Terminal window
./tools/setup-qt.sh
export CMAKE_PREFIX_PATH="$HOME/Qt/6.8.3/macos" # or .../gcc_64 on Linux

QT_VERSION is pinned in tools/setup-qt.sh and in the CI workflows — keep them in sync if you bump it.

C++23 only. C++26 features are not portable across the three CI compilers and are rejected in review: reflection (^^T), contracts (pre/post), std::execution, std::inplace_vector, std::hive, = delete("reason").

Use C++23 freely — std::expected, std::print/std::println, deducing this, and the ranges additions (views::zip, views::enumerate, ranges::to) are all stable on Apple Clang 16, Clang 18, GCC 14, and MSVC 19.40.

New error paths return std::expected<T, ReqloomError>. Add a code to the existing ErrorCode enum rather than introducing a parallel error type — the enum is the QA contract.

PlatformRunner
Linux, WindowsGitHub Actions
macOSGitHub Actions

Both pin the same Qt version and run the same test suite. The docs site deploys separately from docs-site/** changes.

Build problems are covered on the installation page — missing CMake 4.0, Qt not found, stale vcpkg caches, and missing shared libraries.

Two more that only show up in development:

Sanitizer failure in an unrelated test. ASan reports where the corruption was detected, not always where it originated. Run the single failing test in isolation with ctest -R <name> --output-on-failure before assuming the cause.

Configure fails with a boundary error. You’ve linked a Qt UI target into the engine or CLI. Read the CMake error — it names the target and the forbidden dependency.