Multi-Backend Install Layout Implementation Plan¶
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Refactor the CMake build system so a single build produces CPU + GPU backend variants, installing into bin/<backend>/ directories for forge-studio compatibility.
Architecture: Replace the current single-library/single-executable build with a forge_add_backend() CMake function that stamps out ForgeCommon_<backend> libraries and per-backend executables. Backend-specific compile definitions move from global add_definitions() to per-target target_compile_definitions(). Autodetection logic determines which backends to build.
Tech Stack: CMake 3.17+, C++17
Spec: docs/superpowers/specs/2026-03-25-multi-backend-install-design.md
Task 1: Create cmake/ForgeBackend.cmake with the forge_add_backend() function¶
This is the core new file. It defines a function that creates a library + executables + install rules for one backend.
Files:
- Create: cmake/ForgeBackend.cmake
- [ ] Step 1: Write the function skeleton
Create cmake/ForgeBackend.cmake with the following content:
# cmake/ForgeBackend.cmake
# Stamps out ForgeCommon_<backend>, app executables, and install rules
# for a single compute backend (cpu, metal, cuda).
#
# Usage:
# forge_add_backend(<name>
# SOURCES <source-files>...
# [DEFINITIONS <compile-defs>...]
# [EXTRA_LIBS <link-libraries>...]
# [DEPENDS <target-dependencies>...]
# [OBJ_C_SOURCES <objc-source-files>...])
include_guard(GLOBAL)
# The list of app source files and their target base names.
# Each entry is "target_name;relative_source_path" (relative to CMAKE_SOURCE_DIR).
set(_FORGE_APP_TARGETS
"forgeSense;apps/forgeSense.cpp"
"forgePcSense;apps/forgePcSense.cpp"
"forgePcSenseTimeSeg;apps/forgePcSenseTimeSeg.cpp"
"oscillateRecon;apps/lowRank/oscillateRecon.cpp"
"gridCoilImages;apps/reconSupport/gridCoilImages.cpp"
)
# oscillateRecon has extra source files beyond its main .cpp
set(_FORGE_OSCILLATE_EXTRA_SOURCES
"${CMAKE_SOURCE_DIR}/apps/lowRank/R_lowRank.cpp"
"${CMAKE_SOURCE_DIR}/apps/lowRank/LRobj.cpp"
)
# MPI app targets: "target_name;source1;source2;..."
set(_FORGE_MPI_TARGETS
"forgeSenseMPI;apps/MPI/forgeSenseMPI.cpp"
"forgePcSenseMPI;apps/MPI/mpipcSENSE.cpp;apps/MPI/forgePcSenseMPI.cpp"
"forgePcSenseMPI_TS;apps/MPI/mpipcSENSETimeSeg.cpp;apps/MPI/forgePcSenseMPI_TS.cpp"
)
function(forge_add_backend BACKEND_NAME)
# Parse arguments
cmake_parse_arguments(ARG "" "" "SOURCES;DEFINITIONS;EXTRA_LIBS;DEPENDS;OBJ_C_SOURCES" ${ARGN})
set(LIB_TARGET "ForgeCommon_${BACKEND_NAME}")
# ── Library ────────────────────────────────────────────────────────────
add_library(${LIB_TARGET} ${ARG_SOURCES})
target_include_directories(${LIB_TARGET} PUBLIC
${PROJECT_SOURCE_DIR}/forge
${CMAKE_BINARY_DIR} # for generated Version.h
)
# Per-target compile definitions (replaces global add_definitions)
if(ARG_DEFINITIONS)
target_compile_definitions(${LIB_TARGET} PUBLIC ${ARG_DEFINITIONS})
endif()
# Link base libs + any backend-specific extras
target_link_libraries(${LIB_TARGET} PUBLIC ${LIBS})
if(ARG_EXTRA_LIBS)
target_link_libraries(${LIB_TARGET} PUBLIC ${ARG_EXTRA_LIBS})
endif()
# ObjC ARC flags for Metal .mm sources
if(ARG_OBJ_C_SOURCES)
set_source_files_properties(${ARG_OBJ_C_SOURCES}
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
endif()
# Target dependencies (e.g. MetalShaders)
if(ARG_DEPENDS)
add_dependencies(${LIB_TARGET} ${ARG_DEPENDS})
endif()
set_target_properties(${LIB_TARGET} PROPERTIES
LINK_DEPENDS_NO_SHARED true
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
# RPATH: bin/<backend>/ is two levels below lib/
set_target_properties(${LIB_TARGET} PROPERTIES
INSTALL_RPATH "$<IF:$<PLATFORM_ID:Darwin>,@loader_path/../../lib,$ORIGIN/../../lib>"
)
install(TARGETS ${LIB_TARGET} LIBRARY DESTINATION lib)
# ── App executables ────────────────────────────────────────────────────
foreach(ENTRY IN LISTS _FORGE_APP_TARGETS)
list(GET ENTRY 0 BASE_NAME)
list(GET ENTRY 1 SOURCE_REL)
set(EXE_TARGET "${BASE_NAME}_${BACKEND_NAME}")
set(EXE_SOURCES "${CMAKE_SOURCE_DIR}/${SOURCE_REL}")
# oscillateRecon has extra sources
if(BASE_NAME STREQUAL "oscillateRecon")
list(APPEND EXE_SOURCES ${_FORGE_OSCILLATE_EXTRA_SOURCES})
endif()
add_executable(${EXE_TARGET} ${EXE_SOURCES})
target_link_libraries(${EXE_TARGET} ${LIB_TARGET})
# Include directories for app sources that use relative includes
target_include_directories(${EXE_TARGET} PRIVATE
${CMAKE_SOURCE_DIR}/Support
${CMAKE_SOURCE_DIR}/apps)
# Install with the original binary name (strip _<backend> suffix)
set_target_properties(${EXE_TARGET} PROPERTIES
OUTPUT_NAME ${BASE_NAME}
INSTALL_RPATH "$<IF:$<PLATFORM_ID:Darwin>,@loader_path/../../lib,$ORIGIN/../../lib>"
)
install(TARGETS ${EXE_TARGET}
DESTINATION bin/${BACKEND_NAME})
endforeach()
# ── MPI executables (optional) ──────────────────────────────────��──────
if(MPISupport AND MPI_FOUND)
foreach(ENTRY IN LISTS _FORGE_MPI_TARGETS)
list(GET ENTRY 0 BASE_NAME)
# Remaining items are source paths
list(LENGTH ENTRY ENTRY_LEN)
math(EXPR LAST_IDX "${ENTRY_LEN} - 1")
set(MPI_SOURCES "")
foreach(IDX RANGE 1 ${LAST_IDX})
list(GET ENTRY ${IDX} SRC_REL)
list(APPEND MPI_SOURCES "${CMAKE_SOURCE_DIR}/${SRC_REL}")
endforeach()
set(MPI_TARGET "${BASE_NAME}_${BACKEND_NAME}")
add_executable(${MPI_TARGET} ${MPI_SOURCES})
target_link_libraries(${MPI_TARGET} MPI::MPI_CXX ${LIB_TARGET})
target_compile_definitions(${MPI_TARGET} PRIVATE ForgeMPI)
# Include directories for MPI app sources
target_include_directories(${MPI_TARGET} PRIVATE
${CMAKE_SOURCE_DIR}/Support
${CMAKE_SOURCE_DIR}/apps)
set_target_properties(${MPI_TARGET} PROPERTIES
OUTPUT_NAME ${BASE_NAME}
INSTALL_RPATH "$<IF:$<PLATFORM_ID:Darwin>,@loader_path/../../lib,$ORIGIN/../../lib>"
)
install(TARGETS ${MPI_TARGET}
DESTINATION bin/${BACKEND_NAME})
endforeach()
endif()
# ── Export target name for test linking ─────────────────────────────────
set("FORGE_LIB_${BACKEND_NAME}" "${LIB_TARGET}" PARENT_SCOPE)
endfunction()
- [ ] Step 2: Commit
git add cmake/ForgeBackend.cmake
git commit -m "build: add forge_add_backend() CMake function
Stamps out ForgeCommon_<backend> library, app executables, and install
rules for a single compute backend. Supports per-target compile
definitions, optional ObjC ARC sources, MPI variants, and correct
RPATH for bin/<backend>/ layout."
Task 2: Refactor forge/CMakeLists.txt to export source lists instead of building targets¶
Currently forge/CMakeLists.txt builds ForgeCommon directly. It needs to instead export the source file lists so the root CMakeLists.txt can pass them to forge_add_backend().
Files:
- Modify: forge/CMakeLists.txt (full rewrite)
- [ ] Step 1: Replace forge/CMakeLists.txt
Replace the entire content of forge/CMakeLists.txt with:
# forge/CMakeLists.txt
# Defines source file lists for ForgeCommon.
# The actual library targets are created by forge_add_backend() in the root CMakeLists.txt.
set(FORGE_BASE_SOURCES
# Penalties
${PROJECT_SOURCE_DIR}/forge/Penalties/Robject.cpp
${PROJECT_SOURCE_DIR}/forge/Penalties/QuadPenalty.cpp
${PROJECT_SOURCE_DIR}/forge/Penalties/TVPenalty.cpp
# Solvers
${PROJECT_SOURCE_DIR}/forge/Solvers/reconSolve.cpp
# FFT
${PROJECT_SOURCE_DIR}/forge/FFT/fftCPU.cpp
${PROJECT_SOURCE_DIR}/forge/FFT/ftCpu.cpp
${PROJECT_SOURCE_DIR}/forge/FFT/ftCpuWithGrads.cpp
${PROJECT_SOURCE_DIR}/forge/FFT/fftAccelerate.cpp
# Operators
${PROJECT_SOURCE_DIR}/forge/Operators/Gdft.cpp
${PROJECT_SOURCE_DIR}/forge/Operators/GdftR2.cpp
${PROJECT_SOURCE_DIR}/forge/Operators/Gfft.cpp
${PROJECT_SOURCE_DIR}/forge/Operators/Gnufft.cpp
${PROJECT_SOURCE_DIR}/forge/Operators/SENSE.cpp
${PROJECT_SOURCE_DIR}/forge/Operators/pcSENSE.cpp
${PROJECT_SOURCE_DIR}/forge/Operators/pcSenseTimeSeg.cpp
# Gridding
${PROJECT_SOURCE_DIR}/forge/Gridding/TimeSegmentation.cpp
${PROJECT_SOURCE_DIR}/forge/Gridding/griddingSupport.cpp
${PROJECT_SOURCE_DIR}/forge/Gridding/gridding.cpp
# IO
${PROJECT_SOURCE_DIR}/forge/IO/acqTracking.cpp
${PROJECT_SOURCE_DIR}/forge/IO/directRecon.cpp
PARENT_SCOPE
)
set(FORGE_METAL_SOURCES
${PROJECT_SOURCE_DIR}/forge/Metal/MetalGridding.mm
${PROJECT_SOURCE_DIR}/forge/Metal/MetalDFT.mm
${PROJECT_SOURCE_DIR}/forge/Metal/MetalNufftPipeline.mm
${PROJECT_SOURCE_DIR}/forge/Metal/MetalVectorOps.mm
PARENT_SCOPE
)
set(FORGE_CUDA_SOURCES
${PROJECT_SOURCE_DIR}/forge/CUDA/CudaContext.cu
${PROJECT_SOURCE_DIR}/forge/CUDA/CudaVectorOps.cu
${PROJECT_SOURCE_DIR}/forge/CUDA/CudaGridding.cu
${PROJECT_SOURCE_DIR}/forge/CUDA/CudaNufftPipeline.cu
${PROJECT_SOURCE_DIR}/forge/CUDA/CudaDftPipeline.cu
${PROJECT_SOURCE_DIR}/forge/CUDA/CudaPenalty.cu
PARENT_SCOPE
)
- [ ] Step 2: Commit
git add forge/CMakeLists.txt
git commit -m "build: convert forge/CMakeLists.txt to export source lists
Instead of building ForgeCommon directly, export FORGE_BASE_SOURCES,
FORGE_METAL_SOURCES, and FORGE_CUDA_SOURCES for use by
forge_add_backend()."
Task 3: Refactor root CMakeLists.txt — autodetection and backend invocations¶
This is the main refactoring task. The root CMakeLists.txt needs to:
1. Remove global backend add_definitions()
2. Remove the Metal+CUDA mutual exclusion
3. Stop adding Metal/CUDA libs to the global LIBS variable
4. Include ForgeBackend.cmake and invoke it for each detected backend
5. Remove add_subdirectory(apps) (apps are now created by the function)
Files:
- Modify: CMakeLists.txt (lines 52-269 heavily modified)
- [ ] Step 1: Refactor CUDA detection block (lines 100-115)
Replace:
# CUDA compute (future — stub for Phase 4)
if(CUDA_COMPUTE)
if(METAL_COMPUTE)
message(FATAL_ERROR "METAL_COMPUTE and CUDA_COMPUTE cannot be enabled at the same time")
endif()
enable_language(CUDA)
find_package(CUDAToolkit REQUIRED)
set(CMAKE_CUDA_ARCHITECTURES "75;80;86;89;90;120")
add_definitions(-DCUDA_COMPUTE)
set(CUDA_LIBS CUDA::cufft CUDA::cudart CUDA::cublas)
# NVTX3 is header-only in CUDA 12+; nvToolsExt target may not exist
if(TARGET CUDA::nvToolsExt)
list(APPEND CUDA_LIBS CUDA::nvToolsExt)
endif()
set(LIBS ${LIBS} ${CUDA_LIBS})
endif()
With:
# CUDA compute
if(CUDA_COMPUTE)
enable_language(CUDA)
find_package(CUDAToolkit REQUIRED)
set(CMAKE_CUDA_ARCHITECTURES "75;80;86;89;90;120")
set(CUDA_LIBS CUDA::cufft CUDA::cudart CUDA::cublas)
if(TARGET CUDA::nvToolsExt)
list(APPEND CUDA_LIBS CUDA::nvToolsExt)
endif()
# CUDA_LIBS is passed to forge_add_backend(), not added to global LIBS
endif()
- [ ] Step 2: Refactor Metal detection block (lines 140-249)
Replace the Metal section inside the if(APPLE) block. The key changes:
- Keep Metal toolchain detection and shader compilation
- Remove add_definitions(-DMETAL_COMPUTE)
- Remove adding Metal/Foundation/MPS libs to global LIBS
- Store Metal libs in METAL_EXTRA_LIBS instead
Replace lines 152-161 (the option, FindMetal, add_definitions, and LIBS append):
option(METAL_COMPUTE "Enable Apple Metal GPU compute (Apple Silicon only)" ON)
if(METAL_COMPUTE)
include(FindMetal)
if(METAL_FOUND)
set(CMAKE_CXX_STANDARD 17)
find_library(FOUNDATION_LIBRARY Foundation REQUIRED)
set(METAL_EXTRA_LIBS ${METAL_LIBRARY} ${FOUNDATION_LIBRARY} ${MPS_GRAPH_LIBRARY})
(The rest of the Metal shader compilation block stays the same through line 243.)
And replace line 244 (the end of the METAL_FOUND block before else) — remove include_directories(${CMAKE_BINARY_DIR}/forge/Metal) since it will be handled by the library target's include dirs.
Actually, the generated Metal headers in ${CMAKE_BINARY_DIR}/forge/Metal need to be visible to ForgeCommon_metal. Add this to the include directories via the backend function. We'll handle this by adding the Metal binary include dir to the forge_add_backend call.
- [ ] Step 3: Remove global backend definitions and add_subdirectory(apps)
Remove these lines:
# Line 108:
add_definitions(-DCUDA_COMPUTE)
# Lines 256-258:
if(CUDA_COMPUTE)
add_definitions(-DUSE_NVTX)
endif()
# Line 269:
add_subdirectory(apps)
- [ ] Step 4: Add backend invocations after
add_subdirectory(forge)
Replace add_subdirectory(apps) (line 269) with the following block:
# ---------------------------------------------------------------------------
# Multi-backend build: stamp out ForgeCommon + apps for each backend
# ---------------------------------------------------------------------------
include(ForgeBackend)
# CPU backend — always built
forge_add_backend(cpu
SOURCES ${FORGE_BASE_SOURCES})
# Metal backend — macOS only, when Metal toolchain is found
if(METAL_COMPUTE AND METAL_FOUND)
forge_add_backend(metal
SOURCES ${FORGE_BASE_SOURCES} ${FORGE_METAL_SOURCES}
DEFINITIONS METAL_COMPUTE
EXTRA_LIBS ${METAL_EXTRA_LIBS}
DEPENDS MetalShaders
OBJ_C_SOURCES ${FORGE_METAL_SOURCES})
# Metal backend needs the generated shader headers
target_include_directories(ForgeCommon_metal PUBLIC ${CMAKE_BINARY_DIR}/forge/Metal)
endif()
# CUDA backend — when CUDA toolkit is found
if(CUDA_COMPUTE)
forge_add_backend(cuda
SOURCES ${FORGE_BASE_SOURCES} ${FORGE_CUDA_SOURCES}
DEFINITIONS CUDA_COMPUTE USE_NVTX
EXTRA_LIBS ${CUDA_LIBS})
endif()
# Standalone utilities (backend-agnostic, link against CPU)
add_executable(GenSyntheticISMRMRD ${CMAKE_SOURCE_DIR}/apps/GenSyntheticISMRMRD.cpp)
target_include_directories(GenSyntheticISMRMRD PRIVATE ${CMAKE_SOURCE_DIR}/forge/Tests)
target_link_libraries(GenSyntheticISMRMRD ForgeCommon_cpu)
install(TARGETS GenSyntheticISMRMRD DESTINATION bin)
- [ ] Step 5: Update RPATH defaults
Replace lines 28-29:
set(CMAKE_MACOSX_RPATH ON)
set(CMAKE_INSTALL_RPATH "@loader_path/../lib")
set(CMAKE_MACOSX_RPATH ON)
set(CMAKE_INSTALL_RPATH "@loader_path/../../lib")
And replace line 32:
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
set(CMAKE_INSTALL_RPATH "$ORIGIN/../../lib")
Note: standalone utilities (GenSyntheticISMRMRD, forgeview) installed to bin/ still need ../lib. We'll set per-target RPATH overrides for those:
set_target_properties(GenSyntheticISMRMRD PROPERTIES
INSTALL_RPATH "$<IF:$<PLATFORM_ID:Darwin>,@loader_path/../lib,$ORIGIN/../lib>")
- [ ] Step 6: Commit
git add CMakeLists.txt
git commit -m "build: refactor root CMakeLists.txt for multi-backend build
- Remove global add_definitions for METAL_COMPUTE/CUDA_COMPUTE/USE_NVTX
- Remove Metal+CUDA mutual exclusion
- Replace add_subdirectory(apps) with forge_add_backend() calls
- CPU backend always built; Metal autodetected on macOS; CUDA when enabled
- Update RPATH for bin/<backend>/ install layout"
Task 4: Remove apps/CMakeLists.txt and sub-CMakeLists (now handled by function)¶
The app executables are now created by forge_add_backend(). The apps/ CMakeLists files are no longer included.
Files:
- Delete: apps/CMakeLists.txt
- Delete: apps/lowRank/CMakeLists.txt
- Delete: apps/reconSupport/CMakeLists.txt
- Delete: apps/MPI/CMakeLists.txt
- [ ] Step 1: Delete the files
git rm apps/CMakeLists.txt apps/lowRank/CMakeLists.txt apps/reconSupport/CMakeLists.txt apps/MPI/CMakeLists.txt
- [ ] Step 2: Commit
git commit -m "build: remove apps/ CMakeLists files superseded by forge_add_backend()"
Task 5: Update test executables to link against backend-specific libraries¶
Test executables need to reference the new ForgeCommon_<backend> target names and _<backend> suffixed app targets.
Files:
- Modify: CMakeLists.txt (lines 274-380, test executable section)
- [ ] Step 1: Update
metal_testsand benchmarks to linkForgeCommon_metal
In the if(METAL_COMPUTE AND METAL_FOUND) block, replace all occurrences of:
target_link_libraries(metal_tests ForgeCommon ${LIBS})
target_link_libraries(metal_tests ForgeCommon_metal)
Do the same for metal_bench, metal_profile, metal_vecops_bench. The ${LIBS} is no longer needed because ForgeCommon_metal has PUBLIC link dependencies that propagate.
- [ ] Step 2: Update
ismrmrd_teststo linkForgeCommon_cpu
Replace:
target_link_libraries(ismrmrd_tests ForgeCommon ${LIBS})
target_link_libraries(ismrmrd_tests ForgeCommon_cpu)
- [ ] Step 3: Update
cpu_teststo linkForgeCommon_cpuand reference_cpuapp targets
Replace:
target_link_libraries(cpu_tests ForgeCommon ${LIBS})
# CLI tests require the reconstruction binaries to be built first
add_dependencies(cpu_tests forgeSense forgePcSense forgePcSenseTimeSeg oscillateRecon)
target_compile_definitions(cpu_tests PRIVATE
FORGE_SENSE_PATH="$<TARGET_FILE:forgeSense>"
FORGE_PCSENSE_PATH="$<TARGET_FILE:forgePcSense>"
FORGE_PCSENSE_TIMESEG_PATH="$<TARGET_FILE:forgePcSenseTimeSeg>"
FORGE_OSCILLATE_PATH="$<TARGET_FILE:oscillateRecon>")
With:
target_link_libraries(cpu_tests ForgeCommon_cpu)
# CLI tests require the reconstruction binaries to be built first
add_dependencies(cpu_tests forgeSense_cpu forgePcSense_cpu forgePcSenseTimeSeg_cpu oscillateRecon_cpu)
target_compile_definitions(cpu_tests PRIVATE
FORGE_SENSE_PATH="$<TARGET_FILE:forgeSense_cpu>"
FORGE_PCSENSE_PATH="$<TARGET_FILE:forgePcSense_cpu>"
FORGE_PCSENSE_TIMESEG_PATH="$<TARGET_FILE:forgePcSenseTimeSeg_cpu>"
FORGE_OSCILLATE_PATH="$<TARGET_FILE:oscillateRecon_cpu>")
- [ ] Step 4: Commit
git add CMakeLists.txt
git commit -m "build: update test executables for backend-suffixed targets
Link tests against ForgeCommon_cpu / ForgeCommon_metal instead of
ForgeCommon. CLI test paths now reference _cpu suffixed app targets."
Task 6: Build and verify — configure, compile, test, install¶
- [ ] Step 1: Clean build directory and reconfigure
rm -rf build
cmake -B build -S . -DMETAL_COMPUTE=ON
Expected: configure succeeds, output shows Found Metal: and messages about both cpu and metal backends.
- [ ] Step 2: Build all targets
cmake --build build -j4
Expected: builds ForgeCommon_cpu, ForgeCommon_metal, forgeSense_cpu, forgeSense_metal, etc. No errors.
- [ ] Step 3: Run cpu_tests
./build/cpu_tests '~[Benchmark]'
Expected: all tests pass (same as before).
- [ ] Step 4: Run metal_tests
./build/metal_tests '~[Benchmark]'
Expected: all tests pass (same as before).
- [ ] Step 5: Test install layout
cmake --install build --prefix /tmp/forge-install
ls -la /tmp/forge-install/bin/cpu/
ls -la /tmp/forge-install/bin/metal/
ls -la /tmp/forge-install/lib/
Expected:
- bin/cpu/ contains: forgeSense, forgePcSense, forgePcSenseTimeSeg, oscillateRecon, gridCoilImages
- bin/metal/ contains the same set
- lib/ contains libForgeCommon_cpu.dylib and libForgeCommon_metal.dylib
- bin/GenSyntheticISMRMRD and bin/forgeview exist at top level
- [ ] Step 6: Verify RPATH on installed binaries
otool -l /tmp/forge-install/bin/cpu/forgeSense | grep -A2 LC_RPATH
otool -l /tmp/forge-install/bin/metal/forgeSense | grep -A2 LC_RPATH
otool -l /tmp/forge-install/bin/GenSyntheticISMRMRD | grep -A2 LC_RPATH
Expected:
- bin/cpu/forgeSense RPATH: @loader_path/../../lib
- bin/metal/forgeSense RPATH: @loader_path/../../lib
- bin/GenSyntheticISMRMRD RPATH: @loader_path/../lib
- [ ] Step 7: Commit verification notes and clean up
rm -rf /tmp/forge-install
git status # should be clean
- [ ] Step 8: Final commit if any fixups were needed
If any issues were found and fixed during verification, commit the fixes.
Task 7: Print build summary at configure time¶
Add a status summary at the end of CMakeLists.txt so users can see which backends will be built.
Files:
- Modify: CMakeLists.txt (append at end)
- [ ] Step 1: Add summary block
Append to CMakeLists.txt (before the final blank line):
# ---------------------------------------------------------------------------
# Build summary
# ---------------------------------------------------------------------------
message(STATUS "")
message(STATUS "forge ${PROJECT_VERSION} build summary:")
message(STATUS " Backends:")
message(STATUS " cpu ............. ON (always)")
if(APPLE)
if(METAL_COMPUTE AND METAL_FOUND)
message(STATUS " metal ........... ON")
else()
message(STATUS " metal ........... OFF")
endif()
endif()
if(NOT APPLE)
if(CUDA_COMPUTE)
message(STATUS " cuda ............ ON")
else()
message(STATUS " cuda ............ OFF")
endif()
endif()
message(STATUS " Options:")
message(STATUS " MPI ............. ${MPISupport}")
message(STATUS " Shared libs ..... ${BUILD_SHARED_LIBS}")
message(STATUS " forgeview ....... ${BUILD_FORGEVIEW}")
message(STATUS "")
- [ ] Step 2: Commit
git add CMakeLists.txt
git commit -m "build: add configure-time build summary showing active backends"