# 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:
1. **Loads Previous State** - Reads `.ccgo_build_state.json` if exists
2. **Scans Current Files** - Hashes all source/header files
3. **Compares Hashes** - Detects modified, added, and removed files
4. **Checks Configuration** - Detects CCGO.toml or build option changes
5. **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:
```bash
# 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
```bash
$ ccgo build linux
✨ No source changes detected, using cached build
✓ Build completed in 0.5s
```
#### Incremental Build
```bash
$ ccgo build linux
📊 Incremental build - 3 files changed:
Modified: 2
Added: 1
⚡ Rebuilding affected files...
✓ Build completed in 4.2s
```
#### Full Rebuild Required
```bash
$ 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:
```toml
[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:
```bash
# 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:
```bash
# 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:
```bash
# 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:
```json
{
"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
```bash
# 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:
| 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
```yaml
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
```yaml
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**:
1. **Build state file missing**
```bash
ls cmake_build/release/linux/.ccgo_build_state.json
ccgo build linux
```
2. **Config or options changing**
```bash
git diff CCGO.toml
```
3. **CMake cache cleared**
```bash
ls cmake_build/release/linux/CMakeCache.txt
```
### 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:
```bash
# 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**:
```bash
# 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
```rust
// 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:
```rust
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:
1. **CMake detects file changes** - Checks modification times
2. **CCGO detects config changes** - Prevents stale builds
3. **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:
```bash
# 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:
```bash
# Release build
ccgo build linux
# Debug build (separate state)
ccgo build linux --debug
```
### Link Types
Static and shared builds share the same build state:
```bash
# 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](build-caching.md) - Compiler cache for faster builds
- [Build Analytics](build-analytics.md) - Performance metrics and tracking
- [Build System](features/build-system.md) - 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.*