Skip to content

ENH: Update vendored Eigen3 to 5.0.1+master; verify USE_SYSTEM 3.3/3.4/5.x#6176

Merged
hjmjohnson merged 8 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:eigen-5.0.1-update
May 6, 2026
Merged

ENH: Update vendored Eigen3 to 5.0.1+master; verify USE_SYSTEM 3.3/3.4/5.x#6176
hjmjohnson merged 8 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:eigen-5.0.1-update

Conversation

@hjmjohnson
Copy link
Copy Markdown
Member

@hjmjohnson hjmjohnson commented Apr 30, 2026

Vendors Eigen master post-5.0.1 (gitlab libeigen/eigen tip fef1460e, late April 2026; EIGEN_VERSION_STRING="5.0.1-dev+master") via the canonical UpdateFromUpstream.sh flow, and demonstrates ITK_USE_SYSTEM_EIGEN=ON against system Eigen 3.3.9, 3.4.0, and 5.0.1. The 3.3 minimum-version gate is preserved.

Acceptance matrix (build + Eigen-related tests)
Row Eigen source Build Tests
A Vendored gitlab-tip via ISC fork 5a7cc61d6 (Eigen 5.0.1+master) 5246 / 5246 11 / 11
B0 conda-forge eigen=3.3.9 (proves min-version gate) 5974 / 5974 11 / 11
B conda-forge eigen=3.4.0 5974 / 5974 11 / 11
C conda-forge eigen=5.0.1 5974 / 5974 11 / 11

The 11 tests: itkSymmetricEigenAnalysisTest, itkEigenAnalysis2DImageFilterTest, itkSymmetricEigenAnalysisImageFilterTest{OrderByValue,OrderByMagnitude,DoNotOrder}, vnl_algo_test_{complex,generalized,real,symmetric}_eigensystem, ITKEigenKWStyleTest, ITKEigenInDoxygenGroup.

What changed in the vendored tree
  • UpdateFromUpstream.sh tag bumped to the new ISC fork tag (suffix -fef1460ek). Whitelist gained AccelerateSupport, KLUSupport, ThreadPool, Version (the Eigen/Version header is required because Eigen 5 moved EIGEN_{MAJOR,MINOR,PATCH}_VERSION out of src/Core/util/Macros.h).
  • The vendored src/itkeigen/CMakeLists.txt version parser was rewritten on the fork (be4bdb732) to read Eigen/Version (semver MAJOR.MINOR.PATCH) for Eigen 5+, falling back to Macros.h (WORLD.MAJOR.MINOR) for legacy 3.4.x. Eigen3ConfigVersion.cmake now reports PACKAGE_VERSION "5.0.1".
  • One merge conflict during the subtree import, in Eigen/src/Core/products/SelfadjointMatrixVector.h: Eigen 5 fully rewrote that kernel into 4-col / 2-col / 1-col phases, already initializing accumulators with pzero(Packet{}). Resolved by taking upstream entirely — the older in-tree COMP patch 91f6232 ("pzero(Packet{}) for SelfadjointMatrixVector accumulators") is subsumed and obsolete.
ISC fork (InsightSoftwareConsortium/eigen) state
  • New tag at 5a7cc61d6.
  • for/itk-master advanced to 5a7cc61d6.
  • Three ITK-overlay commits on top of gitlab fef1460e: CMake override (be4bdb732), .gitattributes lapacke relax (fb7121abd), and README.kitware.md (5a7cc61d6).
Outer-module CMake

Modules/ThirdParty/Eigen3/CMakeLists.txt keeps _Eigen3_min_version=3.3 (no upper bound). find_package(Eigen3 REQUIRED CONFIG) plus the explicit VERSION_LESS check accepts both 3.x and 5.x system installs without modification.

@github-actions github-actions Bot added the type:Enhancement Improvement of existing methods or implementation label Apr 30, 2026
@hjmjohnson
Copy link
Copy Markdown
Member Author

@greptile review

@greptile-apps

This comment was marked as resolved.

Comment thread Modules/ThirdParty/Eigen3/src/itkeigen/cmake/Eigen3Config.cmake.in
Comment thread Modules/ThirdParty/Eigen3/src/itkeigen/CMakeLists.txt Outdated
Comment thread Modules/ThirdParty/Eigen3/src/itkeigen/CMakeLists.txt Outdated
dzenanz

This comment was marked as resolved.

@dzenanz dzenanz requested a review from phcerdan April 30, 2026 19:14
@hjmjohnson hjmjohnson changed the title ENH: Update vendored Eigen3 to 5.0.1; verify USE_SYSTEM_EIGEN across 3.3, 3.4, 5.x ENH: Update vendored Eigen3 to 5.0.1+master; verify USE_SYSTEM 3.3/3.4/5.x Apr 30, 2026
@hjmjohnson

This comment was marked as resolved.

@hjmjohnson hjmjohnson force-pushed the eigen-5.0.1-update branch 2 times, most recently from 56a7240 to eda5a20 Compare May 1, 2026 00:11
@hjmjohnson
Copy link
Copy Markdown
Member Author

/azp run ITK.Windows

@hjmjohnson

This comment was marked as resolved.

@hjmjohnson
Copy link
Copy Markdown
Member Author

/azp run ITK.Windows

@hjmjohnson hjmjohnson marked this pull request as ready for review May 1, 2026 02:10
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 1, 2026

Too many files changed for review. (319 files found, 100 file limit)

@hjmjohnson hjmjohnson requested a review from dzenanz May 1, 2026 02:33
@hjmjohnson
Copy link
Copy Markdown
Member Author

/azp run ITK.Windows

Copy link
Copy Markdown
Member

@blowekamp blowekamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good.

Thank you for updating the library. After I refactored from an off fetch_content in the root of the project to an itk standard third party library I ran out of steam to upgrade.

There were some rather odd usages of Eigen in external modules. The intention moving forward is just have it behave just like a normal ITK interface library without special cmake code.

Comment thread Modules/ThirdParty/Eigen3/src/itkeigen/CMakeLists.txt Outdated
@hjmjohnson hjmjohnson force-pushed the eigen-5.0.1-update branch from e7a197c to be77e85 Compare May 1, 2026 14:22
@hjmjohnson
Copy link
Copy Markdown
Member Author

/azp run ITK.Windows

hjmjohnson and others added 7 commits May 1, 2026 13:18
Phase 2 prep for Eigen 5.x update.  Points UpdateFromUpstream.sh at the
refreshed InsightSoftwareConsortium/eigen tag derived from gitlab
libeigen/eigen master tip 879885e (2026-05-01), which adds the
"Modernize internal utilities for C++14" patch (libeigen/eigen!2490)
on top of the 5.0.1 release tip plus three small follow-on fixes
(RealQZ pushDownZero counting, small-determinant LU fastpath, and
IncompleteLUT static row matching).

Adds new top-level support headers introduced since the previous import:
AccelerateSupport, KLUSupport, ThreadPool, and Version.  The Version
header is required because Eigen 5 moved EIGEN_{MAJOR,MINOR,PATCH}_VERSION
out of src/Core/util/Macros.h.
Code extracted from:

    https://github.com/InsightSoftwareConsortium/eigen

at commit 505023a2a0fc8eeff5f92d07683ab5ff0c03ba0f (for/itk-20260501-879885e1).
* upstream-Eigen3:
  Eigen3 2026-05-01 (505023a2)

# Conflicts:
#	Modules/ThirdParty/Eigen3/src/itkeigen/Eigen/src/Core/products/SelfadjointMatrixVector.h
The warning is purely from the Eigen master post-5.0.1 update
(EIGEN_VERSION_STRING="5.0.1-dev+master") changing instantiation/
inlining. Eigen's own CMakeLists.txt already adds
-Wno-maybe-uninitialized for its own builds (line 444, with a comment
that GCC 12+ emits false positives), and DisableStupidWarnings.h
doesn't cover this one. The fix is to suppress at the ITK consumer
site, mirroring Eigen's stance.
- Restore @EIGEN3_TARGETS_FILE@ substitution in Eigen3Config.cmake.in.
- Remove duplicate option(ITK_USE_EIGEN_MPL2_ONLY) declaration.
- Remove commented-out binary-dir generator expression.

USE_SYSTEM_EIGEN for 3.3+ unaffected (all under itkeigen, only
configured when USE_SYSTEM_EIGEN=OFF).
Bump line 2 from 3.10.2 to 3.16.3 to match ITK proper, and replace the
if(FALSE) ... endif() wrapper around the upstream Eigen logic with
#[[ ... #]] CMake multiline-comment markers so IDEs render the
disabled region as dimmed dead code.
Tridiagonalization.h emits C4750 ('function with _alloca() inlined into
a loop') under MSVC whenever an ITK consumer instantiates the symmetric
eigen-decomposition path.  The warning is benign (Eigen's intentional
small-allocation alloca path) but cannot be addressed inside ITK and
fails CDash because the dashboard treats any warning as fatal.

The previous attempt to set CMAKE_CXX_FLAGS in the vendored Eigen
CMakeLists was a no-op (Eigen is header-only, so no .cxx file picks up
the flag) and the alternative -- attaching /wd4750 to the eigen_internal
INTERFACE library -- would propagate to ITKCommon (which DEPENDS on
ITKEigen3) and from there to most of the toolkit, suppressing C4750
for non-Eigen ITK code too.  Both rejected per @blowekamp.

Instead, extend the existing 'Modules/ThirdParty/Eigen3/.*warning:.*'
CTestCustom regex with a sibling that matches MSVC's
'warning C####:' form.  Compiler still emits the warning so reviewers
see it in build logs, but the dashboard ignores it for warning-count
purposes -- exactly the same scope the GCC/Clang side has had since
this exception was added.
@hjmjohnson hjmjohnson force-pushed the eigen-5.0.1-update branch from be77e85 to 76d09b8 Compare May 1, 2026 18:21
@hjmjohnson
Copy link
Copy Markdown
Member Author

/azp run ITK.Linux.Python

@hjmjohnson hjmjohnson added this to the ITK 6.0 Release Candidate 1 milestone May 5, 2026
@hjmjohnson
Copy link
Copy Markdown
Member Author

@phcerdan Do you have any suggestions for how this PR can be better instrumented?

@phcerdan
Copy link
Copy Markdown
Contributor

phcerdan commented May 6, 2026

It's looking good to me @hjmjohnson, you performed all the needed steps for updating a remote.

@blowekamp might be more up-to-date after all the work he did on standardizing eigen.

@hjmjohnson hjmjohnson requested a review from blowekamp May 6, 2026 11:01
@hjmjohnson
Copy link
Copy Markdown
Member Author

hjmjohnson commented May 6, 2026

There were some rather odd usages of Eigen in external modules. The intention moving forward is just have it behave just like a normal ITK interface library without special cmake code.

@blowekamp I am uncertain if your previous comment is requesting changes to this PR, or indicating work that was already done. If this PR is OK as is, please approve and merge. If there are additions, please indicate if they should be on this PR, or a followup and what is needed. Thank you, Hans

@blowekamp
Copy link
Copy Markdown
Member

The TVProx was one remote module I spent some time on refactoring to work with the refactored Eigen and the updated ITK CMake. There is still an outstanding PR regarding these changes. The CI could not be made green due to the changes with Eigan being after the most recent tag:
InsightSoftwareConsortium/ITKTotalVariation#57

Eigan is use more by remote modules than internal, which should be an important part of testing. There may be other remote modules that may still have issues with the previous updates.

This is all to say that Eigan usage is rough around the edges, and needs some extra checks. There were options related to what code was included and compile time defines that I could not make sense of too.

Also, the ITK on conda-forge is using the latest eigen with out problems, but that usage is minimum,

@hjmjohnson
Copy link
Copy Markdown
Member Author

Deep-dive verified PR #6176 builds cleanly end-to-end (full ITK 6156/6156 targets) and exports a correctly-configured vendored Eigen 5; smoke-tested via Eigen3::Eigen IMPORTED target. PR #6176 stands on its own — no changes needed here for downstream consumption.

The deep dive did surface one pre-existing ITK architectural detail that affects InsightSoftwareConsortium/ITKTotalVariation#57's modern-target-interfaces refactor (proxTV's <Eigen/Dense> not resolving against the vendored Eigen). That's being addressed in a separate follow-up — see below.

What was tested
Tier What Result
0 Direct Eigen3::Eigen smoke test against vendored Eigen 5 (EIGEN_WORLD.MAJOR.MINOR = 3.5.0)
1 Full ITK build with ITK_BUILD_DEFAULT_MODULES=ON + Module_TotalVariation=ON on Ubuntu 24.04 / gcc 13.3 / CMake 4.2.1 ✅ 6156/6156, zero failures
2 ITKTotalVariation main (94b85b4) as remote module against PR #6176 ✅ proxTV builds, itkProxTVImageFilterTest passes — but silently used system Eigen 3.4 because the longstanding set(Eigen3_DIR "${ITKInternalEigen3_DIR}") plumbing in TotalVariation reads an empty ITKInternalEigen3_DIR at in-tree build time
3 ITKTotalVariation #57 (39e849e blowekamp/cmake_interface_update) as remote module against PR #6176 ❌ proxTV lapackFunctionsWrap.cpp:11:10: fatal error: Eigen/Dense: No such file or directory — but not a PR #6176 bug; root cause below
Architectural finding — pre-existing in ITK, exposed by ITKTotalVariation#57

ITK ships its vendored Eigen3 headers at:

Modules/ThirdParty/Eigen3/src/itkeigen/Eigen/<header>

ITK's own internal code uses a special macro form ITK_EIGEN(<header>) that expands to <itkeigen/Eigen/<header>>, so an include path of ${ITKEigen3_SOURCE_DIR}/src (the parent of itkeigen/) lets the compiler append /itkeigen/Eigen/<header>. ITK proper builds fine with this convention.

Modules/ThirdParty/Eigen3/CMakeLists.txt:58 (vendored case):

set(ITKEigen3_INCLUDE_DIRS ${ITKEigen3_SOURCE_DIR}/src)

This single path then flows into INTERFACE_INCLUDE_DIRECTORIES of both exported targets:

# /tmp/itk-pr6176-build/ITKTargets.cmake:99-107
set_target_properties(ITK::eigen_internal PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES ".../Modules/ThirdParty/Eigen3/src/itkeigen/..")  # → .../Eigen3/src

set_target_properties(ITK::ITKEigen3Module PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES ".../Eigen3/src;.../Modules/ThirdParty/Eigen3/src"
  INTERFACE_LINK_LIBRARIES "ITK::eigen_internal")

External consumers that legitimately use the upstream-Eigen convention <Eigen/<header>> (proxTV, anything pulled via FetchContent that wraps real Eigen) need an include path of .../Eigen3/src/itkeigenone level deeper. No exported IMPORTED target provides that.

The Eigen3::Eigen target produced by Eigen's own target_include_directories(eigen INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>) does have the correct path, but it's declared as add_library(Eigen3::Eigen ALIAS eigen) — an in-source-scope ALIAS, invisible to FetchContent sub-builds (verified empirically: rewriting ITKTotalVariation#57 to link Eigen3::Eigen triggers Target "Eigen3::Eigen" was not found).

This is not introduced by PR #6176upstream/main has the same setup. PR #6176 inherits it. The Eigen 5 update doesn't change the vendored include layout.

Proposed resolution — separate follow-up PR

Single-file, one-block change to Modules/ThirdParty/Eigen3/CMakeLists.txt:58:

-  set(ITKEigen3_INCLUDE_DIRS ${ITKEigen3_SOURCE_DIR}/src)
+  set(
+    ITKEigen3_INCLUDE_DIRS
+    ${ITKEigen3_SOURCE_DIR}/src
+    ${ITKEigen3_SOURCE_DIR}/src/itkeigen
+  )

Both paths flow into INTERFACE_INCLUDE_DIRECTORIES of ITK::ITKEigen3Module / ITK::eigen_internal. ITK's own <itkeigen/Eigen/<header>> consumers continue to find their headers via the first entry; external consumers using <Eigen/<header>> find theirs via the second. No source-code changes anywhere else.

After this lands:

  • ITKTotalVariation#57 builds against vendored Eigen 5 with no further changes (proxTV_Eigen_LIBRARIES = ITK::ITKEigen3Module becomes correct).
  • The longstanding "silent fall-through to system Eigen" bug in ITKTotalVariation main (where set(Eigen3_DIR "${ITKInternalEigen3_DIR}") reads an empty value) becomes moot, since direct linking against ITK::ITKEigen3Module now works without the broken Eigen3_DIR shim.

Branch: hjmjohnson:eigen-include-itkeigen-path (off upstream/main, single COMP commit d36276b8a9). Local end-to-end verification (full ITK + ITKTotalVariation#57 + proxTV) is in progress; PR will be opened once the build settles.

What this PR (#6176) does not need to change

Nothing. The findings above are independent of the Eigen 5 vendored update; the include-dir omission predates this PR by years and would surface against ITKTotalVariation#57 regardless of which Eigen version is vendored. PR #6176 is verified ready on its own merits — vendored Eigen 5 builds clean, exports the correct Eigen3::Eigen (in-source) and exposes its include path through both ITK targets identically to how upstream/main did before this PR.

@hjmjohnson hjmjohnson merged commit f11b2cb into InsightSoftwareConsortium:main May 6, 2026
18 of 19 checks passed
hjmjohnson added a commit that referenced this pull request May 6, 2026
…onsumers

ITK ships its vendored Eigen3 headers at
  Modules/ThirdParty/Eigen3/src/itkeigen/Eigen/<header>

ITK code accesses these via the ITK_EIGEN(<header>) macro
defined in itk_eigen.h, which expands to
  <itkeigen/Eigen/<header>>

When ITK_USE_SYSTEM_EIGEN=OFF, the prior ITKEigen3_INCLUDE_DIRS
contained only ${ITKEigen3_SOURCE_DIR}/src — sufficient for the
macro form (the compiler then appends /itkeigen/Eigen/<header>) but
not for the upstream Eigen convention <Eigen/<header>>, which needs
${ITKEigen3_SOURCE_DIR}/src/itkeigen on the include path.

External consumers that legitimately use the upstream pattern hit
'fatal error: Eigen/Dense: No such file or directory' as soon as
they link against ITK::ITKEigen3Module or ITK::eigen_internal.
This blocks the modern-target-interfaces refactor in
InsightSoftwareConsortium/ITKTotalVariation#57: proxTV's
lapackFunctionsWrap.cpp uses #include <Eigen/Dense> and so cannot
build against the vendored Eigen via either of ITK's exported
imported targets.

Add the itkeigen subdirectory to ITKEigen3_INCLUDE_DIRS so both
include conventions resolve.  ITK's own consumers continue to find
<itkeigen/Eigen/<header>> via the first entry; external consumers
now find <Eigen/<header>> via the second.  Both entries flow into
INTERFACE_INCLUDE_DIRECTORIES of the IMPORTED ITK::ITKEigen3Module
target, so the fix applies in-tree and to find_package(ITK)
consumers alike.

The Eigen3::Eigen IMPORTED target produced by Eigen's own export
already exposes the correct path, but it is in-source-scope only
(declared as add_library(Eigen3::Eigen ALIAS eigen)) and therefore
invisible to FetchContent sub-builds; relying on it is not an
option for downstream remote modules that pull proxTV via
FetchContent.

This change is independent of the Eigen 5 vendored update in
PR #6176; the architectural mismatch predates that PR and applies
to upstream/main as-is.
@seanm
Copy link
Copy Markdown
Contributor

seanm commented May 7, 2026

This MR broke my build:

In file included from /some/path/ITK-install/include/ITK/itkAffineTransform.h:21:
In file included from /some/path/ITK-install/include/ITK/itkMatrixOffsetTransformBase.h:24:
In file included from /some/path/ITK-install/include/ITK/itkTransform.h:24:
In file included from /some/path/ITK-install/include/ITK/itkSymmetricSecondRankTensor.h:29:
/some/path/ITK-install/include/ITK/itkSymmetricEigenAnalysis.h:23:10: fatal error: 'itkeigen/Eigen/Eigenvalues' file not found
#include ITK_EIGEN(Eigenvalues)
         ^~~~~~~~~~~~~~~~~~~~~~

Bisect results:

There are only 'skip'ped commits left to test.
The first bad commit could be any of:
bc87d16
64ddc66
We cannot bisect more!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:Enhancement Improvement of existing methods or implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants