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>
184 lines
8.2 KiB
CMake
184 lines
8.2 KiB
CMake
# tests/cgal/CMakeLists.txt
|
||
#
|
||
# CGAL-dependent test target. Only built when -DWITH_CGAL=ON.
|
||
# Requires Boost (find_package(Boost REQUIRED) is called in the root CMakeLists).
|
||
#
|
||
# Run with:
|
||
# cmake -S code -B build -DWITH_CGAL=ON
|
||
# cmake --build build --target conformallab_cgal_tests
|
||
# ctest --test-dir build -R cgal
|
||
|
||
add_executable(conformallab_cgal_tests
|
||
# ── Phase 3a: mesh infrastructure ──────────────────────────────────────
|
||
test_conformal_mesh.cpp
|
||
|
||
# ── Phase 3b: HyperIdealFunctional ─────────────────────────────────────
|
||
test_hyper_ideal_functional.cpp
|
||
|
||
# ── Phase 3c + 3e: SphericalFunctional + gauge-fix ────────────────────
|
||
test_spherical_functional.cpp
|
||
|
||
# ── Phase 3d: EuclideanCyclicFunctional ───────────────────────────────
|
||
test_euclidean_functional.cpp
|
||
|
||
# ── Phase 3f: Hessians (cotangent Laplacian, spherical + Euclidean) ───
|
||
test_euclidean_hessian.cpp
|
||
test_spherical_hessian.cpp
|
||
|
||
# ── Phase 9b: Hyper-ideal Hessian — block-FD vs full-FD validation ───
|
||
# Verifies the O(F·36) block-local Hessian agrees with the
|
||
# O(F·n) full-FD baseline. Java upstream has no Hessian at all
|
||
# (HyperIdealFunctional.hasHessian() returns false) — both
|
||
# variants are conformallab++ extensions beyond the port.
|
||
test_hyper_ideal_hessian.cpp
|
||
|
||
# ── Phase 4a: Newton solver ────────────────────────────────────────────
|
||
test_newton_solver.cpp
|
||
|
||
# ── Phase 4b: Mesh I/O (CGAL::IO) ─────────────────────────────────────
|
||
test_mesh_io.cpp
|
||
|
||
# ── Phase 4c: End-to-end pipeline + user examples ─────────────────────
|
||
test_pipeline.cpp
|
||
|
||
# ── Phase 5: Layout / embedding + serialization ────────────────────────
|
||
test_layout.cpp
|
||
|
||
# ── Phase 6: Gauss–Bonnet, cut graph, exact trilateration, normalisation
|
||
test_phase6.cpp
|
||
|
||
# ── Phase 7: Java-parity layout — MobiusMap, priority BFS, halfedge_uv,
|
||
# period matrix, fundamental domain, tiling
|
||
test_phase7.cpp
|
||
|
||
# ── Java parity: geometry utility tests ──────────────────────────────────
|
||
# Ported from CuttinUtilityTest, UnwrapUtilityTest,
|
||
# ConvergenceUtilityTests, HomologyTest. All tests active —
|
||
# the v0.7.0 genus-2 homology stub was implemented in Phase 7
|
||
# (HomologyGenerators.Genus2_FourCutEdges, brezel2.obj).
|
||
test_geometry_utils.cpp
|
||
|
||
# ── Scalability smoke tests ────────────────────────────────────────────────
|
||
# Newton convergence on large real-world meshes (cathead, brezel, brezel2).
|
||
# Assert correctness only (< 30 iterations, ||G|| < 1e-8).
|
||
# Wall-clock time is printed for documentation but NOT asserted,
|
||
# so the tests remain stable on slow CI hardware (Raspberry Pi ARM64).
|
||
test_scalability_smoke.cpp
|
||
|
||
# ── Phase 8 MVP: new CGAL-style public API ────────────────────────────────
|
||
# First client of Conformal_map_traits.h + Discrete_conformal_map.h.
|
||
# Acceptance probe before Phase 9a (Inversive-Distance) lands.
|
||
test_cgal_traits_mvp.cpp
|
||
|
||
# ── Phase 9a.1: CPEuclideanFunctional (BPS 2010 circle packing) ──────────
|
||
# Face-based circle-packing functional ported from
|
||
# CPEuclideanFunctional.java. Reference: Bobenko-Pinkall-Springborn 2010.
|
||
test_cp_euclidean_functional.cpp
|
||
|
||
# ── Phase 9a.2: InversiveDistance (Luo 2004 + Glickenstein 2011) ─────────
|
||
# Vertex-based inversive-distance circle-packing functional. No Java
|
||
# reference; implemented from the literature. Cross-validated against
|
||
# EuclideanCyclicFunctional at the natural initial geometry (u = 0).
|
||
test_inversive_distance_functional.cpp
|
||
|
||
# ── Phase 9a: Newton solvers for the two new circle-packing functionals ──
|
||
# Convergence tests for newton_cp_euclidean (analytic Hessian) and
|
||
# newton_inversive_distance (FD Hessian).
|
||
test_newton_phase9a.cpp
|
||
|
||
# ── Phase 8b-Lite: CGAL entry wrappers for the 4 non-Euclidean modes ─────
|
||
# Spherical, HyperIdeal, CircleP-Euclidean, Inversive-Distance via
|
||
# <CGAL/Discrete_*.h> public API + Conformal_layout.h wrapper.
|
||
test_cgal_phase8b_lite.cpp
|
||
)
|
||
|
||
target_include_directories(conformallab_cgal_tests SYSTEM PRIVATE
|
||
${CMAKE_SOURCE_DIR}/deps/eigen-3.4.0
|
||
${CMAKE_SOURCE_DIR}/deps/CGAL-6.1.1/include
|
||
${CMAKE_SOURCE_DIR}/deps/single_includes
|
||
${Boost_INCLUDE_DIRS}
|
||
)
|
||
|
||
target_include_directories(conformallab_cgal_tests PRIVATE
|
||
${CMAKE_SOURCE_DIR}/include
|
||
)
|
||
|
||
target_compile_definitions(conformallab_cgal_tests PRIVATE
|
||
CGAL_DISABLE_GMP
|
||
CGAL_DISABLE_MPFR
|
||
# Data directory — absolute path to code/data/ at build time.
|
||
# Used by tests that load real mesh files (cathead.obj, brezel2.obj, …).
|
||
CONFORMALLAB_DATA_DIR="${CMAKE_SOURCE_DIR}/data"
|
||
)
|
||
|
||
# Suppress warnings from CGAL/Boost headers
|
||
target_compile_options(conformallab_cgal_tests PRIVATE
|
||
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wno-unused-parameter>
|
||
)
|
||
|
||
target_link_libraries(conformallab_cgal_tests PRIVATE GTest::gtest_main)
|
||
|
||
# ── Compile-time speed-up: precompiled headers ───────────────────────────────
|
||
#
|
||
# The CGAL+Eigen template soup dominates every TU in this target:
|
||
# measured at 5.9 s per minimal "include <CGAL/Discrete_conformal_map.h>"
|
||
# TU on Apple M1. A shared PCH absorbs that cost once, slashing the
|
||
# total wall-clock from ~78 s (j8) to ~25 s (3×).
|
||
#
|
||
# Opt-out with -DCONFORMALLAB_USE_PCH=OFF if the PCH itself misbehaves
|
||
# (e.g. older toolchains that don't share PCH across translation units
|
||
# reliably) — falls back to the historical "every TU re-parses CGAL"
|
||
# build mode.
|
||
option(CONFORMALLAB_USE_PCH
|
||
"Enable precompiled headers for the CGAL test target." ON)
|
||
|
||
if(CONFORMALLAB_USE_PCH)
|
||
# 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.
|
||
<CGAL/Surface_mesh.h>
|
||
<CGAL/Simple_cartesian.h>
|
||
<CGAL/Kernel_traits.h>
|
||
<CGAL/boost/graph/iterator.h>
|
||
<CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||
|
||
# Eigen blocks that drive the slowest template instantiations
|
||
# (SelfAdjointEigenSolver<Matrix<2,2>>, ColPivHouseholderQR<
|
||
# Matrix<complex,3,3>>, sparse Cholesky + QR fallback).
|
||
<Eigen/Dense>
|
||
<Eigen/Sparse>
|
||
<Eigen/SparseCholesky>
|
||
<Eigen/SparseQR>
|
||
|
||
# GoogleTest itself; every test includes it.
|
||
<gtest/gtest.h>
|
||
|
||
# std headers that appear in every test.
|
||
<vector>
|
||
<string>
|
||
<cmath>
|
||
<complex>
|
||
)
|
||
endif()
|
||
|
||
include(GoogleTest)
|
||
gtest_discover_tests(conformallab_cgal_tests
|
||
TEST_PREFIX "cgal."
|
||
DISCOVERY_TIMEOUT 60
|
||
)
|