Files
yaze/docs/internal/agents/archive/testing-docs-2025/cmake-validation.md

15 KiB

CMake Configuration Validation

Comprehensive guide to validating CMake configuration and catching dependency issues early.

Overview

The CMake validation toolkit provides four powerful tools to catch configuration issues before they cause build failures:

  1. validate-cmake-config.cmake - Validates CMake cache and configuration
  2. check-include-paths.sh - Verifies include paths in compile commands
  3. visualize-deps.py - Generates dependency graphs
  4. test-cmake-presets.sh - Tests all CMake presets

Quick Start

# 1. Validate configuration after running cmake
cmake --preset mac-dbg
cmake -P scripts/validate-cmake-config.cmake build

# 2. Check include paths
./scripts/check-include-paths.sh build

# 3. Visualize dependencies
python3 scripts/visualize-deps.py build --format graphviz --stats

# 4. Test all presets for your platform
./scripts/test-cmake-presets.sh --platform mac

Tool 1: validate-cmake-config.cmake

Purpose

Validates CMake configuration by checking:

  • Required targets exist
  • Feature flags are consistent
  • Compiler settings are correct
  • Platform-specific configuration (especially Windows/Abseil)
  • Output directories are created
  • Common configuration issues

Usage

# Validate default build directory
cmake -P scripts/validate-cmake-config.cmake

# Validate specific build directory
cmake -P scripts/validate-cmake-config.cmake build_ai

# Validate after configuration
cmake --preset win-ai
cmake -P scripts/validate-cmake-config.cmake build

Exit Codes

  • 0 - All checks passed
  • 1 - Validation failed (errors detected)

What It Checks

1. Required Targets

Ensures core targets exist:

  • yaze_common - Common interface library

2. Feature Flag Consistency

  • When YAZE_ENABLE_AI is ON, YAZE_ENABLE_GRPC must also be ON
  • When YAZE_ENABLE_GRPC is ON, validates gRPC version is set

3. Compiler Configuration

  • C++ standard is set to 23
  • MSVC runtime library is configured correctly on Windows
  • Compiler flags are propagated correctly

4. Abseil Configuration (Windows)

CRITICAL for Windows builds with gRPC:

  • Checks CMAKE_MSVC_RUNTIME_LIBRARY is set to MultiThreaded
  • Validates ABSL_PROPAGATE_CXX_STD is enabled
  • Verifies Abseil include directories exist

This prevents the "Abseil missing include paths" issue.

5. Output Directories

  • build/bin exists
  • build/lib exists

6. Common Issues

  • LTO enabled in Debug builds (warning)
  • Missing compile_commands.json
  • Generator expressions not expanded

Example Output

=== CMake Configuration Validator ===
✓ Build directory: build
✓ Loaded 342 cache variables

=== Validating required targets ===
✓ Required target exists: yaze_common

=== Validating feature flags ===
✓ gRPC enabled: ON
✓ gRPC version: 1.67.1
✓ Tests enabled
✓ AI features enabled

=== Validating compiler flags ===
✓ C++ standard: 23
✓ CXX flags set: /EHsc /W4 /bigobj

=== Validating Windows/Abseil configuration ===
✓ MSVC runtime: MultiThreaded$<$<CONFIG:Debug>:Debug>
✓ Abseil CXX standard propagation enabled

=== Validation Summary ===
✓ All validation checks passed!
Configuration is ready for build

Tool 2: check-include-paths.sh

Purpose

Validates include paths in compile_commands.json to catch missing includes before compilation.

Key Problem Solved: On Windows, Abseil includes from gRPC were sometimes not propagated, causing build failures. This tool catches that early.

Usage

# Check default build directory
./scripts/check-include-paths.sh

# Check specific build directory
./scripts/check-include-paths.sh build_ai

# Verbose mode (shows all include directories)
VERBOSE=1 ./scripts/check-include-paths.sh build

Prerequisites

  • jq (optional but recommended): brew install jq / apt install jq
  • Without jq, uses basic grep parsing

What It Checks

1. Common Dependencies

  • SDL2 includes
  • ImGui includes
  • yaml-cpp includes

2. Platform-Specific Includes

Validates platform-specific headers based on detected OS

3. Abseil Includes (Windows Critical)

When gRPC is enabled:

  • Checks build/_deps/grpc-build/third_party/abseil-cpp exists
  • Validates Abseil paths are in compile commands
  • Warns about unexpanded generator expressions

4. Suspicious Configurations

  • No -I flags at all (error)
  • Relative paths with ../ (warning)
  • Duplicate include paths (warning)

Exit Codes

  • 0 - All checks passed or warnings only
  • 1 - Critical errors detected

Example Output

=== Include Path Validation ===
Build directory: build
✓ Using jq for JSON parsing

=== Common Dependencies ===
✓ SDL2 includes found
✓ ImGui includes found
⚠ yaml-cpp includes not found (may be optional)

=== Platform-Specific Includes ===
Platform: macOS
✓ SDL2 framework/library

=== Checking Abseil Includes (Windows Issue) ===
gRPC build detected - checking Abseil paths...
✓ Abseil from gRPC build: build/_deps/grpc-build/third_party/abseil-cpp

=== Suspicious Configurations ===
✓ Include flags present (234/245 commands)
✓ No duplicate include paths

=== Summary ===
Checks performed: 5
Warnings: 1
✓ All include path checks passed!

Tool 3: visualize-deps.py

Purpose

Generates visual dependency graphs and detects circular dependencies.

Usage

# Generate GraphViz diagram (default)
python3 scripts/visualize-deps.py build

# Generate Mermaid diagram
python3 scripts/visualize-deps.py build --format mermaid -o deps.mmd

# Generate text tree
python3 scripts/visualize-deps.py build --format text

# Show statistics
python3 scripts/visualize-deps.py build --stats

Output Formats

1. GraphViz (DOT)

python3 scripts/visualize-deps.py build --format graphviz -o dependencies.dot

# Render to PNG
dot -Tpng dependencies.dot -o dependencies.png

# Render to SVG (better for large graphs)
dot -Tsvg dependencies.dot -o dependencies.svg

Color Coding:

  • Blue boxes: Executables
  • Green boxes: Libraries
  • Gray boxes: Unknown type
  • Red arrows: Circular dependencies

2. Mermaid

python3 scripts/visualize-deps.py build --format mermaid -o dependencies.mmd

View at https://mermaid.live/edit or include in Markdown:

```mermaid
graph LR
  yaze_app-->yaze_lib
  yaze_lib-->SDL2
```

3. Text Tree

python3 scripts/visualize-deps.py build --format text

Simple text representation for quick overview.

Circular Dependency Detection

The tool automatically detects and highlights circular dependencies:

✗ Found 1 circular dependencies
  libA -> libB -> libC -> libA

Circular dependencies in graphs are shown with red arrows.

Statistics Output

With --stats flag:

=== Dependency Statistics ===
Total targets: 47
Total dependencies: 156
Average dependencies per target: 3.32

Most connected targets:
  yaze_lib: 23 dependencies
  yaze_app: 18 dependencies
  yaze_cli: 15 dependencies
  ...

Tool 4: test-cmake-presets.sh

Purpose

Tests that all CMake presets can configure successfully, ensuring no configuration regressions.

Usage

# Test all presets for current platform
./scripts/test-cmake-presets.sh

# Test specific preset
./scripts/test-cmake-presets.sh --preset mac-ai

# Test only Mac presets
./scripts/test-cmake-presets.sh --platform mac

# Test in parallel (4 jobs)
./scripts/test-cmake-presets.sh --parallel 4

# Quick mode (don't clean between tests)
./scripts/test-cmake-presets.sh --quick

# Verbose output
./scripts/test-cmake-presets.sh --verbose

Options

Option Description
--parallel N Test N presets in parallel (default: 4)
--preset PRESET Test only specific preset
--platform PLATFORM Test only presets for platform (mac/win/lin)
--quick Skip cleaning between tests (faster)
--verbose Show full CMake output

Platform Detection

Automatically skips presets for other platforms:

  • On macOS: Only tests mac-* and generic presets
  • On Linux: Only tests lin-* and generic presets
  • On Windows: Only tests win-* and generic presets

Example Output

=== CMake Preset Configuration Tester ===
Platform: mac
Parallel jobs: 4

Presets to test:
  - mac-dbg
  - mac-rel
  - mac-ai
  - dev
  - ci

Running tests in parallel (jobs: 4)...

✓ mac-dbg configured successfully (12s)
✓ dev configured successfully (15s)
✓ mac-rel configured successfully (11s)
✓ mac-ai configured successfully (45s)
✓ ci configured successfully (18s)

=== Test Summary ===
Total presets tested: 5
Passed: 5
Failed: 0
✓ All presets configured successfully!

Failure Handling

When a preset fails:

✗ win-ai failed (34s)
  Log saved to: preset_test_win-ai.log

=== Test Summary ===
Total presets tested: 3
Passed: 2
Failed: 1
Failed presets:
  - win-ai

Check log files for details: preset_test_*.log

Integration with CI

Add to GitHub Actions Workflow

name: CMake Validation

on: [push, pull_request]

jobs:
  validate-cmake:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Configure CMake
        run: cmake --preset ci-linux

      - name: Validate Configuration
        run: cmake -P scripts/validate-cmake-config.cmake build

      - name: Check Include Paths
        run: ./scripts/check-include-paths.sh build

      - name: Detect Circular Dependencies
        run: python3 scripts/visualize-deps.py build --stats

Pre-Configuration Check

Run validation as first CI step to fail fast:

- name: Fast Configuration Check
  run: |
    cmake --preset minimal
    cmake -P scripts/validate-cmake-config.cmake build

Common Issues and Solutions

Issue 1: Missing Abseil Includes on Windows

Symptom:

✗ Missing required include: Abseil from gRPC build

Solution:

  1. Ensure ABSL_PROPAGATE_CXX_STD is ON in cmake/dependencies/grpc.cmake
  2. Reconfigure with --fresh: cmake --preset win-ai --fresh
  3. Check that gRPC was built successfully

Prevention: Run cmake -P scripts/validate-cmake-config.cmake after every configuration.

Issue 2: Circular Dependencies

Symptom:

✗ Found 2 circular dependencies
  libA -> libB -> libA

Solution:

  1. Visualize full graph: python3 scripts/visualize-deps.py build --format graphviz -o deps.dot
  2. Render: dot -Tpng deps.dot -o deps.png
  3. Identify and break cycles by:
    • Moving shared code to a new library
    • Using forward declarations instead of includes
    • Restructuring dependencies

Issue 3: Preset Configuration Fails

Symptom:

✗ mac-ai failed (34s)
  Log saved to: preset_test_mac-ai.log

Solution:

  1. Check log file: cat preset_test_mac-ai.log
  2. Common causes:
    • Missing dependencies (gRPC build failure)
    • Incompatible compiler flags
    • Platform condition mismatch
  3. Test preset manually: cmake --preset mac-ai -B test_build -v

Issue 4: Generator Expressions Not Expanded

Symptom:

⚠ Generator expressions found in compile commands (may not be expanded)

Solution: This is usually harmless. Generator expressions like $<BUILD_INTERFACE:...> are CMake-internal and won't appear in final compile commands. If build fails, the issue is elsewhere.

Best Practices

1. Run Validation After Every Configuration

# Configure
cmake --preset mac-ai

# Validate immediately
cmake -P scripts/validate-cmake-config.cmake build
./scripts/check-include-paths.sh build

2. Test All Presets Before Committing

# Quick test of all platform presets
./scripts/test-cmake-presets.sh --platform mac --parallel 4

3. Check Dependencies When Adding New Targets

# After adding new target to CMakeLists.txt
cmake --preset dev
python3 scripts/visualize-deps.py build --stats

Look for:

  • Unexpected high dependency counts
  • New circular dependencies

4. Use in Git Hooks

Create .git/hooks/pre-commit:

#!/bin/bash
# Validate CMake configuration before commit

if [ -f "build/CMakeCache.txt" ]; then
    echo "Validating CMake configuration..."
    cmake -P scripts/validate-cmake-config.cmake build || exit 1
fi

5. Periodic Full Validation

Weekly or before releases:

# Full validation suite
./scripts/test-cmake-presets.sh --parallel 4
cmake --preset dev
cmake -P scripts/validate-cmake-config.cmake build
./scripts/check-include-paths.sh build
python3 scripts/visualize-deps.py build --format graphviz --stats -o deps.dot

Troubleshooting

Tool doesn't run on Windows

Bash scripts: Use Git Bash, WSL, or MSYS2 to run .sh scripts.

CMake scripts: Should work natively on Windows:

cmake -P scripts\validate-cmake-config.cmake build

jq not found

Install jq for better JSON parsing:

# macOS
brew install jq

# Ubuntu/Debian
sudo apt install jq

# Windows (via Chocolatey)
choco install jq

Scripts will work without jq but with reduced functionality.

Python script fails

Ensure Python 3.7+ is installed:

python3 --version

No external dependencies required - uses only standard library.

GraphViz rendering fails

Install GraphViz:

# macOS
brew install graphviz

# Ubuntu/Debian
sudo apt install graphviz

# Windows (via Chocolatey)
choco install graphviz

Advanced Usage

Custom Validation Rules

Edit scripts/validate-cmake-config.cmake to add project-specific checks:

# Add after existing checks
log_header "Custom Project Checks"

if(DEFINED CACHE_MY_CUSTOM_FLAG)
  if(CACHE_MY_CUSTOM_FLAG)
    log_success "Custom flag enabled"
  else()
    log_error "Custom flag must be enabled for this build"
  endif()
endif()

Automated Dependency Reports

Generate weekly dependency reports:

#!/bin/bash
# weekly-deps-report.sh

DATE=$(date +%Y-%m-%d)
REPORT_DIR="reports/$DATE"
mkdir -p "$REPORT_DIR"

# Configure
cmake --preset ci

# Generate all formats
python3 scripts/visualize-deps.py build \
  --format graphviz --stats -o "$REPORT_DIR/deps.dot"

python3 scripts/visualize-deps.py build \
  --format mermaid -o "$REPORT_DIR/deps.mmd"

python3 scripts/visualize-deps.py build \
  --format text -o "$REPORT_DIR/deps.txt"

# Render GraphViz
dot -Tsvg "$REPORT_DIR/deps.dot" -o "$REPORT_DIR/deps.svg"

echo "Report generated in $REPORT_DIR"

CI Matrix Testing

Test all presets across platforms:

jobs:
  test-presets:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v3
      - name: Test Presets
        run: ./scripts/test-cmake-presets.sh --parallel 2

Quick Reference

Task Command
Validate config cmake -P scripts/validate-cmake-config.cmake build
Check includes ./scripts/check-include-paths.sh build
Visualize deps python3 scripts/visualize-deps.py build
Test all presets ./scripts/test-cmake-presets.sh
Test one preset ./scripts/test-cmake-presets.sh --preset mac-ai
Generate PNG graph python3 scripts/visualize-deps.py build -o d.dot && dot -Tpng d.dot -o d.png
Check for cycles python3 scripts/visualize-deps.py build --stats
Verbose include check VERBOSE=1 ./scripts/check-include-paths.sh build

See Also