%global _lto_cflags %{nil} # ANTs instantiates ITK templates across 2D/3D/4D; each g++ process peaks at ~3 GB. # Limit parallelism so the build stays within COPR worker memory (typically 16 GB). %global _smp_mflags -j4 # Use 'define' not 'global' for debug_package: EPEL 9 auto-injects the debuginfo # package stanza during spec parsing and 'global' scope causes a conflict. %define debug_package %{nil} Name: ANTs Version: 2.6.5 Release: 19%{?dist} Summary: Advanced Normalization Tools for medical imaging License: Apache-2.0 URL: https://github.com/ANTsX/ANTs Source0: https://github.com/ANTsX/ANTs/archive/v%{version}/%{name}-%{version}.tar.gz Conflicts: ants BuildRequires: gcc-c++ BuildRequires: cmake >= 3.16 BuildRequires: make BuildRequires: zlib-devel BuildRequires: InsightToolkit5-devel >= 5.4.6 # These are transitive deps re-found by ITK's module cmake files (ITKHDF5.cmake, ITKMINC.cmake, etc.) # when a downstream project does include(${ITK_USE_FILE}). BuildRequires: hdf5-devel %if 0%{?fedora} BuildRequires: libminc-devel %endif # itk(abi): ITK_LEGACY_REMOVE changes class layouts at unchanged sonames, so the itk_ver floor alone let a # consumer built against the removed state install over the present one (python3-simpleitk -11 on ITK -23 # returned all-zero images). Equality on the legacy-state token; see InsightToolkit5.spec. Requires: itk(abi) = %{?itk_abi}%{!?itk_abi:UNSET} %description Advanced Normalization Tools (ANTs) extracts information from complex datasets that include imaging. ANTs computes high-dimensional mappings to capture the statistics of brain structure and function. # ----------------------------------------------------------------------- # ANTs-rstats: the R scripts (noarch, opt-in) # ----------------------------------------------------------------------- # Six R scripts ride along upstream: three in /usr/bin (antsNetworkAnalysis.R, # antsBOLDNetworkAnalysis.R, antsLaplacianBoundaryCondition.R) and three in the # extended script collection (antsASLProcessing.R, cbf_*_robust_batch.R). Their # #!Rscript lines made the whole of R a hard requirement of every ANTs install # -- for scripts most users never run, and which need the ANTsR R package, # which is not in Fedora. Split them out so `dnf install ANTs` no longer # pulls R-core, and say plainly what they still need. %package rstats Summary: R scripts shipped with ANTs (network analysis, ASL/CBF batches) BuildArch: noarch Requires: %{name} = %{version}-%{release} Requires: R-core Recommends: R-igraph %description rstats The R scripts distributed with ANTs: antsNetworkAnalysis.R, antsBOLDNetworkAnalysis.R and antsLaplacianBoundaryCondition.R in the path, plus the ASL/CBF batch scripts under %{_datadir}/ANTs/scripts. They require the ANTsR R package, which is not packaged in Fedora, and several CRAN packages (igraph, getopt, psych, gridExtra, glasso, ggplot2); this subpackage provides the scripts and the R interpreter, not those libraries. %prep %autosetup -n %{name}-%{version} # antsUtilities lacks SOVERSION in upstream cmake; add it so the installed # libantsUtilities.so.1 has a valid versioned SONAME (Fedora packaging requirement). sed -i '/^target_link_libraries(antsUtilities/a set_target_properties(antsUtilities PROPERTIES SOVERSION 1)' \ Examples/CMakeLists.txt %build # Pin the ITK layout state this build sees (see the Requires above). test -n "%{?itk_abi}" || { echo "ERROR: itk_abi undefined - needs InsightToolkit5-devel >= 5.4.7-24 (macros.itk)" >&2; exit 1; } # C++17 required by ITK 5.x; permissive mode for older ANTs code on GCC 14+ export CXXFLAGS="%{optflags} -std=c++17 -fpermissive -Wno-error=incompatible-pointer-types" export CFLAGS="%{optflags} -std=gnu17 -Wno-error=implicit-function-declaration -Wno-error=int-conversion -Wno-error=incompatible-pointer-types" # Build ANTs directly against system InsightToolkit5 — no superbuild network downloads. # ANTs_SUPERBUILD=OFF: skip the ExternalProject wrapper and configure ANTs directly. # ITK_DIR points to the versioned cmake config installed by InsightToolkit5-devel. # Not enabled, deliberately: # USE_VTK adds 5 surface/mesh tools (antsSurf, antsVol, CheckTopology, # GetMeshAndTopology, WarpVTKPolyDataMultiTransform) that # need vtk-devel; our VTK is 9.7 and 2.6.5 predates it, so # that is a build to attempt with the VTK owner, not a flag # to flip blind. # INSTALL_DEVELOPMENT headers + link-time .so for ~200 private libl_* libs; # ANTs is packaged as an application, not a dev library -- # same call ANTs3.spec makes. # NB: no comments between the continued lines below -- a '#' inside the # backslash continuation comments out the rest of the command. %cmake \ -DANTS_SUPERBUILD=OFF \ -DITK_DIR:PATH=%{_prefix}/lib/cmake/ITK-5.4 \ -DUSE_SYSTEM_ITK:BOOL=ON \ -DBUILD_TESTING:BOOL=OFF \ -DCMAKE_CXX_STANDARD:STRING=17 \ -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=ON \ -DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} \ -DCMAKE_SKIP_INSTALL_RPATH:BOOL=ON %cmake_build %install %cmake_install # Remove static archives: ANTs' internal l_* libraries are not a public API find %{buildroot}%{_libdir} -name '*.a' -delete # Remove unversioned .so symlinks (devel-file-in-non-devel-package rpmlint warning). # These are internal implementation libraries, not a public development API. find %{buildroot}%{_libdir} -maxdepth 1 -name '*.so' -type l -delete # Install ALL upstream Scripts/ -- ANTS.cmake only ships ~21 curated wrappers # to /usr/bin (see install(PROGRAMS Scripts/...) block). The remaining # ~43 utility/example scripts (buildtemplateparallel.sh, multi_template_*.sh, # the cbf_*.R batch scripts, the waitForXgridJobs.pl helpers, etc.) ship to # %%{_datadir}/ANTs/scripts/ so users can find and use them. # NB: %%cmake_install above already populated /usr/bin/ with the curated set. mkdir -p %{buildroot}%{_datadir}/ANTs/scripts cp -p Scripts/* %{buildroot}%{_datadir}/ANTs/scripts/ for f in %{buildroot}%{_bindir}/*; do rm -f "%{buildroot}%{_datadir}/ANTs/scripts/$(basename "$f")" done # Permissions: .sh/.pl/utility scripts executable; .R aren't chmod 0755 %{buildroot}%{_datadir}/ANTs/scripts/*.sh \ %{buildroot}%{_datadir}/ANTs/scripts/*.pl 2>/dev/null || : chmod 0644 %{buildroot}%{_datadir}/ANTs/scripts/*.R 2>/dev/null || : %check # Upstream's own suite (BUILD_TESTING=ON) is deliberately NOT enabled: ANTs # pulls its test images through CMake ExternalData, i.e. it downloads at build # time, which Fedora builds must not do. Instead we exercise the freshly-built # binaries on data they synthesize themselves — no network, no extra # BuildRequires, a few seconds. This still catches the failures that matter for # a distro rebuild: a bad link, an ABI-mismatched ITK, broken image I/O, or a # miscompiled filter. Behavioural/numerical regression on *real* brains is # covered separately by the BATS pipeline suite in the packaging repo # (tests/pipelines.tsv: N4 correction, Atropos 3-class segmentation, and a # quantitative registration-accuracy check on the MNI152 template). _bin="%{_vpath_builddir}/bin" [ -d "$_bin" ] || _bin="$(dirname "$(find %{_vpath_builddir} -type f -name ImageMath -perm -u+x | head -1)")" export LD_LIBRARY_PATH="%{_vpath_builddir}/lib:${LD_LIBRARY_PATH:-}" _t="$(mktemp -d)" # 1. ITK image I/O + a real filter chain, on an image ANTs makes itself. "$_bin/ImageMath" 3 "$_t/base.nii.gz" MakeImage 16 16 16 "$_bin/ImageMath" 3 "$_t/padded.nii.gz" PadImage "$_t/base.nii.gz" 8 1 "$_bin/ImageMath" 3 "$_t/norm.nii.gz" Normalize "$_t/padded.nii.gz" "$_bin/ThresholdImage" 3 "$_t/padded.nii.gz" "$_t/thr.nii.gz" 0.5 2 # 2. Read the result back and assert the geometry survived the round-trip # (16^3 padded by 8 on each side == 32^3). A broken ITK/IO layer fails here. "$_bin/PrintHeader" "$_t/padded.nii.gz" | grep -q '\[32, 32, 32\]' # 3. The headline binaries must at least load and respond. This step USED to be # `--version >/dev/null 2>&1 || --help >/dev/null 2>&1`, which discards the # one thing worth reading: the loader's complaint. A binary killed by # symbol lookup error: undefined symbol: _ZN3itk35ObjectToObject... # exits non-zero on BOTH arms, so the `||` chain merely moved on. Assert on # the message instead, and require non-empty output so a silently dead # binary cannot pass either. for _p in antsRegistration antsApplyTransforms N4BiasFieldCorrection Atropos; do _out=$("$_bin/$_p" --version 2>&1) || _out=$("$_bin/$_p" --help 2>&1) || : case "$_out" in *"symbol lookup error"*|*"undefined symbol"*|*"error while loading shared libraries"*) echo "ERROR: $_p cannot start:" >&2; echo "$_out" | head -3 >&2; exit 1;; esac test -n "$_out" || { echo "ERROR: $_p produced no output at all" >&2; exit 1; } done # 4. NEW in -16, and the reason -16 exists. Every shipped ANTs library must have # a complete symbol closure against the ITK actually in the buildroot. # # ITK 5.4.7-10 turned ITK_LEGACY_REMOVE ON as a side effect of enabling # ITK_WRAP_PYTHON, which deleted itk::ObjectToObjectOptimizerBaseTemplate< # double>::{Set,Get}NumberOfThreads. Those are VIRTUAL methods, so ANTs did # not have to call them to depend on them -- they occupied vtable slots in # every ANTs class derived from that hierarchy. Measured on the -15 binaries: # 8 relocations for the two symbols in libantsUtilities.so.1, all # R_X86_64_64 inside .data.rel.ro, and ZERO call-site relocations. So every # ANTs binary that touches libantsUtilities died at startup -- which is all of # antsRegistration, antsApplyTransforms and N4BiasFieldCorrection -- while # ANTs itself needed no source change, only a rebuild. # # Step 3 above only covers 4 named binaries, and only their startup path. # This covers every library we ship. # # RELEASE 16 GOT THE SEARCH PATH WRONG AND REJECTED A GOOD BUILD. It swept # %%{buildroot}%%{_libdir} while LD_LIBRARY_PATH still pointed only at the # build tree, so the buildroot libraries could not see their own siblings and # `ldd -r` reported ANTs' OWN symbols as undefined -- ANTSFileIsImage, # itk::ants::CommandLineParser, ants::ImageMathHelper3D. Twenty such symbols, # zero of them real, and the build failed on all 7 chroots after 125 minutes. # Meanwhile the thing it was written for was genuinely fixed: the -16 log # contains ZERO references to ObjectToObjectOptimizerBaseTemplate, so the # rebuild did clear the ITK breakage exactly as predicted. # # The fix is to resolve against the set we actually ship. Prepend the # buildroot's own libdir so a library's siblings resolve from the buildroot, # leaving only genuinely external symbols -- which is the ITK question this # check exists to ask. Verified on the host, where siblings are resolvable by # construction: libl_iMath.so.2 then reports exactly the 4 ITK optimizer # symbols and none of its own. _undef=0 export LD_LIBRARY_PATH="%{buildroot}%{_libdir}:${LD_LIBRARY_PATH:-}" for _l in %{buildroot}%{_libdir}/lib*.so.*; do [ -f "$_l" ] || continue _u=$(ldd -r "$_l" 2>&1 | grep '^undefined symbol:' || :) if [ -n "$_u" ]; then echo "ERROR: $(basename "$_l") has unresolved symbols against this buildroot:" >&2 echo "$_u" | head -5 >&2 echo "$_u" | sed 's/^undefined symbol: //' | c++filt 2>/dev/null | head -5 >&2 _undef=1 fi done test "$_undef" -eq 0 || { echo "ERROR: refusing to ship libraries that cannot resolve their symbols." >&2 echo " A green compile does not mean the result runs; see" >&2 echo " docs/reports/itk-legacy-remove-regression.md." >&2 exit 1; } echo "symbol closure: all shipped ANTs libraries resolve against this buildroot" rm -rf "$_t" %ldconfig_scriptlets %files %license COPYING.txt %doc README.md CONTRIBUTING.md %{_bindir}/* %exclude %{_bindir}/*.R %{_libdir}/libantsUtilities.so.* %{_libdir}/libl_*.so.* %dir %{_datadir}/ANTs %{_datadir}/ANTs/scripts/ %exclude %{_datadir}/ANTs/scripts/*.R %files rstats %{_bindir}/*.R %{_datadir}/ANTs/scripts/*.R %changelog * Tue Oct 06 2026 Morgan Hough - 2.6.5-19 - Pin the ITK layout state: Requires: itk(abi) = %%{itk_abi}, from InsightToolkit5-devel's macros.itk, plus a %%build guard. ITK -23 flipped ITK_LEGACY_REMOVE back off, which changes class layouts at unchanged sonames; this package was built against -10..-21 (legacy removed) and the itk_ver floor let it install over -23, giving silent wrong results or crashes. Rebuild against ITK >= 5.4.7-24. * Tue Oct 06 2026 Morgan Hough - 2.6.5-18 - Rebuild for f43 only: that chroot's 2.6.5-17 binary still links libitkvnl-5.4.so.1 and libitkvnl_algo-5.4.so.1, which InsightToolkit5 5.4.7-8 and later do not provide. ci/check-itkvnl-sweep.sh reports f43 broken=5 (ANTs, plastimatch, python3-samseg, simpleitk, TTK) and fedora-44-x86_64 broken=0 at the SAME NVR -- the ITK unbundling wave simply never reached f43. It blocked 3dslicer there: "nothing provides libitkvnl-5.4.so.1" (11082734). - Release bump rather than a same-NVR rebuild because ci/copr-submit.sh correctly refused one: COPR would add a sibling 2.6.5-17 with different linkage and dnf would have no basis to prefer either copy. - Other chroots are clean at -17 and are deliberately NOT rebuilt here; ANTs is a ~2.5h build and there is nothing for them to fix. * Mon Sep 28 2026 Morgan Hough - 2.6.5-17 - Fix the %%check guard added in -16, which was wrong and rejected a correct build on all 7 chroots after 125 minutes each. It swept %%{buildroot}%%{_libdir} with LD_LIBRARY_PATH still pointing only at the build tree, so those libraries could not see their own siblings and `ldd -r` reported ANTs' own symbols as undefined: ANTSFileIsImage, ANTSFileExists, itk::ants::CommandLineParser, ants::ImageMathHelper{2,3,4}D and 14 more. All twenty are defined in libantsUtilities, which was simply not on the path. - The rebuild itself was right. The -16 build log contains ZERO references to itk::ObjectToObjectOptimizerBaseTemplate, so recompiling against the current ITK cleared the vtable references exactly as -16's changelog predicted, and %%check step 3 (the binaries start and print a version) passed. Only the new guard failed, and only on symbols it should never have looked for. - Prepend %%{buildroot}%%{_libdir} to LD_LIBRARY_PATH so each library resolves against the set we actually ship, leaving only genuinely external symbols -- which is the ITK question the check exists to ask. Verified against the installed tree, where siblings resolve by construction: libl_iMath.so.2 then reports exactly the 4 ITK optimizer symbols and none of its own. * Mon Sep 28 2026 Morgan Hough - 2.6.5-16 - Rebuild against the current ITK. ANTs 2.6.5-15 does not run AT ALL: antsRegistration: symbol lookup error: /lib64/libantsUtilities.so.1: undefined symbol: _ZN3itk35ObjectToObjectOptimizerBaseTemplateIdE18Set... Same for antsApplyTransforms and N4BiasFieldCorrection. ITK 5.4.7-10 turned ITK_LEGACY_REMOVE ON as a side effect of ITK_WRAP_PYTHON, removing itk::ObjectToObjectOptimizerBaseTemplate::{Set,Get}NumberOfThreads. - A rebuild is the whole fix, and that is worth stating precisely because it was not obvious: ANTs never CALLS those methods. Its only references are vtable slots -- they are virtual, declared inline behind #if !defined( ITK_LEGACY_REMOVE), so any class deriving from that hierarchy carries them. Measured with readelf on the -15 library: 8 relocations for the two symbols, all R_X86_64_64 inside .data.rel.ro, ZERO call-site relocations. Every live mention of SetNumberOfThreads in the ANTs tree is commented out. So no source patch is needed here -- but note this also makes it an ABI break on ITK's side, since removing two virtuals shifts vtable layout for every consumer. - Harden %%check step 3, which was nearly vacuous: `--version >/dev/null 2>&1 || --help >/dev/null 2>&1` throws away the loader's message, and a binary that dies on both arms just falls through the ||. Now asserts that no invocation reports "symbol lookup error" / "undefined symbol" / "error while loading shared libraries", and that output is non-empty. - Add %%check step 4: `ldd -r` over every shipped ANTs library, failing the build on any unresolved symbol. This is the check whose absence let a completely non-functional ANTs sit in the repo through several green builds. A compiler and rpmbuild being happy says nothing about whether the result can start. * Wed Sep 23 2026 Morgan Hough - 2.6.5-15 - New noarch subpackage ANTs-rstats for the six R scripts. Their Rscript shebangs made R-core a hard requirement of every ANTs install, for scripts that also need the unpackaged ANTsR library; the main package now needs only bash and perl. Still a versioned upstream release (v2.6.5 is current); the full 99-program application set is shipped. USE_VTK (5 mesh tools) and INSTALL_DEVELOPMENT stay off, with the reasons recorded in %%build. - Packaging acceptance suite added as tests/ants.bats. * Sat Sep 19 2026 Morgan Hough - 2.6.5-14 - Rebuild against InsightToolkit5 5.4.7-8, which unbundles Eigen3, VXL and double-conversion. No source or spec change; the Release bump is what makes the rebuild reach anyone. COPR adds a sibling at an already-published NVR rather than replacing it, and dnf then serves the older copy -- so a rebuild at the same NVR would leave this package linked against the bundled ITK while appearing to succeed. - Validated against -8 in mhough/neurofedora-itk5-test before this bump. - -14 rather than -13: the repo already publishes both -12 and -13, the -13 built elsewhere while the spec still said -12. Incrementing the SPEC's Release is not enough when the repo is ahead of it; the bump has to clear the highest PUBLISHED release, not the local one. * Mon Aug 03 2026 Morgan Hough - 2.6.5-12 - Add a %%check section: network-free validation of the freshly built binaries. Upstream's BUILD_TESTING suite is intentionally left off because it fetches test images via CMake ExternalData (no network in Fedora builds); instead the check synthesizes an image with ANTs' own ImageMath, runs a filter chain, and asserts the geometry survives the ITK I/O round-trip, then verifies the headline binaries load. Catches bad links, ABI-mismatched ITK and broken I/O. * Sun May 24 2026 Morgan Hough - 2.6.5-11 - Re-apply ALL-scripts install + Documentation/code_of_conduct.md docs. Skipping bogus -10 release (its `%%cmake_install` literal in a comment was macro-expanded by RPM and run as a stray shell command, crashing %install). - Comment now uses `%%cmake_install` (escaped) and explicit double-quotes in the rm-loop to prevent any future filename surprises. * Mon May 18 2026 Morgan Hough - 2.6.5-9 - Rebuild against InsightToolkit5 5.4.6 (GDCM CVE-2026-3650, F44 target) - Bump BuildRequires: InsightToolkit5-devel >= 5.4.6 * Fri Feb 27 2026 Morgan Hough - 2.6.5-8 - Rewrite changelog entries to remove RPM directive names (install, prep, files); EPEL 9 rpmbuild treats these as spec directives, causing "second install" error * Thu Feb 26 2026 Morgan Hough - 2.6.5-7 - Add debug_package suppression via define scope to fix EPEL 9 SRPM rebuild * Wed Feb 25 2026 Morgan Hough - 2.6.5-6 - Patch Examples/CMakeLists.txt in prep to add SOVERSION 1 to antsUtilities: fixes rpmlint E: invalid-soname (library installed with unversioned SONAME) - Delete unversioned .so symlinks in install step: resolves devel-file-in-non-devel-package warnings; l_* and antsUtilities are internal libraries, not a public API * Wed Feb 25 2026 Morgan Hough - 2.6.5-5 - Add l_* and libantsUtilities shared libs to files list (required at runtime by ANTs binaries; each binary wraps its corresponding l_*.so entry point) - Add ldconfig scriptlets for proper shared library management * Wed Feb 25 2026 Morgan Hough - 2.6.5-4 - Add -DCMAKE_SKIP_INSTALL_RPATH=ON: ANTs binaries embed /usr/lib64 RPATH which is a standard system path; brp-check-rpaths treats this as a fatal error * Wed Feb 25 2026 Morgan Hough - 2.6.5-3 - Add -DUSE_SYSTEM_ITK=ON: without this, ANTS.cmake's staging/lib64 install rule triggers even with SUPERBUILD=OFF (condition guards on NOT USE_SYSTEM_ITK), causing cmake install to fail when staging dir was never populated by superbuild * Tue Feb 24 2026 Morgan Hough - 2.6.5-2 - Limit parallel build jobs to -j4: each ITK template g++ process peaks at ~3 GB; 16-way parallelism OOMs even on 32 GB hosts and would fail on COPR 16 GB workers * Mon Feb 23 2026 Morgan Hough - 2.6.5-1 - Upgrade to ANTs 2.6.5 - Switch to direct build against system InsightToolkit5-devel (ANTs_SUPERBUILD=OFF) - Remove git BuildRequires (no longer downloading ITK at build time) - Add InsightToolkit5-devel BuildRequires - Use standard cmake/cmake_build/cmake_install RPM macros * Sun Jan 04 2026 mhough - 2.5.4-1 - Switched to SuperBuild due to incompatible system ITK v4 - Added C++17 and C17 flags for GCC 15 compatibility - Added memory constraints for build stability