# LTO is disabled deliberately. MRtrix3 links with its own command line
# ('OBJECTS LINKFLAGS -o EXECUTABLE', configure:336) which never carries
# -flto, so the LTO in %%{optflags} buys nothing at link time and only costs
# a second code-generation pass per object via -ffat-lto-objects.
%global _lto_cflags %{nil}
# Cap build concurrency by MEMORY, not by core count. MRtrix3's ./build
# defaults to SC_NPROCESSORS_ONLN (build:1441-1444) with no memory awareness,
# and at the -O3 a release build actually uses, single Eigen translation units
# are enormous. Measured, one at a time, g++ 16.1.1, x86_64:
#
# cmd/mrregister.cpp 7,381,368 KB 142 s
# src/registration/transform/affine.cpp 3,038,284 KB 30 s
# core/math/average_space.cpp 2,949,976 KB 39 s
#
# So one job can want 7.2 GB. Sixteen in parallel is not survivable on any
# builder we have, and four is not survivable either on a machine with other
# work on it -- both of those were observed, not predicted. The budget below
# is set from the measured maximum, not from the file an OOM happened to name.
# %%_smp_tasksize_proc is MB of RAM per job, so %%{_smp_build_ncpus} scales the
# job count with the builder's memory: 2 jobs on a 16 GB builder.
%global _smp_tasksize_proc 8192
%global install_dir %{_libdir}/%{name}
Name: mrtrix3
Version: 3.0.8
Release: 8%{?dist}
Summary: Advanced Diffusion MRI Processing and Visualisation
License: MPL-2.0
URL: https://www.mrtrix.org/
Source0: https://github.com/MRtrix3/%{name}/archive/refs/tags/%{version}.tar.gz#/%{name}-%{version}.tar.gz
# Bundled Eigen 3.4.0 — system eigen3 5.0.1 on F44+ renamed the version macros
# (EIGEN_WORLD_VERSION → EIGEN_VERSION_MAJOR, etc.) which breaks mrtrix3's
# configure test compile. Bundling lets us pin to a 3.x API.
Source1: https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz
Source2: mrview.metainfo.xml
Provides: bundled(eigen3) = 3.4.0
BuildRequires: gcc-c++
BuildRequires: git
BuildRequires: python3
BuildRequires: python3-devel
BuildRequires: eigen3-devel
BuildRequires: zlib-devel
BuildRequires: fftw-devel
BuildRequires: libtiff-devel
BuildRequires: libpng-devel
# Qt5 Dependencies
BuildRequires: qt5-qtbase-devel
BuildRequires: qt5-qtsvg-devel
BuildRequires: mesa-libGL-devel
BuildRequires: mesa-libGLU-devel
# desktop integration: validate the .desktop we install
BuildRequires: desktop-file-utils
BuildRequires: /usr/bin/appstream-util
Requires: python3
Requires: python3-numpy
Requires: qt5-qtbase
Requires: qt5-qtsvg
Requires: mesa-libGL
# mrview.desktop declares application/x-nifti and application/x-mgh as
# handled types. Those are defined by neuro-mime-types; without it the
# two declarations are inert and .nii never reaches mrview. Weak, not
# hard: mrview is perfectly usable on its own formats alone.
Recommends: neuro-mime-types
Requires: hicolor-icon-theme
%description
MRtrix3 provides a set of tools to perform various types of diffusion MRI
analyses, from various forms of tractography through to next-generation
group-level analyses.
%prep
%autosetup
# Extract bundled Eigen 3.4.0 alongside the source tree
tar xf %{SOURCE1}
%build
# 1. Fix build scripts to use python3 (Required for Mock/Fedora)
# MRtrix3 defaults to 'python', which doesn't exist in clean Fedora chroots.
sed -i 's|#!/usr/bin/env python|#!/usr/bin/python3|' configure build
# 2. Compiler flags. MRtrix3's configure reads CFLAGS and NOTHING ELSE: it
# builds the C++ compile line as "-c CFLAGS SRC -o OBJECT" (configure:333)
# and appends $CFLAGS to it (configure:789). An exported CXXFLAGS is read by
# no part of configure or build, so up to and including 3.0.8-4 the
# %%{optflags} this spec set had never once reached the compiler.
export CFLAGS="%{optflags}"
# 3. Linker Flags (Map Fedora's LDFLAGS to MRtrix's LINKFLAGS)
export LDFLAGS="%{?__global_ldflags}"
export LINKFLAGS="$LDFLAGS"
# 4. Architecture. configure appends -march=$ARCH whenever ARCH is set
# (configure:778-782), and upstream documents 'native' as the value to use.
# A -march=native binary is tuned for whichever builder happened to pick the
# job up, not for the machines that install the RPM, so it must never be set
# here. The baseline -march comes from %%{optflags}.
unset ARCH
# 4b. Parallelism. ./build reads NUMBER_OF_PROCESSORS and otherwise takes
# every core on the builder; see the %%_smp_tasksize_proc note above.
export NUMBER_OF_PROCESSORS=%{_smp_build_ncpus}
# 5. Qt5 Paths
export QMAKE=/usr/bin/qmake-qt5
export MOC=/usr/bin/moc-qt5
export RCC=/usr/bin/rcc-qt5
# Force configure to use bundled Eigen 3.4.0 (avoid system Eigen 5)
export EIGEN_CFLAGS="-isystem $PWD/eigen-3.4.0"
# 6. Configure (now using python3). NOT -debug: that sets optimlevel = 0
# (configure:205-207) and appends -O0 after $CFLAGS (configure:1434), so it
# silently overrode the -O2 in %%{optflags} and, with it, _FORTIFY_SOURCE,
# which is a no-op at -O0. Every mrtrix3 we have ever published says
# "debug version with nooptim" in its own --version banner.
./configure
# 7. Build (now using python3)
./build
%install
mkdir -p %{buildroot}%{install_dir}
mkdir -p %{buildroot}%{_bindir}
# Copy artifacts to private dir
cp -a bin %{buildroot}%{install_dir}/
cp -a lib %{buildroot}%{install_dir}/
cp -a share %{buildroot}%{install_dir}/
# Symlink binaries to /usr/bin
for b in %{buildroot}%{install_dir}/bin/*; do
binary_name=$(basename "$b")
# Only symlink if it's not the python binary itself
if [ "$binary_name" != "python" ]; then
ln -s %{install_dir}/bin/"$binary_name" %{buildroot}%{_bindir}/"$binary_name"
fi
done
# --- SHEBANG FIX ---
# Robustly rewrite ALL python shebangs to #!/usr/bin/python3
# We loop through every file in bin/, check if it's a script calling python,
# and forcefully overwrite the first line.
for f in %{buildroot}%{install_dir}/bin/*; do
if [ -f "$f" ]; then
# Check if the first line contains "python"
if head -n 1 "$f" | grep -q "python"; then
echo "Fixing shebang in $f"
# Replace the entire first line with #!/usr/bin/python3
sed -i '1s|^#!.*|#!/usr/bin/python3|' "$f"
fi
fi
done
# --- DESKTOP INTEGRATION ---
# Upstream ships all of this and we have never installed any of it, so mrview
# and shview have had no menu entry, no icon and no file associations since
# 3.0.8-1. Upstream's own install_mime_types.sh is a per-user xdg-* installer
# (it rewrites Exec= to an absolute path in the source tree), so it is no use
# to a package; the system install is done here instead.
#
# Two corrections to mrview.desktop on the way through, both --set-key:
# its first key is "Value=1.0" where the spec says Version, and its
# Categories names THREE main categories (Science;Development;Education), so
# mrview would appear three times in the menu -- including under Development,
# where an MRI viewer does not belong. desktop-file-validate emitted exactly
# that duplicate-main-category hint before Categories was set here.
#
# The "#!/usr/bin/env xdg-open" shebang upstream puts at the top is left
# alone: desktop-file-install does NOT strip it (checked, rather than
# assumed), and it is a valid comment line, so validation passes with it.
#
# MimeType= is rewritten, not left alone. Declaring mrview as a HANDLER for
# NIfTI is correct -- it opens them -- and we still decline to DEFINE those
# types here; that is what neuro-mime-types answers. But upstream's list
# names four types that do not exist under those names anywhere:
#
# application/x-nifti-gz .nii.gz is a glob of application/x-nifti,
# not a separate type
# application/x-image-mgh the type is application/x-mgh
# application/x-image-mgz .mgz is a glob of application/x-mgh
# application/x-image-analyze deliberately not defined -- Analyze's *.img
# is the single most generic extension there is
#
# A declaration for an undefined type is inert: it costs nothing and does
# nothing, so these four were silently buying us no NIfTI support at all
# while reading as though they did. ci/check-mime-consistency.py now fails
# the build on a declaration nothing we ship defines.
#
# x-mrtrix-tracks is added: mrview does open .tck, and the type is ours.
desktop-file-install \
--dir=%{buildroot}%{_datadir}/applications \
--set-key=Version --set-value=1.0 \
--remove-key=Value \
--set-key=Keywords --set-value="MRI;diffusion;tractography;DWI;neuroimaging;" \
--set-key=Categories --set-value="Science;MedicalSoftware;" \
--set-key=MimeType --set-value="application/x-mrtrix;application/x-mrtrix-gz;application/x-mrtrix-tracks;application/x-nifti;application/x-mgh;" \
mrview.desktop
for s in 16 32 48 64 128; do
install -Dpm0644 icons/desktop/${s}x${s}/mrtrix.png \
%{buildroot}%{_datadir}/icons/hicolor/${s}x${s}/apps/application-x-mrtrix.png
done
# MIME: ship ONLY the formats that are MRtrix's own. Upstream's
# mrtrix-mime.xml also claims application/x-nifti for *.nii and *.nii.gz,
# *.mgh/*.mgz, and -- worst -- application/x-image-analyze for the entirely
# generic *.img. Installing that system-wide would make mrview the owner of
# NIfTI for every user on the machine, ahead of fsleyes, invesalius, mricrogl
# and 3dslicer, and would collide with disk images on *.img. Those types want
# defining once, for all of them, not eight times by whichever package was
# installed last; see docs/gui-wayland-matrix.md.
cat > mrtrix3-mime.xml <<'XML'
MRtrix image
MRtrix image (compressed)
MRtrix streamlines
XML
install -Dpm0644 mrtrix3-mime.xml \
%{buildroot}%{_datadir}/mime/packages/mrtrix3.xml
# AppStream metadata. A .desktop file makes an application launchable; a
# metainfo file makes it DISCOVERABLE -- GNOME Software and KDE Discover list
# only applications that ship one. Validation runs here rather than in
# %check so a malformed file fails the build instead of shipping and being
# silently ignored, which is how Ankur Sinha does it in Fedora's
# python-fsleyes.
install -Dpm 0644 %{SOURCE2} %{buildroot}%{_metainfodir}/mrview.metainfo.xml
appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/mrview.metainfo.xml
%check
desktop-file-validate %{buildroot}%{_datadir}/applications/mrview.desktop
test -f %{buildroot}%{_metainfodir}/mrview.metainfo.xml
%files
%license LICENCE.txt
%doc README.md
%{install_dir}/
%{_bindir}/*
%{_datadir}/applications/mrview.desktop
%{_datadir}/icons/hicolor/*/apps/application-x-mrtrix.png
%{_datadir}/mime/packages/mrtrix3.xml
%{_metainfodir}/mrview.metainfo.xml
%changelog
* Sun Oct 04 2026 Morgan Hough - 3.0.8-8
- Rewrite mrview.desktop's MimeType=. Four of the seven types upstream lists
do not exist under those names anywhere: application/x-nifti-gz (.nii.gz is
a glob of application/x-nifti, not a type), application/x-image-mgh (ours
is application/x-mgh), application/x-image-mgz (a glob of x-mgh), and
application/x-image-analyze, which we deliberately decline to define. A
declaration for an undefined type is INERT -- it costs nothing and does
nothing -- so the line read as though mrview handled NIfTI while in fact
it handled none of it. Added application/x-mrtrix-tracks, which mrview
does open and which is our own type.
- Drop the two duplicate definitions: neuro-mime-types also defined
application/x-mrtrix and application/x-mrtrix-tracks, and its *.mif.gz
glob (weight 60) outranked this package's own application/x-mrtrix-gz
(weight 50). With both packages installed, .mif.gz resolved to a type
mrview.desktop does not declare and stopped opening. Fixed on the
neuro-mime-types side; mrtrix3 remains the sole owner of its formats.
- Recommends: neuro-mime-types, which defines the two generic types the
desktop entry now declares.
- ci/check-mime-consistency.py fails on any of the three: a type defined
twice, a glob two types claim, a declaration nothing defines.
* Thu Oct 01 2026 Morgan Hough - 3.0.8-7
- Fix -6, which failed in %%check after 67 minutes of build time. The
metainfo path had been inserted into %%check, where the shell tried to
EXECUTE it, instead of into %%files, where it belongs. Same anchor mistake
as the four specs repaired in 086b655; mrtrix3 survived that pass because
it was judged clean from a grep of line numbers rather than from reading
the sections.
- %%check now asserts the file exists instead of naming it, and %%files
ships it. ci/check-static-qa.sh gained a rule for this shape.
* Tue Sep 29 2026 Morgan Hough - 3.0.8-6
- Ship AppStream metadata (mrview.metainfo.xml). A desktop entry makes an application
launchable; a metainfo file makes it DISCOVERABLE, because GNOME Software
and KDE Discover list only applications that ship one. Twenty of the
twenty-six applications in this repo had a desktop entry and no metainfo,
so they were invisible in the software centre even once installed.
Validated at build time with appstream-util validate-relax --nonet, in
%install rather than %check, so a malformed file fails the build.
- Added Requires: hicolor-icon-theme, which the icons need.
* Mon Sep 28 2026 Morgan Hough - 3.0.8-5
- Build as an optimised release. Dropped ./configure -debug, which set
optimlevel = 0 and appended -O0 after $CFLAGS, so every mrtrix3 we have
published is an unoptimised debug build -- of a package whose main job is
hours-long tractography. Confirmed in the shipped binary's own banner:
"64 bit debug version with nooptim".
- Pass %%{optflags} through CFLAGS, not CXXFLAGS. configure reads CFLAGS and
nothing else (compile line "-c CFLAGS SRC -o OBJECT", configure:333/789),
so the CXXFLAGS this spec exported was inert and Fedora's flags had never
reached the compiler. Corroborated in mrtrix3-3.0.8-3.fc44.x86_64: zero
__*_chk references, i.e. no _FORTIFY_SOURCE, which -O0 disables anyway.
- Dropped ARCH=native. It makes configure append -march=native, which targets
whichever COPR builder took the job rather than the machines that install
the package. The two defects had to be fixed together: removing -debug
without this would have shipped builder-specific ISA at full optimisation.
- Not re-adding the -std=gnu++17 -fpermissive that rode along in the inert
CXXFLAGS. They have never been in effect and the build does not need them;
upstream's own -std=c++11 (configure:334) is what has always been used.
- Disabled LTO (%%global _lto_cflags %%{nil}): mrtrix3's link line never
carries -flto, so -ffat-lto-objects only pays for a second codegen pass.
- Enabled debuginfo generation, previously off via %%define debug_package
%%{nil}; the binaries were being stripped and the debug info discarded.
- Capped build concurrency by memory (%%global _smp_tasksize_proc 8192 +
NUMBER_OF_PROCESSORS=%%{_smp_build_ncpus}). Not cosmetic: once -O3 is really
in effect, cmd/mrregister.cpp alone peaks at 7.2 GB RSS (142 s), with
affine.cpp and average_space.cpp at 2.9-3.0 GB. ./build's own default of one
job per core OOM-killed cc1plus twice -- at 16 jobs and again at 4 -- and the
budget here is set from the measured maximum rather than from whichever file
the OOM message happened to name. The -O0 builds never showed any of this
because they never optimised.
- Install the desktop integration upstream has always shipped and this spec
has never used: mrview.desktop, an app icon at five sizes, and MIME types.
mrview and shview have had no menu entry, no icon and no file association
since 3.0.8-1. The .desktop needed two fixes on the way through (a shebang
line, and "Value=1.0" where the spec says Version); desktop-file-validate
now runs in %%check.
- Shipping only MRtrix's OWN mime types (.mif/.mih/.mif.gz/.tck), not
upstream's full mrtrix-mime.xml: that file also claims application/x-nifti
for *.nii/*.nii.gz and Analyze for the generic *.img, which would make
mrview the system-wide owner of NIfTI ahead of fsleyes, invesalius,
mricrogl and 3dslicer, and collide with disk images.
- tests/mrtrix3.bats gates this: the BUILD group reads mrinfo --version and
fails on "debug version"/"nooptim", with a second test asserting the banner
still has the shape the first one greps.
* Mon Sep 28 2026 Morgan Hough - 3.0.8-4
- Release bump only, no content change. f44-x86_64 has been serving 3.0.8-3
from build 10426601 (2026-05-05) -- a build that PREDATES the -2 spec
committed on 2026-05-24, but outranks it, because rpm orders -3 above -2.
So the chroot that looked "ahead" was pinned to the older package and every
other chroot correctly served the newer -2. Skipping to -4 restores the
intended content everywhere without reusing -3, which is already published
with different bytes.
- Not an aarch64 gap despite reading as one. The measurement said "ARM behind
on f44" and the cause was a release regression on x86.
* Sun May 24 2026 Morgan Hough - 3.0.8-2
- Bundle Eigen 3.4.0: F44+ system eigen3 5.0.1 renamed the version macros
(EIGEN_WORLD_VERSION → EIGEN_VERSION_MAJOR) which breaks mrtrix3's
configure test-compile of the Eigen3 detection probe. Pinning to a 3.x API
via $PWD/eigen-3.4.0 + EIGEN_CFLAGS sidesteps the Eigen-5 incompatibility.
* Sun Jan 04 2026 Morgan Hough - 3.0.8-1
- Initial package for MRtrix3 version 3.0.8