Incremental Builds¶
Overview¶
CCGO provides smart incremental build detection that automatically rebuilds only changed files and their dependencies. This dramatically improves rebuild times by avoiding unnecessary recompilation.
Benefits¶
- ⚡ Faster Rebuilds - Only recompile changed files (10-50x speedup)
- 🎯 Smart Detection - Tracks file changes, config changes, and dependency changes
- 🔍 Change Analysis - Shows exactly what changed since last build
- 🚀 Zero Configuration - Works automatically, no setup required
- 💾 Persistent State - Build state survives terminal sessions
How It Works¶
Build State Tracking¶
CCGO maintains build state for each platform and link type:
cmake_build/release/linux/
├── .ccgo_build_state.json # Build state (file hashes, metadata)
└── CMakeCache.txt # CMake build cache
The build state tracks: - File Hashes - SHA256 checksums of all source/header files - Config Hash - CCGO.toml configuration changes - Options Hash - Build flags and options changes - CMake Cache - CMake configuration changes - Last Build Time - Timestamp of successful build
Change Detection¶
On each build, CCGO:
- Loads Previous State - Reads
.ccgo_build_state.jsonif exists - Scans Current Files - Hashes all source/header files
- Compares Hashes - Detects modified, added, and removed files
- Checks Configuration - Detects CCGO.toml or build option changes
- Decides Build Strategy:
- Incremental Build - Only changed files if possible
- Full Rebuild - If config/options changed or CMake cache missing
Usage¶
Automatic Incremental Builds¶
Incremental builds work automatically with no configuration:
# First build (full)
ccgo build linux
# ✓ Build completed in 45.2s
# Modify one source file
echo "// comment" >> src/mylib.cpp
# Second build (incremental)
ccgo build linux
# 📊 Incremental build - 1 files changed:
# Modified: 1
# ✓ Build completed in 3.8s (11.9x faster!)
Build Output Examples¶
No Changes¶
Incremental Build¶
$ ccgo build linux
📊 Incremental build - 3 files changed:
Modified: 2
Added: 1
⚡ Rebuilding affected files...
✓ Build completed in 4.2s
Full Rebuild Required¶
$ ccgo build linux
🔄 Full rebuild required: CCGO.toml configuration changed
⚡ Building all files...
✓ Build completed in 42.8s
What Triggers Full Rebuild¶
Configuration Changes¶
Any change to CCGO.toml triggers full rebuild:
[package]
version = "1.0.1" # Changed → Full rebuild
[dependencies]
# Added new dependency → Full rebuild
fmt = "10.1.1"
Build Option Changes¶
Different build options require full rebuild:
# First build with 4 jobs
ccgo build linux --jobs 4
# Second build with 8 jobs → Full rebuild
ccgo build linux --jobs 8
# Different architectures → Full rebuild
ccgo build linux --arch x86_64
ccgo build linux --arch arm64 # Full rebuild
# Feature changes → Full rebuild
ccgo build linux --features networking
ccgo build linux --features advanced # Full rebuild
CMake Cache Changes¶
If CMake reconfigures, full rebuild occurs:
# Clear CMake cache → Full rebuild next time
rm -rf cmake_build/release/linux/CMakeCache.txt
ccgo build linux
New/Removed Files¶
Adding or removing source files triggers CMake reconfiguration:
# Add new source file
touch src/new_feature.cpp
# Next build detects file addition
ccgo build linux
# 📊 Incremental build - 1 files changed:
# Added: 1
# 🔧 CMake reconfiguration needed
Build State Files¶
Location¶
Build state is stored per platform and build mode:
cmake_build/
├── release/
│ ├── linux/.ccgo_build_state.json
│ ├── macos/.ccgo_build_state.json
│ └── windows/.ccgo_build_state.json
└── debug/
└── linux/.ccgo_build_state.json
State File Format¶
.ccgo_build_state.json contains:
{
"project": "myproject",
"platform": "linux",
"link_type": "static",
"last_build_time": 1737433200,
"config_hash": "a1b2c3...",
"options_hash": "d4e5f6...",
"cmake_cache_hash": "g7h8i9...",
"file_hashes": {
"src/mylib.cpp": "sha256_hash...",
"src/utils.cpp": "sha256_hash...",
"include/mylib.h": "sha256_hash..."
}
}
Manual State Management¶
# View build state
cat cmake_build/release/linux/.ccgo_build_state.json
# Force full rebuild by removing state
rm cmake_build/release/linux/.ccgo_build_state.json
ccgo build linux
# Or use clean command
ccgo clean
Performance Comparison¶
Typical rebuild speedups with incremental builds:
| Scenario | Files Changed | Full Build | Incremental | Speedup |
|---|---|---|---|---|
| No changes | 0 | 45s | 0.5s | 90x faster |
| Single file | 1 | 45s | 3.8s | 11.9x faster |
| Few files (5%) | 10/200 | 45s | 8.2s | 5.5x faster |
| Many files (25%) | 50/200 | 45s | 18.5s | 2.4x faster |
| Header change | 1 (affects 50) | 45s | 22.1s | 2.0x faster |
| All files | 200/200 | 45s | 44s | ~1x (full rebuild) |
Note: Speedup depends on: - Project size and complexity - Number of changed files - Dependency relationships (headers) - Compiler cache (ccache/sccache) effectiveness - Hardware (CPU, disk speed)
Best Practices¶
DO¶
✅ Let CCGO decide - Incremental builds are automatic and smart
✅ Use with compiler cache - Combine with --cache sccache for maximum speed
✅ Commit regularly - Smaller changes = faster rebuilds
✅ Separate header changes - Headers trigger more rebuilds
✅ Trust the system - CCGO ensures correctness
DON'T¶
❌ Don't manually edit build state - Files are auto-generated ❌ Don't share build state - State is machine-specific ❌ Don't disable - No way to disable (always beneficial) ❌ Don't modify build directories - Let CCGO manage them
CI/CD Integration¶
GitHub Actions¶
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Cache CMake build directory for incremental builds
- name: Cache CMake Build
uses: actions/cache@v3
with:
path: cmake_build/
key: ${{ runner.os }}-cmake-${{ hashFiles('CCGO.toml', 'src/**') }}
restore-keys: |
${{ runner.os }}-cmake-
# Incremental build will work if cache hit
- name: Build
run: ccgo build linux
Benefits in CI: - 🚀 Faster PR builds - Only rebuild changed files - 💰 Reduced CI costs - Less compute time - ⚡ Quicker feedback - Developers get results faster
GitLab CI¶
build:
image: rust:latest
cache:
paths:
- cmake_build/
key:
files:
- CCGO.toml
- src/**/*.cpp
script:
- ccgo build linux
Troubleshooting¶
Incremental Build Not Working¶
Symptom: Every build is full rebuild
Causes & Solutions:
-
Build state file missing
-
Config or options changing
-
CMake cache cleared
Incorrect Incremental Build¶
Symptom: Build succeeds but changes not reflected in output
Solution: This shouldn't happen - incremental system is conservative. If you suspect issues:
# Force full rebuild
ccgo clean
ccgo build linux
# Or just remove build state
rm cmake_build/release/linux/.ccgo_build_state.json
ccgo build linux
Build State Corruption¶
Symptom: Unexpected errors during incremental build
Solution:
# Clean and rebuild
ccgo clean -y
ccgo build linux
# Or manually remove state
rm -rf cmake_build/
ccgo build linux
Under the Hood¶
Change Detection Algorithm¶
// Pseudocode
fn can_incremental_build() -> bool {
// Load previous build state
let old_state = load_build_state()?;
// Check configuration
if old_state.config_hash != current_config_hash() {
return false; // Config changed
}
// Check build options
if old_state.options_hash != current_options_hash() {
return false; // Options changed
}
// Check CMake cache
if !cmake_cache_exists() || old_state.cmake_cache_hash != current_cmake_cache_hash() {
return false; // CMake needs reconfigure
}
true // Incremental build possible
}
fn analyze_changes() -> ChangeAnalysis {
let mut changes = ChangeAnalysis::new();
// Scan current source files
for file in scan_source_files() {
let current_hash = hash_file(file);
match old_state.file_hashes.get(file) {
Some(old_hash) if old_hash != current_hash => {
changes.modified_files.push(file);
}
None => {
changes.added_files.push(file);
}
_ => {} // Unchanged
}
}
// Detect removed files
for old_file in old_state.file_hashes.keys() {
if !current_files.contains(old_file) {
changes.removed_files.push(old_file);
}
}
changes
}
File Hashing¶
CCGO uses SHA256 for file content hashing:
use sha2::{Digest, Sha256};
fn hash_file(path: &Path) -> String {
let content = std::fs::read(path)?;
let mut hasher = Sha256::new();
hasher.update(&content);
format!("{:x}", hasher.finalize())
}
Why SHA256? - Fast enough for source files (< 1ms per file) - Collision-resistant (no false positives) - Standard and well-tested - Available in Rust std lib
CMake Integration¶
Incremental builds leverage CMake's built-in incremental compilation:
- CMake detects file changes - Checks modification times
- CCGO detects config changes - Prevents stale builds
- Combined approach - Best of both worlds
CCGO's change detection is conservative - when in doubt, full rebuild.
Advanced Topics¶
Multiple Platforms¶
Each platform has independent build state:
# Build Linux (incremental if possible)
ccgo build linux
# Build macOS (independent state, may be full rebuild)
ccgo build macos
Platform changes don't affect each other.
Debug vs Release¶
Debug and release builds have separate state:
Link Types¶
Static and shared builds share the same build state:
# Build static
ccgo build linux --build-as static
# Build shared (incremental, shared source compilation)
ccgo build linux --build-as shared
Both link types use the same source files, so changes propagate.
Future Enhancements¶
Planned features for future releases:
- Dependency graph tracking for header changes
- Parallel incremental compilation
- Remote build cache (share across team)
- Build time predictions
- Automatic cleanup of old build states
- Visual dependency graph
- Per-file build time tracking
See Also¶
- Build Caching - Compiler cache for faster builds
- Build Analytics - Performance metrics and tracking
- Build System - General build system overview
Changelog¶
v3.0.12 (2026-01-21)¶
- ✅ Implemented incremental build detection
- ✅ Build state tracking with file hashing (SHA256)
- ✅ Configuration and option change detection
- ✅ CMake cache tracking
- ✅ Change analysis with modified/added/removed files
- ✅ Automatic build state persistence
- ✅ Per-platform and per-link-type state management
- ✅ Last 100 builds auto-pruning for analytics
Incremental builds make your development workflow significantly faster by rebuilding only what changed.