Skip to content

Build System and CMake Modules

github-actions[bot] edited this page Oct 18, 2026 · 56 revisions

Build System and CMake Modules

SparkEngine uses CMake 3.25+ as its build system with documented options, cross-platform presets, and CI/CD integration.

Source: CMakeLists.txt, cmake/, CMakePresets.json, Tools/buildmatrix/

Release boundary: Presets and compiler paths document configuration coverage, not certification. Only Windows 11 x64 with MSVC v143 is declared in stable-v1, and that profile remains blocked and uncertified. Linux, macOS, MinGW/Wine, other compiler lines, and non-D3D11 graphics paths stay outside it.

CMake Configuration

Minimum Requirements

  • CMake 3.25+
  • C++23 standard (enforced via cxx_std_23, no extensions)
  • CMP0091 policy for consistent MSVC runtime library selection

Native compiler metadata is build-directory state. Keep a build directory tied to one CMake executable, generator, compiler, and toolset; never configure it concurrently or switch CMake installations in place. If any of those inputs change, use a new directory or cmake --fresh so compiler ABI and feature detection run again. The supported Windows preset selects Visual Studio 17 2022, x64, and v143, but does not pin CMake/MSVC/Windows SDK patch versions.

Quick Configuration

# Windows (Visual Studio 2022)
.\generate.bat -g "Visual Studio 17 2022" release

# Linux (Ninja)
./generate.sh release -g Ninja

# Direct CMake
cmake -B build -G "Visual Studio 17 2022" -A x64 -T v143

# Using presets (recommended)
cmake --fresh --preset windows-release
cmake --build --preset windows-release

Configuration Flow

cmake -B build [options]
    │
    ├── Check CMake version (>= 3.25)
    ├── Set C++23 standard (no extensions)
    ├── Apply CMP0091 policy (MSVC runtime)
    │
    ├── Evaluate declared CMake options
    │   ├── consumed options alter definitions, dependencies, or selected targets
    │   └── inert cache variables do not remove a subsystem (tracked by HEAD-220)
    │
    ├── Detect platform and compiler
    │   ├── MSVC → /W4, MSVC runtime selection
    │   ├── GCC  → -Wall -Wextra
    │   └── Clang → -Wall -Wextra
    │
    ├── Configure targets (SparkEngineLib, SparkEngine, SparkGame, ...)
    ├── Include component libraries (cmake/SparkComponentLibraries.cmake)
    ├── Configure tests (if BUILD_TESTS=ON)
    └── Generate build files

Selected Root Build Options

Only options declared and consumed by the current root CMakeLists.txt have a proven build effect. The table below intentionally avoids undocumented pseudo-options.

Undeclared options fail configure (CI-120). The last command of the root CMakeLists.txt is spark_reject_undeclared_options() from cmake/SparkOptionGuard.cmake. Any ENABLE_*, SPARK_* or BUILD_* cache entry that is still UNINITIALIZED after the whole tree has configured -- i.e. it was passed as an untyped -DNAME=VALUE (or a preset string value) and nothing ran option()/set(... CACHE ...) for it -- stops configure with a FATAL_ERROR listing each name and the cmake -U NAME <build-dir> command to drop it. A typo such as -DENABLE_EDTIOR=OFF, or an option that only exists on another platform, can therefore no longer configure "successfully" with the default feature set. Explicitly typed entries (-DNAME:BOOL=ON, or a preset boolean/typed value) are checked too: spark_capture_cli_options(), the first command after cmake_minimum_required(), returns every guarded entry that still carries CMake's command-line helpstring to UNINITIALIZED, so option() adopts it like an untyped entry and an undeclared one reaches the final check. Options that are declared but never read (no if(), ${}, generator expression, forwarded -D or configure_file template consumes them) are reported by Tools/buildmatrix/check_parity.py as the blocking declared-option-unread finding (the inert ENABLE_GRAPHICS was deleted on that basis). Options that must be accepted on every platform are declared unconditionally: SPARK_REQUIRE_WINDOWS_INSTALLERS (SparkBuild passes it everywhere; ON off Windows is itself fatal) and the explicit SPARK_MODULE_CXX_LANGUAGE_ABI override (declared by cmake/SparkGameModule.cmake). Tests/Tools/test_build_option_guard.py (CTest BuildOptions_UnknownOptionRejected) configures a fixture project through the real module (typed and untyped -D entries, and a typed preset) and audits every cache variable in CMakePresets.json against the tree's declarations.

Option Root default Source-backed effect when disabled
ENABLE_VULKAN ON Disables Vulkan discovery and omits SPARK_VULKAN_SUPPORT; root source glob remains
ENABLE_OPENGL ON Disables OpenGL discovery/enablement; verify host context separately
ENABLE_METAL ON on Apple, OFF elsewhere Omits Metal enablement on Apple development builds
ENABLE_DXR ON Skips DXR shader compilation and hardware-RT definition setup
ENABLE_HYBRID_RT ON Omits SPARK_HYBRID_RT and its hardware-RT definition setup
ENABLE_NETWORKING ON Omits networking definition/libraries from SparkEngineLib; service targets use ENABLE_SERVER_PROCESSES
SPARK_HEADLESS_SUPPORT ON Omits the compile definition; host entry sources are still listed
ENABLE_EDITOR ON Omits the SparkEditor target
BUILD_TESTS ON Omits test targets
BUILD_GAME_MODULES ON Omits in-tree game-module targets

Reduced Development Preset

The minimal preset disables networking, DXR, and the optional tool and module targets. Every preset cache variable is a declared root option (the option guard rejects anything else), but disabling them does not remove the graphics/RHI sources, so this is not a core-only build contract. Disable declared targets such as the editor explicitly when needed; HEAD-220 tracks a true stripped/headless configuration.

cmake --preset minimal
cmake -B build -DENABLE_EDITOR=OFF

Headless / Software Rendering Build (Linux)

Build with OpenGL enabled for CPU-based software rendering via Mesa llvmpipe:

# Install dependencies
sudo apt-get install -y libgl-dev libx11-dev

# Configure with OpenGL backend
cmake -B build -DENABLE_OPENGL=ON -DBUILD_TESTS=ON

# Build
cmake --build build --config Release

# Run with software rendering (no GPU required)
Xvfb :99 -screen 0 1024x768x24 &
DISPLAY=:99 LIBGL_ALWAYS_SOFTWARE=1 ./build/bin/SparkEngine

The GLAD OpenGL loader is bundled in ThirdParty/glad/. A bare RHIFactory::CreateDevice call does not retry a failed backend, but runtime RHIBridge::Initialize retries its available GPU candidates after device or swap-chain setup fails and creates NullRHIDevice only after all candidates fail. That no-render resilience path is in stable-v1 only on Windows 11 x64; other hosts are uncertified.

Third-Party Manifest + Configure-Time Audit

SparkEngine now tracks third-party dependency metadata in ThirdParty/dependencies.lock (single source of truth).

Each manifest row declares:

  • dependency name + upstream source URL/repo,
  • exact pinned version/tag/commit,
  • license,
  • local path,
  • fallback/shim behavior (SPARK_HAS_* macro + stub/fallback path).

cmake/SparkThirdPartyAudit.cmake is invoked from root CMakeLists.txt early in configure and:

  • validates required files exist for each declared dependency,
  • prints source/version/license summary during configure,
  • warns on manifest mismatches; with -DSPARK_STRICT_DEPS=ON every locked entry is required and any missing dependency or pin mismatch fails configure (see ThirdParty Dependencies Audit).

CI enforces manifest hygiene via tools/check-thirdparty-manifest-sync.sh: dependency path/URL/version wiring changes must include a matching ThirdParty/dependencies.lock update.

MSVC Toolset Selection

cmake -G "Visual Studio 17 2022" -A x64 -T v143 ...  # VS 2022
cmake -G "Visual Studio 18 2026" -A x64 ...          # VS 2026 (v145 default)

Toolset and platform are generator inputs; select them with -T/-A or the preset toolset/architecture fields, not project cache variables.

CMake Presets

CMakePresets.json provides ready-made configurations:

Preset availability is configuration coverage, not release certification. The Windows 11 x64/v143 line is the only toolchain family in stable-v1, which remains blocked; Linux and MinGW/Wine rows are development paths outside the profile.

Preset Generator Compiler Config Notes
windows-debug VS 2022 MSVC Debug Full features
windows-release VS 2022 MSVC Release Full features
linux-gcc-debug Ninja GCC Debug Full features
linux-gcc-release Ninja GCC Release Full features
linux-clang-debug Ninja Clang Debug Full features
linux-clang-release Ninja Clang Release Full features
ci-linux-asan Ninja GCC Debug AddressSanitizer + UBSan
ci-linux-tsan Ninja GCC Debug ThreadSanitizer
linux-mingw-release Makefiles MinGW-w64 Release Cross-compile the Windows D3D11 path; D3D12/DXR are excluded; run under Wine
linux-mingw-debug Makefiles MinGW-w64 Debug Cross-compile the Windows D3D11 path; D3D12/DXR are excluded; run under Wine
minimal Default Default Release Core runtime with optional tools, modules, scripting, networking, and experimental rendering breadth disabled
# List available presets
cmake --list-presets

# Configure and build with a preset
cmake --preset windows-release
cmake --build --preset windows-release

Documented commands are checked against the presets

Every preset writes build/<preset>, and the Visual Studio presets are multi-config, so a tree built or tested without --config/-C produces Debug. tools/site-data/documented_commands.py (run by tools/site-data/validate.py and the BuildOptions_DocumentedCommandsMatchPresets CTest) resolves every cmake/ctest/cpack command in the shell code blocks and inline code spans of every root-level Markdown page (README.md, CLAUDE.md, TROUBLESHOOTING.md, CONTRIBUTING.md, AGENTS.md, ...), wiki/, docs/, .github/prompts/, the Copilot instructions, the .claude/skills/ and .codex/skills/ runbooks, and the Markdown under SparkBuild/, SparkSDK/, FuzzerTests/, GameModules/ and Templates/ against CMakePresets.json. A cd is followed: cd MyGame then cmake -B build configures MyGame/build, not the root build, and cd into the directory a documented git clone created is the repository root. It fails when:

  • --preset names no visible preset of that family;
  • a build, install, test or package tree (cmake --build/--install, ctest, cpack --config <tree>/CPackConfig.cmake, or the directory a cd entered) is neither a preset binaryDir nor configured earlier in the document with -B or a repository configure script (generate.sh, generate.bat, build.sh and build.ps1 all configure build);
  • a block that configured presets then uses any other tree, including another preset's (the classic cmake --preset <name> then cmake --build build);
  • an ad-hoc -B configure writes into a preset's tree;
  • a multi-config preset tree omits its preset's configuration (a preset with no generator counts as multi-config unless its condition pins a non-Windows host, because Visual Studio is the Windows default), or any stated configuration differs from it. cmake --install and cpack default a multi-config tree to Release, so they may omit it only for a Release preset; --build and ctest default to Debug;
  • an ad-hoc configure with a generator the presets use omits the -A/-T values those presets pin (-A x64 -T v143 for VS 2022; -T v143,host=x64 states the same toolset). A generator no preset uses has no pin to compare.

Placeholders (<preset>, $VAR, ~) and absolute paths are skipped. Generated pages (docs/api/, wiki/reference/, the readiness handoff), dated plans under docs/superpowers/ and the CHANGELOG.md history are out of scope.

Configured-target build-matrix evidence

The build-matrix tooling uses CMake File API replies to prove which targets a concrete build profile actually configured. The capture command creates a unique stateful File API query, invokes the canonical configure itself, and records only the matching reply transaction before inventory generation:

python3 Tools/buildmatrix/capture_provenance.py \
  --profile windows-shipping \
  --build-dir build/windows-shipping
python3 Tools/buildmatrix/inventory.py \
  --codemodel windows-shipping=build/windows-shipping \
  --output docs/readiness/build-matrix-inventory.json
python3 Tools/buildmatrix/check_parity.py \
  --inventory docs/readiness/build-matrix-inventory.json \
  --baseline docs/readiness/build-matrix-parity-findings.json

The capture step requires an exactly clean repository, derives the commit itself, creates the query before configuring, and binds the profile, source/build directories, CMake executable and version, generator, cache values, and exact index/codemodel/cache/target reply digests. Inventory rejects missing, malformed, oversized, linked, out-of-directory, changed, unbound, or post-hoc reply data. Caller-supplied commit text is not provenance, and missing material fields or expected cache values remain blocking findings.

The local record detects reply substitution but cannot authorize itself. The Windows Shipping build matrix job records that evidence and succeeds; it never attests anything. The Build Matrix Verifier workflow (.github/workflows/build-matrix-verifier.yml) runs afterwards from the exact current Working default-branch checkout, binds one successful source run/job/artifact through the Actions API, downloads by immutable artifact ID with digest mismatch failure, reparses the File API replies as bounded data, rehashes every declared product, reconstructs the inventory and parity report with trusted code, attests only the resulting verified receipt, and posts the Build Matrix Verifier / Exact Source commit status. Work item CI-120 stays open until a verifier run on Working proves this path end to end.

Cross-Compilation: Windows on Linux (MinGW + Wine)

The repository can cross-compile Windows D3D11 code paths on a Linux host using MinGW-w64 for development evaluation. The resulting .exe files run under Wine, with DXVK translating D3D11 calls to Vulkan (or WineD3D as fallback). Combined with Mesa Lavapipe, this exercises D3D11 paths without a GPU; it does not certify D3D11 or a Linux host for stable-v1.

Full guide: See Cross-Compilation: Wine Testing for complete setup, troubleshooting, and the automated test suite.

Quick Start

# 1. Install prerequisites
sudo apt-get install mingw-w64 wine64 mesa-vulkan-drivers

# 2. Install DirectXMath headers (MinGW doesn't ship them)
# See the full guide for download instructions
sudo cp DirectX*.h DirectX*.inl /usr/x86_64-w64-mingw32/include/

# 3. Build
cmake --preset linux-mingw-release
cmake --build build/linux-mingw-release --parallel $(nproc)

# 4. Run tests under Wine
tools/wine-run.sh build/linux-mingw-release/bin/SparkTests.exe

# 5. Run automated test suite (7 phases)
python3 tools/test-windows-wine.py --build-dir build/linux-mingw-release

What Gets Built

5 Windows executables + game module DLLs: SparkEngine.exe, SparkEditor.exe, SparkTests.exe, SparkConsole.exe, SparkShaderCompiler.exe

Key Differences from MSVC

  • D3D12 excluded (MinGW headers too old for ID3D12Device5/DXR)
  • D3D11 paths exercised under Wine + DXVK; this is outside stable-v1 and not certification
  • DirectXMath must be installed manually to the MinGW sysroot
  • -municode required for wWinMain Unicode entry point

Key Files

File Purpose
cmake/toolchains/mingw-w64-x86_64.cmake CMake toolchain for MinGW cross-compilation
tools/wine-run.sh Wine runner with DXVK/VKD3D-Proton auto-setup
tools/test-windows-wine.py Automated 7-phase Wine test suite
CMakePresets.json linux-mingw-release / linux-mingw-debug presets

Development Software/No-Render Routes and Bridge Fallback

The routes below are configuration/development paths, not universal host certification. RHIBridge::Initialize tries the available GPU candidates in order after device or swap-chain failure, then creates NullRHIDevice if none succeeds; the bare RHIFactory::CreateDevice operation has no retry loop. The bridge does not probe every conceptual backend row regardless of what was compiled or made available.

Backend Platform Software Fallback
D3D11 Windows WARP route where explicitly selected by the backend
D3D12 Windows WARP adapter route where explicitly selected by the backend
Vulkan Host/runtime dependent A CPU ICD such as Lavapipe, only when installed and selected
OpenGL Linux development Mesa llvmpipe with the required EGL/GLX/display setup
Metal macOS No software fallback declared
None Host-independent implementation Explicit NullRHIDevice; no pixels are rendered

RHIDeviceCapabilities contains an isSoftwareDevice field, but that field is not evidence of automatic fallback or uniform runtime probing.

Build Targets

Target Type Description
SparkEngineLib Static library Core engine systems (all subsystems linked here)
SparkEngine Executable Runtime host (loads game modules)
SparkGame Shared library Default game module DLL
SparkEditor Executable ImGui visual editor with Windows and experimental non-Windows build paths
SparkConsole Executable Debug console with named-pipe transport on Windows and bidirectional inherited stdio transport elsewhere
SparkShaderCompiler Executable Offline HLSL/GLSL shader compilation tool
SparkTests Executable Unit test runner (when BUILD_TESTS=ON)
uninstall Custom target Manifest-driven removal of the last full cmake --install (see below)

Install and Uninstall

cmake --install <build> records every file it writes in <build>/install_manifest.txt (install_manifest_<component>.txt for a --component install). cmake/SparkUninstall.cmake removes exactly those files:

cmake --build <build> --target uninstall      # full install into CMAKE_INSTALL_PREFIX
cmake -DPREFIX=<prefix> -DMANIFEST=<build>/install_manifest_runtime.txt \
      -P cmake/SparkUninstall.cmake           # --prefix or --component installs

Every manifest entry is validated before anything is deleted. The helper refuses the whole manifest if any entry is relative, not normalized, outside the prefix, a link, a directory, or under a parent that resolves outside the prefix. It also refuses a manifest containing a semicolon or an entry with unbalanced square brackets (CMake list handling would merge it with its neighbors), and a filesystem-root prefix. Entries that are already gone are skipped, so a second uninstall succeeds. Directories are pruned only when they are left empty, so data written under the prefix after install (saves, settings, caches) survives. The emptiness check escapes glob metacharacters, so a prefix such as C:/Games [Beta] is listed literally rather than read as a pattern. DESTDIR is applied as cmake --install applies it: the manifest holds unstaged paths, and a leading drive letter is dropped before DESTDIR is prepended. The DESTDIR stage is tested on Linux; the drive-letter mapping has not yet run on a Windows host. The vendored SDL2 uninstall target is disabled (SDL2_DISABLE_UNINSTALL) because it deletes manifest paths without these checks.

SparkTrackedInstall.Contract covers the contract. It runs two install, reinstall and uninstall cycles, asserts that reinstall is byte-identical and that only declared user data remains, and checks the adversarial manifests, a DESTDIR stage, and a prefix containing glob metacharacters with user data inside an installed directory. This is local CMake-tree evidence only. Windows CPack/NSIS uninstall and SparkInstaller are separate and not yet qualified (ASSET-220, INST-130).

Build Output

build/
├── bin/           # Executables and DLLs
│   ├── SparkEngine.exe
│   ├── SparkGame.dll
│   ├── SparkEditor.exe
│   ├── SparkConsole.exe
│   └── SparkTests.exe
├── lib/           # Static libraries (.lib / .a)
│   └── SparkEngineLib.lib
├── Shaders/       # Compiled shader bytecode
└── Assets/        # Game assets (copied from source tree)

SparkBuild

SparkBuild is an in-tree C++17 terminal-UI wrapper around CMake. The source lives at SparkBuild/ (vendored from the now-archived Krilliac/SparkBuild; see SparkBuild/UPSTREAM.md for the pinned commit). It is built as part of the normal engine build under the ENABLE_SPARKBUILD option (ON by default).

Output: build/<preset>/bin/SparkBuild (or build/<preset>/bin/<Config>/SparkBuild.exe on Windows).

cmake --preset linux-gcc-release
cmake --build build/linux-gcc-release --target SparkBuild
./build/linux-gcc-release/bin/SparkBuild

Because SparkBuild only shells out to cmake, it has no dependency on any SparkEngine header or library — so in-tree hosting introduces no circular build dependency. To skip it:

cmake -B build -DENABLE_SPARKBUILD=OFF ...

CMake Helper Modules

SparkGameModule.cmake

Source: cmake/SparkGameModule.cmake

Provides spark_add_game_module() for creating game module DLLs:

include(cmake/SparkGameModule.cmake)
spark_add_game_module(MyGame ${GAME_SOURCES})

What it does

Step Action
1 Creates a SHARED library from provided sources
2 Defines SPARK_MODULE_DLL and SPARK_GAME_DLL compile definitions
3 Links against Spark::SparkEngineLib (private)
4 Sets SDK include directories (SPARK_ENGINE_INCLUDE_DIR, Spark/, SparkEngine/)
5 Enforces C++23 via target_compile_features(cxx_std_23)
6 On MSVC: sets runtime library to MultiThreaded$<$<CONFIG:Debug>:Debug>DLL

See Creating a Game Module for a complete usage guide.

SparkEnginePreflight.cmake

Source: cmake/SparkEnginePreflight.cmake

Validates that a SparkEngine SDK installation is complete before find_package runs. Include it in standalone projects to get clear error messages when required files are missing.

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../cmake")
include(SparkEnginePreflight)

find_package(SparkEngine REQUIRED)

Validation checks

The spark_preflight_check() function searches candidate directories and verifies:

Required File Purpose
SparkEngineConfig.cmake CMake package configuration
SparkEngineTargets.cmake Imported target definitions for Spark::SparkEngineLib
SparkGameModule.cmake Game module helper function

If any file is missing, it emits a FATAL_ERROR with the exact missing path and remediation steps (re-run cmake --install).

SparkComponentLibraries.cmake

Source: cmake/SparkComponentLibraries.cmake

Defines per-subsystem OBJECT library targets that partition the monolithic SparkEngineLib into fine-grained component libraries.

include(cmake/SparkComponentLibraries.cmake)
spark_define_component_libraries()

Component Library Targets

Target Sources Dependencies Description
SparkCore Core/*.cpp/.h -- Platform, EngineContext, Assert, Logger
SparkUtils Utils/*.cpp/.h SparkCore Console, Profiler, JobSystem, Octree
SparkECS Engine/ECS/**/*.cpp/.h SparkCore Components, Systems, World, ReactiveSystem
SparkGraphics Graphics/**/*.cpp/.h SparkCore, SparkUtils GraphicsEngine, RHI, Shaders, PostProcessing
SparkPhysics Engine/Physics/**/*.cpp/.h SparkCore, SparkECS PhysicsSystem, Jolt Physics integration
SparkAudio Engine/Audio/**/*.cpp/.h SparkCore, SparkECS AudioEngine, XAudio2
SparkAI Engine/AI/**/*.cpp/.h SparkCore, SparkECS, SparkUtils AISystem, BehaviorTree, NavMesh
SparkAnimation Engine/Animation/**/*.cpp/.h SparkCore, SparkECS Skeleton, Clips, Blending, IK
SparkNetworking Engine/Networking/**/*.cpp/.h SparkCore NetworkManager, Transport

Migration from Monolithic to Component Libraries

# Before (monolithic)
target_link_libraries(MyTarget PRIVATE SparkEngineLib)

# After (component-based — link only what you need)
target_link_libraries(MyTarget PRIVATE SparkECS SparkGraphics SparkPhysics)

SparkEngineLib remains as an umbrella target that links all components for backward compatibility.

SparkCxxRuntime.cmake

On non-Windows producers, this helper detects libc++ or libstdc++ from the selected standard-library headers for each configuration. It rejects ambiguous or mixed-family configurations. The selected family is exported as C++ compile and link requirements on SparkEngineLib and SparkEngineInterface, so installed consumers retain the producer's standard-library choice. Windows keeps its existing CRT/toolset contract.

SDKCxxRuntime_ExportContract checks the configure/export/import wiring without enabling a compiler. It does not establish native ABI compatibility; the installed SDK consumer build and module-load checks remain necessary.

SparkUIFonts.cmake

Source: cmake/SparkUIFonts.cmake

Stages the shared Spark UI fonts (IBM Plex Sans, JetBrains Mono, Font Awesome and their LICENSES/, all from SparkEditor/Fonts) next to an executable, in <exe dir>/EditorAssets/Fonts, which is the first place Spark::Ui::FindFontDirectory looks. The root CMakeLists.txt includes it before the SparkEngine executable block.

include(cmake/SparkUIFonts.cmake)
spark_stage_ui_fonts(SparkEngine)   # POST_BUILD copy into $<TARGET_FILE_DIR:SparkEngine>/EditorAssets/Fonts

The POST_BUILD step runs the same file in script mode (cmake -DSPARK_UI_FONTS_SOURCE=<dir> -DSPARK_UI_FONTS_DEST=<dir> -P cmake/SparkUIFonts.cmake). Several executables share one output directory, so the copy takes a file lock on the destination and copies only files whose contents differ; concurrent and repeated builds are safe. It fails the build when the source directory holds no fonts. Install rules stay with each consumer.

SparkEngineConfig.cmake

Enables find_package(SparkEngine) for standalone game projects. Defines the Spark::SparkEngineLib imported target.

Build Scripts

Script Platform Description
generate.bat Windows CMake configuration wrapper (accepts generator and config)
generate.sh Linux/macOS CMake configuration wrapper
build.ps1 Windows PowerShell build script
build.sh Linux/macOS Bash build script

Documentation Generation

# Generate API docs from headers (no Doxygen required)
docs/generate-api-docs.sh generate    # Full generation
docs/generate-api-docs.sh check       # Only if headers changed (checksum-based)
docs/generate-api-docs.sh status      # Show generation status

# Sync wiki pages with codebase inventory
docs/sync-wiki.sh sync               # Update auto-generated sections
docs/sync-wiki.sh check              # Dry-run: report what's stale

# Legacy Doxygen (optional, requires doxygen + graphviz)
cd docs && ./generate-docs.sh

See the Documentation Index and the Doc Tooling page for full documentation tooling details.

CI/CD (GitHub Actions)

build.yml

Runs on pushes to main, develop, Working, and release/**; pull requests targeting main, develop, or Working; and manual dispatch. Topic branches (claude/**, codex/**, feature/**) are covered by the pull-request trigger only, so a push to one of them no longer queues the matrix a second time.

CI Job Matrix

Job Runner Compiler Configs Key Flags
check-format ubuntu-24.04 clang-format -- --dry-run --Werror
validate-prompts ubuntu-24.04 -- -- --ci
build-linux-gcc ubuntu-24.04 GCC Debug, Release -DBUILD_TESTS=ON
build-linux-clang ubuntu-24.04 Clang Debug, Release -DBUILD_TESTS=ON
build-linux-asan ubuntu-24.04 GCC Debug ASan + UBSan
build-windows-vs2022 windows-2022 MSVC v143 Debug, Release Ninja Multi-Config + sccache (hash-pinned, SCCACHE_DIR restore/save; PCH, module scan, Jolt /Zi off), -DBUILD_TESTS=ON -DBUILD_GAME_MODULES=ON
build-windows-vs2026 windows-2025-vs2026 MSVC v145 Debug, Release Ninja Multi-Config + sccache inside the VS 2026 dev shell; advisory until runner availability is guaranteed
coverage ubuntu-24.04 GCC Debug --coverage + lcov
clang-tidy ubuntu-24.04 Clang Debug continue-on-error
todo-count ubuntu-24.04 -- -- threshold: 20

Reproducing CI Builds Locally

Linux GCC:

cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON \
    -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
cmake --build build --parallel $(nproc)
cd build && ctest --output-on-failure --no-tests=error && ./bin/SparkTests && cd ..

Linux Clang:

cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON \
    -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build build --parallel $(nproc)
cd build && ctest --output-on-failure --no-tests=error && ./bin/SparkTests && cd ..

AddressSanitizer (ASan + UBSan):

cmake -B build -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON \
    -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" \
    -DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" \
    -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" \
    -DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,undefined"
cmake --build build --parallel $(nproc)
cd build && ctest --output-on-failure --no-tests=error && ./bin/SparkTests && cd ..

Windows MSVC (VS 2022, as build-windows-vs2022 runs it — from an "x64 Native Tools" shell):

cmake --fresh -B build -G "Ninja Multi-Config" \
    -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl \
    -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache \
    -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded \
    -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -DCMAKE_CXX_SCAN_FOR_MODULES=OFF \
    -DGENERATE_DEBUG_SYMBOLS=OFF \
    -DBUILD_TESTS=ON -DBUILD_GAME_MODULES=ON
cmake --build build --config Release --parallel
ctest --test-dir build -C Release --output-on-failure --no-tests=error

Omit the two _LAUNCHER flags without sccache; with sccache keep -DGENERATE_DEBUG_SYMBOLS=OFF (Jolt's /Zi otherwise breaks every Jolt TU under sccache). The Visual Studio generator (-G "Visual Studio 17 2022" -A x64 -T v143) still works for local IDE builds but ignores compiler launchers; in CI only build-windows-shipping uses it, through its preset, uncached.

release.yml (rolling pre-release artifacts)

Runs for release/** pushes, v* tags, the nightly schedule, and manual dispatch:

  • Can publish rolling nightly assets with make_latest: false for development evaluation; these are not versioned releases and do not supply stable-v1 signing, install, or attestation certification
  • Builds Windows, Linux, and macOS Debug/Release packages plus configured Windows installer artifacts
  • Formats include .zip (Windows) and .tar.gz (Linux/macOS)
  • Includes exact commit hash and timestamp

Compiler Support

Compiler Version Platform Status
MSVC v143 (VS 2022) Windows Declared stable-v1 toolset line; profile blocked and uncertified
MSVC v145 (VS 2026) Windows Experimental (continue-on-error)
GCC 13+ Linux Development build floor; outside stable-v1
Clang 17+ Linux Development build floor; outside stable-v1
Apple Clang C++23 capable macOS Experimental

Compiler Flags

Compiler Warning Flags Additional
MSVC /W4 Zero warnings enforced
GCC -Wall -Wextra Zero warnings enforced
Clang -Wall -Wextra Zero warnings enforced

Code Formatting

SparkEngine enforces consistent code style via .clang-format (Microsoft-based, Allman braces, 120-col, 4-space indent).

# Check formatting (dry run)
find SparkEngine/Source GameModules SparkEditor/Source SparkConsole/src SparkShaderCompiler/src \
     SparkBuild/src SparkInstaller/src SparkDaemon/src SparkServer/src SparkGateway/src \
     SparkCooker/src SparkWorker/src SparkAutomation/src SparkLauncher/src SparkUI Tests FuzzerTests \
  -not -path '*/Metal/*' \( -name '*.h' -o -name '*.hpp' -o -name '*.cpp' \) \
  | xargs clang-format --dry-run --Werror 2>&1

# Fix formatting automatically
find SparkEngine/Source GameModules SparkEditor/Source SparkConsole/src SparkShaderCompiler/src \
     SparkBuild/src SparkInstaller/src SparkDaemon/src SparkServer/src SparkGateway/src \
     SparkCooker/src SparkWorker/src SparkAutomation/src SparkLauncher/src SparkUI Tests FuzzerTests \
  -not -path '*/Metal/*' \( -name '*.h' -o -name '*.hpp' -o -name '*.cpp' \) \
  | xargs clang-format -i

CI rejects PRs with formatting violations.


See Also

Combined SDK runtime qualification

The installed EmptyProject consumer check now launches the installed engine with the exact generated module and -require-game, from the generated project. Its 120-second headless run must pass the existing production NullRHI lifecycle parser (one initialized module, update/fixed/unload callbacks and zero faults). The module image hash must remain unchanged. This is a same-build runtime ABI check; it does not establish N-1 compatibility, hot reload or rendered behavior. Source checks alone do not qualify this runtime gate.

SparkEngine Wiki

Website Entry Points

Getting Started

Engine Subsystems

Gameplay & Tools

Platform Support

Graphics

Advanced

Development & Process

Research & Analysis

Engineering Notes & Audits

Specifications

Reference

Clone this wiki locally