Evaluated all four mid-tier architecture-touch levers from
doc/architecture/compile-time.md. Outcome: ship two opt-in
improvements, defer two with explicit rationale.
#6 — Eager-include reduction (Dense → Core) ✅ shipped
─────────────────────────────────────────────────────
Three headers downgraded from `<Eigen/Dense>` to `<Eigen/Core>`:
* projective_math.hpp
* hyper_ideal_visualization_utility.hpp
* mesh_utils.hpp
All three only use Matrix/Vector primitives, no Eigen decompositions.
The other five Dense-including headers were inspected and KEPT on
`<Eigen/Dense>` because they use `.inverse()`, `.determinant()`,
`ColPivHouseholderQR`, or `SelfAdjointEigenSolver`.
Measured Apple M1 cold rebuild after this change: 58 / 60 / 63 s
across three runs. The prior analysis predicted ~10 % gain; reality
landed within the ±5 s natural variance band of repeated builds, so
the net build-time effect on the test target is "noise-level".
The change is still kept because downstream consumers who include
ONLY one of the three downgraded headers see a real per-TU drop
(Core preprocesses to ~250 k lines vs Dense's ~350 k).
#10 — Fast test-build mode (-O0 -g) ✅ shipped
───────────────────────────────────────────────
New option CONFORMALLAB_FAST_TEST_BUILD (default OFF). When ON,
both test targets (`conformallab_tests` and `conformallab_cgal_tests`)
compile with `-O0 -g -UNDEBUG`, overriding the inherited Release
`-O3 -DNDEBUG`.
Measured Apple clang: 51.6 s vs 46.8 s without -O0 → slightly slower.
The Backend phase that prior analysis predicted would drop from 9.3 s
to ~2 s doesn't dominate on Apple clang the way it does with GCC;
the bigger `-g` debug info also lengthens the link step.
Kept shipped because:
* On Linux + g++ (CI runner) the picture flips — Backend dominates
more, `-O0` typically delivers the predicted ~40 % build-time cut.
* Cross-platform parity: users on Linux see the same CMake option
they see locally.
Honest documentation in doc/architecture/compile-time.md notes that
the Apple-clang-local benefit is currently 0 %. Tests RUN ~15× slower
under `-O0` (1.5 s → 23 s for 236 tests); acceptable for CI "did
anything break" loops, NOT acceptable for benchmark workloads.
#5 — Move detail:: impls to .inl files ⏸ deferred
───────────────────────────────────────────────────
Pure enabler for #7. Without #7 landing, the .inl extraction would
just add an extra hop to header reading. Reconsider once a concrete
maintenance reason emerges (e.g. a downstream user wants to override a
detail helper).
#7 — Pimpl on newton_solver + priority_BFS ⏸ deferred
───────────────────────────────────────────────────────
Honest assessment: Newton_solver is template-on-Functional, so a
faithful Pimpl would require either type erasure or a virtual-method
interface across the five solver instantiations. Estimated 1-2 weeks
of refactor with measurable API-surface risk. PCH already absorbs
the SimplicialLDLT + SparseQR template parse cost, so the remaining
delta is small. Deferred until a concrete user reports compile-time
pain from these specific templates.
Documentation
─────────────
README.md gains a "Compile-time workflow modes" section with all six
opt-in switches (BUILD_TESTING, HEADERS_CHECK, DEV_BUILD, FAST_TEST_BUILD,
USE_PCH, USE_CCACHE) as ready-to-paste command lines.
doc/architecture/compile-time.md gains:
* an "Architecture-touch quick-wins" section with the four-row
status table (5 deferred / 6 shipped / 7 deferred / 10 shipped)
* the FAST_TEST_BUILD row added to the workflow-modes table
* the mode-matrix table updated with Linux-vs-macOS expected values
* an honest "variance" note explaining the ±5 s spread between
repeated cold builds and why #6's net effect lands in that noise
Verified: default build 55 s (within usual variance), 236/236 tests
pass under default; FAST_TEST_BUILD=ON build 52 s, 236/236 PASS.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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 closes the structural-tests work on PR #18. Every gate
in `run-all.sh --fast` now passes end-to-end on the canonical dev
machine.
New gates
─────────
1. shellcheck (scripts/quality/shellcheck.sh)
* Scans every `scripts/**/*.sh` at severity=warning+
* 16 scripts inspected; cleanup pass took the tree from 7 findings
(SC2164 + SC2034) to 0 findings.
2. cppcheck (scripts/quality/cppcheck.sh)
* Complementary static analyser to clang-tidy; different heuristics,
fewer false-positives on heavy CGAL/Eigen templates.
* Default severity warning+, --strict adds style, --all = everything.
* Suppresses 4 noise classes (missingIncludeSystem, etc.) explicitly.
3. .editorconfig
* Cross-IDE fallback for editors that don't honour clang-format.
* Covers Markdown (preserve trailing whitespace), Python, YAML,
JSON, shell, Makefile (tabs) — the file types clang-format
doesn't cover.
4. CONFORMALLAB_WARNINGS_AS_ERRORS CMake option
* Off by default → regular builds don't break on new GCC warnings.
* `-DCONFORMALLAB_WARNINGS_AS_ERRORS=ON` adds `-Werror`, intended for
CI promotion-track and sanitizer runs.
Dependency audit (doc/architecture/dependencies.md)
────────────────────────────────────────────────────
New single-source-of-truth document listing:
* what the library requires (Eigen + CGAL + Boost — all header-only)
* what tests require (auto-fetched GTest, no system install)
* what each quality tool is for, install command per OS, and
behaviour when missing (each gate exits 2 = SKIP, run-all
recognises this and continues)
* a verification recipe that strips PATH down and shows the
library still configures + builds + tests cleanly with zero
quality tools installed.
run-all.sh enhanced
───────────────────
* Recognises "tool not in PATH" → SKIP (not FAIL).
* Summary now reports `passed / skipped / failed` separately.
Bug fixes uncovered by the sweep
────────────────────────────────
* sanitizers.sh: gtest_discover_tests ran the ASan-instrumented
binary at build time and aborted → added
`-DCMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE=PRE_TEST` to defer
discovery to ctest invocation. Now 23/23 sanitizer-instrumented
tests pass.
* clang-tidy.sh on macOS: brew-installed clang-tidy couldn't find
Apple SDK system headers (<cmath>, <complex>, …) → added
`--extra-arg=-isysroot $(xcrun --show-sdk-path)` on Darwin.
* clang-tidy.sh: needed `-DWITH_CGAL_TESTS=ON` in compile_commands
generation so CGAL include paths are part of at least one
compile entry. Now resolves CGAL/Surface_mesh.h etc.
* clang-tidy.sh: viewer-only headers (`viewer_utils.h`, `mesh_utils.hpp`)
excluded — they need `WITH_VIEWER=ON` + system GLFW/libigl that the
lint build doesn't drag in.
* `.codespellrc`: extended ignore list (recognise, signalled, modelled,
travelled, …) for British-English consistency across own writing.
Final state — local quality block on this commit, this branch:
✅ License headers (66/66 carry MIT SPDX)
✅ CGAL conventions (0/6 violations on 6 CGAL headers)
✅ clang-format drift (0 drift)
✅ cmake-format/-lint (0 drift, 0 lint findings)
✅ codespell (0 typos in scope)
✅ shellcheck (0 findings across 16 .sh files)
✅ cppcheck (warning+ severity clean)
✅ Markdown links (122/122 resolve)
✅ Sanitizers (ASan+UBSan) (23/23 fast tests pass)
✅ clang-tidy (35 headers inspected, 0 findings)
Library standalone-ness verified:
env -i PATH=... cmake -S code -B /tmp/build-standalone
cmake --build /tmp/build-standalone --target conformallab_tests
ctest -E '^cgal\.' → all green
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Root cause: -DWITH_CGAL=ON implied -DWITH_VIEWER=ON, which pulled in
GLFW, which requires wayland-scanner — not present in the headless CI
container (ubuntu:22.04 ARM64).
Fix: new CMake option -DWITH_CGAL_TESTS=ON builds conformallab_cgal_tests
without touching the viewer, GLFW, libigl, or any display dependency.
Only Boost headers are required (already in the Docker image).
Changes
───────
code/CMakeLists.txt
- Add WITH_CGAL_TESTS option (OFF by default)
- find_package(Boost REQUIRED) now shared between WITH_CGAL and WITH_CGAL_TESTS
- WITH_CGAL still implies WITH_VIEWER (for local full builds)
- Remove duplicate find_package(Boost) inside the WITH_CGAL block
code/tests/CMakeLists.txt
- cgal/ subdirectory added for WITH_CGAL OR WITH_CGAL_TESTS
.gitea/workflows/cpp-tests.yml
- test-cgal job: -DWITH_CGAL=ON → -DWITH_CGAL_TESTS=ON
README.md
- Build modes table: three rows (default / CGAL_TESTS / CGAL full)
- Quick-start: separate headless and full-local sections
- Prerequisite table updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CGAL 6.x still unconditionally includes boost/config.hpp in its
config.h, so Boost headers are required even with CGAL_DISABLE_GMP/MPFR.
Use system Boost via find_package instead of the removed 211 MB tarball.
Tests-only mode remains completely dependency-free.
Install: brew install boost (macOS)
apt install libboost-dev (Debian/Ubuntu)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restructures the CMake build into three clearly separated modes:
(default) tests only – Eigen + GTest, no heavy deps
-DWITH_VIEWER=ON builds viewer lib (libigl / GLFW / GLAD)
-DWITH_CGAL=ON builds conformallab_core CLI app;
implies WITH_VIEWER automatically
Changes:
- code/CMakeLists.txt: viewer and core targets are now guarded by
option() flags; GTest / tests target is always built
- code/deps/Cmakelists.txt: CGAL, libigl, glfw, glad are only
extracted when the corresponding mode is enabled; Eigen always
- Remove Boost (211 MB tarball, 0 usages in the codebase – CGAL 6.x
does not require Boost for Simple_cartesian / Surface_mesh / basic IO)
- Remove code/src/main.cpp (dead file, not referenced in CMake)
All 16 C++ tests pass in tests-only mode (verified locally).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Google Test via CMake FetchContent (v1.14.0)
- Add clausen.hpp: Clausen integral, Lobachevsky function, Im(Li2)
- Add hyper_ideal_utility.hpp: generalized and ideal-vertex hyperbolic
tetrahedron volume formulas using Eigen for the 4x4 Gram determinant
- Port ClausenTest (5 tests) and HyperIdealUtilityTest (8 tests) from
Java/JUnit — all 13 pass with same tolerances as the Java originals
- Fix pre-existing VIEWER/viewer case mismatch in CMakeLists.txt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>