diff --git a/CMakeLists.txt b/CMakeLists.txt index da1c6d035d..31cca7da1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -491,7 +491,32 @@ function(MFC_SETUP_TARGET) # Here we need to split into "library" and "executable" to perform IPO on the NVIDIA compiler. # A little hacky, but it *is* an edge-case for *one* compiler. if (NVHPC_USE_TWO_PASS_IPO AND NOT(MFC_OpenMP AND ARGS_OpenMP)) + # nvfortran -Mextract does not produce .o files, only inline library + # data. An OBJECT library with -Mextract causes CMake to rebuild + # everything on every build because the expected .o outputs never + # exist. We use a wrapper script as RULE_LAUNCH_COMPILE that runs + # the compiler and then touches the expected .o output file. + set(_ipo_wrapper "${CMAKE_BINARY_DIR}/${ARGS_TARGET}_extract_wrapper.sh") + file(WRITE "${_ipo_wrapper}" [=[#!/bin/sh +# Find the -o argument (the object file CMake expects) +out= +prev= +for arg do + if [ "$prev" = "-o" ]; then out="$arg"; break; fi + prev="$arg" +done +# Run the compiler; propagate its exit status on failure +"$@" +status=$? +[ "$status" -eq 0 ] || exit "$status" +# Touch the .o so CMake's dependency tracking sees it +[ -n "$out" ] && touch "$out" +exit 0 +]=]) + file(CHMOD "${_ipo_wrapper}" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE) add_library(${ARGS_TARGET}_lib OBJECT ${ARGS_SOURCES}) + set_target_properties(${ARGS_TARGET}_lib PROPERTIES + RULE_LAUNCH_COMPILE "${_ipo_wrapper}") target_compile_options(${ARGS_TARGET}_lib PRIVATE $<$:-Mextract=lib:${ARGS_TARGET}_lib> $<$:-Minline>