Skip to content

COMP: Build and test against ITK 5.4 and ITK 6 - #61

Merged
hjmjohnson merged 7 commits into
InsightSoftwareConsortium:mainfrom
hjmjohnson:ci-itk5-and-itk6
Oct 13, 2026
Merged

hjmjohnson merged 7 commits into
InsightSoftwareConsortium:mainfrom
hjmjohnson:ci-itk5-and-itk6

Conversation

@hjmjohnson

@hjmjohnson hjmjohnson commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Every CI job has been red since 2026-01-27 because src/CMakeLists.txt links ITK::LesionSizingToolkitModule, an interface library that exists only in ITK 6, while the workflow builds against ITK 5.4. This picks the module library at configure time so the module builds against both majors, runs the C++ and Python workflows twice, pinned to ITKRemoteModuleBuildTestPackageAction v5.4.6 and v6.0b02, and fixes the four defects that CI exposed once it could build again, including a Windows-only crash in two flooding filters. Carries the commits of #59 and #60, which it needs to go green; those can merge first or be closed in favor of this. CI is green: 26 of 26 jobs on d108038.

Changes
  • src/CMakeLists.txt: use ITK::LesionSizingToolkitModule when that target exists (ITK 6), else the bare LesionSizingToolkitModule, else ${LesionSizingToolkit_LIBRARIES} (ITK 5.4).
  • .github/workflows/build-test-package.yml: cxx-build-workflow-itk5 / -itk6 and python-build-workflow-itk5 / -itk6, each using the action release's default ITK, wheel, and package tags (v5.4.6; c6e1c1be / v6.0b02). Only the ITK 6 Python job receives the PyPI secret, so a v* tag publishes one set of wheels.
  • wrapping/itkCannyEdgeDetectionRecursiveGaussianImageFilter.wrap: floating-point types only; the filter's IsFloatingPoint concept checks, enforced by ITK 5.4, rejected the integer instantiations at castxml time.
  • wrapping/itkLesionSegmentationImageFilter8.wrap: output float only; the filter grafts its segmentation module's float image onto the output, so the double output instantiation failed to compile.
  • pyproject.toml: package renamed itk-lesionsizingtoolkit, the name the wheel validation expects; neither name is on PyPI.
  • VotingBinaryHoleFillFloodingImageFilter and RegionCompetitionImageFilter copied the image offset table with memcpy sized by sizeof(unsigned long) (4 bytes on Windows, 8-byte OffsetValueType), leaving the slice and volume strides uninitialized; wrong neighbor offsets everywhere, access violations on the ITK 6 Windows heap. Now std::copy_n over OffsetValueType.
  • The ITK 6 C++ job builds ITK main at 5d31af3c (2026-10-01) rather than the action's default c6e1c1be (2026-03-10); replace with v6.0.0 when it exists.
  • From COMP: Do not include UseITK when building as an external module #60: drop include(${ITK_USE_FILE}), which made every test object reference IO factories the driver does not link.
  • From BUG: Name the real superclass in ITK_EXERCISE_BASIC_OBJECT_METHODS calls #59: name the real superclass in nine ITK_EXERCISE_BASIC_OBJECT_METHODS calls; MSVC's variant of the macro compares the name, and the Windows jobs failed exactly those three tests.
Test plan

Configured, built, and ran ctest in two external-module builds on macOS arm64 (clang, Release):

  • ITK v5.4.7-61-gb3abd15c12, wrapping off: configure and build succeed, 52 of 52 tests pass.
  • ITK main (6.0), wrapping on: configure, build, and wrapping succeed, 52 of 52 tests pass; ITK::LesionSizingToolkitModule exists there, so the first branch is taken.

CI history on this PR: 7b023ac built everywhere for the first time since January and exposed the wrap-file and superclass-name failures; 033c429 exposed the Windows ITK 6 access violations, which a cdb run on a fork branch placed in VotingBinaryHoleFillFloodingImageFilter's neighbor loop; d108038 passes all 26 jobs (ITK 5.4.6 and ITK 6 C++ on Linux, macOS Intel, macOS arm64, Windows; 16 wheel jobs). Linux ASan+UBSan at the pinned ITK commit was clean throughout, which is consistent with an uninitialized read rather than an invalid access.

UseITK registers every IO factory of the ITK build as a directory-wide
compile definition, so each test object references the
*ImageIOFactoryRegister__Private symbols of modules this module never
links, and the test driver fails to link against an ITK that has
ITKIOGE or ITKIOFDF enabled. ITKModuleExternal already applies ITK's
flags, and the module template does not include the use file.
src/CMakeLists.txt linked ITK::LesionSizingToolkitModule, an interface
library that exists only in ITK 6, so configuring against ITK 5.4
failed and every CI job has been red since 2026-01-27. Pick the module
library at configure time and fall back to LesionSizingToolkit_LIBRARIES.

Run the C++ and Python workflows twice, pinned to the v5.4.6 and
v6.0b02 releases of ITKRemoteModuleBuildTestPackageAction, so both
supported ITK majors are covered. Only the ITK 6 Python job publishes.
ITK_EXERCISE_BASIC_OBJECT_METHODS compares Superclass::GetNameOfClass()
with the stringified third argument and fails the test on a mismatch.
Nine calls named a class that is not the object's direct superclass:

- MaximumFeatureAggregator derives from FeatureAggregator, not
  UnaryFunctorImageFilter (itkDescoteauxSheetnessFeatureGeneratorMultiScaleTest1).
- LesionSegmentationMethod derives from ProcessObject, not LightObject
  (itkLesionSegmentationMethodTest10).
- SatoVesselnessSigmoidFeatureGenerator derives from
  SatoVesselnessFeatureGenerator, not FeatureGenerator
  (itkSatoVesselnessSigmoidFeatureGeneratorMultiScaleTest1, four calls;
  itkFeatureAggregatorTest1, one call).
- LungWallFeatureGenerator and SigmoidFeatureGenerator derive from
  FeatureGenerator, not FeatureAggregator (itkFeatureAggregatorTest1).

The first three tests fail identically against ITK main and ITK
release-5.4 in the downstream build matrix. itkFeatureAggregatorTest1 is
only built when TEST_CORNELL_DATA_ROOT is set, so its three mismatches
were latent.
CannyEdgeDetectionRecursiveGaussianImageFilter requires floating-point
input and output, which ITK 5.4's concept checks enforce, so its
integer instantiations fail castxml. LesionSegmentationImageFilter8
grafts the float image of its segmentation module onto its output, so
a double output cannot be const_cast from it; wrap the output as float.
@hjmjohnson

Copy link
Copy Markdown
Member Author

The first run (7b023ac) was the first time CI configured and built on every platform since January. It exposed three things, now pushed as 7b023ac..7316dbb (two commits added, nothing rewritten): the two wrap files instantiated types the filters reject under ITK 5.4 concept checks and ITK 6 double wrapping, and the Windows C++ jobs failed the three superclass-name tests that #59 fixes, so that commit is cherry-picked here.

ITKRemoteModuleBuildTestPackageAction validates that each job produced
an itk_* wheel, and every published ITK remote module uses the itk-
prefix. Neither name is on PyPI.
The v6.0b02 release of ITKRemoteModuleBuildTestPackageAction builds
ITK at c6e1c1be (2026-03-10), which is older than the v6.0b02 tag and
6,400 commits behind main. Three tests segfault on Windows against
that snapshot and pass against main, so pin the C++ job to the main
commit the module was verified with.
@hjmjohnson

Copy link
Copy Markdown
Member Author

Run for 033c429: every ITK 5 job that finished passed (Windows C++ 52/52, all Linux and Windows wheels), and all ITK 6 wheel jobs passed. The one failure was the ITK 6 Windows C++ job: three tests segfault against the action's default ITK 6 commit c6e1c1be (2026-03-10), which predates the v6.0b02 tag and is 6,400 commits behind main; the same tests pass against main on macOS here. fa84590 pins that job to ITK main at 5d31af3c (2026-10-01), to be replaced by v6.0.0 when it exists.

@hjmjohnson
hjmjohnson marked this pull request as ready for review October 8, 2026 14:34
Both flooding filters copied the offset table with memcpy sized by
sizeof(unsigned long), which is 4 bytes on Windows while
OffsetValueType is 8 bytes there (ITK_USE_64BITS_IDS defaults to ON on
64-bit Windows). Only the first two strides were copied and the slice
and volume strides kept whatever the heap held, so neighbor offsets
were garbage: silently wrong on platforms that happened to hand back
zeros, and access violations under ITK 6 on Windows. Copy the table
element-wise and accumulate the neighbor offset in OffsetValueType.
@hjmjohnson

Copy link
Copy Markdown
Member Author

Root cause of the Windows ITK 6 segfaults, caught under cdb on a fork run: VotingBinaryHoleFillFloodingImageFilter and RegionCompetitionImageFilter copied the image offset table with memcpy sized by sizeof(unsigned long), 4 bytes on Windows while OffsetValueType is 8 bytes there. Only the first two strides were copied; the slice and volume strides kept heap garbage, so z-neighbor offsets were wrong everywhere and out of bounds on the ITK 6 Windows heap. d108038 copies the table element-wise. Linux ASan could not see it (uninitialized read, not an invalid access), which is why it was clean.

Debugger excerpt
(1e20.fd8): Access violation - code c0000005 (first chance)
LesionSizingToolkitTestDriver!std::_Vector_const_iterator<...<__int64>>::operator++
  [inlined in itk::VotingBinaryHoleFillFloodingImageFilter...]
cmp     byte ptr [r14+rax],r8b ds:0000017c`9d88ce0a=??

@hjmjohnson

Copy link
Copy Markdown
Member Author

Green on d108038: 26 of 26 jobs pass (ITK 5.4.6 and ITK 6 C++ on ubuntu, macOS Intel, macOS arm64, Windows; 16 wheel jobs for both). Body updated with the offset-table fix and the ITK 6 pin.

@hjmjohnson
hjmjohnson requested a review from dzenanz October 8, 2026 15:49
@hjmjohnson

Copy link
Copy Markdown
Member Author

@dzenanz no hurry on this. Based on comments for ITK regarding issues with InsightSoftwareConsortium/ITK#6891. I wanted to ensure that LesionSizingToolkit did not have other issues causing the failures.

It turns out that the LSTK had several CI exposed problems, and this rather large PR is the set of fixes needed to make CI green. Breaking it apart will result in non-green CI's.

@dzenanz dzenanz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good even as is.

Comment thread .github/workflows/build-test-package.yml
@hjmjohnson
hjmjohnson merged commit 772e7dd into InsightSoftwareConsortium:main Oct 13, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants