%global _lto_cflags %{nil} # Use 'define' not 'global' for debug_package: EPEL 9 auto-injects the # debuginfo stanza during spec parsing and 'global' scope causes a conflict. %define debug_package %{nil} # ITK's own Python wrapping (ITK_WRAP_PYTHON), off by default. # # This is NOT SimpleITK. python3-simpleitk is a separate upstream project with a # simplified, non-templated procedural API; code written for one does not run on # the other. monai-physio, python3-trame-slicer and SlicerOpenLIFU want `import # itk` -- the full templated API -- and nothing in this repo provides it. # # ON by default since 5.4.7-18, on Morgan's decision 2026-09-27. Disable with # --without python_wrapping (or rpmbuild --without) # # Why on, given it turns a ~6 minute build into ~128: python3-itk requires # InsightToolkit5 = %%{version}-%%{release} EXACTLY, so with the bcond off the first # ITK rebuild by anyone at a higher release makes python3-itk unsatisfiable and it # disappears from the repo silently. There is no warning and no failing build -- the # package is simply gone, and the thing that notices is a consumer's depsolve weeks # later. Paying 128 minutes per ITK rebuild is the cost of python3-itk existing at all. # # monai-physio is the consumer that needs it (40 of its 80 files import itk), plus # python-monai's optional itk extra. python-trame-slicer does NOT, despite declaring # it -- see that spec. # Reference points for the cost: ITK core alone builds in ~6 minutes on a COPR # builder (11034910), while SimpleITK -- which wraps a SUBSET of ITK with a # simplified API -- takes 6.8 hours (11032535) and needed --timeout 36000. Full # templated wrapping instantiates across every pixel type x dimension, so expect # it to exceed SimpleITK rather than approach it. Measure before assuming it fits # inside a COPR build timeout. %bcond_without python_wrapping # Keep ITK's pre-5.4 legacy API compiled in WITH python wrapping (ITK forces it off; see %%prep). %bcond_without keep_legacy_api # The layout state consumers must match. ITK_LEGACY_REMOVE changes class layouts (vtables) at UNCHANGED sonames, # so the token encodes the STATE, not only the version: a removed-state ITK must not satisfy a consumer built # against the present state, and the reverse. Python wrapping forces removal unless keep_legacy_api overrides it. %if %{with python_wrapping} && %{without keep_legacy_api} %global itk_abi 5.4-nolegacy %else %global itk_abi 5.4-legacy %endif Name: InsightToolkit5 Version: 5.4.7 Release: 24%{?dist} Summary: Insight Segmentation and Registration Toolkit (ITK) v5 # Licenses of everything shipped, bundled code included. Derived from the # libraries our own build installs (rpm -qpl of 5.4.7-4), following the # accounting Ankur Sinha added to Fedora's InsightToolkit (84675f7): # Apache-2.0 ITK core # BSD-3-Clause DICOMParser (Copyright.txt), KWSys/itksys (Copyright.txt), # MetaIO (License.txt) # BSD-2-Clause OpenJPEG (LICENSE) # MIT libLBFGS (lbfgs.h header) # Zlib NrrdIO (source headers; no separate licence file) # LicenseRef-Fedora-Public-Domain # GIFTI (LICENSE.gifti), NIFTI + znz (LICENSE), # Netlib/SLATEC (public domain via netlib.org) # Eigen3, DoubleConversion and VXL are system libraries now, so their licences # are carried by eigen3-devel, double-conversion and vxl, not here. License: Apache-2.0 AND BSD-3-Clause AND BSD-2-Clause AND MIT AND Zlib AND LicenseRef-Fedora-Public-Domain URL: https://itk.org/ Source0: https://github.com/InsightSoftwareConsortium/ITK/releases/download/v%{version}/InsightToolkit-%{version}.tar.gz # ITK remote module required by ANTs (pinned commit from ITK 5.4.5's GenericLabelInterpolator.remote.cmake) %global glinterp_commit ebf2436469ccf82c08fab54b7446f699ad0eae01 Source1: https://github.com/InsightSoftwareConsortium/ITKGenericLabelInterpolator/archive/%{glinterp_commit}/ITKGenericLabelInterpolator-%{glinterp_commit}.tar.gz # AdaptiveDenoising remote module: provides itkAdaptiveNonLocalMeansDenoisingImageFilter.h # required by ANTs 2.6.5 DenoiseImage and antsJointFusion %global adaptive_commit 24825c8d246e941334f47968553f0ae388851f0c Source2: https://github.com/ntustison/ITKAdaptiveDenoising/archive/%{adaptive_commit}/ITKAdaptiveDenoising-%{adaptive_commit}.tar.gz # MorphologicalContourInterpolation remote module: required by ITK-SNAP 4.x # (pinned commit from ITK 5.4.5's MorphologicalContourInterpolation.remote.cmake) %global morphci_commit 821bf9b3ef8eaaab10391ed060dc9ca5e4d37b39 Source3: https://github.com/KitwareMedical/ITKMorphologicalContourInterpolation/archive/%{morphci_commit}/ITKMorphologicalContourInterpolation-%{morphci_commit}.tar.gz # GrowCut remote module: provides itkFastGrowCut.h required by MITK Segmentation %global growcut_commit cbf93ab65117abfbf5798745117e34f22ff04728 Source4: https://github.com/InsightSoftwareConsortium/ITKGrowCut/archive/%{growcut_commit}/ITKGrowCut-%{growcut_commit}.tar.gz # SimpleITKFilters remote module: required by SimpleITK %global sitkfilters_commit bb896868fc6480835495d0da4356d5db009592a6 Source5: https://github.com/InsightSoftwareConsortium/ITKSimpleITKFilters/archive/%{sitkfilters_commit}/ITKSimpleITKFilters-%{sitkfilters_commit}.tar.gz # LabelErodeDilate remote module: required by SimpleITK %global labelerodedilate_commit 22d8846dbe4368312aa3aa95ecfe3542ab894e15 Source6: https://github.com/InsightSoftwareConsortium/ITKLabelErodeDilate/archive/%{labelerodedilate_commit}/ITKLabelErodeDilate-%{labelerodedilate_commit}.tar.gz # MGHIO remote module: 3D Slicer needs MGH/MGZ (Freesurfer) image format I/O # (pinned commit from ITK 5.4.6's MGHIO.remote.cmake) %global mghio_commit 0adac35fa22945c7a5f3a63dd8d01454577c24d3 Source7: https://github.com/InsightSoftwareConsortium/itkMGHImageIO/archive/%{mghio_commit}/itkMGHImageIO-0adac35f.tar.gz # IOScanco remote module: 3D Slicer needs Scanco microCT .isq image I/O # (pinned commit from ITK 5.4.6's IOScanco.remote.cmake) %global ioscanco_commit 10b80f69048e79ab3069e89635822a6851099278 Source8: https://github.com/KitwareMedical/ITKIOScanco/archive/%{ioscanco_commit}/ITKIOScanco-10b80f69.tar.gz # ITK 5.4.7 carries the NRRD AxesReorder / 5D I/O API and the ImageFileReader # short-axis crash fix that we used to backport as Patch0 and Patch1 for # 3D Slicer's vtkITKImageSequenceReader. Both are upstream now, so the # backports are gone. # https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval ExcludeArch: %{ix86} BuildRequires: gcc-c++ %if %{with python_wrapping} # ITK_WRAP_PYTHON drives castxml to parse the headers and swig to emit the # bindings. Both are packaged in Fedora, which is why this is a compute question # rather than a prerequisites one. BuildRequires: castxml BuildRequires: swig BuildRequires: python3-devel BuildRequires: python3-numpy # For stripping build-tree RUNPATHs off the wrapped extension modules; see %%install. BuildRequires: chrpath %endif BuildRequires: cmake >= 3.16 BuildRequires: fftw-devel BuildRequires: expat-devel BuildRequires: libtiff-devel BuildRequires: libjpeg-devel BuildRequires: libpng-devel BuildRequires: zlib-devel %if 0%{?fedora} BuildRequires: libminc-devel BuildRequires: eigen3-devel BuildRequires: double-conversion-devel BuildRequires: vxl-devel %endif BuildRequires: hdf5-devel BuildRequires: gdcm-devel BuildRequires: dcmtk-devel BuildRequires: openjpeg2-devel # System VTK for ITKVtkGlue BuildRequires: vtk-devel BuildRequires: python3-devel # Transitive deps of VTK's cmake config (find_package calls in # VTK-vtk-module-find-packages.cmake); should be Requires of vtk-devel BuildRequires: json-devel BuildRequires: utf8cpp-devel BuildRequires: PEGTL-devel BuildRequires: fmt-devel BuildRequires: lz4-devel BuildRequires: xz-devel BuildRequires: libogg-devel BuildRequires: libtheora-devel BuildRequires: sqlite-devel BuildRequires: libharu-devel BuildRequires: proj-devel BuildRequires: pugixml-devel BuildRequires: jsoncpp-devel BuildRequires: freetype-devel BuildRequires: libxml2-devel BuildRequires: double-conversion-devel # VTK 9.6.2 added CLI11 as a module dependency; its cmake config # find_package(CLI11)s at configure time, so any find_package(VTK) consumer # (here: Modules/Bridge/VtkGlue) now needs CLI11 present in the buildroot. BuildRequires: cli11-devel BuildRequires: cmake(Qt6) BuildRequires: cmake(Qt6Quick) BuildRequires: cmake(Qt6OpenGL) BuildRequires: cmake(Qt6OpenGLWidgets) BuildConflicts: InsightToolkit-devel # From Fedora's InsightToolkit (Ankur Sinha, 0001-remove-vxl-netlib.patch). # With ITK_USE_SYSTEM_VXL=ON, ITK links both v3p_netlib and a stray "netlib" # that system VXL does not ship -- Fedora's vxl provides only # libv3p_netlib.so. Without this, the build dies at link with # "cannot find -lnetlib" (our COPR 10990784). Applies unchanged to 5.4.7. Patch0: InsightToolkit5-remove-vxl-netlib.patch # System-library mode drops include dirs that bundled mode provided for free, # because bundled Eigen, VXL and double-conversion installed under ITK's own # include dir. Export them: Eigen and double-conversion into the module # include dirs (${ITK_INCLUDE_DIRS} consumers: charm-gems, elastix), VXL onto # the ITKVNLInstantiation target (target consumers: mitk). Upstream ITK main # has the same gaps; not yet reported. Patch1: InsightToolkit5-export-system-include-dirs.patch # Lets the packager append flags to the castxml parse only. castxml embeds its own # Clang, and Fedora 44's castxml 0.7.0 carries a Clang older than the gcc 16.2.1 # whose libstdc++ it has to read, so ITK_WRAP_PYTHON dies at the FIRST castxml # invocation while the real compilation is fine. Two parse errors, both parse-only: # libstdc++ 16's uses explicit object parameters (Clang wants C++23), # and Eigen 5.0.1 takes its GCC-strict SSE path because --castxml-cc-gnu makes # Clang claim to be GCC, then calls __builtin_ia32_sqrtsd, which Clang lacks. # Measured by fsk-dual on f44: c++17 and c++20 both fail, c++23 parses libstdc++, # c++23 + EIGEN_DONT_VECTORIZE parses Eigen too. The flags are appended last so # they beat the -std= derived from CMAKE_CXX_STANDARD, which leaves the standard # the library is COMPILED with untouched. Empty by default. Not yet reported # upstream, which does not hit this because it downloads a prebuilt castxml with a # matched Clang -- the same reason this will recur whenever gcc or eigen moves # ahead of Fedora's castxml. Patch2: InsightToolkit5-castxml-extra-flags.patch # Backport of upstream ITK 9e8f0c77b5 (PR #6484, merged 2026-06-22), master only: # no 5.4.x release has it. swig 4.4.0 switched Python to PEP 489 multi-phase init, # so PyInit_* returns a raw PyModuleDef; ITK packs several swig modules per shared # object and injects C that treats that return value as a module, so the build is # clean and "import itk" dies on # AttributeError: 'moduledef' object has no attribute 'delete_SwigPyIterator' # Established by measurement, not inference: 11039812 (limited API ON) and # 11040244 (limited API OFF, verified *.cpython-314*.so with no Py_LIMITED_API in # the build at all) each compiled 3643 targets and produced the SAME error. That # rules out ITK_USE_PYTHON_LIMITED_API, which is what upstream #6479 and the # closed PR #6544 both recommend turning off. swig offers no escape either: # python/pyinit.swg ends SWIG_init with an unconditional # "return PyModuleDef_Init(&SWIG_module);" for Python 3, with no guarding macro. # See the patch header for why only the module-packing hunk is taken. Patch3: InsightToolkit5-swig44-multiphase-init.patch # swig 4.5.0 removed the Python 2 compatibility macros that swig <= 4.4 emitted from # python/pyhead.swg. ITK's pyBase.i uses PyInt_Check, PyInt_AsLong and PyInt_FromLong # in 25 places, all inside %%typemap bodies, so on swig >= 4.5 every generated module # wrapper fails with # error: 'PyInt_Check' was not declared in this scope # Isolated to swig rather than Python by comparing releases, since both moved at once: # f44 has swig 4.4.1 with Python 3.14 and builds; f45 has swig 4.5.0 and rawhide # 4.5.1, both with Python 3.15, and both fail. Verified directly -- the define exists # under /usr/share/swig/4.4.1/python and nowhere under 4.5.0. # # The patch substitutes PyLong_* in all 31 places, which is exact: pyhead.swg defined # PyInt_Check as PyLong_Check and so on, so this changes spelling only. 25 are %%typemap # bodies in pyBase.i; the other 6 are C++ headers under Modules/Bridge/NumPy # (itkPyVnl.hxx, itkPyBuffer.hxx, itkPyVectorContainer.hxx) -- NOT under Wrapping/ at # all, which is why -16 only moved the error there instead of removing it. I had grepped # Wrapping/ because that is all I had extracted. # # It has to be the typemap bodies. -15 instead added the macros back in a # %%insert("begin") block in pyBase.i and failed identically (11043124), because SWIG # emits such a block only into the wrapper generated FROM that file, while typemap # bodies inline into every module's own wrapper -- the definitions and the uses ended # up in different translation units. Upstream master is affected identically (26 uses) # with no issue open for it. Patch4: InsightToolkit5-swig45-pyint-compat.patch # ITK_WRAP_PYTHON=ON forces ITK_LEGACY_REMOVE on (see the cmake flags), and # TransformFactoryBase guards the registration of v3::Rigid3DTransform and # BSplineDeformableTransform behind it. A .tfm naming either class then fails to # load ("Could not create an instance of Rigid3DTransform_double_3_3"). 3D Slicer's # CTest caught it: 9 of its 26 failures, and real user files are affected. Both # classes are plain headers that compile with the macro set, so the patch only # drops the guards in itkTransformFactoryBase{.cxx,Register.hxx}. Patch5: InsightToolkit5-register-legacy-transforms.patch # Legacy-only upstream bug that the wrapper trips over. SurfaceSpatialObject::Approximate3DNormals() # is compiled only without ITK_LEGACY_REMOVE and reads "return ComputeNormals;" -- the member # function name without "()", so it cannot compile. Nothing ever noticed because a template member # is only instantiated when called; the Python wrapper instantiates every wrapped member and dies in # itkSurfaceSpatialObjectPython.cpp ("cannot convert ... from type 'bool (...)()' to type 'bool'"). # This is the concrete reason upstream forces ITK_LEGACY_REMOVE on with ITK_WRAP_PYTHON: legacy code is # not exercised by the wrapper. Only needed while the legacy API is kept (keep_legacy_api). Patch6: InsightToolkit5-surfacespatialobject-legacy-normals.patch # ITK 5.x is not fully compatible with ITK 4.x, so we package it separately. # We use ITK's versioned install paths to allow side-by-side installation. # Unbundling, converged with Fedora's InsightToolkit (Ankur Sinha) 2026-09-15. # # Eigen3, DoubleConversion and VXL are now taken from the system. The previous # note here claimed eigen3 5.0.1 broke "ITK's find_package(Eigen3 3.3)" — ITK # makes no such call. Modules/ThirdParty/Eigen3/CMakeLists.txt does a versionless # find_package(Eigen3 REQUIRED CONFIG) and then an `if(VERSION_LESS 3.3)` check, # which 5.0.1 passes. Fedora has built ITK with ITK_USE_SYSTEM_EIGEN=ON against # eigen3 5.0.1 since 2026-08-10. # # ITK_USE_SYSTEM_LIBRARIES is only the *default* for each individual option # (`option(ITK_USE_SYSTEM_EIGEN ... ${ITK_USE_SYSTEM_LIBRARIES})`), so the # explicit per-library flags below win regardless of it. # # Still bundled, and why — ITK offers no system option for these: # NIFTI no ITK_USE_SYSTEM_NIFTI option (bundled nifti_clib) # OpenJPEG no ITK_USE_SYSTEM_OPENJPEG option; ITK bundles OpenJPEG 1.x. # We used to pass -DITK_USE_SYSTEM_OPENJPEG=ON, which CMake # silently ignored — it was always a no-op. # MetaIO, KWSys, NrrdIO, Netlib, DICOMParser, GIFTI, VNLInstantiation # not packaged in Fedora # # VXL is unbundled too, via Patch0 below. Our first attempt failed at link on # "cannot find -lnetlib"; the cause was not our module set but a stray # "netlib" in ITK's own link lines, which Fedora's spec already patches out. # Bundled third-party code, declared per Fedora's bundling policy. Merged from # Fedora's own InsightToolkit.spec (Ankur Sinha), which carried 11 of these to # our 4 -- every one of them is a library ITK vendors and offers no working # system option for, so they ship inside our rpm whether or not we name them. # Versions corroborated against the ITK source tree where the code carries one # (NrrdIO 1.11.1, OpenJPEG 1.2.0, liblbfgs 1.10, googletest 1.13.0); gifticlib # and nifti are taken from Fedora's spec, whose maintainer researched them. # Re-check these on every ITK version bump -- a bundled version can move without # the ITK version telling you. Provides: bundled(DICOMParser) Provides: bundled(gifticlib) = 1.16 Provides: bundled(googletest) = 1.13.0 Provides: bundled(kwsys) Provides: bundled(liblbfgs) = 1.10 Provides: bundled(metaio) Provides: bundled(netlib) Provides: bundled(nifti) = 2.1.0 Provides: bundled(NrrdIO) = 1.11.1 Provides: bundled(openjpeg) = 1.2.0 Provides: bundled(VNLInstantiation) Provides: itk(abi) = %{itk_abi} # Pin the exact VTK ABI this package was built against. VTK freezes its soname at # libvtk*.so.1 across all of 9.x, so rpm cannot tell 9.5 from 9.6 from 9.7: a consumer # built against one installs cleanly against another and fails at LOAD with undefined # symbols. A >= floor does not help -- 9.7.0 satisfies >= 9.6.2 -- so this is an exact # match. %%vtk_abi comes from vtk-devel's macros.vtk, so it re-pins on every rebuild. # # The missing-macro check lives in %%build, deliberately, NOT at parse time. A # parse-time %%error cannot distinguish "COPR is generating the SRPM" from "this is a # real buildroot": rpkg srpm parses the spec with no buildroot and therefore no # vtk-devel, so a parse-time guard killed every SCM build of every guarded package # before any chroot existed (python-simpleitk 10980296 failed in 0 minutes with # "can't parse specfile"). Expanding to UNSET keeps the SRPM parse alive, and the # %%build test still fails loudly in a buildroot lacking vtk-devel, so no RPM carrying # the placeholder can ever be produced. Requires: vtk(abi) = %{?vtk_abi}%{!?vtk_abi:UNSET} # Fedora 45 rebased its own InsightToolkit from 4.13.3 to 5.4.6, which installs the # SAME versioned sonames we do -- libITKCommon-5.4.so.1 and 82 more. Both packages # then own the same 83 files in %%{_libdir}, and because rpm generates our consumers' # dependencies from sonames rather than package names, dnf sees two providers for # most of them and can try to install both. That is what makes the f45 Slicer stack # uninstallable despite building green: # file /usr/lib64/libITKCommon-5.4.so.1 conflicts between attempted installs of # InsightToolkit5-5.4.7-9.fc45 and InsightToolkit-5.4.6-3.fc45 # # Bounded at >= 5 deliberately. On f44 Fedora still ships 4.13.3 with # libITKCommon-4.13.so.1, which does not collide, and side-by-side ITK4 + ITK5 is # something this package was built to allow. An unbounded Conflicts would break that # for no reason. # # Measured before adding this, because a Conflicts on a base library is not a cheap # thing to get wrong: # * 9 of the 91 ITK sonames 3dslicer needs are provided ONLY by us -- # ITKDeprecated, GrowCut, MGHIO, IOScanco, IODCMTK, VtkGlue, AdaptiveDenoising, # SimpleITKFilters, IOPhilipsREC. dnf is therefore FORCED to choose our ITK, and # this Conflicts only stops it also dragging in Fedora's. Deterministic, not a # coin toss. # * The only Fedora-native ITK consumers on f45 are alizams (3 ITK sonames) and # petpvc (27). We provide every one, so both stay installable against ours. # Everything else in --whatrequires InsightToolkit is our own package. Conflicts: InsightToolkit >= 5 # Pin the exact DCMTK snapshot this package was built against. dcmtk is packaged from git # HEAD and upstream's DCMTK_ABI_VERSION stays 20 across snapshots, so every snapshot installs # libdcm*.so.20 and rpm cannot tell them apart: a consumer built against one installs cleanly # against another and fails at load with undefined symbols (dcmqi on f45, with OverlapUtil). # %%dcmtk_abi comes from dcmtk-devel's macros.dcmtk, so it re-pins on every rebuild. The # missing-macro check is in %%build, not at parse time, for the reason spelled out at the vtk # pin in 3dslicer.spec: an SRPM parse has no buildroot. Requires: dcmtk(abi) = %{?dcmtk_abi}%{!?dcmtk_abi:UNSET} %description The Insight Toolkit (ITK) is an open-source, cross-platform system that provides developers with an extensive suite of software tools for image analysis. This package provides version 5 of the toolkit. %package devel Summary: Development files for %{name} Requires: %{name}%{?_isa} = %{version}-%{release} Requires: %{name}-vtk-devel%{?_isa} = %{version}-%{release} # Transitive cmake find_package deps: downstream consumers of ITK's UseITK.cmake # will have find_package() called for each system library ITK was built against. Requires: fftw-devel Requires: hdf5-devel Requires: expat-devel Requires: libjpeg-devel Requires: libpng-devel Requires: libtiff-devel Requires: zlib-devel Requires: gdcm-devel Requires: dcmtk-devel Requires: openjpeg2-devel %if 0%{?fedora} Requires: libminc-devel %endif # Unbundled since -4/-5, and still part of ITK's public build interface: # ITKEigen3.cmake calls find_package(Eigen3 REQUIRED CONFIG), and # ITKVNL_INCLUDE_DIRS points at /usr/include/vxl, whose headers ITK's public # headers include (itkVector.h -> vnl/vnl_vector_ref.h). double-conversion's # headers are exported too (Patch1), matching the flat layout bundled ITK # installed; elastix includes "double-conversion.h" directly. Requires: eigen3-devel Requires: vxl-devel%{?_isa} Requires: double-conversion-devel%{?_isa} # Same file collision as the base package; see the note there. Conflicts: InsightToolkit-devel >= 5 %description devel The %{name}-devel package contains libraries and header files for developing applications that use %{name}. %package vtk Summary: Provides an interface between ITK and VTK Requires: %{name}%{?_isa} = %{version}-%{release} # Same file collision as the base package; see the note there. Conflicts: InsightToolkit-vtk >= 5 %description vtk Provides an interface between ITK and VTK. %package vtk-devel Summary: Development files for the ITK-VTK bridge Requires: %{name}-vtk%{?_isa} = %{version}-%{release} Requires: vtk-devel%{?_isa} # Same file collision as the base package; see the note there. Conflicts: InsightToolkit-vtk-devel >= 5 %description vtk-devel Libraries and header files for developing applications that use the ITK-VTK bridge (ITKVtkGlue). %package doc Summary: Documentation for %{name} BuildArch: noarch %description doc Documentation, copyright notices, and the ITK Software Guide references for version 5 of the Insight Toolkit. %package examples Summary: Example programs and data for %{name} BuildArch: noarch Requires: %{name}-devel = %{version}-%{release} %description examples Example source code, CMakeLists.txt, and test data for building applications with ITK 5. Useful as starting points for new projects. %prep %autosetup -p1 -n InsightToolkit-%{version} %if %{with python_wrapping} && %{with keep_legacy_api} # ITK declares ITK_LEGACY_REMOVE with cmake_dependent_option(... OFF "NOT ITK_WRAPPING" ON): when # wrapping is on the condition fails and cmake FORCES the last argument, ON. Changing that forced # value to OFF keeps the legacy API compiled in. Without this, enabling python3-itk (ITK_WRAP_PYTHON) # silently removes the legacy API for every consumer of the C++ headers. perl -0pi -e 's/(ITK_LEGACY_REMOVE\s+"Remove current legacy code completely\."\s+OFF\s+"NOT ITK_WRAPPING"\s+)ON\)/${1}OFF)/' CMakeLists.txt # Assert the EFFECT, not the command: perl exits 0 whether or not the pattern matched. perl -0ne 'exit(!/ITK_LEGACY_REMOVE\s+"Remove current legacy code completely\."\s+OFF\s+"NOT ITK_WRAPPING"\s+OFF\)/)' CMakeLists.txt \ || { echo "ERROR: ITK_LEGACY_REMOVE forced-value edit did not apply; ITK's CMakeLists.txt changed" >&2; exit 1; } %endif # Unpack the GenericLabelInterpolator remote module into the expected location. # ITK's Module_GenericLabelInterpolator=ON normally fetches this at cmake time; we # pre-populate the source directory so the build works offline (mock/COPR policy). mkdir -p Modules/Remote/GenericLabelInterpolator tar -xzf %{SOURCE1} --strip-components=1 \ -C Modules/Remote/GenericLabelInterpolator mkdir -p Modules/Remote/AdaptiveDenoising tar -xzf %{SOURCE2} --strip-components=1 \ -C Modules/Remote/AdaptiveDenoising mkdir -p Modules/Remote/MorphologicalContourInterpolation tar -xzf %{SOURCE3} --strip-components=1 \ -C Modules/Remote/MorphologicalContourInterpolation mkdir -p Modules/Remote/GrowCut tar -xzf %{SOURCE4} --strip-components=1 \ -C Modules/Remote/GrowCut mkdir -p Modules/Remote/SimpleITKFilters tar -xzf %{SOURCE5} --strip-components=1 \ -C Modules/Remote/SimpleITKFilters mkdir -p Modules/Remote/LabelErodeDilate tar -xzf %{SOURCE6} --strip-components=1 \ -C Modules/Remote/LabelErodeDilate mkdir -p Modules/Remote/MGHIO tar -xzf %{SOURCE7} --strip-components=1 \ -C Modules/Remote/MGHIO mkdir -p Modules/Remote/IOScanco tar -xzf %{SOURCE8} --strip-components=1 \ -C Modules/Remote/IOScanco %build # dcmtk_abi comes from dcmtk-devel's macros.dcmtk. Absent means the buildroot has a dcmtk-devel # that predates the snapshot, and the Requires above would carry the UNSET placeholder. test -n "%{?dcmtk_abi}" || { echo "ERROR: dcmtk_abi undefined - needs the dcmtk-devel that ships macros.dcmtk" >&2; exit 1; } # vtk_abi comes from vtk-devel's macros.vtk. Absent means BuildRequires: vtk-devel is # missing, and the Requires above would ship as the vacuous "vtk(abi) = UNSET". test -n "%{?vtk_abi}" || { echo "ERROR: vtk_abi undefined - add 'BuildRequires: vtk-devel'" >&2; exit 1; } # Relax compiler checks for compatibility with GCC 14+ and force local include # path to avoid system header conflicts export CXXFLAGS="%{optflags} -fpermissive -Wno-error=incompatible-pointer-types -Wno-error=int-conversion -D_GNU_SOURCE -I%{_builddir}/InsightToolkit-%{version}/Modules/Core/Common/include" # FFTW (ITK_USE_FFTWD/F) is ON, matching Fedora's InsightToolkit. ITK_USE_SYSTEM_FFTW # alone does nothing. FFTW is GPL-2.0-or-later; ITK's own configure warns that # the ITK libraries built this way, and every executable linked against them, # are covered by the GPL. This is a deliberate choice (Morgan Hough, # 2026-09-17), documented in docs/licensing/itk-fftw-gpl.md. The License: tag # is unchanged because it describes this package's sources, and FFTW is not # bundled. %cmake \ -DCMAKE_CXX_STANDARD:STRING=17 \ -DBUILD_EXAMPLES:BOOL=OFF \ -DBUILD_TESTING:BOOL=OFF \ -DBUILD_SHARED_LIBS:BOOL=ON \ -DITK_BUILD_DEFAULT_MODULES:BOOL=ON \ -DITK_USE_SYSTEM_LIBRARIES:BOOL=OFF \ -DITK_USE_SYSTEM_EIGEN:BOOL=ON \ -DITK_USE_SYSTEM_EXPAT:BOOL=ON \ -DITK_USE_SYSTEM_FFTW:BOOL=ON \ -DITK_USE_FFTWD:BOOL=ON \ -DITK_USE_FFTWF:BOOL=ON \ -DITK_USE_SYSTEM_HDF5:BOOL=ON \ -DITK_USE_SYSTEM_JPEG:BOOL=ON \ -DITK_USE_SYSTEM_PNG:BOOL=ON \ -DITK_USE_SYSTEM_TIFF:BOOL=ON \ -DITK_USE_SYSTEM_ZLIB:BOOL=ON \ -DITK_USE_SYSTEM_GDCM:BOOL=ON \ -DITK_USE_SYSTEM_DCMTK:BOOL=ON \ -DITK_USE_SYSTEM_DOUBLECONVERSION:BOOL=ON \ -DITK_USE_SYSTEM_VXL:BOOL=ON \ -DModule_ITKGoogleTest:BOOL=OFF \ -DModule_GenericLabelInterpolator:BOOL=ON \ -DModule_AdaptiveDenoising:BOOL=ON \ -DModule_MorphologicalContourInterpolation:BOOL=ON \ -DModule_GrowCut:BOOL=ON \ -DModule_SimpleITKFilters:BOOL=ON \ -DModule_LabelErodeDilate:BOOL=ON \ -DModule_ITKVtkGlue:BOOL=ON \ -DModule_ITKIOPhilipsREC:BOOL=ON \ -DModule_ITKReview:BOOL=ON \ -DModule_ITKDeprecated:BOOL=ON \ %if %{with python_wrapping} -DITK_WRAP_PYTHON:BOOL=ON \ `# ITK_LEGACY_REMOVE: ITK forces it ON whenever wrapping is enabled` \ `# (cmake_dependent_option ... "NOT ITK_WRAPPING" ON); the %%prep edit above` \ `# changes that forced value to OFF so the legacy API stays compiled in. Do NOT` \ `# pass -DITK_LEGACY_REMOVE here: it would be ignored either way. The effect is` \ `# asserted on the SHIPPED itkConfigure.h in %%install. History: 5.4.7-18..-22` \ `# shipped with it forced ON, which broke itksnap (c3d) and medInria (RPI) on all` \ `# six chroots and needed per-class workarounds (Patch5).` \ `#` \ `# Double-precision wrapping. ITK wraps float only by default and the pip wheels turn` \ `# double on. VectorImage is therefore absent from itk.PyBuffer, so` \ `# itk.image_from_array(float64_array, is_vector=True) raises "No suitable template` \ `# parameter" -- icon_registration (unigradicon-register) hits exactly that on its` \ `# displacement field. These three also cover Image,3> and` \ `# ImageDuplicator for it.` \ -DITK_WRAP_double:BOOL=ON \ -DITK_WRAP_vector_double:BOOL=ON \ -DITK_WRAP_covariant_vector_double:BOOL=ON \ `# ITK_USE_SYSTEM_CASTXML and ITK_USE_SYSTEM_SWIG both default to OFF, so` \ `# ITK_WRAP_PYTHON alone adds ExternalProjects that DOWNLOAD a prebuilt` \ `# castxml tarball and build their own swig and PCRE. COPR 11039472 died in` \ `# 3 minutes on that download. Worse than a failure locally: a workstation` \ `# mock HAS network, so the download succeeds and the build looks correct` \ `# while wrapping against an upstream prebuilt BINARY castxml 0.6.5 instead` \ `# of Fedora's 0.7.0 -- unshippable, and any timing measured that way is the` \ `# timing of the wrong toolchain. pygccxml, the third generator input, needs` \ `# nothing: ITK bundles it under Modules/ThirdParty/pygccxml/src.` \ -DITK_USE_SYSTEM_CASTXML:BOOL=ON \ -DCASTXML_EXECUTABLE:FILEPATH=%{_bindir}/castxml \ -DITK_USE_SYSTEM_SWIG:BOOL=ON \ -DSWIG_EXECUTABLE:FILEPATH=%{_bindir}/swig \ `# Enabled by Patch2; see the patch comment for the measurement.` \ `#` \ `# __NO_LONG_DOUBLE_MATH is aarch64-only and is NOT about long double math.` \ `# glibc bits/floatn.h:28 reads "#ifndef __NO_LONG_DOUBLE_MATH / # define` \ `# __HAVE_FLOAT128 1", and with __HAVE_FLOAT128 on it declares wcstof128,` \ `# strtof128 and the rest of the binary128 API in terms of a bare _Float128.` \ `# castxml embeds a Clang that does not know that type name on aarch64, so` \ `# the FIRST castxml invocation dies with 74 "unknown type name '_Float128'"` \ `# errors before it parses a line of ITK. glibc has a compat path that would` \ `# typedef _Float128 to long double (floatn.h:79) -- correct on aarch64,` \ `# where long double IS binary128 -- but it is gated on !__GNUC_PREREQ(13,0)` \ `# and --castxml-cc-gnu hands Clang gcc 16's predefines, so glibc concludes` \ `# the compiler has the type natively. Defining __NO_LONG_DOUBLE_MATH makes` \ `# the header not declare the API at all. This flag reaches the castxml` \ `# parse only, never the compiled C++, and ITK wraps no long double API.` \ `#` \ `# Measured in fedora:44 and fedora:45 aarch64 containers, controls first` \ `# (a deliberate #error must fail, a trivial struct must pass):` \ `# flags f44/castxml 0.7.0 f45/castxml 0.8.0` \ `# -std=c++17 74 errors 74 errors` \ `# -std=c++20 74 errors 74 errors` \ `# -std=c++23 (as shipped) 74 errors 74 errors` \ `# -std=c++23 -D__NO_LONG_DOUBLE_MATH 0, rc=0 0, rc=0` \ `# -std=c++23 -D__HAVE_FLOAT128=0 74 errors 74 errors` \ `# -std=c++23 -D_Float128=__float128 57 errors 57 errors` \ `#` \ `# Two things this corrects in the Patch2 comment above. First, the` \ `# -std= ladder it records ("c++17 and c++20 both fail, c++23 parses` \ `# libstdc++") was measured on x86_64; on aarch64 all three fail and the` \ `# standard makes no difference, because the failure is in glibc, not` \ `# libstdc++. Second, this is not an f45 regression -- f44 with the older` \ `# castxml fails identically. ITK_WRAP_PYTHON has simply never been able to` \ `# build on aarch64, which was invisible because the bcond is off in git and` \ `# every wrapping build to date (ci/build-itk-python.sh) went to x86_64.` \ `# -D__HAVE_FLOAT128=0 looks like the obvious fix and is not: floatn.h` \ `# defines it unconditionally, so the header wins over the command line.` \ %ifarch aarch64 -DITK_WRAP_CASTXML_EXTRA_FLAGS:STRING="-std=c++23 -DEIGEN_DONT_VECTORIZE -D__NO_LONG_DOUBLE_MATH" \ %else -DITK_WRAP_CASTXML_EXTRA_FLAGS:STRING="-std=c++23 -DEIGEN_DONT_VECTORIZE" \ %endif `# NOT the fix for the swig 4.4 import failure -- Patch3 is. I set this in -12` \ `# on upstream's recommendation (#6479, #6544) and it made no difference:` \ `# 11040244 built *.cpython-314*.so with no Py_LIMITED_API anywhere and failed` \ `# at import identically to 11039812, which had it on. Kept anyway because it` \ `# is the simpler configuration and costs nothing: the limited API buys` \ `# minor-version portability that a package rebuilt per Fedora release does` \ `# not need, and it keeps upstream's two limited-API cmake hunks (which do not` \ `# apply to 5.4.7) out of the picture. Patch3 is correct either way.` \ -DITK_USE_PYTHON_LIMITED_API:BOOL=OFF \ %endif `# 3D Slicer's Libs/ITKFactoryRegistration requires MGHIO + IOScanco +` \ `# ITKIOTransformMatlab + ITKIODCMTK. MGHIO and IOScanco are REMOTE` \ `# modules (sources pre-staged in %prep from Source7/Source8).` \ `# ITKIOTransformMatlab and ITKIODCMTK are built-in but EXCLUDE_FROM_DEFAULT.` \ -DModule_MGHIO:BOOL=ON \ -DModule_IOScanco:BOOL=ON \ -DModule_ITKIOTransformMatlab:BOOL=ON \ -DModule_ITKIODCMTK:BOOL=ON \ -DITK_FORBID_DOWNLOADS:BOOL=ON \ %if 0%{?fedora} -DITK_USE_SYSTEM_MINC:BOOL=ON \ %else -DITK_USE_SYSTEM_MINC:BOOL=OFF \ %endif -DITK_INSTALL_PACKAGE_SUFFIX:STRING=-5.4 \ -DITK_INSTALL_LIBRARY_DIR:PATH=%{_lib} \ -DITK_INSTALL_INCLUDE_DIR:PATH=include/ITK-5.4 \ -DITK_SKIP_PATH_LENGTH_CHECKS:BOOL=ON %cmake_build %install %cmake_install # Move bundled docs to doc subpackage location mkdir -p %{buildroot}%{_docdir}/%{name}-doc if [ -d %{buildroot}%{_datadir}/doc/ITK-5.4 ]; then mv %{buildroot}%{_datadir}/doc/ITK-5.4/* %{buildroot}%{_docdir}/%{name}-doc/ 2>/dev/null || true rm -rf %{buildroot}%{_datadir}/doc/ITK-5.4 fi # Install examples for downstream developers mkdir -p %{buildroot}%{_datadir}/%{name}/examples cp -a Examples/* %{buildroot}%{_datadir}/%{name}/examples/ 2>/dev/null || true # Remove zero-length stub headers (rpmlint zero-length error; ITK uses them as placeholders) find %{buildroot}%{_includedir} -name stub.h -empty -delete # Remove cmake configs for ITK's internal bundled MINC library (installed to lib64/cmake/ # when ITK_USE_SYSTEM_MINC=OFF on EPEL; directory does not exist on Fedora) if [ -d %{buildroot}%{_libdir}/cmake ]; then find %{buildroot}%{_libdir}/cmake -maxdepth 1 \ \( -name 'itkLIBMINC*.cmake' -o -name 'UseitkLIBMINC.cmake' \) -delete fi # Bundled licence texts, renamed to avoid collisions (after 84675f7 in Fedora's # InsightToolkit). NrrdIO has no separate file: its Zlib notice is in the source # headers. NIFTI's LICENSE is installed here too, which Fedora's spec does not. install -d %{buildroot}%{_defaultlicensedir}/%{name} install -pm 0644 Modules/ThirdParty/DICOMParser/src/DICOMParser/Copyright.txt \ %{buildroot}%{_defaultlicensedir}/%{name}/LICENSE.dicomparser install -pm 0644 Modules/ThirdParty/GIFTI/src/gifticlib/LICENSE.gifti \ %{buildroot}%{_defaultlicensedir}/%{name}/LICENSE.gifti install -pm 0644 Modules/ThirdParty/KWSys/src/KWSys/Copyright.txt \ %{buildroot}%{_defaultlicensedir}/%{name}/LICENSE.kwsys install -pm 0644 Modules/ThirdParty/MetaIO/src/MetaIO/License.txt \ %{buildroot}%{_defaultlicensedir}/%{name}/LICENSE.metaio install -pm 0644 Modules/ThirdParty/NIFTI/src/nifti/LICENSE \ %{buildroot}%{_defaultlicensedir}/%{name}/LICENSE.nifti install -pm 0644 Modules/ThirdParty/OpenJPEG/src/LICENSE \ %{buildroot}%{_defaultlicensedir}/%{name}/LICENSE.openjpeg %if %{with python_wrapping} # ITK_WRAP_PYTHON copies the whole ITK runtime into the Python package, every copy # linked against the build tree. check-rpaths rejected 79 distinct files in COPR # 11039490 -- 78 shared libraries plus a duplicate itkTestDriver -- each carrying # /builddir/.../Wrapping/Generators/Python/itk in its RUNPATH and an empty entry # besides. That is what ended a build whose 3643 targets had all compiled, and it # is a %%install failure, so it costs the full two hours before it shows. # # The 78 libraries are redundant, not merely unshippable: every one matches a # libITK*/libitk* glob the main package already owns, and python3-itk requires # InsightToolkit5 = %%{version}-%%{release}, so the real ones are always present. # Delete the copies and strip the extension modules in place. ITKPyBase and # ITKPyUtils survive this -- they exist only as _ITK*Python.abi3.so, never as # lib*.so.1. Counted and verified by fsk-dual against 11039490's log. rm -f %{buildroot}%{python3_sitearch}/itk/libITK*.so.1 \ %{buildroot}%{python3_sitearch}/itk/libitk*.so.1 \ %{buildroot}%{python3_sitearch}/itk/itkTestDriver find %{buildroot}%{python3_sitearch}/itk -name '*.so' -print0 \ | xargs -0 -r chrpath -d 2>/dev/null || : # Print the top-level site-packages manifest while we still can. check-rpaths and # check-files both run after %%install, so a failure in either aborts before rpm # ever lists what was installed -- and each round trip here is two hours. This # makes the log answer "what does ITK_WRAP_PYTHON actually install?" even when the # build dies. echo "=== python3-itk install manifest (site-packages, depth 1) ===" find %{buildroot}%{python3_sitearch} -maxdepth 1 -mindepth 1 | \ sed "s|%{buildroot}||" | LC_ALL=C sort echo "=== end manifest ===" %endif %if %{with python_wrapping} %check # The gate that 11039812 needed and did not have. That build compiled all 3643 # targets, installed a complete 3,557-entry tree, passed rpmlint's file checks and # produced a python3-itk rpm that could not execute "import itk" -- and rpm called # it a success, because rpm verifies files, not imports. Nothing downstream of a # Python package matters if the package does not import, so assert it here where a # failure costs a build rather than a release. # # LD_LIBRARY_PATH is needed because the extension modules have had their RUNPATHs # stripped in %%install (see above) and the ITK libraries they need are not yet # installed on the system at %%check time. export PYTHONPATH=%{buildroot}%{python3_sitearch} export LD_LIBRARY_PATH=%{buildroot}%{_libdir}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %{python3} -c "import itk; print('itk', itk.Version.GetITKVersion())" # Beyond a bare import: the templated API is the whole reason this package exists, # and it resolves lazily, so "import itk" alone can pass while the templates that # every consumer uses are broken. %{python3} -c " import itk img = itk.Image[itk.F, 3].New() img.SetRegions([4, 4, 4]); img.Allocate(); img.FillBuffer(1.5) arr = itk.array_view_from_image(img) assert arr.shape == (4, 4, 4), arr.shape assert abs(float(arr[0, 0, 0]) - 1.5) < 1e-6, arr[0, 0, 0] print('templated API and numpy bridge ok', arr.shape, arr.dtype) " # float64 vector images: the call icon_registration (unigradicon-register) makes on its displacement # field. Absent from itk.PyBuffer until ITK_WRAP_double/_vector_double were turned on. %{python3} -c " import itk, numpy as np for dt in (np.float32, np.float64): im = itk.image_from_array(np.zeros((4, 5, 6, 3), dtype=dt), is_vector=True) assert tuple(itk.size(im)) == (6, 5, 4), itk.size(im) print('vector image_from_array ok', dt.__name__, type(im).__name__) assert tuple(itk.size(itk.image_from_array(np.zeros((4, 5, 6), dtype=np.float64)))) == (6, 5, 4) " %endif %ldconfig_scriptlets %ldconfig_scriptlets vtk %if %{with python_wrapping} && %{with keep_legacy_api} # Assert on what SHIPPED, not on what we asked for. Consumers see ITK through these two files; the # last five releases told them the legacy API was gone while the spec said otherwise. grep -q '^/\* #undef ITK_LEGACY_REMOVE \*/' %{buildroot}%{_includedir}/ITK-5.4/itkConfigure.h \ || { echo "ERROR: shipped itkConfigure.h defines ITK_LEGACY_REMOVE" >&2; exit 1; } grep -q 'set(ITK_LEGACY_REMOVE "OFF")' %{buildroot}%{_prefix}/lib/cmake/ITK-5.4/ITKConfig.cmake \ || { echo "ERROR: shipped ITKConfig.cmake has ITK_LEGACY_REMOVE ON" >&2; exit 1; } %endif %if %{with python_wrapping} # ITK_WRAP_PYTHON installs no *.dist-info, so rpm's Python dependency generator emits no # python3dist(itk) and nothing that Requires "itk" (monai-physio needs itk>=5.3,<6) can be # satisfied by this package. A minimal dist-info is all the generator reads. DI=%{buildroot}%{python3_sitearch}/itk-%{version}.dist-info mkdir -p "$DI" cat > "$DI/METADATA" < "$DI/INSTALLER" %endif # Ship %itk_ver so a consumer can pin the ITK it was actually BUILT against. # # Why this is needed: ITK freezes its sonames across releases -- libITKFFT-5.4.so.1 # is identical in name in 5.4.7-2 and 5.4.7-8 -- while ADDING symbols. 5.4.7-8 # enabled FFTW, which exports # _ZN3itk46FFTWFFTImageFilterInitFactoryRegister__PrivateEv. rpm generates # dependencies from sonames, so it cannot tell the two apart: a consumer built # against -8 installs cleanly over -2 and then dies at exit 127 on every # invocation. c3d does exactly this, measured on a real host. # # itk_ver is a FLOOR and is right ONLY for additive changes (a newer ITK that merely adds symbols). # It is NOT enough on its own: flipping ITK_LEGACY_REMOVE is not additive. It changes class layouts at # unchanged sonames (measured with nm -S over every libITK*.so, -21 vs -23: 176 of 1681 vtables differ, # MultiThreaderBase and PlatformMultiThreader +2 virtual slots, the whole itk::Transform family +2), so # a consumer built against one state and run on the other calls the wrong slot: python3-simpleitk -11 on # ITK -23 returned an all-zero sitk.Resample and sitk.Add and crashed a 26-operation script with SIGSEGV, # with no error at install or at import. The floor was satisfied by -23, so nothing stopped it. # # itk(abi) is the EQUALITY pin, like vtk(abi) and dcmtk(abi). Its value encodes the legacy state # (5.4-legacy / 5.4-nolegacy), so it only changes when the layout does, not on every release. Consumers take # Requires: itk(abi) = %%{?itk_abi}%%{!?itk_abi:UNSET} # plus a %%build guard, because an undefined macro would otherwise ship a pin on the literal string UNSET. # A python-* spec that builds only subpackages must put the Requires INSIDE the subpackage: a preamble Requires # belongs to the main package, which never becomes an rpm there (ci/check-pin-ships.sh). mkdir -p %{buildroot}%{_rpmmacrodir} cat > %{buildroot}%{_rpmmacrodir}/macros.itk <<'EOF' %%itk_ver %{version}-%{release} %%itk_abi %{itk_abi} EOF grep -qx '%%itk_abi %{itk_abi}' %{buildroot}%{_rpmmacrodir}/macros.itk \ || { echo "ERROR: macros.itk does not carry itk_abi" >&2; exit 1; } %if %{with python_wrapping} %package -n python3-itk Summary: Python bindings for the Insight Toolkit Requires: %{name}%{?_isa} = %{version}-%{release} Requires: python3-numpy %description -n python3-itk ITK's own Python wrapping: the full templated ITK API exposed through SWIG. This is distinct from python3-simpleitk, which is a separate upstream project offering a simplified procedural interface. Code written against one will not run against the other. %endif %files %license LICENSE %license %{_defaultlicensedir}/%{name}/LICENSE.dicomparser %license %{_defaultlicensedir}/%{name}/LICENSE.gifti %license %{_defaultlicensedir}/%{name}/LICENSE.kwsys %license %{_defaultlicensedir}/%{name}/LICENSE.metaio %license %{_defaultlicensedir}/%{name}/LICENSE.nifti %license %{_defaultlicensedir}/%{name}/LICENSE.openjpeg %doc NOTICE README.md %{_libdir}/libITK*.so.1 %{_libdir}/libitk*.so.1 %exclude %{_libdir}/libITKVtkGlue*.so.1 %files devel %{_rpmmacrodir}/macros.itk %{_includedir}/ITK-5.4/ %exclude %{_includedir}/ITK-5.4/itkImageToVTKImageFilter.h* %exclude %{_includedir}/ITK-5.4/itkVTKImageToImageFilter.h* %exclude %{_includedir}/ITK-5.4/QuickView.h %exclude %{_includedir}/ITK-5.4/vtkCaptureScreen.h %{_prefix}/lib/cmake/ITK*/ %exclude %{_prefix}/lib/cmake/ITK-5.4/Modules/ITKVtkGlue.cmake %{_libdir}/libITK*.so %{_libdir}/libitk*.so %exclude %{_libdir}/libITKVtkGlue*.so %{_bindir}/itkTestDriver %files vtk %{_libdir}/libITKVtkGlue*.so.1 %files vtk-devel %{_libdir}/libITKVtkGlue*.so %{_includedir}/ITK-5.4/itkImageToVTKImageFilter.h* %{_includedir}/ITK-5.4/itkVTKImageToImageFilter.h* %{_includedir}/ITK-5.4/QuickView.h %{_includedir}/ITK-5.4/vtkCaptureScreen.h %{_prefix}/lib/cmake/ITK-5.4/Modules/ITKVtkGlue.cmake %files doc %{_docdir}/%{name}-doc/ %files examples %{_datadir}/%{name}/examples/ %if %{with python_wrapping} %files -n python3-itk # ITK_WRAP_PYTHON installs exactly two things at the site-packages root: itk/ and # itkConfig.py. A bare %%{python3_sitearch}/itk* glob looks like it covers both and # does not -- byte-compiling a ROOT-level module puts its bytecode in # %%{python3_sitearch}/__pycache__/, and a glob anchored on "itk" cannot match a # path beginning "__pycache__". One unpackaged .pyc would fail check-files, which # runs after check-rpaths, i.e. only once the two-hour compile is already spent. # %%pycached owns the bytecode without claiming the shared __pycache__ directory, # which other packages co-own. Caught statically by fsk-dual before it cost a # build. The %%install manifest above is the standing check on the claim. %{python3_sitearch}/itk/ %pycached %{python3_sitearch}/itkConfig.py %{python3_sitearch}/itk-%{version}.dist-info/ %endif %changelog * Tue Oct 06 2026 Morgan Hough - 5.4.7-24 - ADD itk(abi) = 5.4-legacy and %%itk_abi in macros.itk. -23 flipped ITK_LEGACY_REMOVE back off and nothing stopped consumers built against the removed state (-10..-21) from installing over it, although the class layouts differ at the same sonames: python3-simpleitk -11 on -23 returned an all-zero sitk.Resample and sitk.Add and segfaulted a 26-operation script (fsk-triple, A/B on f45). Measured here with nm -S: 176 of 1681 ITK vtables differ -21 vs -23 (threaders +2 slots, itk::Transform family +2). The floor in itk_ver assumed additive-only changes; this one is not. The token encodes the legacy STATE so the pin works in both directions. No change to the libraries or headers: -24 is ABI-identical to -23, so consumers already built against -23 stay valid against it. - Consumers (every one built against ITK -10..-21) must be rebuilt with Requires: itk(abi) = %%{itk_abi}. * Tue Oct 06 2026 Morgan Hough - 5.4.7-23 - Keep the legacy ITK API compiled in WITH python wrapping (new bcond keep_legacy_api, on). ITK forces ITK_LEGACY_REMOVE on when wrapping is enabled (cmake_dependent_option ... "NOT ITK_WRAPPING" ON); %%prep now changes that forced value to OFF, asserts the edit applied, and %%install asserts the SHIPPED itkConfigure.h and ITKConfig.cmake say so. Since -18 every consumer saw an ITK with the legacy API removed: itksnap (c3d: ProgressAccumulator:: ResetFilterProgressAndKeepAccumulatedProgress) and medInria (RPI headers: scalar -> Vector FillBuffer) FTBFS on all six chroots after the dcmtk-pin rebuild. Patch5 (-22) is now redundant but harmless and is kept. - Patch6: SurfaceSpatialObject::Approximate3DNormals() returns "ComputeNormals" without "()" (legacy-only code, never instantiated until the wrapper tried). First -23 mock died on it at step 2773/3643 in itkSurfaceSpatialObjectPython.cpp. Legacy code is not exercised by ITK's wrapper, so more of this class of bug is possible; the trial build runs ninja -k 0 to list every one at once. - Wrap double precision (ITK_WRAP_double, _vector_double, _covariant_vector_double). VectorImage was missing from itk.PyBuffer, so itk.image_from_array(float64, is_vector=True) raised "No suitable template parameter can be found"; unigradicon-register died there after its network had run on the GPU. %%check now asserts float32 and float64 vector image_from_array. - Ship itk-%%{version}.dist-info (METADATA with Name: itk, Version) so python3-itk provides python3dist(itk) = %%{version}. Nothing could depend on "itk" before; python-monai-physio requires itk>=5.3,<6. Proven with a fixture RPM first (provides python3dist(itk) = 5.4.7). Rides this rebuild so ITK is rebuilt once, not twice. Proposed by fsk-triple. - Functional change, needs a rebuild of ITK and python3-itk, and a much longer wrap build. UNVERIFIED that castxml/swig tolerate the legacy API: first build is the test. * Mon Oct 05 2026 Morgan Hough - 5.4.7-22 - Register v3::Rigid3DTransform ("Rigid3DTransform_double_3_3") and BSplineDeformableTransform ("BSplineDeformableTransform_double_2_2" and _3_3) with TransformFactory regardless of ITK_LEGACY_REMOVE (Patch5). Since -18 ITK_WRAP_PYTHON=ON has forced ITK_LEGACY_REMOVE on, and upstream guards those two registrations behind it, so any .tfm naming either class failed with "Could not create an instance of ...". Found by 3D Slicer's nightly CTest (vtkMRMLTransformStorageNodeTest3, py_SampleData, ResampleDTIVolume*): stock 5.4.7-11 reproduces it with a 12-line TransformFileReader probe, and registering the two classes fixes it. Both headers compile with the macro set (their only guard is the itkv3 alias), so this restores reading existing files, not the legacy API. - Functional change: unlike -20, and like -21, this needs a rebuild of ITK and python3-itk. * Mon Oct 05 2026 Morgan Hough - 5.4.7-21 - Pin the exact DCMTK snapshot: Requires: dcmtk(abi) = %%{dcmtk_abi}, from dcmtk-devel's macros.dcmtk, plus a %%build guard against the UNSET placeholder. dcmtk is now packaged from git HEAD (policy in dcmtk.spec) and upstream's DCMTK_ABI_VERSION stays 20 across snapshots, so rpm cannot tell snapshots apart by soname; this is the same mechanism as vtk(abi). - This release exists to be rebuilt against the snapshot; the pin means it cannot be installed against a different one. * Tue Sep 29 2026 Morgan Hough - 5.4.7-20 - Drop -DITK_LEGACY_SILENT:BOOL=ON and explain why in its place. It never took effect: ITK declares it with cmake_dependent_option(... OFF "NOT ITK_LEGACY_REMOVE" OFF), and ITK_LEGACY_REMOVE is itself forced ON by cmake_dependent_option(... OFF "NOT ITK_WRAPPING" ON) as soon as ITK_WRAP_PYTHON is enabled. Read out of the SHIPPED itkConfigure.h rather than the build log: 5.4.7-19 has "#define ITK_LEGACY_REMOVE" and "/* #undef ITK_LEGACY_SILENT */" where 5.4.7-2 (pre-wrapping) had neither. - No functional change and no rebuild required -- the flag was already inert, so -20 would produce a byte-identical build. The release is bumped only so the spec and the NVR that carries this explanation stay in step. - The consequence is repo-wide and belongs on the record: python3-itk and the pre-5.4 legacy API cannot both come from one ITK build. Consumers that use class-scope enum aliases FTBFS against this ITK; 3dslicer-spharm-pdm was the first found (7 call sites). The fix is the modern enum spelling, which is unconditional in itkCommonEnums.h and compiles against either setting. * Mon Sep 28 2026 Morgan Hough - 5.4.7-19 - aarch64: append -D__NO_LONG_DOUBLE_MATH to the castxml parse flags. With -18 turning python_wrapping ON by default this stops being a wrapping-track detail and becomes a hard blocker: ITK5 cannot build on aarch64 AT ALL, on any release, so the arch would freeze at its currently published ITK (f44 5.4.7-12, f45 -9, rawhide -11) while x86_64 moves on. - -18's changelog says to expect f45 and rawhide to fail until the swig 4.5 work in Patch4 is proven there. That is right on x86_64 and wrong on aarch64, and the distinction matters because proving Patch4 will never make aarch64 pass. Both aarch64 chroots of 11043724 failed while both x86_64 chroots were still running, and the aarch64 logs carry 128 hits for _Float128 and ZERO for PyInt_: castxml dies long before anything reaches Modules/Bridge/NumPy. f44 fails the same way, so it is not an f45/rawhide problem either. - The cause is glibc, not ITK and not castxml's version. bits/floatn.h:28 declares the binary128 API in terms of a bare _Float128 unless __NO_LONG_DOUBLE_MATH is defined, and castxml's embedded Clang does not know that type name on aarch64. glibc has a compat path that would typedef it to long double -- correct here, where long double IS binary128 -- but it is gated on !__GNUC_PREREQ(13,0), and --castxml-cc-gnu hands Clang gcc 16's predefines, so glibc concludes the compiler has the type natively. - Measured in fedora:44 and fedora:45 aarch64 containers, controls first (a deliberate #error must fail, a trivial struct must pass): flags f44/castxml 0.7.0 f45/castxml 0.8.0 -std=c++17 / c++20 / c++23 (shipped) 74 errors 74 errors -std=c++23 -D__NO_LONG_DOUBLE_MATH 0, rc=0 0, rc=0 -std=c++23 -D__HAVE_FLOAT128=0 74 errors 74 errors -std=c++23 -D_Float128=__float128 57 errors 57 errors -D__HAVE_FLOAT128=0 looks like the obvious fix and is not: floatn.h defines it unconditionally, so the header wins over the command line. -D_Float128= __float128 clears 17 of the 74, which is worse than useless -- it looks like progress. - Corrects the Patch2 comment twice. Its -std= ladder ("c++17 and c++20 both fail, c++23 parses libstdc++") was measured on x86_64; on aarch64 all three fail identically and the standard makes no difference, because the failure is in glibc rather than libstdc++. And this is not an f45 regression -- f44 with the older castxml fails the same way. ITK_WRAP_PYTHON has never once built on aarch64; that stayed invisible while the bcond was off and every wrapping build went to x86_64. - The flag reaches the castxml parse only, never the compiled C++, and ITK wraps no long double API. %%ifarch aarch64; both branches rendered with rpmspec -P --with python_wrapping and checked to emit exactly one flags line, x86_64 byte-identical to before. NOT yet proven against a full ITK build -- the container measurement covers and , not 3643 targets. * Sun Sep 27 2026 Morgan Hough - 5.4.7-18 - python_wrapping ON by default, on Morgan's decision. Every ITK build now takes ~128 minutes instead of ~6 and pulls castxml, swig and chrpath into the buildroot. - The reason it is worth that: python3-itk requires InsightToolkit5 at an EXACT NVR, so with the bcond off the first ITK rebuild at a higher release by anyone makes python3-itk unsatisfiable and it vanishes from the repo. No warning, no failed build -- just a package that is no longer there, noticed weeks later by a consumer's depsolve. This is the class of silent regression we have spent the week removing. - Expect ITK builds on f45 and rawhide to FAIL until the swig 4.5 work in Patch4 is proven there. That failure is loud and harmless: a failed build does not remove the published 5.4.7-9, so those chroots keep a working ITK meanwhile. * Sun Sep 27 2026 Morgan Hough - 5.4.7-17 - Patch4 extended from 25 substitutions to 31. -16 fixed the %%typemap bodies in pyBase.i and the error MOVED rather than went away (11043331): six more PyInt_* uses live in C++ headers under Modules/Bridge/NumPy -- itkPyVnl.hxx, itkPyBuffer.hxx and itkPyVectorContainer.hxx -- which are not under Wrapping/ at all. I had grepped only Wrapping/ because that was the only part of the tarball I had extracted, so a whole-tree search was the fix as much as the patch was. Verified by asserting zero residual PyInt_ across every .i/.hxx/.h/.cxx after applying. * Sun Sep 27 2026 Morgan Hough - 5.4.7-16 - Patch4 rewritten. -15 put the removed swig macros back in a %%insert("begin") block in pyBase.i and failed byte-identically (11043124, all four f45/rawhide chroots): SWIG emits that block only into the wrapper generated FROM pyBase.i, while the 25 PyInt_* uses are in %%typemap bodies that inline into every module's own wrapper, so the definitions and the uses landed in different translation units. Substituting PyLong_* into the typemap bodies reaches every wrapper, and is exact -- pyhead.swg defined PyInt_Check as PyLong_Check, PyInt_AsLong as PyLong_AsLong and PyInt_FromLong as PyLong_FromLong -- so it changes spelling, not behaviour, and works on every swig version rather than only 4.5+. * Sun Sep 27 2026 Morgan Hough - 5.4.7-15 - Patch4 restores the Python 2 compatibility macros swig 4.5.0 removed. python3-itk built and imported on f44-x86_64 (swig 4.4.1) but 11042620 failed on all four f45/rawhide chroots, because pyBase.i uses PyInt_Check, PyInt_AsLong and PyInt_FromLong in 25 places and swig >= 4.5 no longer defines them. Isolated to swig rather than Python by comparing chroots: f44 swig 4.4.1 + Python 3.14 builds, f45 swig 4.5.0 and rawhide swig 4.5.1 both with Python 3.15 both fail. - Does NOT address the fifth failure. f44-aarch64 died earlier, in castxml, with "unknown type name '_Float128'" from /usr/include/wchar.h -- castxml's embedded Clang does not know aarch64 glibc's _Float128. Separate problem, still open, and deliberately not conflated with this one. * Sun Sep 27 2026 Morgan Hough - 5.4.7-14 - Conflicts: InsightToolkit >= 5 on the base, devel, vtk and vtk-devel subpackages. Fedora 45 rebased its own InsightToolkit from 4.13.3 to 5.4.6, which installs the same versioned sonames we do, so both packages own the same 83 files in %%{_libdir}. Our consumers' dependencies are generated from sonames rather than package names, so dnf sees two providers and tries to install both: file /usr/lib64/libITKCommon-5.4.so.1 conflicts between attempted installs of InsightToolkit5-5.4.7-9.fc45 and InsightToolkit-5.4.6-3.fc45 That is why the f45 Slicer stack builds green and cannot be installed. - Bounded at >= 5 so it is inert on f44, where Fedora still ships 4.13.3 with libITKCommon-4.13.so.1. Side-by-side ITK4 + ITK5 is a design goal of this package and an unbounded Conflicts would break it for nothing. - Measured before adding, since a Conflicts on a base library is expensive to get wrong. 9 of the 91 ITK sonames 3dslicer needs are ours alone -- ITKDeprecated, GrowCut, MGHIO, IOScanco, IODCMTK, VtkGlue, AdaptiveDenoising, SimpleITKFilters, IOPhilipsREC -- so dnf is forced to pick our ITK and this only stops it also pulling Fedora's. The only Fedora-native ITK consumers on f45 are alizams (3 ITK sonames) and petpvc (27), and we provide every one, so both stay installable. - Validated before building: with Fedora's ITK excluded, 3dslicer and slicer-preview each install rc=0 on f45-x86_64, which is exactly what this Conflicts achieves. * Sun Sep 27 2026 Morgan Hough - 5.4.7-13 - Patch3 backports upstream ITK 9e8f0c77b5 (PR #6484, master only -- no 5.4.x release carries it), which is the actual fix for the swig 4.4 import failure. ITK packs several swig modules per shared object and injects C that treats PyInit_*'s return value as a module; swig 4.4 returns a PyModuleDef instead. The patch detects that at runtime and instantiates it with PyModule_FromDefAndSpec + PyModule_ExecDef, leaving the swig <= 4.3 path alone. - Corrects -12. ITK_USE_PYTHON_LIMITED_API=OFF was NOT the fix, though upstream #6479 and PR #6544 both recommend it: 11040244 built *.cpython-314*.so with no Py_LIMITED_API anywhere in the build and failed at import identically to 11039812, which had the limited API on. The %%check added in -12 is what caught that, at %%check rather than in a user's traceback. The flag stays OFF as the simpler configuration, not as a remedy. - swig offers no opt-out: python/pyinit.swg ends SWIG_init with an unconditional "return PyModuleDef_Init(&SWIG_module);" for Python 3. Patching ITK was the only route short of a swig 4.3 compat package. * Sat Sep 26 2026 Morgan Hough - 5.4.7-12 - python_wrapping: ITK_USE_PYTHON_LIMITED_API=OFF. -11 built clean on COPR (11039812, 130 min, all 3643 targets) and produced a python3-itk that cannot be imported: "import itk" dies with AttributeError: 'moduledef' object has no attribute 'delete_SwigPyIterator' swig 4.4.0 added Python multi-phase module initialisation, and the limited-API wrappers it generates are incompatible with ITK packing several swig modules into one shared object -- ours exports both PyInit__ITKPyBasePython and PyInit__pyBasePython while only the first has a matching file, so "from . import _pyBasePython" binds a raw PyModuleDef. ITK 5.4.7 validates against a swig master snapshot from 2024-03-26 and checks only a FLOOR (VERSION_LESS 4.2.0, and only a warning), so Fedora's swig 4.4.1 passes silently. Upstream issue #6479; PR #6544 proposed a configure guard and was closed unmerged. Of upstream's three remedies only this one is available to us: system swig is mandatory and swig 4.3.x would mean a compat package. - Added a %%check, wrapping builds only, that imports itk and exercises the templated API and the NumPy bridge. This is the gate 11039812 lacked: rpm verifies files, not imports, so it called a non-importable package a success. A Python package that does not import has no value, so the assertion belongs where it costs a build instead of a release. * Sat Sep 26 2026 Morgan Hough - 5.4.7-11 - python_wrapping is now buildable from git alone. -10 fixed 1 of the 79 files check-rpaths rejected and carried none of the toolchain work, so a build from main died in 3 minutes. Six changes, all measured by fsk-dual on COPR: * Patch2 adds ITK_WRAP_CASTXML_EXTRA_FLAGS. castxml embeds its own Clang, and Fedora 44's castxml 0.7.0 cannot parse gcc 16's libstdc++ (explicit object parameters need C++23) or eigen 5.0.1 (its GCC-only SSE path calls a builtin Clang lacks). Parse-time only; the compiled library keeps its own standard. * ITK_USE_SYSTEM_CASTXML + ITK_USE_SYSTEM_SWIG, with explicit executables. Both default OFF, so ITK_WRAP_PYTHON downloads a prebuilt castxml and builds its own swig -- 3 minutes to failure on a COPR builder (11039472), and worse on a workstation, where the download SUCCEEDS and silently wraps against an unshippable prebuilt binary toolchain. * The wrapping copies 78 ITK shared libraries into sitearch with build-tree RUNPATHs. All 78 duplicate libraries the main package already owns, and python3-itk requires it by exact NVR, so they are deleted and the remaining extension modules get chrpath -d. * %%pycached %%{python3_sitearch}/itkConfig.py. itk* does not match the root-level module's bytecode, which lands in %%{python3_sitearch}/__pycache__. - Whether "import itk" works is still open; the build proves files, not imports. * Sat Sep 26 2026 Morgan Hough - 5.4.7-10 - python_wrapping: drop the duplicate itkTestDriver that ITK_WRAP_PYTHON installs into %%{python3_sitearch}/itk/. It is linked against the build tree, so check-rpaths rejects it (ERROR 0002 invalid runpath, ERROR 0010 empty runpath) and the build dies in %%install with the compile already finished. The real binary ships as %%{_bindir}/itkTestDriver from the core build. - Measured cost of ITK_WRAP_PYTHON on a COPR f44-x86_64 builder: 121 minutes to reach %%install (build 11039490), against ~6 minutes for ITK core alone (11034910). That is well inside the default timeout -- the header comment's worry that full templated wrapping would exceed SimpleITK's 6.8 hours was wrong, and the guess is now replaced by a number. - %%install prints the site-packages manifest, so a failure in check-rpaths or check-files still reports what was installed instead of costing another two hours to find out. - No change to the default build: still the same six subpackages. * Wed Sep 23 2026 Morgan Hough - 5.4.7-9 - InsightToolkit5-devel now ships %%{_rpmmacrodir}/macros.itk defining %%itk_ver, so a consumer can pin the ITK it was actually built against. - The problem it solves: ITK freezes sonames across releases while adding symbols. libITKFFT-5.4.so.1 is identical in name in 5.4.7-2 and -8, but -8 enabled FFTW and exports a registration symbol -2 does not. rpm derives dependencies from sonames, so a consumer built against -8 installs cleanly over -2 and dies at 127 on every invocation. Measured: c3d, itksnap, itksnap-alpha, simpleitk and quit all reference that symbol; 3dslicer and slicer-preview do not. - A floor rather than a vtk(abi)-style equality: the breakage is additive, so a newer ITK is always fine. Equality would force every consumer to rebuild on every ITK release for nothing. * Thu Sep 17 2026 Morgan Hough - 5.4.7-8 - Enable FFTW (ITK_USE_FFTWD and ITK_USE_FFTWF ON), matching Fedora's InsightToolkit. Earlier releases set only ITK_USE_SYSTEM_FFTW, which does nothing on its own: the installed ITKConfig.cmake of -7 has ITK_USE_FFTWD and ITK_USE_FFTWF OFF, while -devel still required fftw-devel. - Licensing consequence: FFTW is GPL-2.0-or-later, so the ITK libraries and anything linked against them are covered by the GPL (ITK's configure says so). This choice was made deliberately; see docs/licensing/itk-fftw-gpl.md. * Wed Sep 16 2026 Morgan Hough - 5.4.7-7 - Patch1: export the include dirs that system Eigen, VXL and double-conversion need. Bundled copies lived under /usr/include/ITK-5.4, so consumers never had to ask; unbundled, three consumer styles broke against -6: charm-gems (Eigen/Eigenvalues via ${ITK_INCLUDE_DIRS}), mitk (vnl/vnl_vector_ref.h via the ITKCommon target), elastix ("double-conversion.h"). Verified with a configure-only build: the installed module files and ITKTargets.cmake now carry the directories. - devel: Require double-conversion-devel, whose headers Patch1 now exports. -6 said no -devel was needed because no public ITK header includes it; true, but consumers do. * Wed Sep 16 2026 Morgan Hough - 5.4.7-6 - devel: Require eigen3-devel and vxl-devel. -5 unbundled both but left them out of the devel dependencies, so every consumer failed: find_package(Eigen3) from ITKEigen3.cmake, or a missing vnl/vnl_vector_ref.h and vxl_version.h. Found by test-rebuilding all 26 consumers against -5 (mhough/neurofedora-itk5-test): 18 of 18 finished builds failed this way. Fedora's InsightToolkit spec has the same gap. * Wed Sep 16 2026 Morgan Hough - 5.4.7-5 - Unbundle VXL, using Ankur Sinha's 0001-remove-vxl-netlib.patch from Fedora's InsightToolkit. -3 failed at link on "cannot find -lnetlib": with ITK_USE_SYSTEM_VXL=ON, ITK's own link lines add a "netlib" that system VXL does not ship (Fedora's vxl provides libv3p_netlib.so only). The patch removes it in two places and applies to 5.4.7 unchanged. - Correct the License field, which covered only ITK core (Apache-2.0) while the package ships bundled BSD-3-Clause, BSD-2-Clause, MIT, Zlib and public-domain code. Accounting follows Ankur's 84675f7, but is derived from what this build actually installs rather than copied, since our unbundling now differs. - Install each bundled library's licence text with %%license. Adds NIFTI's LICENSE, which Fedora's spec does not ship. * Tue Sep 15 2026 Morgan Hough - 5.4.7-4 - Revert ITK_USE_SYSTEM_VXL=ON: Fedora's vxl ships its netlib as libv3p_netlib.so while ITK links -lnetlib, so -3 died at link with "cannot find -lnetlib" (COPR 10990784). Eigen3 and DoubleConversion stay unbundled; they were the well-evidenced half of the convergence. * Tue Sep 15 2026 Morgan Hough - 5.4.7-3 - Unbundle Eigen3, DoubleConversion and VXL, converging with Fedora's InsightToolkit (Ankur Sinha), which has shipped all three from the system for some time. eigen3-devel 5.0.1, double-conversion-devel 3.4.0 and vxl-devel 3.5.0 all satisfy what ITK asks for. - The note justifying the Eigen bundling was wrong: it claimed eigen3 5.0.1 broke "ITK's find_package(Eigen3 3.3)", but ITK does a versionless find_package followed by an if(VERSION_LESS 3.3) check, which 5.0.1 passes. The SameMajorVersion failure is real for an explicitly versioned call, which ITK never makes. Fedora has built with ITK_USE_SYSTEM_EIGEN=ON since 2026-08-10, seven months after eigen3 5.0.1 landed. - Drop -DITK_USE_SYSTEM_OPENJPEG=ON. ITK defines no such option and bundles OpenJPEG 1.x, so CMake was silently ignoring the flag; declare Provides: bundled(openjpeg) instead, which was missing. - Document the remaining bundles and why each has no system option, following the same accounting Fedora's spec keeps. * Thu Sep 03 2026 Morgan Hough - 5.4.7-1 - Update to 5.4.7. Drops both Slicer backports and both %%prep seds: * ITK-slicer-5d-nrrd-io.patch: AxesReorder appears 13 times in 5.4.7's itkNrrdImageIO.{h,cxx} and 0 times in 5.4.6 -- the API is upstream. * ITK-slicer-short-axis-crashfix.patch: the bounds guard and identity fallback are in itkImageFileReader.hxx at lines 184 and 190. * the cstdint sed: itkFloatingPointExceptions.h now includes itself, so the sed only added a duplicate. * the bundled-Eigen typename sed: no occurrences left in Quaternion.h. * Mon Aug 24 2026 Morgan Hough - 5.4.6-9 - Rebuild against VTK 9.7.0. VTK here installs unversioned sonames (libvtk*.so.1), so 9.7 replaces 9.6 in place and every consumer must be rebuilt or it fails at runtime with undefined symbols. Release bumped past the aarch64 dcmtk rebuild that landed on main with the same number: that NVR is already published, and a same-NVR rebuild does not supersede (ci/PROCEDURES.md rule 3). * Sat Aug 22 2026 Morgan Hough - 5.4.6-8 - Rebuild for aarch64 against dcmtk 3.7.0-3 (SONAME 19 -> 20). The aarch64 5.4.6-7 build was compiled against Fedora's dcmtk 3.6.9 (.so.19) before the COPR dcmtk reached that arch, so it still requires libdcm*.so.19 -- which nothing in the repo provides now, making ITK uninstallable on aarch64 and taking the whole stack with it (ctk-dicom, plastimatch, 3dslicer, medInria, OpenImageIO). x86_64 at -7 was already built against .so.20 and is correct; this Release bump exists only so the replacement aarch64 RPM reliably supersedes the broken -7, since both arches shared that NVR. x86_64 deliberately not rebuilt. * Sun May 31 2026 Morgan Hough - 5.4.6-7 - Add cli11-devel BuildRequires: VTK 9.6.2 added CLI11 as a module dependency, so VTK's cmake config now find_package(CLI11)s at configure time and any find_package(VTK) consumer (Modules/Bridge/VtkGlue) needs it in the buildroot. * Sun May 31 2026 Morgan Hough - 5.4.6-6 - Backport two accepted-upstream ITK commits that 3D Slicer's curated Slicer/ITK fork carries (the full fork is pristine v5.4.6 + only 5 such patches). Patch0: 5D NRRD I/O / NrrdImageIO AxesReorder (cherry-pick of InsightSoftwareConsortium/ITK@10389fb0), required by Slicer's vtkITKImageSequenceReader which fails to compile without the itk::NrrdImageIOEnums::AxesReorder enum and Set/GetAxesReorder API. Patch1: ImageFileReader crash fix for short axis direction vectors. Both are additive and scoped to NRRD/ImageBase; no ABI change for existing consumers (NrrdImageIO is only used via New()/SmartPointer). * Thu May 28 2026 Morgan Hough - 5.4.6-5 - Enable Module_ITKIODCMTK. Built-in but EXCLUDE_FROM_DEFAULT in ITK 5.4. Surfaced by 3dslicer-9 retry after MGHIO/IOScanco were resolved. * Thu May 28 2026 Morgan Hough - 5.4.6-4 - Fix MGHIO + IOScanco for 3D Slicer. MGHIO and IOScanco are ITK *remote* modules (not built-in), so Module_MGHIO/Module_IOScanco only have effect if the module sources are present under Modules/Remote/ — they would normally be Git-fetched at cmake time but our ITK_FORBID_DOWNLOADS=ON policy blocks that. Add Source7 (itkMGHImageIO@0adac35f) and Source8 (ITKIOScanco@10b80f69), pre-staged in %prep. Also drop the misspelled -DModule_ITKIOMGH (the correct name is Module_MGHIO; -3's flag was silently ignored, per cmake's "unused variables" warning). * Thu May 28 2026 Morgan Hough - 5.4.6-3 - Enable Module_ITKIOMGH, Module_ITKIOTransformMatlab, Module_IOScanco. 3D Slicer's Libs/ITKFactoryRegistration calls find_package(ITK COMPONENTS MGHIO ITKIOTransformMatlab IOScanco ...) and aborts if any are missing. * Sun May 24 2026 Morgan Hough - 5.4.6-2 - Strip the invalid `typename std::is_nothrow_move_*::value` keyword from bundled itkeigen/Eigen/src/Geometry/Quaternion.h (GCC 16 now enforces what was always-invalid C++: typename only applies to types). Fixes downstream FTBFS in every ITK consumer that touches Eigen Quaternion code (quit, medInria, plastimatch, simpleitk, ...). Companion fix in InsightToolkit6.spec. * Mon May 18 2026 Morgan Hough - 5.4.6-1 - Update to ITK 5.4.6 (upstream release 2026-05-01) - Backport of GDCM CVE-2026-3650 fix and a GDCM upstream sync - Stability fixes: VoronoiDiagram2DGenerator infinite loop, IPLCommonImageIO null-check hardening, integer-only Bresenham line construction - Remote module commits unchanged from 5.4.5 (verified against 5.4.6 tags) * Tue Mar 17 2026 Morgan Hough - 5.4.5-15 - Add doc and examples subpackages (matches Fedora ITK4 package structure) * Sun Mar 15 2026 Morgan Hough - 5.4.5-14 - Add SimpleITKFilters and LabelErodeDilate remote modules (Source5, Source6): required by SimpleITK 2.5.x * Fri Mar 06 2026 Morgan Hough - 5.4.5-13 - Add GrowCut remote module (Source4): provides itkFastGrowCut.h required by MITK's Segmentation module * Thu Mar 05 2026 Morgan Hough - 5.4.5-12 - Fedora-submission polish: unbundle DCMTK (ITK_USE_SYSTEM_DCMTK=ON), split vtk/vtk-devel subpackages for ITKVtkGlue bridge, add Provides: bundled() for double-conversion/eigen3/nifti/metaio/kwsys, add ExcludeArch: ix86, add ldconfig scriptlets, suppress debug_package - Enable VtkGlue, PhilipsREC, Review, Deprecated modules - Add VTK transitive cmake deps as BuildRequires (python3-devel, json-devel, Qt6, etc.) needed by VTK-vtk-module-find-packages.cmake * Thu Mar 05 2026 Morgan Hough - 5.4.5-11 - Enable Module_ITKReview=ON: provides itkLabelGeometryImageFilter.h required by MITK's Multilabel module (ITKDeprecated alone was insufficient) * Thu Mar 05 2026 Morgan Hough - 5.4.5-10 - Enable Module_ITKDeprecated=ON: dependency of ITKReview * Fri Feb 27 2026 Morgan Hough - 5.4.5-9 - Add MorphologicalContourInterpolation remote module (Source3): required by ITK-SNAP 4.x which requests it as a FIND_PACKAGE(ITK COMPONENTS ...) component * Wed Feb 25 2026 Morgan Hough - 5.4.5-8 - Guard bundled MINC cmake cleanup with directory existence check * Wed Feb 25 2026 Morgan Hough - 5.4.5-7 - Remove cmake configs for ITK's bundled MINC library in the install step * Tue Feb 24 2026 Morgan Hough - 5.4.5-6 - Add AdaptiveDenoising remote module (Source2) * Tue Feb 24 2026 Morgan Hough - 5.4.5-5 - Bundle GenericLabelInterpolator remote module (Source1) * Tue Feb 24 2026 Morgan Hough - 5.4.5-4 - Disable Module_ITKGoogleTest (OFF) * Tue Feb 24 2026 Morgan Hough - 5.4.5-3 - Add transitive system-lib Requires to -devel * Tue Feb 24 2026 Morgan Hough - 5.4.5-2 - Remove zero-length stub.h placeholders * Mon Feb 23 2026 Morgan Hough - 5.4.5-1 - Initial package of ITK 5.4.5 * Tue Feb 03 2026 Maintainer - 5.4.2-1 - Initial package for ITK 5.4.2