From 0c3fe5169ca7e6f33d348ea2ee77543182576659 Mon Sep 17 00:00:00 2001 From: Joe Rivera Date: Thu, 3 Sep 2026 18:44:19 -0500 Subject: [PATCH 1/4] fix(sdf): stop reg3data.h leaking an `error` macro out of the header reg3data.h defined #define error(x) {fprintf(stderr, "%s\n", x); exit(1);} at file scope in a header. A function-like macro with that name rewrites any later declaration that uses the identifier, and `error()` matches a one-parameter macro with an empty argument, so any header parsed afterwards that declares a member or function called `error` becomes a syntax error. Three call sites already carried workarounds for it: algorithm.cpp "CGAL headers must come before SDF headers due to macro conflicts" DistanceTransform.cpp "Include app.h BEFORE DistanceTransform.h ... reg3data.h defines error() as a macro which conflicts with cvc::app" mtxlib_test.cpp seventeen lines explaining #undef barriers placed to stop clang-format's IncludeBlocks:Regroup from reordering the includes back into a broken state, ending "Do not merge these blocks" Include ordering is not a fix, and CGAL 6 broke it. CGAL/AABB_traits.h is now deprecated and forwards to AABB_traits_3.h, which pulls in Static_filters/Static_filter_error.h and its `double error() const`. algorithm.cpp includes AABB_traits.h *after* reg3data.h, so the ordering workaround does not cover it, and every macOS and Windows build fails there once the package managers ship CGAL 6.2 (Homebrew and vcpkg both do now). Reduced repro against the pre-fix header: struct Static_filter_error { double _e; double error() const { return _e; } }; reg3data.h:12: error: expected unqualified-id before '{' token The macro had exactly two users, both in RawivParser.cpp. Replaced with a file-local function of the same behaviour, including the exit(1), so the name cannot leave that translation unit. All three workarounds are then dead and are removed; mtxlib_test.cpp now takes clang-format's natural include order -- the order its comment said would break the build -- and compiles. Adds Reg3DataHeaderHygiene.ErrorIsNotAMacro to mtxlib_test, which declares a struct mirroring CGAL's, so reintroducing the macro anywhere reg3data.h can reach fails to compile rather than waiting for the next CGAL bump. mtxlib_test 43/43 and algorithm_test 10/10 pass. --- .../DistanceTransform.cpp | 2 - .../SignDistanceFunction_v2/RawivParser.cpp | 20 ++++++- .../SDF/SignDistanceFunction_v2/reg3data.h | 2 - src/cvc/tests/mtxlib_test.cpp | 58 ++++++++++--------- src/cvc/utility/algorithm.cpp | 1 - 5 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/cvc/geometry/SDF/SignDistanceFunction_v2/DistanceTransform.cpp b/src/cvc/geometry/SDF/SignDistanceFunction_v2/DistanceTransform.cpp index 6d0051a2..878f7548 100644 --- a/src/cvc/geometry/SDF/SignDistanceFunction_v2/DistanceTransform.cpp +++ b/src/cvc/geometry/SDF/SignDistanceFunction_v2/DistanceTransform.cpp @@ -36,8 +36,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -// Include app.h BEFORE DistanceTransform.h to avoid macro conflicts -// (reg3data.h defines error() as a macro which conflicts with cvc::app) #include #include "DistanceTransform.h" diff --git a/src/cvc/geometry/SDF/SignDistanceFunction_v2/RawivParser.cpp b/src/cvc/geometry/SDF/SignDistanceFunction_v2/RawivParser.cpp index d90ea76c..d90544c6 100644 --- a/src/cvc/geometry/SDF/SignDistanceFunction_v2/RawivParser.cpp +++ b/src/cvc/geometry/SDF/SignDistanceFunction_v2/RawivParser.cpp @@ -12,6 +12,22 @@ #include "reg3data.h" #include "bio.h" +namespace { + +// Was a function-like macro named `error(x)` in reg3data.h. A macro by that +// name escaping a header collides with any later declaration that uses the +// identifier -- CGAL 6's Static_filter_error::error(), boost.parameter's +// error(), cvc::app -- which is why three separate call sites carried +// include-ordering workarounds. Kept as a file-local function so the name +// cannot leave this translation unit. +void reg3_fatal(const char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +} // namespace + ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -45,7 +61,7 @@ bool RawivParser::parse(Reg3Data* data, const char* fname) DiskIO *pio = new BufferedIO(fname); if(!pio->open()) { - error("Data File Open Failed"); + reg3_fatal("Data File Open Failed"); } pio->get(minext, 3); @@ -78,7 +94,7 @@ bool RawivParser::write(const Reg3Data& data, const char* fname) { DiskIO *pio = new BufferedIO(fname, DiskIO::WRITE); if(!pio->open()) { - error("Cannot Open Data File to write"); + reg3_fatal("Cannot Open Data File to write"); return false; } float maxext[3]; diff --git a/src/cvc/geometry/SDF/SignDistanceFunction_v2/reg3data.h b/src/cvc/geometry/SDF/SignDistanceFunction_v2/reg3data.h index 8bc9491c..fbfe19e9 100644 --- a/src/cvc/geometry/SDF/SignDistanceFunction_v2/reg3data.h +++ b/src/cvc/geometry/SDF/SignDistanceFunction_v2/reg3data.h @@ -9,8 +9,6 @@ #include "cubes.h" -#define error(x) {fprintf(stderr, "%s\n", x); exit(1);} - /** * Reg3Data: A class representing a scalar field on a regular 3D grid. * diff --git a/src/cvc/tests/mtxlib_test.cpp b/src/cvc/tests/mtxlib_test.cpp index 2d177cbf..19486e6b 100644 --- a/src/cvc/tests/mtxlib_test.cpp +++ b/src/cvc/tests/mtxlib_test.cpp @@ -2,19 +2,11 @@ // mtxlib (vector2/3/4, matrix33/44), FaceVertSet3D, BufferedIO, the parsers // (Geom3DParser, RawivParser) and DistanceTransform construction + geometric // predicates. -// -// Include order matters here, and is enforced against clang-format. reg3data.h -// (pulled in by DistanceTransform.h) defines a function-like macro `error(x)`. -// boost/parameter/parameters.hpp — reached transitively through cvc/core/app.h -// and gtest via boost.signals2 — contains a bare `error();` call, which that -// macro clobbers into a syntax error. So the boost-pulling headers must be -// parsed BEFORE the SDF v2 headers define the macro. -// -// The repo .clang-format is IncludeBlocks:Regroup with quoted includes sorted -// ahead of angle-bracket ones, so it would hoist the SDF headers above the -// cvc/boost includes and re-break the build — unless a non-include line splits -// them into separate, individually-sorted blocks. The #undef barriers below do -// exactly that (and are correct on their own merits). Do not merge these blocks. +#include "DistanceTransform.h" // pulls in FaceVertSet3D.h, reg3data.h, RawivParser.h +#include "Geom3DParser.h" +#include "bufferedio.h" +#include "mtxlib.h" + #include #include #include @@ -23,21 +15,21 @@ #include #include -#ifdef error -#undef error // no-op here; keeps this block separate from the SDF block below -#endif - -#include "DistanceTransform.h" // pulls in FaceVertSet3D.h, reg3data.h, RawivParser.h -#include "Geom3DParser.h" -#include "bufferedio.h" -#include "mtxlib.h" - -#ifdef error -#undef error // reg3data.h's error(x) macro must not leak into the test body -#endif - namespace { +// Regression guard for the `error(x)` macro that reg3data.h used to define. +// A function-like macro with that name escaping a header rewrites any later +// declaration that uses the identifier. CGAL 6 is the case that broke the +// build: CGAL/AABB_traits.h forwards to AABB_traits_3.h, which pulls in +// Static_filter_error with a `double error() const` member, and `error()` +// matches the one-parameter macro with an empty argument. boost.parameter and +// cvc::app hit the same thing. This struct mirrors the CGAL declaration, so +// reintroducing the macro anywhere reg3data.h can reach makes this file fail +// to compile. +struct StaticFilterErrorLookalike { + double error() const { return 1.0; } +}; + const float kEps = 1e-5f; // Mirror of DistanceTransform::MAX_FLOAT (== 1.0e12f, DistanceTransform.cpp:52), @@ -101,6 +93,20 @@ void expectMat44Near(const matrix44 &a, const matrix44 &b, float tol) { } // namespace +// =========================================================================== +// header hygiene +// =========================================================================== + +// Compiles only while no reachable header defines `error` as a macro; see +// StaticFilterErrorLookalike above. +TEST(Reg3DataHeaderHygiene, ErrorIsNotAMacro) { +#ifdef error + FAIL() << "a reachable header defines `error` as a macro again"; +#endif + const StaticFilterErrorLookalike probe; + EXPECT_DOUBLE_EQ(1.0, probe.error()); +} + // =========================================================================== // vector2 // =========================================================================== diff --git a/src/cvc/utility/algorithm.cpp b/src/cvc/utility/algorithm.cpp index 283a6ea3..b74be33e 100644 --- a/src/cvc/utility/algorithm.cpp +++ b/src/cvc/utility/algorithm.cpp @@ -24,7 +24,6 @@ #include #include -// CGAL headers must come before SDF headers due to macro conflicts #ifndef DISABLE_CGAL #include #include From 6482eaafad5b9c4323424377a1b51b6b4132bbe9 Mon Sep 17 00:00:00 2001 From: Joe Rivera Date: Thu, 3 Sep 2026 19:33:21 -0500 Subject: [PATCH 2/4] cvcpkg(libcvc): bump cvc_revision to 4 so the bundle finally ships cvc::xmlrpc The published 3.3.0+cvc.3 bundle still has no cvc::xmlrpc. Verified by installing it from the live catalog: cvcpkg install libcvc --prefix p --config release --link shared grep -c cvc::xmlrpc p/lib/cmake/cvc/cvcTargets.cmake -> 0 ls p/lib | grep -i xmlrpc -> (nothing) ls p/include/xmlrpc -> headers present publish-cvcpkg.yml already passes -DCVC_USING_XMLRPC=ON on every lane and hard-fails when the archive or the exported target is missing, but +cvc.3 predates those guards, so no artifact ever carried them. Only a republish can fix it, and only at a revision above the catalog's max -- 3, not the recipe's stale 2 -- so this goes straight to 4. At or below the published max the publish is a silent no-op / 409. Why this matters beyond libcvc: transfix/F2Dock hard-requires cvc::xmlrpc. Its _libcvc_check_usable() rejects any libcvc package that lacks the target and src/CMakeLists.txt FATAL_ERRORs without it, so both catalog strategies have always been rejected and F2Dock has always fallen through to building libcvc FROM SOURCE. Demonstrated with a cvcpkg prefix on CMAKE_PREFIX_PATH: -- Prebuilt libcvc download failed: 22;"HTTP response code said error" -- Building libcvc v3.3.0 from source That source build is the only reason CGAL and the platform toolchains enter F2Dock's compile at all -- and therefore the only reason CGAL 6.2 broke its macOS jobs and the VS18 v180 CL.exe crash broke its Windows jobs. A bundle that actually exports cvc::xmlrpc removes the source build and both failure modes with it. Pairs with the reg3data.h fix in this PR: the +cvc.4 republish carries both. --- cvcpkg/recipes/libcvc/recipe.yaml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/cvcpkg/recipes/libcvc/recipe.yaml b/cvcpkg/recipes/libcvc/recipe.yaml index 25fd4bbe..c68154ec 100644 --- a/cvcpkg/recipes/libcvc/recipe.yaml +++ b/cvcpkg/recipes/libcvc/recipe.yaml @@ -43,7 +43,27 @@ recipe: # spelling. Verified against the published bundle: 0 occurrences of # cvc::xmlrpc in cvcTargets.cmake and no archive, while include/xmlrpc/ # headers shipped. - cvc_revision: 2 + # Bumped 2 -> 4 (not 3: the catalog already has 3.3.0+cvc.3, and a revision + # at or below the published max is a silent no-op / 409). The +cvc.3 bundle + # STILL ships include/xmlrpc/ headers with no lib/libxmlrpc* archive and no + # cvc::xmlrpc in cvcTargets.cmake -- verified by installing it: + # cvcpkg install libcvc --prefix p --config release --link shared + # grep -c cvc::xmlrpc p/lib/cmake/cvc/cvcTargets.cmake -> 0 + # ls p/lib | grep -i xmlrpc -> (nothing) + # publish-cvcpkg.yml now passes -DCVC_USING_XMLRPC=ON on every lane AND hard- + # fails when the archive or the exported target is missing, but +cvc.3 was + # published before those guards landed, so the artifact never picked them up. + # This bump is what actually carries the fix to consumers. + # + # It is load-bearing downstream: transfix/F2Dock hard-requires cvc::xmlrpc + # (src/CMakeLists.txt FATAL_ERRORs without it, and its _libcvc_check_usable + # rejects any libcvc package lacking it). That rejection is why F2Dock has + # always fallen through to building libcvc FROM SOURCE -- which is the only + # reason CGAL and the platform toolchains enter its build at all, and hence + # why CGAL 6.2 (macOS/Windows) and the VS18 v180 CL.exe crash (Windows) break + # it. A bundle that actually exports cvc::xmlrpc removes the source build, + # and those failures with it. + cvc_revision: 4 maintainer: "cvcpkg group" maintainer_email: "info@cvcpkg.org" maintainer_url: "https://cvcpkg.org" From 29eb0ddbc6696dab6083d6e27816ba7be143a356 Mon Sep 17 00:00:00 2001 From: Joe Rivera Date: Thu, 3 Sep 2026 19:37:36 -0500 Subject: [PATCH 3/4] build: derive CVC_VERSION from PROJECT_VERSION instead of hardcoding 3.0 src/cvc/CMakeLists.txt pinned CVC_VERSION_MAJOR/MINOR at 3/0 while the top-level project() said 3.3.0. CVC_VERSION feeds write_basic_package_version_file, so every published bundle exported a cvcConfigVersion.cmake reading set(PACKAGE_VERSION "3.0") with COMPATIBILITY SameMajorVersion. Any downstream find_package(cvc 3.x.y) with y > 0 failed the version check against every bundle ever published -- the requested version is simply greater than 3.0. transfix/F2Dock is the case in hand: it asked for 3.2.0, never matched, and fell through to building libcvc from source. Together with the missing cvc::xmlrpc target (previous commit) that is two independent reasons a consumer could not use a published bundle, and the source build is what put CGAL and the host toolchain into F2Dock's compile. SOVERSION still comes from CVC_VERSION_MAJOR, so the runtime link name is unchanged and nothing relinks -- verified: lib/libcvc.so -> libcvc.so.3 (unchanged) lib/libcvc.so.3 -> libcvc.so.3.3.0 (was libcvc.so.3.0) Only the full VERSION suffix and the exported package version move. Both still match the recipe's `lib/libcvc*` pack glob. --- src/cvc/CMakeLists.txt | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/cvc/CMakeLists.txt b/src/cvc/CMakeLists.txt index f9fd0ad5..347f50c9 100644 --- a/src/cvc/CMakeLists.txt +++ b/src/cvc/CMakeLists.txt @@ -251,10 +251,22 @@ if(NOT CVC_STATE_MEMORY_MANAGER) list(REMOVE_ITEM SOURCE_FILES core/state_memory_manager.cpp core/state_eviction_store.cpp) endif() -# The libcvc version number -set(CVC_VERSION_MAJOR 3) -set(CVC_VERSION_MINOR 0) -set(CVC_VERSION ${CVC_VERSION_MAJOR}.${CVC_VERSION_MINOR}) +# The libcvc version number, derived from project(libcvc VERSION ...) in the +# top-level CMakeLists so the two cannot drift apart. +# +# They had: this was hardcoded 3.0 while the project said 3.3.0, so every +# published bundle exported a cvcConfigVersion.cmake reading +# PACKAGE_VERSION "3.0" with COMPATIBILITY SameMajorVersion. Any downstream +# find_package(cvc 3.x.y) with y > 0 therefore failed the version check no +# matter which bundle was installed -- e.g. transfix/F2Dock asked for 3.2.0, +# never matched, and silently fell back to building libcvc from source. +# +# SOVERSION stays CVC_VERSION_MAJOR, so the runtime link name (libcvc.so.3) +# is unchanged and no consumer relinks. Only the full VERSION suffix +# (libcvc.so.3.0 -> libcvc.so.3.3.0) and the exported package version move. +set(CVC_VERSION ${PROJECT_VERSION}) +set(CVC_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) +set(CVC_VERSION_MINOR ${PROJECT_VERSION_MINOR}) message(STATUS "libcvc version: ${CVC_VERSION}") set(CVC_LINK_LIBS "") From f37762a3fa0645e10c9133b6f4b62ca4840800f3 Mon Sep 17 00:00:00 2001 From: Joe Rivera Date: Thu, 3 Sep 2026 19:44:58 -0500 Subject: [PATCH 4/4] ci(publish): publish a windows-debug libcvc bundle The matrix excluded config=debug on windows-2022 because the catalog had no windows-debug dep bundles, so a Debug libcvc would have linked Release MSVC deps -- a debug/release CRT mismatch producing a broken artifact. That was the right call at the time; the fix is to close the gap, not keep excluding. Measured it across libcvc's 34 runtime deps by querying the catalog for platform=windows build-type=debug. Twenty-three already had bundles; ten did not: gmp, mpfr, gsl, tiff, libiimod, assimp, levmar, grpc, cgal, imagemagick. (fontconfig also came back missing but is scoped platforms: [linux, macos] in this recipe, so it never applied to a Windows build.) Those ten are building now via libcvc-deps' windows-build.yml with config=debug, dispatched in dependency order so each publishes before the next installs it. Downstream this is what lets a consumer run a Debug lane at all: transfix/F2Dock builds Debug and Release on all three platforms and now takes libcvc from the catalog instead of compiling it, so a missing windows-debug bundle would leave that lane with nothing to link. Do not merge ahead of the dep builds -- without them the lane produces exactly the mismatched artifact the exclusion was guarding against. --- .github/workflows/publish-cvcpkg.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish-cvcpkg.yml b/.github/workflows/publish-cvcpkg.yml index 96ba207a..90f8a0d1 100644 --- a/.github/workflows/publish-cvcpkg.yml +++ b/.github/workflows/publish-cvcpkg.yml @@ -350,15 +350,17 @@ jobs: # same root cause as ci.yml's package-windows failures after the # image flip). Revisit when the v180 toolset stabilizes. - { os: windows-2022, platform: windows, arch: x86_64 } - exclude: - # Windows debug is unsound to publish here: the catalog has no - # windows-debug dep bundles, so a Debug libcvc would link against - # Release MSVC deps — a debug/release CRT mismatch producing a - # broken artifact. Restore once debug Windows dep bundles exist - # (via the remote-builder fleet). Linux/macOS have no such issue: - # a Debug libcvc links the Release (shared, ABI-stable) deps fine. - - config: debug - target: { os: windows-2022, platform: windows, arch: x86_64 } + # No windows-debug exclusion any more. It used to be unsound because + # the catalog had no windows-debug dep bundles, so a Debug libcvc + # would have linked Release MSVC deps — a debug/release CRT mismatch + # producing a broken artifact. The gap was measured across libcvc's + # 34 runtime deps and closed by publishing the ten that were missing: + # gmp, mpfr, gsl, tiff, libiimod, assimp, levmar, grpc, cgal and + # imagemagick. (fontconfig is scoped linux/macos, so it never + # applied.) A windows-debug libcvc bundle is what lets downstream + # consumers run a Debug matrix lane at all — transfix/F2Dock builds + # Debug and Release on all three platforms and now takes libcvc from + # the catalog rather than compiling it. include: # Extra pycvc-column jobs (linux x86_64, release only): each builds # libcvc + cvcgl locally to link against, then packs+publishes ONLY