Skip to content

Compile and Test CAT Standalone #12

Compile and Test CAT Standalone

Compile and Test CAT Standalone #12

name: Compile and Test CAT Standalone
on:
workflow_dispatch:
inputs:
source:
description: "Source of standalone binaries"
required: false
default: "build"
type: choice
options:
- build
- release
release_tag:
description: "Release tag (only for release source)"
required: false
type: string
env:
MLM_LICENSE_TOKEN: ${{ secrets.MATLAB_BATCH_TOKEN }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# ────────────────────────────────────────────────────
# Job 1: Download release standalone (if source == release)
# ────────────────────────────────────────────────────
download_release_standalone:
name: Download Release Standalone
if: inputs.source == 'release'
runs-on: ubuntu-latest
strategy:
matrix:
standalone_os: [Linux, Mac, Mac_arm64, Win]
steps:
- name: Download release asset
env:
GH_TOKEN: ${{ github.token }}
run: |
TAG="${{ inputs.release_tag }}"
OS="${{ matrix.standalone_os }}"
ASSET_NAME="CAT_R2023b_MCR_${OS}.zip"
echo "Downloading $ASSET_NAME from release $TAG"
gh release download "$TAG" --repo ${{ github.repository }} --pattern "$ASSET_NAME"
- name: Upload as artifact
uses: actions/upload-artifact@v5
with:
name: cat-standalone-${{ matrix.standalone_os }}
path: CAT_R2023b_MCR_${{ matrix.standalone_os }}.zip
retention-days: 1
# ────────────────────────────────────────────────────
# Job 2: Build standalone (if source == build or default)
# ────────────────────────────────────────────────────
build_standalone:
name: Build Standalone on ${{ matrix.os_name }}
if: inputs.source == 'build' || inputs.source == ''
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version: ["R2023b"]
os: ["ubuntu-22.04", "macos-15-intel", "macos-latest", "windows-latest"]
include:
- os: ubuntu-22.04
os_name: Linux
standalone_os: Linux
mex_ext: mexa64
- os: macos-15-intel
os_name: macOS_Intel
standalone_os: Mac
mex_ext: mexmaci64
- os: macos-latest
os_name: macOS_ARM64
standalone_os: Mac_arm64
mex_ext: mexmaca64
- os: windows-latest
os_name: Windows
standalone_os: Win
mex_ext: mexw64
steps:
- name: Checkout CAT
uses: actions/checkout@v5
- name: Update
run: make update
- name: Install rsync
if: runner.os == 'Windows'
run: choco install -y rsync
- name: Checkout SPM
uses: actions/checkout@v5
with:
repository: spm/spm
path: spm
- name: Install CAT in SPM toolbox
shell: bash
run: |
mkdir -p spm/toolbox/CAT
rsync -a --exclude='.git' \
--exclude='spm/toolbox/CAT/' \
--exclude='batches/' \
--exclude='catQC/' \
--exclude='check_pipeline/' \
--exclude='development/' \
--exclude='html/' \
--exclude='internal/' \
--exclude='mexmaca/' \
--exclude='mexmaci/' \
--exclude='spm/' \
--exclude='Makefile' \
./ spm/toolbox/CAT/
- name: Cleanup (Linux/Mac)
if: runner.os != 'Windows'
run: rm -rf standalone
- name: Cleanup (Windows)
if: runner.os == 'Windows'
run: Remove-Item -Recurse -Force standalone
- name: Install zip on Windows
if: runner.os == 'Windows'
run: choco install zip -y
shell: bash
- name: Set up MATLAB
uses: matlab-actions/setup-matlab@v2
with:
release: ${{ matrix.version }}
products: MATLAB_Compiler
- name: Set environment variable with MATLAB version
shell: bash
run: |
echo "MATLAB_VERSION=R2023b" >> $GITHUB_ENV
- name: Compile CAT mex-files
uses: matlab-actions/run-command@v2
with:
command: |
addpath('spm');
cd('spm/toolbox/CAT')
compile
# Decompress .nii.gz templates so they are available as .nii in the compiled standalone.
# Without this, atlas config (cat_conf_ROI.m) fails because it checks exist(...'.nii','file').
- name: Decompress NII.GZ templates
shell: bash
run: |
echo "Decompressing .nii.gz files in CAT templates..."
find spm/toolbox/CAT/templates_MNI152NLin2009cAsym -name '*.nii.gz' -exec gunzip -f {} \;
find spm/toolbox/CAT/templates_surfaces -name '*.nii.gz' -exec gunzip -f {} \;
find spm/toolbox/CAT/templates_surfaces_32k -name '*.nii.gz' -exec gunzip -f {} \;
echo "Decompression complete"
# Build SPM standalone (which includes CAT as toolbox)
- name: Build MATLAB standalone
uses: matlab-actions/run-command@v2
with:
command: |
cd('spm');
addpath(genpath('.'));
savepath;
cd('config');
spm_make_standalone
- name: Compress standalone to ZIP
shell: bash
run: |
mv spm/toolbox/CAT/standalone standalone/
mv standalone cat_standalone
zip -r CAT_${{ env.MATLAB_VERSION }}_MCR_${{ matrix.standalone_os }}.zip cat_standalone/*
- name: Upload standalone artifact
uses: actions/upload-artifact@v5
with:
name: cat-standalone-${{ matrix.standalone_os }}
path: CAT_*.zip
retention-days: 7
# ────────────────────────────────────────────────────
# Job 3: Test standalone on Linux
# ────────────────────────────────────────────────────
test_standalone:
name: Test Standalone on ${{ matrix.os_name }}
needs: [build_standalone, download_release_standalone]
if: |
always() &&
(needs.build_standalone.result == 'success' || needs.download_release_standalone.result == 'success')
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ["ubuntu-22.04"]
include:
- os: ubuntu-22.04
os_name: Linux
standalone_os: Linux
steps:
- name: Download standalone artifact
uses: actions/download-artifact@v5
with:
name: cat-standalone-${{ matrix.standalone_os }}
path: .
- name: Extract standalone
shell: bash
run: |
unzip -q CAT_*_MCR_${{ matrix.standalone_os }}.zip
echo "Contents of cat_standalone:"
ls -la cat_standalone
# ── Install MATLAB Runtime ──
- name: Install MATLAB Runtime (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
# Download MCR R2023b
echo "Downloading MATLAB Runtime R2023b for Linux..."
wget -q https://ssd.mathworks.com/supportfiles/downloads/R2023b/Release/10/deployment_files/installer/complete/glnxa64/MATLAB_Runtime_R2023b_Update_10_glnxa64.zip -O mcr.zip
unzip -q mcr.zip -d mcr_installer
echo "Installing MATLAB Runtime..."
sudo ./mcr_installer/install -agreeToLicense yes -destinationFolder /usr/local/MATLAB/MATLAB_Runtime 2>&1
echo "MCRROOT=/usr/local/MATLAB/MATLAB_Runtime/R2023b" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=/usr/local/MATLAB/MATLAB_Runtime/R2023b/runtime/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/bin/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/sys/os/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/sys/opengl/lib/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/R2023b/extern/bin/glnxa64" >> $GITHUB_ENV
echo "MCR_INHIBIT_CTF_LOCK=1" >> $GITHUB_ENV
echo "SPM_HTML_BROWSER=0" >> $GITHUB_ENV
rm -rf mcr.zip mcr_installer
echo "MATLAB Runtime installed at /usr/local/MATLAB/MATLAB_Runtime/R2023b"
# ── Setup and extract CTF ──
- name: Setup CAT standalone (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
chmod +x cat_standalone/spm25
echo "Extracting CTF archive..."
cat_standalone/spm25 function exit || true
echo "CAT standalone setup complete"
# ── Find test data (single_subj_T1.nii from SPM canonical directory) ──
- name: Locate test data
shell: bash
run: |
echo "Searching for single_subj_T1.nii inside standalone..."
T1=$(find cat_standalone -name "single_subj_T1.nii" -type f 2>/dev/null | head -n 1)
# If not found as .nii, try .nii.gz and decompress
if [ -z "$T1" ]; then
T1GZ=$(find cat_standalone -name "single_subj_T1.nii.gz" -type f 2>/dev/null | head -n 1)
if [ -n "$T1GZ" ]; then
echo "Found compressed: $T1GZ — decompressing..."
gunzip -k "$T1GZ"
T1="${T1GZ%.gz}"
fi
fi
if [ -z "$T1" ]; then
echo "ERROR: single_subj_T1.nii not found in standalone"
echo "Listing all directories:"
find cat_standalone -maxdepth 4 -type d 2>/dev/null
echo "Listing all .nii and .nii.gz files:"
find cat_standalone -name "*.nii" -o -name "*.nii.gz" 2>/dev/null | head -30
exit 1
fi
echo "Found test data: $T1"
# Copy to working directory so output goes there
cp "$T1" ./single_subj_T1.nii
echo "Test data ready: ./single_subj_T1.nii"
# ── Run CAT segmentation test ──
- name: Test CAT segmentation (Linux)
timeout-minutes: 60
shell: bash
run: |
SPMROOT=$(pwd)/cat_standalone
BATCH=$(find cat_standalone -name "cat_standalone_segment.m" -type f | head -n 1)
CAT_SH=$(find cat_standalone -name "cat_standalone.sh" -type f | head -n 1)
if [ -z "$BATCH" ]; then
echo "ERROR: cat_standalone_segment.m not found"
exit 1
fi
if [ -z "$CAT_SH" ]; then
echo "ERROR: cat_standalone.sh not found"
exit 1
fi
chmod +x "$CAT_SH"
echo "Using batch file: $BATCH"
echo "Using launcher: $CAT_SH"
echo "Running CAT segmentation on single_subj_T1.nii..."
"$CAT_SH" -b "$BATCH" -m "$MCRROOT" -s "$SPMROOT" "$(pwd)/single_subj_T1.nii"
# ── Verify outputs ──
- name: Verify segmentation outputs
shell: bash
run: |
echo "Checking for segmentation output files..."
# Look for typical CAT output files
found=0
for pattern in "mri/mwp1*" "mri/p0*" "report/cat_*" "surf/lh.thickness*"; do
matches=$(find . -path "./$pattern" 2>/dev/null)
if [ -n "$matches" ]; then
echo "Found: $matches"
found=1
fi
done
if [ "$found" -eq 0 ]; then
echo "WARNING: No standard CAT output files found in current directory"
echo "Checking all nii files created:"
find . -name "*.nii" -newer single_subj_T1.nii 2>/dev/null || echo "No new .nii files"
find . -name "*.gii" 2>/dev/null || echo "No .gii files"
find . -name "*.xml" -path "*/report/*" 2>/dev/null || echo "No report XMLs"
fi
echo "Test completed successfully"