Summary
Building xmsmesher for msvc 192 (VS2019) fails the cxxtest suite — 21 of 214 tests — while the same source passes under msvc 194 (VS2022) in CI. The failures are floating-point comparison mismatches against checked-in baseline files, not build or link errors.
Found while putting xmsmesher 6.0.8 onto the VS2019 bridge (aquaveo-vs2019). Every other library in the suite — xmscore, xmsgrid, xmsinterp, xmsextractor — built 14/14 clean; xmsmesher is the only one that is this FP-sensitive.
Evidence
Divergence appears around the 9th significant digit:
ND 27 8.5108203108082 31.7579582765 <- baseline (generated with VS2022 / msvc 194)
ND 27 8.5108203218325 31.75795805983 <- produced by VS2019 / msvc 192
Failing assertions are in:
xmsmesher/meshing/MeMultiPolyTo2dm.cpp:333 and :572 — ~18 Files different on line N failures
xmsmesher/tutorial/TutMeshing.cpp:284 — 3 failures
Which configurations
The split is exactly along the testing option. Everything that only compiles and links succeeds; only the four configurations that run the suite fail.
| result |
configurations |
| FAIL (4) |
Debug-dynamic-testing, Debug-static-testing, Release-dynamic-testing, Release-static-testing |
| ok (10) |
both wchar_t variants × Debug/Release × static/dynamic, plus Release-dynamic-pybind for py3.10 and py3.13 |
So the msvc 192 binaries themselves are fine — it is the baseline comparison that does not hold across compilers.
Why the existing FP workaround does not cover this
build.toml already carries an FP-determinism guard:
# Disable FP contraction (FMA fusion) for consistent floating-point results across
# architectures. GCC on ARM emits fmadd at -O2+ which breaks exact arithmetic
# predicates and produces non-deterministic geometry results.
if (NOT MSVC)
add_compile_options(-ffp-contract=off)
endif()
It is scoped if (NOT MSVC) because MSVC does not contract by default. That reasoning holds for x86_64-vs-ARM under GCC, but it does not address msvc 192 vs msvc 194 producing different results from the same source — which is what this issue is about.
Current state
xmsmesher 6.0.8 is published to aquaveo-vs2019 with 10 of 14 package ids. The four testing=True variants are absent for msvc 192. Nothing in the XMS dependency DAG consumes xmsmesher's testing package, so this does not block any other library; it means xmsmesher's own test variants cannot be built for VS2019.
aquaveo-stable is unaffected and carries the full msvc 194 / gcc / clang set.
Options
- Relax the comparison tolerance in
MeMultiPolyTo2dm.cpp and TutMeshing.cpp so the assertions compare with an epsilon rather than exact text. Correct long-term; needs someone who knows the acceptable numerical tolerance for these meshes.
- Pin FP behavior for MSVC (
/fp:strict, or extending the contraction guard to MSVC) so both compilers agree. Most principled, but it would change VS2022 output and therefore require regenerating baselines anyway.
- Accept the gap and keep skipping the testing variants on VS2019 via
--filter '{"options": {"testing": false}}'. This is the current state.
Option 3 is what is in place. 1 or 2 wants an owner who knows the meshing numerics.
Note: unrelated tooling bug
xmsconan vs2019 build exited with code 0 despite 4 failed configurations — the summary table reported succeeded 9 / failed 4 but the process return code was 0. A script trusting the exit code would treat the run as clean and publish a partial set silently. Filed separately against xmsconan; noting here because it is how this nearly went unnoticed.
Summary
Building xmsmesher for msvc 192 (VS2019) fails the cxxtest suite — 21 of 214 tests — while the same source passes under msvc 194 (VS2022) in CI. The failures are floating-point comparison mismatches against checked-in baseline files, not build or link errors.
Found while putting xmsmesher 6.0.8 onto the VS2019 bridge (
aquaveo-vs2019). Every other library in the suite — xmscore, xmsgrid, xmsinterp, xmsextractor — built 14/14 clean; xmsmesher is the only one that is this FP-sensitive.Evidence
Divergence appears around the 9th significant digit:
Failing assertions are in:
xmsmesher/meshing/MeMultiPolyTo2dm.cpp:333and:572— ~18Files different on line Nfailuresxmsmesher/tutorial/TutMeshing.cpp:284— 3 failuresWhich configurations
The split is exactly along the
testingoption. Everything that only compiles and links succeeds; only the four configurations that run the suite fail.Debug-dynamic-testing,Debug-static-testing,Release-dynamic-testing,Release-static-testingwchar_tvariants × Debug/Release × static/dynamic, plusRelease-dynamic-pybindfor py3.10 and py3.13So the msvc 192 binaries themselves are fine — it is the baseline comparison that does not hold across compilers.
Why the existing FP workaround does not cover this
build.tomlalready carries an FP-determinism guard:It is scoped
if (NOT MSVC)because MSVC does not contract by default. That reasoning holds for x86_64-vs-ARM under GCC, but it does not address msvc 192 vs msvc 194 producing different results from the same source — which is what this issue is about.Current state
xmsmesher 6.0.8 is published to
aquaveo-vs2019with 10 of 14 package ids. The fourtesting=Truevariants are absent for msvc 192. Nothing in the XMS dependency DAG consumes xmsmesher's testing package, so this does not block any other library; it means xmsmesher's own test variants cannot be built for VS2019.aquaveo-stableis unaffected and carries the full msvc 194 / gcc / clang set.Options
MeMultiPolyTo2dm.cppandTutMeshing.cppso the assertions compare with an epsilon rather than exact text. Correct long-term; needs someone who knows the acceptable numerical tolerance for these meshes./fp:strict, or extending the contraction guard to MSVC) so both compilers agree. Most principled, but it would change VS2022 output and therefore require regenerating baselines anyway.--filter '{"options": {"testing": false}}'. This is the current state.Option 3 is what is in place. 1 or 2 wants an owner who knows the meshing numerics.
Note: unrelated tooling bug
xmsconan vs2019 buildexited with code 0 despite 4 failed configurations — the summary table reportedsucceeded 9 / failed 4but the process return code was 0. A script trusting the exit code would treat the run as clean and publish a partial set silently. Filed separately against xmsconan; noting here because it is how this nearly went unnoticed.