perf: add 4 workflow modes (BUILD_TESTING / DEV_BUILD / HEADERS_CHECK / ccache)

Four orthogonal opt-in build modes on top of the existing PCH + Unity
defaults.  Each addresses a specific iteration scenario; defaults are
unchanged (PCH + Unity stays the canonical fast full-rebuild path).

(A) HEADERS_CHECK target — opt-in via -DCONFORMALLAB_HEADERS_CHECK=ON
    Per-public-header smoke-compile sentinels.  For each of the six
    public CGAL umbrella headers, a stub TU `#include <…>\nint main(){}`
    is generated at configure time and compiled in isolation.
      * Full headers_check build:  ≈ 12 s
      * Incremental after touching one header:  ≈ 0.1 s
    Use case: "did my refactor still parse the public API?" without
    waiting 55 s for the full CGAL test build.

(C) DEV_BUILD mode — opt-in via -DCONFORMALLAB_DEV_BUILD=ON
    PCH stays on; Unity Build is forced off (both globally AND on the
    cgal-tests target which previously overrode the global setting).
    Trade-off: full clean rebuild ~75 s (+36 % vs the 55 s default)
    but incremental rebuild after editing a single test file drops
    from ~46 s (unity batch) to ~16 s (single TU + relink).
    Flip on for trial-and-error sessions, flip off before measuring
    CI build time or shipping a PR.

(D) ccache integration — default ON, disable with -DCONFORMALLAB_USE_CCACHE=OFF
    Detects `ccache` on PATH and prepends it to compile + link
    launchers.  On Apple clang + PCH + Unity the macOS-local hit
    rate is currently 0 % (3 separate friction points documented
    in doc/architecture/compile-time.md § "ccache — honesty notes");
    stays neutral when it doesn't help.  Real payoff on Linux CI
    (g++ + traditional PCH) where 80 %+ hit rates are typical.

(BUILD_TESTING=OFF) Standard CMake gate, now respected end-to-end.
    Wrapped both `add_subdirectory(tests)` AND the FetchContent of
    GoogleTest in `if(BUILD_TESTING)`.  Pass `-DBUILD_TESTING=OFF`:
      * Configure ≈ 1 s
      * Build ≈ 0 s
      * 0 object files
      * No GTest fetch
    Use case: IDE-syntax-check workflow that needs
    `compile_commands.json` but does NOT need to download GTest
    or build any test binary.

doc/architecture/compile-time.md gains:
  * a "Workflow modes — what to choose when" section with a 4-row
    switch matrix and a "mode matrix at a glance" comparison table
  * a ccache honesty-notes block listing the three macOS friction
    points (PCH artefact caching, Unity Build path randomisation,
    CMake launcher integration) — Linux CI is where the lever pays
    off

Verified: default build 53 s wall, 236/236 tests pass; all opt-in
modes tested end-to-end with their expected workflow numbers
documented in the doc.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-26 08:35:44 +02:00
parent 5fbc4bcc7f
commit 9ea7d15aa0
3 changed files with 188 additions and 26 deletions

View File

@@ -133,14 +133,21 @@ option(CONFORMALLAB_USE_PCH
"Enable precompiled headers for the CGAL test target." ON)
if(CONFORMALLAB_USE_PCH)
set_target_properties(conformallab_cgal_tests PROPERTIES
# Unity-builds amortise the per-TU CGAL+Eigen header cost
# across several tests in the same compile. Batch size 4 keeps
# gtest's TEST(...) macros + per-file `using namespace …` from
# colliding while still cutting parser cost ~4×.
UNITY_BUILD ON
UNITY_BUILD_MODE BATCH
UNITY_BUILD_BATCH_SIZE 4)
# Per-target Unity Build property takes precedence over the global
# CMAKE_UNITY_BUILD; honour CONFORMALLAB_DEV_BUILD's preference here
# so `-DCONFORMALLAB_DEV_BUILD=ON` truly turns Unity Build off for
# incremental-rebuild workflows.
if(NOT CONFORMALLAB_DEV_BUILD)
set_target_properties(conformallab_cgal_tests PROPERTIES
# Unity-builds amortise the per-TU CGAL+Eigen header cost
# across several tests in the same compile. Batch size 4
# keeps gtest's TEST(...) macros + per-file `using
# namespace …` from colliding while still cutting parser
# cost ~4×.
UNITY_BUILD ON
UNITY_BUILD_MODE BATCH
UNITY_BUILD_BATCH_SIZE 4)
endif()
target_precompile_headers(conformallab_cgal_tests PRIVATE
# CGAL headers that every test transitively includes.