Resolve Eigen once, before Ceres, and refuse a build that mixes two
Ceres asks for Eigen with a version range - find_package(Eigen3 3.3.4...5 NO_MODULE) - and Eigen's own Eigen3ConfigVersion.cmake rejects any range whose endpoints differ in major version. A 3.4 Eigen therefore declares itself INCOMPATIBLE with Ceres' query, the search falls through, and Ceres binds whatever older Eigen comes next on the prefix path. Where a distro eigen3-devel 3.3.4 is installed alongside a 3.4 one, Ceres created Eigen3::Eigen first, in its own directory scope, pointing at the older headers, and exported it publicly; the project's own find_package then ran afterwards and made a second target pointing at the newer ones. Targets linking both - the geometry refinement and the scale/merge libraries - took the older Eigen first. The result was a binary holding Eigen 3.3.4 and 3.4.90 template instantiations at once. Identically mangled, they are merged at link time with disagreeing evaluator layouts, so the program is undefined: at -O2 it segfaulted inside an Eigen product under the lattice reduction, nine runs out of nine, and at -O3 it happened not to, which is luck rather than correctness. Resolve Eigen before Ceres is added. The first find_package to run creates the imported target and later ones leave it alone, so Ceres inherits ours. Then assert it: if Ceres ever creates an Eigen3::Eigen of its own, the configure fails with an explanation rather than producing a binary that is quietly ill-formed. The guard fires only on that condition, not merely because two Eigens are installed. After the change no translation unit sees the older headers - 0 of 227 flags files, against 30 before - and Ceres reports the Eigen it actually compiled against. The same nine runs that all crashed now all complete. Release output is unaffected: eight datasets give byte-identical reflection files and identical merging statistics either way, so nothing previously measured is invalidated. Eigen and ZLIB stay external find_package dependencies on every platform, and OVERRIDE_FIND_PACKAGE is not reintroduced. Where only one Eigen is installed - the Windows and macOS case - Ceres' non-range fallback honours the same Eigen3_DIR and the change is a no-op. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016NNnL26LAvruQ9eLUUWvrJ
This commit is contained in:
@@ -18,6 +18,7 @@ This is an UNSTABLE release. It includes many experimental features, as well as
|
||||
* HDF5 and image stream: `mirror_y` records whether the assembled image is mirrored in Y relative to the detector's raw readout.
|
||||
* rugnux: an image integrated in pyFAI through the `.poni` file written by `--mode calibration` now comes out with the correct azimuth. Radial integration is unchanged.
|
||||
* rugnux: the `.poni` file declares pyFAI's `orientation`, which needs pyFAI 2024.01 or newer.
|
||||
* The build resolves a single Eigen for the whole project, and refuses to configure if Ceres picks up a different one; a build that mixed two Eigen versions was undefined behaviour and crashed at -O2.
|
||||
* rugnux: scaling and merging are faster, with identical output.
|
||||
* The per-image resolution estimate now predicts the resolution the merged data reach, rather than reporting the highest-resolution spot found; rugnux reports the run's value as `SPOT_RESOLUTION_ESTIMATE` in its report.
|
||||
* rugnux: fixing the space group with `-S` no longer prevents the lattice from being found; the group is applied to scaling and merging rather than to the indexing search.
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# Eigen has to be resolved BEFORE Ceres is added below. Whichever find_package(Eigen3) runs first
|
||||
# creates the Eigen3::Eigen imported target, and every later one leaves an existing target alone --
|
||||
# so the first one wins for the whole build, Ceres included. See the guard after Ceres for why that
|
||||
# matters here.
|
||||
FIND_PACKAGE(Eigen3 3.4 REQUIRED NO_MODULE) # provides Eigen3::Eigen
|
||||
|
||||
SET(PROVIDE_UNINSTALL_TARGET OFF)
|
||||
# Force Ceres to build WITHOUT its own CUDA support: Jungfraujoch never uses Ceres' GPU solvers, so
|
||||
# this just drops unused code and build time (Ceres would otherwise enable CUDA whenever a toolkit is
|
||||
@@ -17,6 +23,23 @@ FetchContent_Declare(
|
||||
|
||||
FetchContent_MakeAvailable(ceres)
|
||||
|
||||
# Ceres asks for Eigen with a version RANGE -- find_package(Eigen3 3.3.4...5 NO_MODULE) -- and
|
||||
# Eigen's own Eigen3ConfigVersion.cmake rejects any range whose two endpoints differ in major
|
||||
# version. A 3.4 Eigen therefore reports itself INCOMPATIBLE with Ceres' query and the search falls
|
||||
# through to whatever older Eigen comes next on the prefix path (a distro eigen3-devel, say). Having
|
||||
# resolved Eigen above, Ceres inherits our Eigen3::Eigen instead, because a generated targets file
|
||||
# returns early when its targets already exist. If that ever stops holding, Ceres compiles against
|
||||
# one Eigen and the rest of the project against another; the two versions' identically mangled
|
||||
# template instantiations are then merged at link time -- an ODR violation whose symptom is a crash
|
||||
# inside Eigen. Refuse to build it.
|
||||
GET_PROPERTY(CERES_IMPORTED_TARGETS DIRECTORY ${ceres_SOURCE_DIR} PROPERTY IMPORTED_TARGETS)
|
||||
IF ("Eigen3::Eigen" IN_LIST CERES_IMPORTED_TARGETS)
|
||||
MESSAGE(FATAL_ERROR "Ceres created an Eigen3::Eigen of its own instead of using the Eigen this "
|
||||
"project resolved. Two Eigen versions in one binary is undefined behaviour. Leave a "
|
||||
"single Eigen on the find_package path, or point CMAKE_PREFIX_PATH / Eigen3_DIR at the "
|
||||
"one to use.")
|
||||
ENDIF()
|
||||
|
||||
ADD_LIBRARY(JFJochImageAnalysis STATIC
|
||||
MXAnalysisWithoutFPGA.cpp
|
||||
MXAnalysisWithoutFPGA.h
|
||||
@@ -42,8 +65,6 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC
|
||||
rotation_indexer/RotationIndexerCounter.cpp
|
||||
rotation_indexer/RotationIndexerCounter.h)
|
||||
|
||||
FIND_PACKAGE(Eigen3 3.4 REQUIRED NO_MODULE) # provides Eigen3::Eigen
|
||||
|
||||
ADD_SUBDIRECTORY(spot_finding)
|
||||
ADD_SUBDIRECTORY(bragg_integration)
|
||||
ADD_SUBDIRECTORY(bragg_prediction)
|
||||
|
||||
@@ -21,7 +21,7 @@ TARGET_LINK_LIBRARIES(JFJochIndexing JFJochCommon JFJochLatticeSearch)
|
||||
IF (JFJOCH_CUDA_AVAILABLE)
|
||||
# GIT_SUBMODULES "" -> do not fetch ffbidx's bundled eigen submodule; it would add_subdirectory
|
||||
# a second Eigen3::Eigen target. ffbidx instead resolves Eigen via the project-level Eigen3
|
||||
# (OVERRIDE_FIND_PACKAGE in the top-level CMakeLists).
|
||||
# (the find_package(Eigen3) at the top of image_analysis/CMakeLists.txt).
|
||||
FetchContent_Declare(
|
||||
fast-indexer
|
||||
GIT_REPOSITORY https://github.com/paulscherrerinstitute/fast-feedback-indexer/
|
||||
|
||||
Reference in New Issue
Block a user