Genyleap/Docs
Stack Development Guide · C++

Modern C++ development.

A production-oriented C++26-first environment: project-owned modules, explicit error contracts, RAII, target-based CMake, Ninja and platform-native toolchains. C++23 remains the compatibility path when a required compiler or standard library is not ready for the selected C++26 feature set.

Primary C++26 Compatibility C++23 Build CMake 3.30+ · Ninja 1.11+ Targets Desktop · Mobile · Web

Engineering baseline.

AreaDefaultRule
LanguageC++26Prefer the current language path; use C++23 when concrete toolchain support requires it.
Project boundariesC++ modulesNew project-owned production boundaries use .cppm modules by default.
Standard libraryMinimal headersUse normal standard headers in the global module fragment; do not depend on experimental import std;.
Errorsstd::expectedMake recoverable failure part of the API contract instead of hiding it behind sentinel values.
Console outputstd::print / std::printlnPrefer C++23 formatted output over new iostream insertion chains.
Build modelTarget-based CMakeKeep compile features, sources, definitions and dependencies attached to owning targets.
GeneratorNinjaUse separate build trees per compiler, configuration and target.

Start with modules, not headers.

Project-owned boundaries should communicate responsibility directly. Export declarations from module interfaces, keep non-trivial implementation in implementation units, and isolate platform or third-party code at explicit adapter boundaries.

C++ module interfacesrc/greeting/greeting.cppm
module;

#include <expected>
#include <string>
#include <string_view>

export module genyleap.greeting;

export namespace genyleap::greeting {

enum class GreetingError {
    EmptyName
};

[[nodiscard]] auto makeGreeting(std::string_view name)
    -> std::expected<std::string, GreetingError>;

}
C++ implementation unitsrc/greeting/greeting.cpp
module;

#include <expected>
#include <format>
#include <string>
#include <string_view>

module genyleap.greeting;

namespace genyleap::greeting {

auto makeGreeting(std::string_view name)
    -> std::expected<std::string, GreetingError>
{
    if (name.empty()) {
        return std::unexpected {GreetingError::EmptyName};
    }

    return std::format("Hello, {}.", name);
}

}
Composition rootsrc/main.cpp
#include <print>

import genyleap.greeting;

int main()
{
    const auto greeting = genyleap::greeting::makeGreeting("Genyleap");

    if (!greeting) {
        std::println("Unable to create greeting.");
        return 1;
    }

    std::println("{}", *greeting);
    return 0;
}

Target-based CMake with module scanning.

Keep the language standard, module file set and dependency graph on the target. Do not fall back to global compiler flags or project-wide include directories to simulate classic header architecture.

CMakeCMakeLists.txt
cmake_minimum_required(VERSION 3.30)

project(GenyleapHello
    VERSION 0.1.0
    LANGUAGES CXX
)

add_library(genyleap_greeting)

target_compile_features(genyleap_greeting
    PUBLIC
        cxx_std_26
)

target_sources(genyleap_greeting
    PUBLIC
        FILE_SET CXX_MODULES
        FILES
            src/greeting/greeting.cppm
    PRIVATE
        src/greeting/greeting.cpp
)

set_property(
    TARGET genyleap_greeting
    PROPERTY CXX_SCAN_FOR_MODULES ON
)

add_executable(genyleap_hello
    src/main.cpp
)

target_link_libraries(genyleap_hello
    PRIVATE
        genyleap_greeting
)

target_compile_features(genyleap_hello
    PRIVATE
        cxx_std_26
)
ShellConfigure · build · test
cmake -S . -B build/dev -G Ninja \
  -DCMAKE_BUILD_TYPE=Debug

cmake --build build/dev --parallel

ctest --test-dir build/dev \
  --output-on-failure \
  --no-tests=error

Platform toolchains.

The C++ architecture stays portable; the compiler, SDK, linker, packaging and runtime remain explicit platform boundaries. Never reuse a configured CMake tree after switching compilers or target SDKs.

macOS.

Install full Xcode for the Apple SDK and platform tools. Apple Clang is the default native compiler; upstream LLVM can live beside it when newer compiler features or diagnostics are required.

ShellInstall and verify
sudo xcode-select --switch /Applications/Xcode.app
sudo xcodebuild -license accept

brew install cmake ninja llvm

xcrun clang++ --version
cmake --version
ninja --version
xcrun --show-sdk-path
Do not globally replace Apple Clang.

Select upstream LLVM per build when needed; Apple SDK integration and upstream language experimentation are separate concerns.

Linux.

Keep both GCC and Clang available when portability matters. Configure a separate build directory for each compiler and verify module support with the actual CMake/compiler/generator combination instead of inferring support from version numbers alone.

ShellUbuntu / Debian baseline
sudo apt update
sudo apt install -y \
  build-essential \
  clang \
  lld \
  cmake \
  ninja-build \
  gdb
ShellSeparate compiler builds
cmake -S . -B build/gcc -G Ninja \
  -DCMAKE_CXX_COMPILER=g++

cmake -S . -B build/clang -G Ninja \
  -DCMAKE_CXX_COMPILER=clang++

Windows.

Use Visual Studio Build Tools with the C++ workload for the Windows SDK and MSVC ABI. Add LLVM when you want clang-cl diagnostics while retaining MSVC-compatible platform integration.

PowerShellInstall toolchains
winget install --id Microsoft.VisualStudio.2022.BuildTools `
  --override "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"

winget install --id Kitware.CMake
winget install --id Ninja-build.Ninja
winget install --id LLVM.LLVM
Use Developer PowerShell.

The MSVC compiler, linker and Windows SDK environment must be initialized before configuring CMake.

Android.

Use the Android NDK's Clang toolchain and CMake toolchain file rather than treating Android as a normal Linux desktop build. For projects that also use the current Qt baseline, the compatibility manifest currently resolves NDK r27c (27.2.12479018).

CMakeNative Android shape
cmake -S . -B build/android-arm64 -G Ninja \
  -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" \
  -DANDROID_ABI=arm64-v8a \
  -DANDROID_PLATFORM=android-28

cmake --build build/android-arm64 --parallel

Keep Android-specific JNI, lifecycle, storage and permission code behind adapters so the domain and application modules remain ordinary C++.

iOS.

Use Xcode 16 or newer for the current Qt compatibility profile, and treat Apple frameworks, entitlements, signing and bundle resources as platform boundaries. Device and simulator builds are distinct targets even when they share application modules.

ShellInspect active Apple SDKs
xcodebuild -version
xcrun --sdk iphoneos --show-sdk-path
xcrun --sdk iphonesimulator --show-sdk-path
xcrun --sdk iphoneos clang++ --version

WebAssembly.

Use Emscripten when the target runtime is the browser. For the current Qt compatibility profile, Emscripten 5.0.5 is pinned automatically from upstream Qt documentation; a standalone C++/WASM project may intentionally choose a newer SDK after its own verification.

POSIX shellPin an emsdk toolchain
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk

./emsdk install 5.0.5./emsdk activate 5.0.5
source ./emsdk_env.sh
em++ --version
PowerShellWindows activation
git clone https://github.com/emscripten-core/emsdk.git
Set-Location emsdk

.\emsdk.bat install 5.0.5.\emsdk.bat activate 5.0.5
.\emsdk_env.ps1
em++ --version

Browser threading, SIMD, filesystem access and network behavior are runtime constraints, not merely compiler switches. Model them as target capabilities and verify them in the browser configuration you will ship.

Diagnostics are part of the development environment.

Compile-time correctness is only one layer. Keep sanitizer and static-analysis builds available from the start rather than adding them after a hard-to-reproduce failure appears.

ToolUseRecommendation
ASanMemory safety failuresDebug and CI where supported
UBSanUndefined behaviorPair with ASan in a dedicated diagnostic build
TSanData racesSeparate build because instrumentation changes runtime behavior
clang-tidyStatic analysis and modernizationEditor plus CI on changed production surfaces
CMakeTarget-local sanitizer example
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
    target_compile_options(genyleap_greeting PRIVATE
        -fsanitize=address,undefined
        -fno-omit-frame-pointer
    )

    target_link_options(genyleap_greeting PRIVATE
        -fsanitize=address,undefined
    )
endif()

Boost is part of the native foundation.

Use the C++ standard library first when it cleanly provides the required facility, then use Boost for capabilities that remain stronger or broader there. Keep Boost dependencies target-local, architecture-specific when compiled, and visible through modern CMake imported targets.

User-facing applications: move into Qt deliberately.

For a new graphical Genyleap-style application, the default interface stack is Qt Quick, QML and Qt Quick Controls over module-based C++ application/domain code. The UI is an adapter; it does not own duplicated business logic.