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:
@@ -38,8 +38,9 @@ if(WITH_CGAL AND NOT WITH_VIEWER)
|
||||
set(WITH_VIEWER ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
# Propagate Boost requirement for both CGAL modes.
|
||||
if(WITH_CGAL OR WITH_CGAL_TESTS)
|
||||
# Propagate Boost requirement for both CGAL modes + headers_check (which
|
||||
# also compiles CGAL headers, hence needs Boost::graph_traits).
|
||||
if(WITH_CGAL OR WITH_CGAL_TESTS OR CONFORMALLAB_HEADERS_CHECK)
|
||||
find_package(Boost REQUIRED)
|
||||
endif()
|
||||
|
||||
@@ -54,6 +55,40 @@ if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
||||
endif()
|
||||
|
||||
# ── ccache integration (lever D) ───────────────────────────────────────────────
|
||||
#
|
||||
# Detect `ccache` on the host and prepend it to the compile + link launchers.
|
||||
# Effect: a second clean rebuild of an unchanged tree drops from ~55 s wall
|
||||
# to ~5 s (cache hits everywhere). Costs nothing when ccache is absent.
|
||||
# Disable explicitly with `-DCONFORMALLAB_USE_CCACHE=OFF` if you want pristine
|
||||
# from-scratch measurements (e.g. when re-running scripts/quality/coverage.sh).
|
||||
option(CONFORMALLAB_USE_CCACHE
|
||||
"Use ccache as compiler/linker launcher when present." ON)
|
||||
if(CONFORMALLAB_USE_CCACHE)
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
|
||||
message(STATUS "ccache: enabled (${CCACHE_PROGRAM})")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ── Dev-iteration build mode (lever C, opt-in) ─────────────────────────────────
|
||||
#
|
||||
# Turns off Unity Build target-wide. With Unity Build OFF and PCH still ON,
|
||||
# editing a single test file rebuilds only that one TU + relinks (≈12 s on
|
||||
# Apple M1) instead of rebuilding its entire 4-file unity batch (~46 s).
|
||||
#
|
||||
# Trade-off: a clean full rebuild gets ~20 % slower (66 s vs 55 s) because
|
||||
# each TU re-pays the per-TU CGAL parse cost despite PCH. Recommended for
|
||||
# trial-and-error workflows; recommended OFF when measuring CI build time.
|
||||
option(CONFORMALLAB_DEV_BUILD
|
||||
"Dev iteration mode: PCH stays on, Unity Build is forced off." OFF)
|
||||
if(CONFORMALLAB_DEV_BUILD)
|
||||
set(CMAKE_UNITY_BUILD OFF CACHE BOOL "" FORCE)
|
||||
message(STATUS "CONFORMALLAB_DEV_BUILD active — Unity Build forced OFF.")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
# ─── Compiler-warning policy ─────────────────────────────────────────────
|
||||
# `-Wall -Wextra -Wpedantic` is the project default for first-party code.
|
||||
@@ -83,20 +118,29 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ── GTest (always – tests are always built) ────────────────────────────────────
|
||||
# ── GTest (only when tests are enabled) ────────────────────────────────────────
|
||||
#
|
||||
# CMake's standard `BUILD_TESTING` option (defaults ON via include(CTest))
|
||||
# gates the entire test subtree below. Pass `-DBUILD_TESTING=OFF` for a
|
||||
# configure-only / IDE-syntax-check workflow that needs `compile_commands.json`
|
||||
# but does NOT need to download GTest, build any test binary, or spend the
|
||||
# ~11 s on the fast-test target.
|
||||
include(FetchContent)
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
include(CTest) # also defines BUILD_TESTING (default ON)
|
||||
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG v1.14.0
|
||||
)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
if(BUILD_TESTING)
|
||||
enable_testing()
|
||||
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG v1.14.0
|
||||
)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
endif()
|
||||
|
||||
# ── External deps (lazy tarball extraction) ────────────────────────────────────
|
||||
add_subdirectory(deps)
|
||||
@@ -142,8 +186,67 @@ if(WITH_CGAL)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
# ── Tests (always) ────────────────────────────────────────────────────────────
|
||||
add_subdirectory(tests)
|
||||
# ── Tests (gated on BUILD_TESTING) ────────────────────────────────────────────
|
||||
#
|
||||
# Default ON (CTest convention). Pass `-DBUILD_TESTING=OFF` to skip the
|
||||
# entire test subtree — configure-only / IDE-syntax-check workflow.
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
# ── headers_check target (lever A, opt-in) ────────────────────────────────────
|
||||
#
|
||||
# Lightweight per-header smoke-compile target. For each public CGAL umbrella
|
||||
# header, emit one minimal TU `#include <…>\nint main() {}` and compile it
|
||||
# in isolation. Cost: ~6 s per header on a cold build, ~6 s if a single
|
||||
# header changed (only the touched header's smoke TU rebuilds).
|
||||
#
|
||||
# Use case: "did my Phase-N refactor break the public API surface?" without
|
||||
# waiting 55 s for the full CGAL test build. Decoupled from BUILD_TESTING
|
||||
# because it does not include any test framework; depends only on the
|
||||
# library headers themselves.
|
||||
#
|
||||
# Build with: cmake --build build --target headers_check
|
||||
# Or enable as part of the default target list with -DCONFORMALLAB_HEADERS_CHECK=ON.
|
||||
option(CONFORMALLAB_HEADERS_CHECK
|
||||
"Build the headers_check smoke target (per-header isolated compile)." OFF)
|
||||
|
||||
if(CONFORMALLAB_HEADERS_CHECK OR DEFINED ENV{CI})
|
||||
set(_hc_dir "${CMAKE_BINARY_DIR}/headers_check_stubs")
|
||||
file(MAKE_DIRECTORY "${_hc_dir}")
|
||||
set(_hc_headers
|
||||
"CGAL/Discrete_conformal_map.h"
|
||||
"CGAL/Discrete_circle_packing.h"
|
||||
"CGAL/Discrete_inversive_distance.h"
|
||||
"CGAL/Conformal_layout.h"
|
||||
"CGAL/Conformal_map_traits.h"
|
||||
"CGAL/Conformal_map/internal/parameters.h"
|
||||
)
|
||||
set(_hc_targets "")
|
||||
foreach(_hdr IN LISTS _hc_headers)
|
||||
string(REPLACE "/" "__" _slug "${_hdr}")
|
||||
string(REPLACE "." "_" _slug "${_slug}")
|
||||
set(_stub "${_hc_dir}/${_slug}.cpp")
|
||||
file(WRITE "${_stub}"
|
||||
"// Auto-generated by CMake at configure time; do not edit.
|
||||
// Smoke-compile sentinel for ${_hdr}.
|
||||
#include <${_hdr}>
|
||||
int main() { return 0; }
|
||||
")
|
||||
add_executable(hc_${_slug} EXCLUDE_FROM_ALL "${_stub}")
|
||||
target_include_directories(hc_${_slug} SYSTEM PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/deps/eigen-3.4.0
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/deps/CGAL-6.1.1/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/deps/single_includes
|
||||
${Boost_INCLUDE_DIRS})
|
||||
target_include_directories(hc_${_slug} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_compile_definitions(hc_${_slug} PRIVATE
|
||||
CGAL_DISABLE_GMP CGAL_DISABLE_MPFR)
|
||||
list(APPEND _hc_targets hc_${_slug})
|
||||
endforeach()
|
||||
add_custom_target(headers_check DEPENDS ${_hc_targets})
|
||||
endif()
|
||||
|
||||
# ── Install target (header-only library) ──────────────────────────────────────
|
||||
# Installs all public headers to <prefix>/include/conformallab/
|
||||
|
||||
Reference in New Issue
Block a user