Multi-Backend Install Layout¶
Date: 2026-03-25 Status: Approved
Problem¶
forge-studio expects reconstruction binaries organized as <forgeDir>/bin/<backend>/forgeSense (where backend is cpu, metal, or cuda). The current CMake build produces a flat layout with all executables in the build directory root and installs to a flat bin/. Additionally, METAL_COMPUTE and CUDA_COMPUTE are mutually exclusive — only one backend can be built per CMake configuration, making it impossible to install both CPU and GPU variants from a single build.
Solution¶
A single CMake build that autodetects available backends and produces per-backend library and executable variants, installing into the bin/<backend>/ directory structure that forge-studio expects.
Design¶
Autodetection Logic¶
- CPU: Always built. No option required.
- Metal: On macOS,
METAL_COMPUTEoption (default ON). If the Metal toolchain is found, themetalbackend is built alongsidecpu. If not found, a warning is emitted and onlycpuis built. - CUDA: On non-Apple platforms,
CUDA_COMPUTEoption (default OFF). If enabled andCUDAToolkitis found, thecudabackend is built alongsidecpu. - The old
FATAL_ERRORpreventing Metal+CUDA simultaneously is removed — it was a single-library constraint. In practice they won't coexist on the same machine.
forge_add_backend() CMake Function¶
A new file cmake/ForgeBackend.cmake defines a function forge_add_backend(<backend>) that stamps out a complete set of targets for a given backend:
-
ForgeCommon_<backend>— library built from the base source list plus backend-specific sources (Metal.mmfiles, CUDA.cufiles), with per-target compile definitions viatarget_compile_definitions()(not globaladd_definitions()). -
App executables —
forgeSense_<backend>,forgePcSense_<backend>,forgePcSenseTimeSeg_<backend>,oscillateRecon_<backend>,gridCoilImages_<backend>— each linked againstForgeCommon_<backend>. -
Install rules — each executable installs to
bin/<backend>/with the suffix stripped:install(TARGETS forgeSense_metal DESTINATION bin/metal RENAME forgeSense)ForgeCommon_<backend>installs tolib/. -
MPI variants — if
MPISupportis ON, MPI executables are also stamped per-backend and install tobin/<backend>/.
Function signature:
forge_add_backend(<name>
SOURCES <source-files>...
[DEFINITIONS <compile-defs>...]
[EXTRA_LIBS <link-libraries>...]
[DEPENDS <target-dependencies>...])
Invocation:
forge_add_backend(cpu SOURCES ${BASE_SOURCES})
forge_add_backend(metal SOURCES ${BASE_SOURCES} ${METAL_SOURCES}
DEFINITIONS METAL_COMPUTE
EXTRA_LIBS ${METAL_LIBRARY} ${FOUNDATION_LIBRARY} ${MPS_GRAPH_LIBRARY}
DEPENDS MetalShaders)
forge_add_backend(cuda SOURCES ${BASE_SOURCES} ${CUDA_SOURCES}
DEFINITIONS CUDA_COMPUTE USE_NVTX
EXTRA_LIBS ${CUDA_LIBS})
Global vs Per-Target Compile Definitions¶
Moves to per-target (inside forge_add_backend):
- -DMETAL_COMPUTE
- -DCUDA_COMPUTE
- -DUSE_NVTX
Stays global (applies to all backends equally):
- -DARMA_NO_DEBUG
- -DARMA_DONT_USE_HDF5
- -DACCELERATE_NEW_LAPACK
- -DUSE_SIGNPOST
Test Executables¶
Tests are not stamped per-backend — they remain hand-defined in the root CMakeLists.txt:
cpu_testslinks againstForgeCommon_cpu. CLI testtarget_compile_definitionspoint at_cpusuffixed app targets.metal_tests,metal_bench,metal_profile,metal_vecops_benchlink againstForgeCommon_metal.- No new test executables are created by the function.
Standalone Utilities¶
forgeview— single binary, installed tobin/(top-level). Backend-agnostic.GenSyntheticISMRMRD— single binary linked againstForgeCommon_cpu, installed tobin/(top-level).
Install Layout¶
<prefix>/
├── bin/
│ ├── cpu/
│ │ ├── forgeSense
│ │ ├── forgePcSense
│ │ ├── forgePcSenseTimeSeg
│ │ ├── oscillateRecon
│ │ └── gridCoilImages
│ ├── metal/ # macOS only, when Metal toolchain found
│ │ ├── forgeSense
│ │ ├── forgePcSense
│ │ ├── forgePcSenseTimeSeg
│ │ ├── oscillateRecon
│ │ └── gridCoilImages
│ ├── cuda/ # Linux only, when CUDAToolkit found
│ │ └── ...
│ ├── forgeview
│ └── GenSyntheticISMRMRD
├── lib/
│ ├── libForgeCommon_cpu.{so,dylib}
│ └── libForgeCommon_metal.{so,dylib} # or _cuda
└── ...
CMake Options¶
| Option | Default | Effect |
|---|---|---|
METAL_COMPUTE |
ON (macOS only) | Build Metal backend alongside CPU |
CUDA_COMPUTE |
OFF | Build CUDA backend alongside CPU |
MPISupport |
ON | Build MPI variants for each backend |
BUILD_SHARED_LIBS |
ON | Shared vs static libraries |
BUILD_FORGEVIEW |
ON | Build the TUI viewer |