673 lines
15 KiB
Markdown
673 lines
15 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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)
|
|
```bash
|
|
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
|
|
```bash
|
|
python3 scripts/visualize-deps.py build --format mermaid -o dependencies.mmd
|
|
```
|
|
|
|
View at https://mermaid.live/edit or include in Markdown:
|
|
|
|
````markdown
|
|
```mermaid
|
|
graph LR
|
|
yaze_app-->yaze_lib
|
|
yaze_lib-->SDL2
|
|
```
|
|
````
|
|
|
|
#### 3. Text Tree
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```yaml
|
|
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:
|
|
|
|
```yaml
|
|
- 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# Quick test of all platform presets
|
|
./scripts/test-cmake-presets.sh --platform mac --parallel 4
|
|
```
|
|
|
|
### 3. Check Dependencies When Adding New Targets
|
|
|
|
```bash
|
|
# 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`:
|
|
```bash
|
|
#!/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:
|
|
```bash
|
|
# 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:
|
|
```powershell
|
|
cmake -P scripts\validate-cmake-config.cmake build
|
|
```
|
|
|
|
### jq not found
|
|
|
|
Install jq for better JSON parsing:
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
python3 --version
|
|
```
|
|
|
|
No external dependencies required - uses only standard library.
|
|
|
|
### GraphViz rendering fails
|
|
|
|
Install GraphViz:
|
|
```bash
|
|
# 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:
|
|
|
|
```cmake
|
|
# 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:
|
|
|
|
```bash
|
|
#!/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:
|
|
|
|
```yaml
|
|
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
|
|
|
|
- [Build Quick Reference](../../public/build/quick-reference.md) - Build commands
|
|
- [Build Troubleshooting](../../BUILD-TROUBLESHOOTING.md) - Common build issues
|
|
- [CMakePresets.json](../../../CMakePresets.json) - All available presets
|
|
- [GitHub Actions Workflows](../../../.github/workflows/) - CI configuration
|