Maintainer Guide¶
CI/CD architecture, CMake presets, and release workflows.
Pipeline Architecture¶
Defined in azure-pipelines.yml on self-hosted agents (Default pool):
flowchart TD
subgraph Triggers["Trigger"]
T1["Push to master / main / release/*"]
T2["Pull Request"]
end
subgraph Matrix["Build Matrix"]
W["Windows Stage (MSVC)"]
L["Linux Stage (GCC & Clang)"]
D["Darwin Stage (AppleClang)"]
end
subgraph Verification["Verification"]
V1["CTest Execution"]
V2["Benchmark Collection"]
V3["Coverage (gcovr)"]
end
subgraph Publish["Publication (main / master)"]
G1{"GitHub Release Approval"}
P1["GitHub Release"]
P0["NuGet Package"]
P2["MkDocs Site"]
end
T1 --> Matrix
T2 --> Matrix
W --> Verification
L --> Verification
D --> Verification
Verification --> G1
G1 --> P1
P1 --> P0
G1 --> P2
Build Stages & Platform Matrix¶
The build matrix targets Windows, Linux, and macOS (Darwin) across x64 and arm64 architectures:
| Platform Stage | Target Architectures | Compilers | CMake Presets Prefix | CI Template | Artifacts Published |
|---|---|---|---|---|---|
| Windows | x64, arm64 |
MSVC (Visual Studio 2022) | Windows-${arch}-${buildType} |
.azure/az-build-windows.yml |
Binaries, CTest JUnit XML, Benchmarks |
| Linux | x64, arm64 |
Clang (17+), GCC (13+) | Linux-${compiler}-${buildType} |
.azure/az-build-unix.yml |
Binaries, CTest JUnit XML, Benchmarks, Coverage XML |
| Darwin (macOS) | x64, arm64 |
AppleClang (Xcode / CLT) | Darwin-Clang-${buildType} |
.azure/az-build-unix.yml |
Binaries, CTest JUnit XML, Benchmarks |
Unified Unix Pipeline
The Linux and Darwin stages share the parameterized template .azure/az-build-unix.yml. It dynamically adapts agent OS demands, compiler flags, and preset names based on the target platform.
CMake Presets Architecture¶
The repository employs a decoupled, highly reusable CMake Presets structure separated across two files:
flowchart TD
subgraph PB["project-base.json (Project-Specific)"]
PBase["Project-Base<br/>• sip2json_BUILD_TESTS=ON<br/>• sip2json_BUILD_BENCHMARKS=OFF<br/>• CMAKE_CXX_STANDARD=20<br/>• CI_BUILDID=0.0.0"]
end
subgraph CP["CMakePresets.json (Generic / Portable)"]
CBase["Common-Base<br/>• Generator: Ninja<br/>• binaryDir: build/${presetName}<br/>• installDir: install/${presetName}<br/>• CPM_SOURCE_CACHE"]
subgraph Darwin["Darwin / macOS"]
ABase["Apple-Base (Darwin condition)"]
ADebug["Apple-Debug (Debug)"]
ARelease["Apple-Release (Release)"]
DCDebug["Darwin-Clang-Debug"]
DCRelease["Darwin-Clang-Release"]
DDefault["Darwin"]
end
subgraph Linux["Linux"]
LBase["Linux-Base (Linux condition)"]
LClangBase["Linux-Clang-Base (/usr/bin/clang)"]
LGCCBase["Linux-GCC-Base (/usr/bin/gcc)"]
LCDebug["Linux-Clang-Debug"]
LCRelease["Linux-Clang-Release"]
LGDebug["Linux-GCC-Debug"]
LGRelease["Linux-GCC-Release"]
end
subgraph Windows["Windows"]
WBase["Windows-Base (Windows condition, cl.exe)"]
Wx64Base["Windows-x64-Base (host=x64, arch=x64)"]
WarmBase["Windows-arm64-Base (arch=arm64)"]
Wx64Debug["Windows-x64-Debug"]
Wx64Release["Windows-x64-Release"]
WarmDebug["Windows-arm64-Debug"]
WarmRelease["Windows-arm64-Release"]
end
end
PBase --> CBase
CBase --> ABase
CBase --> LBase
CBase --> WBase
ABase --> ADebug & ARelease
ADebug --> DCDebug
ARelease --> DCRelease & DDefault
LBase --> LClangBase & LGCCBase
LClangBase --> LCDebug & LCRelease
LGCCBase --> LGDebug & LGRelease
WBase --> Wx64Base & WarmBase
Wx64Base --> Wx64Debug & Wx64Release
WarmBase --> WarmDebug & WarmRelease
Architectural Separation of Concerns¶
project-base.json:- Holds all per-project settings (e.g.
sip2json_BUILD_TESTS,CMAKE_CXX_STANDARD: 20,CI_BUILDID: 0.0.0). -
Project maintainers configure project-specific variables here without altering toolchain presets.
- Contains zero project-specific names or flags.
- Fully portable and reusable across any C++20/23 library or service repository.
- Defines platform bases (
Apple-Base,Linux-Base,Windows-Base) and standardizedTest-Baseexecution rules.
Available Presets Quick Reference¶
Configure Presets¶
| Preset Name | Platform | Compiler | Build Type | Notes |
|---|---|---|---|---|
Apple-Debug |
macOS | AppleClang | Debug | Native Xcode / Command Line Tools |
Apple-Release |
macOS | AppleClang | Release | Native Xcode / Command Line Tools |
Darwin-Clang-Debug |
macOS | AppleClang | Debug | Inherits Apple-Debug |
Darwin-Clang-Release |
macOS | AppleClang | Release | Inherits Apple-Release |
Darwin |
macOS | AppleClang | Release | Default macOS alias (inherits Apple-Release) |
Linux-Clang-Debug |
Linux | Clang (/usr/bin/clang++) |
Debug | Clang toolchain |
Linux-Clang-Release |
Linux | Clang (/usr/bin/clang++) |
Release | Clang toolchain |
Linux-Clang |
Linux | Clang (/usr/bin/clang++) |
Release | Clang release alias |
Linux-GCC-Debug |
Linux | GCC (/usr/bin/g++) |
Debug | GCC toolchain |
Linux-GCC-Release |
Linux | GCC (/usr/bin/g++) |
Release | GCC toolchain |
Linux-GCC |
Linux | GCC (/usr/bin/g++) |
Release | GCC release alias |
Windows-x64-Debug |
Windows | MSVC (cl.exe) |
Debug | x64 architecture, host=x64 |
Windows-x64-Release |
Windows | MSVC (cl.exe) |
Release | x64 architecture, host=x64 |
Windows-x64 |
Windows | MSVC (cl.exe) |
Release | Windows x64 release alias |
Windows-arm64-Debug |
Windows | MSVC (cl.exe) |
Debug | ARM64 cross/native compilation |
Windows-arm64-Release |
Windows | MSVC (cl.exe) |
Release | ARM64 cross/native compilation |
Windows-arm64 |
Windows | MSVC (cl.exe) |
Release | Windows ARM64 release alias |
Local Development & Maintainer Workflow¶
1. Configure, Build, and Test¶
Maintainers can build and execute the full test suite (320+ unit and compliance tests) with standard CMake commands:
# Configure with desired preset (e.g. Darwin-Clang-Release, Linux-GCC-Release, Windows-x64-Release)
cmake --preset <preset-name>
# Build all targets
cmake --build --preset <preset-name>
# Execute test suite (use -j 4 or higher for fast parallel execution)
ctest --preset <preset-name> -j 4
Test Execution Parallelism
Specifying -j <num_workers> (e.g. -j 4) with ctest runs tests efficiently across worker threads without hitting operating system process limits.
2. Standalone Validation Subproject Testing¶
To test sip2json against historical versions or external CPM consumers, use the subproject located in tests/validation/:
# Configure standalone validation client
cd tests/validation
cmake --preset Apple-Release
# Build and run client test suite
cmake --build --preset Apple-Release
ctest --preset Apple-Release -j 4
3. macOS Toolchain & xcode-select Coexistence¶
Zero-Flipping Workflow: Developing with Xcode and CLI Concurrently
Maintainers frequently develop native macOS/iOS applications in Xcode IDE while simultaneously working on sip2json via terminal, VS Code, or CLion. You can leave xcode-select permanently set to /Applications/Xcode.app/Contents/Developer without encountering CLI build failures or having to toggle xcode-select.
The Problem: xcrun, xcodebuild, and Exit Code 65280¶
On macOS, running generic compiler shims such as /usr/bin/c++, /usr/bin/clang++, or /usr/bin/make triggers Apple's /usr/bin/xcrun dispatcher. When xcode-select points to /Applications/Xcode.app, xcrun invokes:
Symbol not found: _XPCTypeBool in Mercury.framework referenced by /Library/Developer/PrivateFrameworks/CoreDevice.framework), xcodebuild crashes with exit code 255 (which the shell surfaces as c++: error: ... failed with exit code 65280).
Historically, developers were forced to repeatedly flip xcode-select:
# Flipping to Command Line Tools for CLI CMake builds:
sudo xcode-select -s /Library/Developer/CommandLineTools
# Flipping back to Xcode for GUI/iOS/simulator development:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
How sip2json Eliminates Toolchain Flipping¶
sip2json handles toolchain resolution automatically through two complementary mechanisms:
-
Direct Compiler Paths in Presets: The
Apple-Debug,Apple-Release, andDarwinpresets inCMakePresets.jsonexplicitly configureCMAKE_C_COMPILERandCMAKE_CXX_COMPILERto direct binary paths (e.g./Library/Developer/CommandLineTools/usr/bin/clang++). Because the binary path is fully qualified, CMake and Ninja invoke the compiler directly, completely bypassing/usr/bin/xcrunandxcodebuild. -
Automatic Toolchain Discovery in
CMakeLists.txt: If you configure CMake outside presets (e.g.cmake -B buildor using IDE plugins),CMakeLists.txtinspects candidate toolchains beforeproject(): - Standalone Command Line Tools (
/Library/Developer/CommandLineTools/usr/bin/clang++) - Xcode Default Toolchain (
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++) - Homebrew LLVM (
/opt/homebrew/opt/llvm/bin/clang++)
If a developer has only Xcode installed (without standalone CLT), CMake falls back to the internal Xcode toolchain binary automatically.
Caveats & Best Practices¶
- Environment Override with
DEVELOPER_DIR: If you need to temporarily direct Apple toolchains to a specific location for a single terminal session without modifying system-wide settings withsudo xcode-select, exportDEVELOPER_DIR: - Xcode Generator vs. Ninja: The repository presets standardly use the
Ninjagenerator. If you explicitly generate an Xcode IDE project (cmake -G Xcode), CMake must interact directly withxcodebuild. Ensure that your installed Xcode version matches your macOS version if using the Xcode generator. For command-line builds, CI, and test execution, Ninja with AppleClang is recommended. - Homebrew LLVM: If you prefer building with upstream Clang from Homebrew (
brew install llvm), you can override the compiler by setting-DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++.
Self-Hosted Build Agent Requirements¶
All build agents must be registered in the Default pool and expose the required Agent.OS demand:
Darwin (macOS) Agents¶
- Demand:
Agent.OS -equals Darwin - OS: macOS Sonoma (14+) on Apple Silicon (
arm64) or Intel (x64). - Toolchain: Xcode 15+ / Command Line Tools (
AppleClang 15+). Presets and build files automatically resolve direct compiler binaries, coexisting seamlessly with anyxcode-selectsetting. - Utilities: CMake 3.29+, Ninja 1.11+, Python 3.10+.
- Note: No external Homebrew LLVM installation required.
Linux Agents¶
- Demand:
Agent.OS -equals Linux - OS: Red Hat Enterprise Linux (RHEL 9+) on
x64orarm64. - Toolchain: GCC 13+ (
/usr/bin/gcc,/usr/bin/g++) or Clang 17+ (/usr/bin/clang,/usr/bin/clang++). - Utilities: CMake 3.29+, Ninja, Python 3.10+,
gcovr(for coverage).
Windows Agents¶
- Demand:
Agent.OS -equals Windows_NT - OS: Windows 11 / Windows Server 2022 (
x64orarm64). - Toolchain: Visual Studio 2022 (MSVC v143+), Windows 11 SDK.
- Prerequisites: Execute
scripts/prep_windows_machine.ps1as Administrator to configureLongPathsEnabled = 1andgit config --system core.longpaths true.
Release & Publication Lifecycle¶
sequenceDiagram
autonumber
actor Maintainer
participant Git as Git Repository
participant Pipeline as Azure Pipelines
participant GitVersion as GitVersion Task
participant GitHub as GitHub Releases
participant Pages as GitHub Pages (MkDocs)
Maintainer->>Git: Push tag / merge to master or release/*
Git->>Pipeline: Webhook Trigger
Pipeline->>GitVersion: Calculate SemVer (GitVersion.yml)
GitVersion-->>Pipeline: Major.Minor.Patch & FullSemVer
Pipeline->>Pipeline: Run Windows, Linux, Darwin build matrix
Pipeline->>Pipeline: Aggregate benchmark outputs & test results
Pipeline->>Maintainer: Request Approval for GitHub Release
Maintainer->>Pipeline: Approve GitHub Release
Pipeline->>GitHub: Create Release with Binaries & Tarballs
Pipeline->>NuGet: Push SiddiqSoft.sip2json Package to nuget.org (gated by GitHub Release)
Pipeline->>Pages: Build MkDocs Site with Dynamic Version & Benchmarks
Dynamic Versioning & Documentation Hooks¶
docs/hooks.py: Dynamically injects GitVersion SemVer into site metadata (config['extra']['version']) and replaces3.1.5-2/v3.1.5placeholders across markdown files.scripts/publish_benchmarks.py: Collects benchmark outputs across build matrix platforms, extracts CPU architecture and core count, and renders responsive platform-grouped benchmark tables and visual comparison charts intodocs/architecture/benchmarks.md.- NuGet Packaging & Publication: NuGet packaging (
NuGetCommand@2 pack) runs during the Windows Release job to package header files,.natvis, and.targets. Publication (Stage 5: PublishNuGet) is auto-enabled onmain/masterreleases and strictly gated behind the manual review and successful completion ofStage 4: PublishGitHubbefore pushing tonuget.orgvia thesqs-nugetservice connection.
Building & Previewing Documentation Locally¶
Maintainers can preview and validate documentation changes locally before pushing:
1. Live-Reload Development Server¶
# Activate Python environment and install requirements
source venv/bin/activate
pip install -r docs/requirements.txt
# Start live-reloading server
mkdocs serve
- Local URL: Open
http://127.0.0.1:8000/in your browser. - Live Reload: Any edits saved in
docs/files update automatically in real time.
2. Strict Build Validation¶
Verify there are zero broken links or markdown syntax issues:
The output compiles into site/. Open site/index.html directly in any browser.
3. Updating Benchmark Data Prior to Serving¶
Pipeline Parameters Reference¶
When manually triggering a pipeline in Azure DevOps, maintainers can customize:
| Parameter | Type | Default | Allowed Values | Purpose |
|---|---|---|---|---|
Platforms |
stringList |
[ Windows, Linux, Darwin ] |
Windows, Linux, Darwin |
Target OS platforms to build |
Architectures |
stringList |
[ arm64 ] |
arm64, x64 |
Target CPU architectures |
Compilers_Windows |
stringList |
[ MSVC ] |
MSVC |
Windows compiler toolsets |
Compilers_Linux |
stringList |
[ Clang ] |
Clang, GCC |
Linux compiler toolsets |
Compilers_Darwin |
stringList |
[ Clang ] |
Clang |
macOS compiler toolsets (AppleClang) |
BuildTypes |
stringList |
[ Release ] |
Release, Debug |
Build configurations |
RunTests |
boolean |
true |
true, false |
Execute unit and compliance test suites |
RunBenchmarks |
boolean |
true |
true, false |
Execute performance benchmark harnesses |
PublishNuGet |
boolean |
false |
true, false |
Trigger NuGet Release (auto on master/main) |
PublishGitHub |
boolean |
false |
true, false |
Trigger GitHub Release (auto on master/main) |
PublishDocs |
boolean |
false |
true, false |
Publish documentation site (auto on master/main) |
Cleanup |
boolean |
false |
true, false |
Run cache and workspace cleanup only |