$npx -y skills add mohitmishra786/low-level-dev-skills --skill build-accelerationBuild acceleration skill for C/C++ projects. Use when reducing compilation times with ccache, sccache, distcc, unity builds, precompiled headers, split DWARF, or IWYU. Covers caching strategies, distributed compilation, link time reduction, and diagnosing build bottlenecks. Activ
| 1 | # Build Acceleration |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Guide agents through reducing C/C++ build times using caching (ccache/sccache), distributed compilation (distcc), unity/jumbo builds, precompiled headers, split-DWARF for faster linking, and include pruning with IWYU. |
| 6 | |
| 7 | ## Triggers |
| 8 | |
| 9 | - "My C++ build is too slow — how do I speed it up?" |
| 10 | - "How do I set up ccache / sccache?" |
| 11 | - "How do precompiled headers work with CMake?" |
| 12 | - "How do I set up distributed compilation with distcc?" |
| 13 | - "How do I reduce link times with split-DWARF?" |
| 14 | - "How do I find which headers are slowing down compilation?" |
| 15 | |
| 16 | ## Workflow |
| 17 | |
| 18 | ### 1. Diagnose the bottleneck first |
| 19 | |
| 20 | ```bash |
| 21 | # Time the full build |
| 22 | time cmake --build build -j$(nproc) |
| 23 | |
| 24 | # Find the slowest TUs (CMake ≥3.16 with --profiling-output) |
| 25 | cmake -S . -B build -DCMAKE_CXX_FLAGS="-ftime-report" |
| 26 | cmake --build build 2>&1 | grep "Total" | sort -t: -k2 -rn | head -20 |
| 27 | |
| 28 | # Ninja build timings (use ninja -j1 for serial timing) |
| 29 | ninja -C build -j1 2>&1 | grep "^\[" | sort -t" " -k2 -rn | head -20 |
| 30 | ``` |
| 31 | |
| 32 | ### 2. ccache — compiler cache |
| 33 | |
| 34 | ```bash |
| 35 | # Install |
| 36 | apt-get install ccache # Ubuntu/Debian |
| 37 | brew install ccache # macOS |
| 38 | |
| 39 | # Check hit rate |
| 40 | ccache -s |
| 41 | |
| 42 | # Configure cache size (default 5GB) |
| 43 | ccache -M 20G |
| 44 | |
| 45 | # Invalidate cache if needed |
| 46 | ccache -C |
| 47 | ``` |
| 48 | |
| 49 | CMake integration (recommended over prefix hacks): |
| 50 | |
| 51 | ```cmake |
| 52 | # CMakeLists.txt |
| 53 | find_program(CCACHE_PROGRAM ccache) |
| 54 | if(CCACHE_PROGRAM) |
| 55 | set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PROGRAM}) |
| 56 | set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM}) |
| 57 | endif() |
| 58 | ``` |
| 59 | |
| 60 | Key `~/.config/ccache/ccache.conf` options: |
| 61 | |
| 62 | ```ini |
| 63 | max_size = 20G |
| 64 | compression = true |
| 65 | compression_level = 6 |
| 66 | # For CI: share cache across jobs |
| 67 | cache_dir = /shared/ccache |
| 68 | ``` |
| 69 | |
| 70 | ### 3. sccache — cloud-compatible cache (Rust, C/C++) |
| 71 | |
| 72 | ```bash |
| 73 | cargo install sccache |
| 74 | # Or: brew install sccache |
| 75 | |
| 76 | # Set as compiler launcher |
| 77 | export RUSTC_WRAPPER=sccache # for Rust |
| 78 | export CMAKE_C_COMPILER_LAUNCHER=sccache # for CMake |
| 79 | |
| 80 | # With S3 backend |
| 81 | export SCCACHE_BUCKET=my-build-cache |
| 82 | export SCCACHE_REGION=us-east-1 |
| 83 | sccache --start-server |
| 84 | |
| 85 | sccache --show-stats |
| 86 | ``` |
| 87 | |
| 88 | ### 4. Precompiled headers (PCH) |
| 89 | |
| 90 | PCH compiles a large header once and reuses the binary form. |
| 91 | |
| 92 | ```cmake |
| 93 | # CMake ≥3.16 native PCH support |
| 94 | target_precompile_headers(mylib PRIVATE |
| 95 | <vector> |
| 96 | <string> |
| 97 | <unordered_map> |
| 98 | "myproject/common.h" |
| 99 | ) |
| 100 | |
| 101 | # Share PCH across targets (avoids recompilation) |
| 102 | target_precompile_headers(myapp REUSE_FROM mylib) |
| 103 | ``` |
| 104 | |
| 105 | ```c |
| 106 | // Traditional: stdafx.h / pch.h approach |
| 107 | // All TUs include pch.h as the very first include |
| 108 | // pch.h includes heavy system headers |
| 109 | #pragma once |
| 110 | #include <stdio.h> |
| 111 | #include <stdlib.h> |
| 112 | #include <string.h> |
| 113 | ``` |
| 114 | |
| 115 | PCH is most effective when headers are large and stable (STL, Boost, Qt). Avoid PCH for frequently-changing project headers. |
| 116 | |
| 117 | ### 5. Unity / jumbo builds |
| 118 | |
| 119 | Combine multiple `.cpp` files into one TU to reduce header parsing overhead and improve inlining. |
| 120 | |
| 121 | ```cmake |
| 122 | # CMake ≥3.16 unity build |
| 123 | set_target_properties(mylib PROPERTIES UNITY_BUILD ON) |
| 124 | # Control batch size (default 8 files per unity TU) |
| 125 | set_target_properties(mylib PROPERTIES UNITY_BUILD_BATCH_SIZE 16) |
| 126 | |
| 127 | # Exclude specific files from unity (e.g., if they have ODR issues) |
| 128 | set_source_files_properties(problem.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) |
| 129 | ``` |
| 130 | |
| 131 | Manual unity file: |
| 132 | |
| 133 | ```cpp |
| 134 | // unity_build.cpp |
| 135 | #include "module_a.cpp" |
| 136 | #include "module_b.cpp" |
| 137 | #include "module_c.cpp" |
| 138 | ``` |
| 139 | |
| 140 | Watch out for: anonymous namespaces (each TU has its own), `using namespace` in headers, duplicate static variables. |
| 141 | |
| 142 | ### 6. split-DWARF — reduce link time |
| 143 | |
| 144 | Split DWARF puts debug info in `.dwo` sidecar files, dramatically reducing what the linker must process. |
| 145 | |
| 146 | ```bash |
| 147 | # GCC / Clang |
| 148 | gcc -g -gsplit-dwarf -o prog main.c |
| 149 | |
| 150 | # CMake global |
| 151 | add_compile_options(-gsplit-dwarf) |
| 152 | |
| 153 | # Combine .dwo files for distribution (optional) |
| 154 | dwp -o prog.dwp prog # GNU dwp tool |
| 155 | ``` |
| 156 | |
| 157 | Pair with `--gdb-index` for faster GDB startup: |
| 158 | |
| 159 | ```bash |
| 160 | gcc -g -gsplit-dwarf -Wl,--gdb-index -o prog main.c |
| 161 | ``` |
| 162 | |
| 163 | Link time comparison (large project, typical): `-g` full DWARF ~4×–6× longer link vs `-gsplit-dwarf`. |
| 164 | |
| 165 | ### 7. distcc — distributed compilation |
| 166 | |
| 167 | ```bash |
| 168 | # Install on all machines |
| 169 | apt-get install distcc |
| 170 | |
| 171 | # Start daemon on worker machines |
| 172 | distccd --daemon --allow 192.168.1.0/24 --jobs 8 |
| 173 | |
| 174 | # Client: set DISTCC_HOSTS |
| 175 | export DISTCC_HOSTS="localhost/4 worker1/8 worker2/8" |
| 176 | make -j20 CC="distcc gcc" |
| 177 | |
| 178 | # CMake integration |
| 179 | set(CMAKE_C_COMPILER_LAUNCHER distcc) |
| 180 | set(CMAKE_CXX_COMPILER_LAUNCHER distcc) |
| 181 | ``` |
| 182 | |
| 183 | Stack with ccache: `CC="ccache distcc gcc"` — ccache checks local cache first, falls |