%define debug_package %{nil} %global pypi_name charm-gems %global pkg_name charm_gems Name: python-%{pypi_name} Version: 1.3.3 Release: 7%{?dist} Summary: Python bindings for the GEMS segmentation package License: GPL-3.0-only URL: https://github.com/simnibs/charm-gems Source0: %{url}/archive/v%{version}/%{pypi_name}-%{version}.tar.gz BuildRequires: gcc-c++ BuildRequires: cmake >= 3.9 BuildRequires: make BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-wheel BuildRequires: python3-pip BuildRequires: python3-numpy BuildRequires: python3-pybind11 BuildRequires: pybind11-devel BuildRequires: InsightToolkit5-devel >= 5.4.5 BuildRequires: zlib-devel # ITK 5.4.5 VtkGlue cmake config transitively requires VTK at find_package time # (was pinned to <9.3 for the retired system Qt5 VTK 9.2.6; F44 no longer ships # that, so use COPR VTK 9.5/9.6 — charm-gems doesn't use VTK directly) BuildRequires: vtk-devel BuildRequires: java-devel BuildRequires: libtheora-devel %description charm-gems provides Python bindings for the GEMS (Generative Model for brain MRI segmentation) library. It is used by SimNIBS's CHARM tool for creating individualized head models from MRI scans. %package -n python3-%{pkg_name} Summary: %{summary} Requires: python3-numpy # 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. # NOTE: this pin lives on the SUBPACKAGE, not in the preamble. The preamble # belongs to the main "python-*" package, which this spec never builds -- so a # pin there ships on nothing at all. Verified with rpmspec -q --builtrpms. Requires: vtk(abi) = %{?vtk_abi}%{!?vtk_abi:UNSET} %description -n python3-%{pkg_name} Python bindings for the GEMS segmentation package used by SimNIBS. %prep %autosetup -n %{pypi_name}-%{version} # Remove bundled ITK and pybind11 submodule stubs (use system packages) rm -rf ITK pybind11 # Patch CMakeLists.txt to use system pybind11 via find_package sed -i 's|add_subdirectory(pybind11)|find_package(pybind11 REQUIRED)|' CMakeLists.txt # Relax -Werror (GCC 15 triggers new warnings on old code) sed -i 's/-Werror//' CMakeLists.txt # Fix x86-only SSE flags for aarch64 compatibility sed -i 's/-msse2 -mfpmath=sse//' gems/CMakeLists.txt sed -i 's/-msse2 -mfpmath=sse//' gems_python/CMakeLists.txt # Patch setup.py to pass ITK_DIR and pybind11_DIR to cmake sed -i "s|'-H.'|'-H.', '-DITK_DIR=%{_prefix}/lib/cmake/ITK-5.4', '-Dpybind11_DIR=%{_datadir}/cmake/pybind11'|" setup.py # Fix C++11 → C++17 for ITK 5.4 compatibility sed -i 's/CMAKE_CXX_STANDARD 11/CMAKE_CXX_STANDARD 17/' CMakeLists.txt sed -i 's/CMAKE_CXX_STANDARD 11/CMAKE_CXX_STANDARD 17/' gems/CMakeLists.txt # ---- ITK 4.13 → 5.4 API migration ---- # itkExceptionObject.h must not be included directly find . \( -name '*.h' -o -name '*.cxx' -o -name '*.cpp' \) \ -exec grep -l 'itkExceptionObject' {} + | \ xargs -r sed -i 's|itkExceptionObject\.h|itkMacro.h|g' # Threading API changes find . \( -name '*.h' -o -name '*.cxx' \) -exec sed -i \ -e 's|ITK_THREAD_RETURN_TYPE|itk::ITK_THREAD_RETURN_TYPE|g' \ -e 's|ITK_THREAD_RETURN_VALUE|itk::ITK_THREAD_RETURN_DEFAULT_VALUE|g' \ -e 's|itk::MultiThreader::ThreadInfoStruct|itk::PlatformMultiThreader::WorkUnitInfo|g' \ -e 's|->ThreadID|->WorkUnitID|g' \ -e 's|->NumberOfThreads|->NumberOfWorkUnits|g' \ -e 's|itk::SimpleFastMutexLock|std::mutex|g' \ -e 's|\.Lock()|.lock()|g' \ -e 's|\.Unlock()|.unlock()|g' \ -e 's|itk::MultiThreader::GetGlobalDefaultNumberOfThreads|itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads|g' \ -e 's|itk::MultiThreader::Pointer|itk::PlatformMultiThreader::Pointer|g' \ -e 's|itk::MultiThreader::New|itk::PlatformMultiThreader::New|g' \ {} + # Add missing ITK 5 threading headers sed -i '/#include "kvlAtlasMesh.h"/a #include "itkPlatformMultiThreader.h"' gems/kvlAtlasMeshRasterizor.h sed -i '1i #include ' gems/kvlAtlasMeshRasterizor.cxx sed -i '1i #include "itkMultiThreaderBase.h"' gems/kvlAtlasParameterEstimator.cxx # ITK 5.x SmartPointer: convert '= 0' to '= nullptr' for known Pointer members # Whitelist approach avoids false positives on int/double member assignments for m in m_CostFunction m_BinnedImage m_Image m_MeshCollection \ m_CompressionLookupTable m_LabelImage m_ProbabilityImage \ m_PositionGradient m_TargetPoints m_LabelStatistics \ m_PointParameters m_Cells m_ReferenceTetrahedronInfos \ m_ReferencePosition m_CellLinks m_Mesh m_Calculator \ m_Position m_Gradient m_OldGradient m_OldSearchDirection; do find gems gems_python \( -name '*.cxx' -o -name '*.h' \) \ -exec sed -i "s/${m} = 0;/${m} = nullptr;/g" {} + done # Convert 'Pointer/ConstPointer varname = 0' local variable declarations find gems gems_python \( -name '*.cxx' -o -name '*.h' \) \ -exec sed -i -E 's/(Pointer\s+\w+)\s*=\s*0;/\1 = nullptr;/g' {} + # Convert 'return 0;' → 'return nullptr;' (all instances are in Pointer-returning functions) find gems gems_python \( -name '*.cxx' -o -name '*.h' \) \ -exec sed -i 's/return 0;/return nullptr;/g' {} + %build # 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; } export ITK_DIR=%{_prefix}/lib/cmake/ITK-5.4 export CXXFLAGS="%{optflags} -std=c++17 -include cstdint -fpermissive" %pyproject_wheel %install %pyproject_install %pyproject_save_files %{pkg_name} %check export PYTHONPATH=%{buildroot}%{python3_sitearch} %{python3} -c "import charm_gems; print('charm_gems imported successfully')" %files -n python3-%{pkg_name} -f %{pyproject_files} %license LICENSE %changelog * Sat Sep 19 2026 Morgan Hough - 1.3.3-7 - 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. * Tue Sep 15 2026 Morgan Hough - 1.3.3-6 - The vtk(abi) pin was in the preamble, which belongs to the main "python-*" package this spec never builds -- so it shipped on nothing. Moved onto the python3-* subpackage, where the VTK linkage actually is. Verified with rpmspec -q --builtrpms rather than by reading the spec. - The package does link VTK despite the older note saying it does not: three libvtk*.so.1 sonames, pulled in transitively through ITK's VtkGlue. * Sun Aug 23 2026 Morgan Hough - 1.3.3-5 - 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. * Fri Jun 12 2026 Morgan Hough - 1.3.3-4 - Rebuild for rawhide's Python 3.15 transition (the -3 build was built against python 3.14, stale on rawhide). Refreshes the SimNIBS chain so python-samseg and simnibs resolve and install on rawhide. * Sat May 23 2026 Morgan Hough - 1.3.3-3 - Drop vtk-devel <9.3 pin (system VTK 9.2.6 Qt5 retired on F44+); charm-gems pulls vtk transitively via ITK VtkGlue, doesn't use it directly * Wed Mar 11 2026 Morgan Hough - 1.3.3-2 - Fix SmartPointer nullptr conversion: use whitelist instead of blanket regex * Tue Mar 10 2026 Morgan Hough - 1.3.3-1 - Initial package