# SlicerDMRI — diffusion MRI for 3D Slicer: tractography, tensor estimation, # fiber-bundle visualization. C++ extension (vtkDMRI library + loadable/CLI # modules), built NON-superbuild against the system foundation (3dslicer-devel # >= -46, which ships the install-tree SlicerConfig + the Base/Logic and # loadable-module headers these modules #include). Standalone: find_package is # only Slicer/DCMTK/SlicerExecutionModel — no extra bundled libraries. The # EXTENSION_DEPENDS (UKFTractography, SlicerDcm2nii) are soft extension-manager # companions, not build dependencies. %global commit a40200bfb9df21a6092b308188175d1e339b5771 %global shortcommit %(c=%{commit}; echo ${c:0:8}) %global snapdate 20260601 %global slicer_inst %{_prefix}/lib/slicer %global slicer_subdir Slicer-5.12 Name: 3dslicer-dmri Version: 1.0 Release: 0.12.%{snapdate}git%{shortcommit}%{?dist} Summary: Diffusion MRI (tractography, tensors, fiber bundles) extension for 3D Slicer # Slicer's License.txt: the 3D Slicer Contribution and Software License # Agreement v1.0 (SPDX 3D-Slicer-1.0), PROVISIONALLY accepted as BSD-compatible # on 2026-10-12 (ci/check-fedora-licence.py) pending Fedora Legal. License: 3D-Slicer-1.0 URL: https://github.com/SlicerDMRI/SlicerDMRI Source0: %{url}/archive/%{commit}/SlicerDMRI-%{shortcommit}.tar.gz # Qt 6 removed QRegExp; DICOM2FullBrainTractography's panel failed with # "module 'qt' has no attribute 'QRegExp'". PythonQt's findChildren takes QRegularExpression. Patch0: 3dslicer-dmri-qt6-qregularexpression.patch BuildRequires: cmake >= 3.20.6 BuildRequires: ninja-build BuildRequires: gcc-c++ BuildRequires: python3-devel BuildRequires: 3dslicer-devel >= 5.12.1 # Full Qt6 set find_package(Slicer)'s Qt check demands. BuildRequires: cmake(Qt6Core) BuildRequires: cmake(Qt6Gui) BuildRequires: cmake(Qt6Widgets) BuildRequires: cmake(Qt6Network) BuildRequires: cmake(Qt6Sql) BuildRequires: cmake(Qt6Svg) BuildRequires: cmake(Qt6Xml) BuildRequires: cmake(Qt6OpenGL) BuildRequires: cmake(Qt6OpenGLWidgets) BuildRequires: cmake(Qt6PrintSupport) BuildRequires: cmake(Qt6Multimedia) BuildRequires: cmake(Qt6MultimediaWidgets) BuildRequires: cmake(Qt6Core5Compat) BuildRequires: cmake(Qt6StateMachine) BuildRequires: cmake(Qt6WebEngineCore) BuildRequires: cmake(Qt6WebEngineWidgets) BuildRequires: cmake(Qt6WebChannel) BuildRequires: cmake(Qt6Qml) BuildRequires: cmake(Qt6Quick) BuildRequires: cmake(Qt6QuickWidgets) BuildRequires: cmake(Qt6Test) BuildRequires: cmake(Qt6UiTools) BuildRequires: qt6-qttools-devel BuildRequires: InsightToolkit5-devel >= 5.4.6-7 BuildRequires: InsightToolkit5-vtk-devel BuildRequires: vtk-devel >= 9.6 # Defines %%vtk_abi on Fedora's vtk (via vtk-abi-compat); our vtk provides it itself. BuildRequires: vtk(abi) BuildRequires: ctk-devel BuildRequires: qttesting-devel BuildRequires: vtkAddon-devel BuildRequires: qRestAPI-devel BuildRequires: python-pythonqt-devel BuildRequires: commontk-applauncher-devel BuildRequires: dcmtk-devel BuildRequires: teem-devel BuildRequires: SlicerExecutionModel-devel BuildRequires: rapidjson-devel BuildRequires: libcurl-devel BuildRequires: jsoncpp-devel Requires: 3dslicer # 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} # 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} # 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 SlicerDMRI brings diffusion-weighted MRI analysis to 3D Slicer: diffusion-tensor estimation, deterministic and interactive tractography, fiber-bundle handling and visualization, and a set of diffusion CLI tools. It is a core neuroimaging extension. The vtkDMRI library and its loadable/CLI modules are built against the system 3D Slicer foundation. %prep %autosetup -p1 -n SlicerDMRI-%{commit} # Distro build: install modules directly, not as an Extension-Manager bundle, so # skip SlicerExtensionCPack (wants README/license + the s4ext description # template the install tree doesn't ship). sed -i '/include(${Slicer_EXTENSION_CPACK})/d' CMakeLists.txt # vtkDMRI does find_package(Teem); include(${Teem_USE_FILE}) directly, but # Fedora's teem ships no TeemUse.cmake (resolves to a nonexistent path). Drop # the include — modern Teem needs no use-file. sed -i '/include(${Teem_USE_FILE})/d' Libs/vtkDMRI/CMakeLists.txt # Qt6 removed the QString overloads of QComboBox::currentIndexChanged and # ::activated; the text-changed equivalents are currentTextChanged(QString) / # textActivated(QString). The TractographyDisplay glyph .ui connects # currentIndexChanged(QString) (uic then emits a signal/slot-mismatched connect # that FAILS to compile), and a widget .cxx uses the same in a string SIGNAL(). # Rewrite to the Qt6 signals everywhere they appear. grep -rlZ -e 'currentIndexChanged(QString)' -e 'activated(QString)' \ --include=*.ui --include=*.cxx --include=*.h . 2>/dev/null \ | xargs -0 -r sed -i \ -e 's/currentIndexChanged(QString)/currentTextChanged(QString)/g' \ -e 's/\bactivated(QString)/textActivated(QString)/g' # (No shims: foundation -53 makes the install-tree config self-sufficient — the # imported targets now carry the Qt include dirs and the full inter-Slicer + CTK # link closure, so the Qt-include and qt-loadable-modules link_directories hacks # this package used against -51/-52 are no longer needed.) %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; } # 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; } %cmake -G Ninja \ -DSlicerDMRI_SUPERBUILD:BOOL=OFF \ -DSlicer_DIR:PATH=%{slicer_inst}/lib/%{slicer_subdir} \ -DBUILD_TESTING:BOOL=OFF \ -DSlicer_SKIP_SlicerBlockAdditionalLauncherSettings:BOOL=TRUE \ -DCMAKE_INSTALL_PREFIX:PATH=%{slicer_inst} %cmake_build %install %cmake_install # The eight SEM CLIs install into /bin, but Slicer scans only # lib//cli-modules, so they were never registered (same shape as # 3dslicer-rt's plastimatch CLIs). ExtractDWIShells.py already lands in the # right place. Fail if any expected CLI or its .xml is missing, so a renamed # upstream target cannot silently fall out of the module list again. clidir=%{buildroot}%{slicer_inst}/lib/%{slicer_subdir}/cli-modules install -d "$clidir" for m in DICOMTract_to_VTK DWIToDTIEstimation DiffusionTensorScalarMeasurements \ DiffusionWeightedVolumeMasking FiberBundleLabelSelect FiberTractMeasurements \ TractographyLabelMapSeeding VTK_to_DICOMTract; do for f in "$m" "$m.xml"; do test -e "%{buildroot}%{slicer_inst}/bin/$f" \ || { echo "ERROR: expected CLI file bin/$f not built" >&2; exit 1; } mv "%{buildroot}%{slicer_inst}/bin/$f" "$clidir/$f" done done # Nothing SEM-shaped may remain in bin/: a CLI there is a CLI Slicer never sees. if ls %{buildroot}%{slicer_inst}/bin/*.xml >/dev/null 2>&1; then echo "ERROR: CLI descriptors left in bin/:" >&2 ls %{buildroot}%{slicer_inst}/bin/*.xml >&2 exit 1 fi # Catch-all file list (files + symlinks only, so the shared module dirs that # 3dslicer owns are never claimed). Tightened later. ( cd %{buildroot} && find . \( -type f -o -type l \) | sed 's|^\.||' ) \ > %{_builddir}/dmri.files %files -f %{_builddir}/dmri.files %license License.txt %doc README.md %changelog * Thu Oct 22 2026 Morgan Hough - 1.0-0.12.20260601gita40200bf - License: 3D-Slicer-1.0 (was mislabelled BSD-3-Clause). - Move the eight SEM CLIs (DICOMTract_to_VTK, DWIToDTIEstimation, DiffusionTensorScalarMeasurements, DiffusionWeightedVolumeMasking, FiberBundleLabelSelect, FiberTractMeasurements, TractographyLabelMapSeeding, VTK_to_DICOMTract) and their .xml from bin/ to lib/Slicer-5.12/cli-modules. Slicer scans only cli-modules, so none of them was ever registered; found on the Fedora install by hand on 2026-10-19 (the Ubuntu port had the same gap). %%install now fails on a missing CLI or on any .xml left in bin/. * Sat Oct 10 2026 Morgan Hough - 1.0-0.11.20260601gita40200bf - Patch0: QRegExp -> QRegularExpression in DICOM2FullBrainTractography (Qt 6 removed QRegExp; the module panel failed with "module 'qt' has no attribute 'QRegExp'"). Found by the tests/slicer UI sweep (framework x86_64, neurospark aarch64). * Tue Oct 06 2026 Morgan Hough - 1.0-0.10.20260601gita40200bf - 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. * Mon Oct 05 2026 Morgan Hough - 1.0-0.9.20260601gita40200bf - 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. * Sat Sep 19 2026 Morgan Hough - 1.0-0.8.git - 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. * Mon Aug 24 2026 Morgan Hough - 1.0-0.7.20260601gita40200bf - 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 - 1.0-0.6 - Rebuild for aarch64 against dcmtk 3.7.0-3 (SONAME 19 -> 20). The previous aarch64 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 provides now, leaving it uninstallable. x86_64 is already correct and is not rebuilt. * Wed Jul 22 2026 Morgan Hough - 1.0-0.4.20260601gita40200bf - Retarget from Slicer-5.11 to Slicer-5.12 core (3dslicer 5.12.1); bump 3dslicer-devel floor to 5.12.1. * Mon Jun 22 2026 Morgan Hough - 1.0-0.3.20260601gita40200bf - Rebuild against foundation -54, which adds the ITK link closure to the install-tree imported targets. -53 fixed the loadable-module GUI link (qSlicer/qMRML/ctk); the build then reached the CLI fiber modules (FiberBundleLabelSelect, TractographyLabelMapSeeding) which use ITK directly and failed with undefined itk::* — now resolved by the foundation carrying ITK on its target interfaces. * Sun Jun 21 2026 Morgan Hough - 1.0-0.2.20260601gita40200bf - Rebuild against foundation -53, which completes the install-tree imported-target link interface (inter-Slicer + CTK closure). Drop the transitional Qt-include / qt-loadable-modules link_directories shims — the foundation config is now self-sufficient. Keep the Qt6 currentIndexChanged(QString) -> currentTextChanged source fix (a genuine upstream Qt6 port, not a packaging workaround). * Tue Jun 16 2026 Morgan Hough - 1.0-0.1.20260601gita40200bf - Initial real package. SlicerDMRI (vtkDMRI library + tractography/tensor loadable & CLI modules) built non-superbuild against system 3dslicer-devel >= -46. Replaces the stale Version-0 stub.