From 14d7dd02d2136dfbf673f5190441d453bbc788cb Mon Sep 17 00:00:00 2001 From: Daksh Mamodiya Date: Mon, 26 Oct 2026 11:40:09 +0100 Subject: [PATCH] FindOpenMP: Add OpenMP::OpenMP__Offload targets OpenMP::OpenMP_ carries no device flags, and for GCC and Clang links the OpenMP runtime without the OpenMP flag, so target regions built through it fail to link or silently run on the host. Once OpenMP__OFFLOAD or OpenMP__OFFLOAD_FLAGS is set, the new targets add the device flags, plus the OpenMP flag at link time; otherwise they match the host targets. FindOpenMP.Offload runs a target kernel on a GPU and is enabled in the nvhpc job. Fixes: #21784, #26701 --- .gitlab/ci/configure_nvhpc_ninja.cmake | 8 + .../release/dev/FindOpenMP-offload-target.rst | 7 + Modules/FindOpenMP.cmake | 140 ++++++++++++++++++ Tests/FindOpenMP/CMakeLists.txt | 23 +++ Tests/FindOpenMP/Offload/CMakeLists.txt | 79 ++++++++++ Tests/FindOpenMP/Offload/main.c | 10 ++ Tests/FindOpenMP/Offload/main.f90 | 5 + Tests/FindOpenMP/Offload/offload.c | 20 +++ Tests/FindOpenMP/Offload/offload.f90.in | 15 ++ Tests/FindOpenMP/Test/CMakeLists.txt | 2 +- Tests/RunCMake/CMakeLists.txt | 5 + Tests/RunCMake/FindOpenMP/CMakeLists.txt | 3 + .../FindOpenMP/FlagsImplyOn-build-check.cmake | 5 + Tests/RunCMake/FindOpenMP/FlagsImplyOn.cmake | 2 + .../RunCMake/FindOpenMP/NoDefault-result.txt | 1 + .../RunCMake/FindOpenMP/NoDefault-stderr.txt | 4 + Tests/RunCMake/FindOpenMP/NoDefault.cmake | 2 + .../RunCMake/FindOpenMP/Off-build-check.cmake | 1 + Tests/RunCMake/FindOpenMP/Off.cmake | 3 + .../FindOpenMP/OffEmpty-build-check.cmake | 1 + Tests/RunCMake/FindOpenMP/OffEmpty.cmake | 3 + .../RunCMake/FindOpenMP/Offload-common.cmake | 17 +++ .../FindOpenMP/RefindFlags-build-check.cmake | 5 + Tests/RunCMake/FindOpenMP/RefindFlags.cmake | 5 + .../FindOpenMP/RefindOff-build-check.cmake | 1 + Tests/RunCMake/FindOpenMP/RefindOff.cmake | 5 + Tests/RunCMake/FindOpenMP/RunCMakeTest.cmake | 21 +++ .../FindOpenMP/SwitchOn-build-check.cmake | 2 + Tests/RunCMake/FindOpenMP/SwitchOn.cmake | 2 + .../FindOpenMP/Unset-build-check.cmake | 1 + Tests/RunCMake/FindOpenMP/Unset.cmake | 1 + .../WhitespaceFlags-build-check.cmake | 1 + .../RunCMake/FindOpenMP/WhitespaceFlags.cmake | 2 + Tests/RunCMake/FindOpenMP/check-flags.cmake | 60 ++++++++ Tests/RunCMake/FindOpenMP/lib.c | 4 + Tests/RunCMake/FindOpenMP/main.c | 4 + Tests/RunCMake/FindOpenMP/main.cxx | 4 + 37 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/FindOpenMP-offload-target.rst create mode 100644 Tests/FindOpenMP/Offload/CMakeLists.txt create mode 100644 Tests/FindOpenMP/Offload/main.c create mode 100644 Tests/FindOpenMP/Offload/main.f90 create mode 100644 Tests/FindOpenMP/Offload/offload.c create mode 100644 Tests/FindOpenMP/Offload/offload.f90.in create mode 100644 Tests/RunCMake/FindOpenMP/CMakeLists.txt create mode 100644 Tests/RunCMake/FindOpenMP/FlagsImplyOn-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/FlagsImplyOn.cmake create mode 100644 Tests/RunCMake/FindOpenMP/NoDefault-result.txt create mode 100644 Tests/RunCMake/FindOpenMP/NoDefault-stderr.txt create mode 100644 Tests/RunCMake/FindOpenMP/NoDefault.cmake create mode 100644 Tests/RunCMake/FindOpenMP/Off-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/Off.cmake create mode 100644 Tests/RunCMake/FindOpenMP/OffEmpty-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/OffEmpty.cmake create mode 100644 Tests/RunCMake/FindOpenMP/Offload-common.cmake create mode 100644 Tests/RunCMake/FindOpenMP/RefindFlags-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/RefindFlags.cmake create mode 100644 Tests/RunCMake/FindOpenMP/RefindOff-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/RefindOff.cmake create mode 100644 Tests/RunCMake/FindOpenMP/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/FindOpenMP/SwitchOn-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/SwitchOn.cmake create mode 100644 Tests/RunCMake/FindOpenMP/Unset-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/Unset.cmake create mode 100644 Tests/RunCMake/FindOpenMP/WhitespaceFlags-build-check.cmake create mode 100644 Tests/RunCMake/FindOpenMP/WhitespaceFlags.cmake create mode 100644 Tests/RunCMake/FindOpenMP/check-flags.cmake create mode 100644 Tests/RunCMake/FindOpenMP/lib.c create mode 100644 Tests/RunCMake/FindOpenMP/main.c create mode 100644 Tests/RunCMake/FindOpenMP/main.cxx diff --git a/.gitlab/ci/configure_nvhpc_ninja.cmake b/.gitlab/ci/configure_nvhpc_ninja.cmake index b72c4aac21..694f4af220 100644 --- a/.gitlab/ci/configure_nvhpc_ninja.cmake +++ b/.gitlab/ci/configure_nvhpc_ninja.cmake @@ -5,6 +5,14 @@ set(CMake_TEST_CUDA_CUPTI "ON" CACHE STRING "") set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "") set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23;26" CACHE STRING "") +set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "") +set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "") +set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "") +set(CMake_TEST_FindOpenMP_Fortran "ON" CACHE BOOL "") +set(CMake_TEST_FindOpenMP_C_OFFLOAD "ON" CACHE BOOL "") +set(CMake_TEST_FindOpenMP_CXX_OFFLOAD "ON" CACHE BOOL "") +set(CMake_TEST_FindOpenMP_Fortran_OFFLOAD "ON" CACHE BOOL "") + set(configure_no_sccache 1) include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") diff --git a/Help/release/dev/FindOpenMP-offload-target.rst b/Help/release/dev/FindOpenMP-offload-target.rst new file mode 100644 index 0000000000..b970cb6add --- /dev/null +++ b/Help/release/dev/FindOpenMP-offload-target.rst @@ -0,0 +1,7 @@ +FindOpenMP-offload-target +------------------------- + +* The :module:`FindOpenMP` module now provides ``OpenMP::OpenMP__Offload`` + imported targets for code whose OpenMP ``target`` regions may be offloaded + to a device. Offload is enabled with the new ``OpenMP__OFFLOAD`` and + ``OpenMP__OFFLOAD_FLAGS`` variables. diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake index 617774dd0b..b642dd7f75 100644 --- a/Modules/FindOpenMP.cmake +++ b/Modules/FindOpenMP.cmake @@ -59,6 +59,27 @@ This module provides the following :ref:`Imported Targets`: Target encapsulating the OpenMP usage requirements for language ````. +``OpenMP::OpenMP__Offload`` + .. versionadded:: 4.6 + + Target for code whose OpenMP ``target`` regions may be offloaded to a + device, for ```` of ``C``, ``CXX``, or ``Fortran``. It links + ``OpenMP::OpenMP_`` and, when offload is enabled with the + ``OpenMP__OFFLOAD`` or ``OpenMP__OFFLOAD_FLAGS`` variables, + adds the offload flags when compiling ```` sources. It also adds + them, together with the OpenMP flags, when the link is done by a compiler + with the same :variable:`CMAKE__COMPILER_ID`, because compilers + need both in order to link device code. When offload is not enabled, it + is equivalent to ``OpenMP::OpenMP_``. + + With NVHPC, an executable linked by NVHPC must also link the offload + target when it uses a shared library with offloaded code, for example + through ``$_Offload>`` in the library's + ``INTERFACE`` link libraries. + + Linking through a separate linker, as with Visual Studio generators or + ``clang-cl``, is not supported. + Input Variables ^^^^^^^^^^^^^^^ @@ -75,6 +96,49 @@ The following variables may be set to influence this module's behavior: .. _`msvc-openmp`: https://learn.microsoft.com/en-us/cpp/build/reference/openmp-enable-openmp-2-0-support +``OpenMP__OFFLOAD`` + .. versionadded:: 4.6 + + Enables OpenMP ``target`` offload for targets that link + ``OpenMP::OpenMP__Offload``. If not defined, offload is enabled + when ``OpenMP__OFFLOAD_FLAGS`` is non-empty. If defined, its + boolean value decides, so ``OFF`` disables offload even when flags are + set. + + The offload flags are ``OpenMP__OFFLOAD_FLAGS`` if non-empty, and + otherwise a default for the compiler: + + * GNU: none. GCC offloads to the devices whose offload compilers are + installed, such as ``gcc-offload-nvptx`` on Debian and Ubuntu. + * NVHPC: ``-mp=gpu``. + * IntelLLVM with a GNU-like command line (``icx``, ``icpx``, ``ifx``): + ``-fopenmp-targets=spir64``. + * Cray, CrayClang: none. The device comes from the loaded + ``craype-accel-*`` module. + + Other compilers, including Clang, have no default. Enabling offload for + them without ``OpenMP__OFFLOAD_FLAGS`` is an error, even if the + package is ``QUIET`` or the component is optional. + + Targets linking only ``OpenMP::OpenMP_`` are not affected. + Projects using the result variables must add the device flags for + compiling and linking themselves. Disabling offload only removes what + the offload target would add; it does not undo offload enabled by other + compiler flags or by the environment. ``OpenMP__FOUND`` and + ``OpenMP__VERSION`` describe host OpenMP support only; the module + does not check that offload works. + +``OpenMP__OFFLOAD_FLAGS`` + .. versionadded:: 4.6 + + Compiler flags selecting the device(s) to offload OpenMP ``target`` + regions to, replacing the compiler's default described above. For + example, ``--offload-arch=sm_80`` for Clang, ``-foffload=nvptx-none`` for + GCC, or ``-mp=gpu -gpu=cc80`` for NVHPC. The value is a command-line + string, split into arguments as by the ``SHELL:`` prefix of + :command:`target_compile_options`. An empty or whitespace-only value + counts as not set. + Result Variables ^^^^^^^^^^^^^^^^ @@ -203,6 +267,19 @@ using the C language component: find_package(OpenMP) target_link_libraries(project_target PRIVATE OpenMP::OpenMP_C) + +Linking a library whose ``target`` regions may be offloaded to a GPU: + +.. code-block:: cmake + + find_package(OpenMP REQUIRED) + target_link_libraries(kernels PRIVATE OpenMP::OpenMP_CXX_Offload) + +and enabling offload when configuring the build, e.g. with Clang: + +.. code-block:: console + + $ cmake -B build -DOpenMP_CXX_OFFLOAD_FLAGS=--offload-arch=sm_80 #]=======================================================================] cmake_policy(PUSH) @@ -824,6 +901,69 @@ foreach(LANG IN LISTS OpenMP_FINDLIST) set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}") endif() + + if(NOT LANG STREQUAL "CUDA") + if(NOT TARGET OpenMP::OpenMP_${LANG}_Offload) + add_library(OpenMP::OpenMP_${LANG}_Offload INTERFACE IMPORTED) + set_property(TARGET OpenMP::OpenMP_${LANG}_Offload PROPERTY + INTERFACE_LINK_LIBRARIES OpenMP::OpenMP_${LANG}) + endif() + string(STRIP "${OpenMP_${LANG}_OFFLOAD_FLAGS}" _OpenMP_OFFLOAD_FLAGS) + if(DEFINED OpenMP_${LANG}_OFFLOAD) + set(_OpenMP_OFFLOAD "${OpenMP_${LANG}_OFFLOAD}") + elseif(NOT _OpenMP_OFFLOAD_FLAGS STREQUAL "") + set(_OpenMP_OFFLOAD ON) + else() + set(_OpenMP_OFFLOAD OFF) + endif() + # A repeated find_package() with different inputs replaces these + # options rather than adding to them. + set(_OpenMP_COMPILE_OPTIONS "") + set(_OpenMP_LINK_OPTIONS "") + if(_OpenMP_OFFLOAD) + # GCC and Cray need no default: GCC offloads to whichever offload + # compilers are installed, and Cray's wrappers take the device from + # the craype-accel module. + if(_OpenMP_OFFLOAD_FLAGS STREQUAL "" + AND NOT CMAKE_${LANG}_COMPILER_ID MATCHES "^(GNU|Cray|CrayClang)$") + if(CMAKE_${LANG}_COMPILER_ID STREQUAL "NVHPC") + set(_OpenMP_OFFLOAD_FLAGS "-mp=gpu") + elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "IntelLLVM" + AND NOT "x${CMAKE_${LANG}_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC") + set(_OpenMP_OFFLOAD_FLAGS "-fopenmp-targets=spir64") + else() + message(FATAL_ERROR + "OpenMP_${LANG}_OFFLOAD is enabled, but FindOpenMP has no default " + "offload flags for the ${CMAKE_${LANG}_COMPILER_ID} compiler. " + "Set OpenMP_${LANG}_OFFLOAD_FLAGS to select the device, e.g. " + "--offload-arch= for Clang.") + endif() + endif() + # Links by the same compiler family, e.g. a C kernel library in a + # C++ executable, take these flags; another vendor's driver can't. + set(_OpenMP_LINK_DRIVER "$,$,$>") + # The compiler driver only runs the offload link step if it sees + # the OpenMP flags when linking. + string(STRIP "${OpenMP_${LANG}_FLAGS}" _OpenMP_FLAGS) + if(NOT _OpenMP_FLAGS STREQUAL "") + list(APPEND _OpenMP_LINK_OPTIONS "$<${_OpenMP_LINK_DRIVER}:SHELL:${_OpenMP_FLAGS}>") + endif() + if(NOT _OpenMP_OFFLOAD_FLAGS STREQUAL "") + list(APPEND _OpenMP_COMPILE_OPTIONS "$<$:SHELL:${_OpenMP_OFFLOAD_FLAGS}>") + list(APPEND _OpenMP_LINK_OPTIONS "$<${_OpenMP_LINK_DRIVER}:SHELL:${_OpenMP_OFFLOAD_FLAGS}>") + endif() + unset(_OpenMP_FLAGS) + unset(_OpenMP_LINK_DRIVER) + endif() + set_property(TARGET OpenMP::OpenMP_${LANG}_Offload PROPERTY + INTERFACE_COMPILE_OPTIONS "${_OpenMP_COMPILE_OPTIONS}") + set_property(TARGET OpenMP::OpenMP_${LANG}_Offload PROPERTY + INTERFACE_LINK_OPTIONS "${_OpenMP_LINK_OPTIONS}") + unset(_OpenMP_COMPILE_OPTIONS) + unset(_OpenMP_LINK_OPTIONS) + unset(_OpenMP_OFFLOAD_FLAGS) + unset(_OpenMP_OFFLOAD) + endif() endif() endif() endforeach() diff --git a/Tests/FindOpenMP/CMakeLists.txt b/Tests/FindOpenMP/CMakeLists.txt index c8d684aee6..549adc36fd 100644 --- a/Tests/FindOpenMP/CMakeLists.txt +++ b/Tests/FindOpenMP/CMakeLists.txt @@ -26,3 +26,26 @@ endif() if(CMake_TEST_FindOpenMP_FLAG_Fortran) set_property(TEST FindOpenMP.Test APPEND PROPERTY LABELS "Fortran") endif() + +unset(offload_options) +foreach(c C CXX Fortran) + if(CMake_TEST_FindOpenMP_${c}_OFFLOAD) + list(APPEND offload_options -DOpenMP_TEST_OFFLOAD_${c}=1) + if(CMake_TEST_FindOpenMP_${c}_OFFLOAD_FLAGS) + list(APPEND offload_options "-DOpenMP_${c}_OFFLOAD_FLAGS=${CMake_TEST_FindOpenMP_${c}_OFFLOAD_FLAGS}") + endif() + endif() +endforeach() +if(offload_options) + add_test(NAME FindOpenMP.Offload COMMAND + ${CMAKE_CTEST_COMMAND} -C $ + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindOpenMP/Offload" + "${CMake_BINARY_DIR}/Tests/FindOpenMP/Offload" + ${build_generator_args} + --build-project TestFindOpenMPOffload + --build-options ${build_options} ${offload_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $ + ) + set_property(TEST FindOpenMP.Offload APPEND PROPERTY LABELS "OpenMPOffload") +endif() diff --git a/Tests/FindOpenMP/Offload/CMakeLists.txt b/Tests/FindOpenMP/Offload/CMakeLists.txt new file mode 100644 index 0000000000..0fa4e42e5b --- /dev/null +++ b/Tests/FindOpenMP/Offload/CMakeLists.txt @@ -0,0 +1,79 @@ +cmake_minimum_required(VERSION 4.0) +project(TestFindOpenMPOffload NONE) +include(CTest) + +foreach(c C CXX Fortran) + if(OpenMP_TEST_OFFLOAD_${c}) + enable_language(${c}) + list(APPEND langs ${c}) + # Offload is enabled here as a builder would; the targets below opt in + # by linking the offload target. + set(OpenMP_${c}_OFFLOAD ON) + endif() +endforeach() + +find_package(OpenMP REQUIRED COMPONENTS ${langs}) + +set(main_C main.c) +set(offload_C offload.c) +if("CXX" IN_LIST langs) + configure_file(main.c main.cxx COPYONLY) + configure_file(offload.c offload.cxx COPYONLY) + set(main_CXX ${CMAKE_CURRENT_BINARY_DIR}/main.cxx) + set(offload_CXX ${CMAKE_CURRENT_BINARY_DIR}/offload.cxx) +endif() +if("Fortran" IN_LIST langs) + if(OpenMP_Fortran_HAVE_OMPLIB_MODULE) + set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none") + else() + set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'") + endif() + configure_file(offload.f90.in offload.f90 @ONLY) + set(main_Fortran main.f90) + set(offload_Fortran ${CMAKE_CURRENT_BINARY_DIR}/offload.f90) +endif() + +# Each compiler handles the offload flags for its own language. +foreach(c IN LISTS langs) + add_executable(offload_exe_${c} ${main_${c}} ${offload_${c}}) + target_link_libraries(offload_exe_${c} PRIVATE OpenMP::OpenMP_${c}_Offload) + list(APPEND tests exe_${c}) +endforeach() + +# How the flags reach the link that embeds the device code doesn't depend +# on the language, so the library layouts are only built for C. +if("C" IN_LIST langs) + # Static library: the flags reach the executable's link through the + # library's usage requirements. + add_library(offload_lib STATIC offload.c) + target_link_libraries(offload_lib PRIVATE OpenMP::OpenMP_C_Offload) + add_executable(offload_static main.c) + target_link_libraries(offload_static PRIVATE offload_lib) + + # Shared library: its own link embeds the device code. + add_library(offload_dso SHARED offload.c) + target_link_libraries(offload_dso PRIVATE OpenMP::OpenMP_C_Offload) + add_executable(offload_shared main.c) + target_link_libraries(offload_shared PRIVATE offload_dso) + if(CMAKE_C_COMPILER_ID STREQUAL "NVHPC") + # Without -mp=gpu, NVHPC links host-only stubs of its GPU runtime into + # the executable, and they shadow the ones the library needs. + target_link_libraries(offload_shared PRIVATE + "$") + endif() + + list(APPEND tests static shared) + + if("CXX" IN_LIST langs AND CMAKE_C_COMPILER_ID STREQUAL CMAKE_CXX_COMPILER_ID) + # C kernel library linked by the C++ compiler driver. + add_executable(offload_mixed ${main_CXX}) + target_link_libraries(offload_mixed PRIVATE offload_lib) + list(APPEND tests mixed) + endif() +endif() + +foreach(t IN LISTS tests) + add_test(NAME offload_${t} COMMAND offload_${t}) + # A silent fallback to the host fails the test instead of passing it. + set_property(TEST offload_${t} PROPERTY ENVIRONMENT OMP_TARGET_OFFLOAD=MANDATORY) +endforeach() diff --git a/Tests/FindOpenMP/Offload/main.c b/Tests/FindOpenMP/Offload/main.c new file mode 100644 index 0000000000..5aa4a7a749 --- /dev/null +++ b/Tests/FindOpenMP/Offload/main.c @@ -0,0 +1,10 @@ +#ifdef __cplusplus +extern "C" +#endif + int + offload_check(void); + +int main(void) +{ + return offload_check(); +} diff --git a/Tests/FindOpenMP/Offload/main.f90 b/Tests/FindOpenMP/Offload/main.f90 new file mode 100644 index 0000000000..49c1d400fa --- /dev/null +++ b/Tests/FindOpenMP/Offload/main.f90 @@ -0,0 +1,5 @@ + program main + implicit none + integer, external :: offload_check + if (offload_check() /= 0) error stop 1 + end program main diff --git a/Tests/FindOpenMP/Offload/offload.c b/Tests/FindOpenMP/Offload/offload.c new file mode 100644 index 0000000000..499c14d19f --- /dev/null +++ b/Tests/FindOpenMP/Offload/offload.c @@ -0,0 +1,20 @@ +#include + +#ifdef __cplusplus +extern "C" +#endif + int + offload_check(void) +{ + int i; + int on_host = 1; + int sum = 0; +#pragma omp target map(tofrom : on_host, sum) + { + on_host = omp_is_initial_device(); + for (i = 1; i <= 10; ++i) { + sum += i; + } + } + return on_host || sum != 55; +} diff --git a/Tests/FindOpenMP/Offload/offload.f90.in b/Tests/FindOpenMP/Offload/offload.f90.in new file mode 100644 index 0000000000..23e9bd30ef --- /dev/null +++ b/Tests/FindOpenMP/Offload/offload.f90.in @@ -0,0 +1,15 @@ + integer function offload_check() + @OpenMP_Fortran_INCLUDE_LINE@ + integer :: i, s + logical :: on_host + on_host = .true. + s = 0 +!$omp target map(tofrom: on_host, s) + on_host = omp_is_initial_device() + do i = 1, 10 + s = s + i + end do +!$omp end target + offload_check = 0 + if (on_host .or. s /= 55) offload_check = 1 + end function offload_check diff --git a/Tests/FindOpenMP/Test/CMakeLists.txt b/Tests/FindOpenMP/Test/CMakeLists.txt index 9aee098129..ba8cd92e3e 100644 --- a/Tests/FindOpenMP/Test/CMakeLists.txt +++ b/Tests/FindOpenMP/Test/CMakeLists.txt @@ -54,7 +54,7 @@ if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_SIMULATE_ID STREQUAL "MSVC") endif() endif() -# FIXME(#26701) Needed to check target offload conditions +# Cray needs the OpenMP flags at link time to use its offload linker foreach(c C CXX Fortran) if(NOT "${OpenMP_TEST_${c}}") continue() diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 5d10fbf18c..85cd803fdc 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -558,6 +558,11 @@ if(CMake_TEST_FindRuby) ) endif() add_RunCMake_test(FindOpenGL) +if(CMake_TEST_FindOpenMP_C AND CMake_TEST_FindOpenMP_CXX + AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$" + AND NOT WIN32 AND CMAKE_GENERATOR MATCHES "Make|Ninja") + add_RunCMake_test(FindOpenMP -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}) +endif() add_RunCMake_test(FindTclStub) add_RunCMake_test(InitialFlags) if(CMake_TEST_FindOpenSSL) diff --git a/Tests/RunCMake/FindOpenMP/CMakeLists.txt b/Tests/RunCMake/FindOpenMP/CMakeLists.txt new file mode 100644 index 0000000000..8a40c227d5 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 4.0) +project(${RunCMake_TEST} C CXX) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/FindOpenMP/FlagsImplyOn-build-check.cmake b/Tests/RunCMake/FindOpenMP/FlagsImplyOn-build-check.cmake new file mode 100644 index 0000000000..40ba743953 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/FlagsImplyOn-build-check.cmake @@ -0,0 +1,5 @@ +set(mark MARK_A) +set(link_omp exe static mixed) +set(link_mark exe static mixed) +set(compile_mark exe lib) +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/FlagsImplyOn.cmake b/Tests/RunCMake/FindOpenMP/FlagsImplyOn.cmake new file mode 100644 index 0000000000..44c9e69479 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/FlagsImplyOn.cmake @@ -0,0 +1,2 @@ +set(OpenMP_C_OFFLOAD_FLAGS -DMARK_A) +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) diff --git a/Tests/RunCMake/FindOpenMP/NoDefault-result.txt b/Tests/RunCMake/FindOpenMP/NoDefault-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/NoDefault-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/FindOpenMP/NoDefault-stderr.txt b/Tests/RunCMake/FindOpenMP/NoDefault-stderr.txt new file mode 100644 index 0000000000..1d7f644c6c --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/NoDefault-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at [^ +]*/FindOpenMP\.cmake:[0-9]+ \(message\): + OpenMP_C_OFFLOAD is enabled, but FindOpenMP has no default offload flags + for the [A-Za-z]+ compiler\. diff --git a/Tests/RunCMake/FindOpenMP/NoDefault.cmake b/Tests/RunCMake/FindOpenMP/NoDefault.cmake new file mode 100644 index 0000000000..e098626228 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/NoDefault.cmake @@ -0,0 +1,2 @@ +set(OpenMP_C_OFFLOAD ON) +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) diff --git a/Tests/RunCMake/FindOpenMP/Off-build-check.cmake b/Tests/RunCMake/FindOpenMP/Off-build-check.cmake new file mode 100644 index 0000000000..48ea2bd011 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/Off-build-check.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/Off.cmake b/Tests/RunCMake/FindOpenMP/Off.cmake new file mode 100644 index 0000000000..67462df466 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/Off.cmake @@ -0,0 +1,3 @@ +set(OpenMP_C_OFFLOAD OFF) +set(OpenMP_C_OFFLOAD_FLAGS -DMARK_A) +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) diff --git a/Tests/RunCMake/FindOpenMP/OffEmpty-build-check.cmake b/Tests/RunCMake/FindOpenMP/OffEmpty-build-check.cmake new file mode 100644 index 0000000000..48ea2bd011 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/OffEmpty-build-check.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/OffEmpty.cmake b/Tests/RunCMake/FindOpenMP/OffEmpty.cmake new file mode 100644 index 0000000000..11aa82ba3c --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/OffEmpty.cmake @@ -0,0 +1,3 @@ +set(OpenMP_C_OFFLOAD "") +set(OpenMP_C_OFFLOAD_FLAGS -DMARK_A) +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) diff --git a/Tests/RunCMake/FindOpenMP/Offload-common.cmake b/Tests/RunCMake/FindOpenMP/Offload-common.cmake new file mode 100644 index 0000000000..eb69e7038c --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/Offload-common.cmake @@ -0,0 +1,17 @@ +find_package(OpenMP REQUIRED COMPONENTS C CXX) + +add_executable(exe main.c) +target_link_libraries(exe PRIVATE OpenMP::OpenMP_C_Offload) + +add_library(lib STATIC lib.c) +target_link_libraries(lib PRIVATE OpenMP::OpenMP_C_Offload) +add_executable(static main.c) +target_link_libraries(static PRIVATE lib) +add_executable(mixed main.cxx) +target_link_libraries(mixed PRIVATE lib) + +# Not opted in, so these get no offload flags. +add_executable(hostc main.c) +target_link_libraries(hostc PRIVATE OpenMP::OpenMP_C) +add_executable(host main.cxx) +target_link_libraries(host PRIVATE OpenMP::OpenMP_CXX) diff --git a/Tests/RunCMake/FindOpenMP/RefindFlags-build-check.cmake b/Tests/RunCMake/FindOpenMP/RefindFlags-build-check.cmake new file mode 100644 index 0000000000..4075363a52 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/RefindFlags-build-check.cmake @@ -0,0 +1,5 @@ +set(mark MARK_B) +set(link_omp exe static mixed) +set(link_mark exe static mixed) +set(compile_mark exe lib) +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/RefindFlags.cmake b/Tests/RunCMake/FindOpenMP/RefindFlags.cmake new file mode 100644 index 0000000000..81ec6c4792 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/RefindFlags.cmake @@ -0,0 +1,5 @@ +set(OpenMP_C_OFFLOAD_FLAGS -DMARK_A) +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) + +set(OpenMP_C_OFFLOAD_FLAGS -DMARK_B) +find_package(OpenMP REQUIRED COMPONENTS C CXX) diff --git a/Tests/RunCMake/FindOpenMP/RefindOff-build-check.cmake b/Tests/RunCMake/FindOpenMP/RefindOff-build-check.cmake new file mode 100644 index 0000000000..48ea2bd011 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/RefindOff-build-check.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/RefindOff.cmake b/Tests/RunCMake/FindOpenMP/RefindOff.cmake new file mode 100644 index 0000000000..4834cdf631 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/RefindOff.cmake @@ -0,0 +1,5 @@ +set(OpenMP_C_OFFLOAD_FLAGS -DMARK_A) +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) + +set(OpenMP_C_OFFLOAD OFF) +find_package(OpenMP REQUIRED COMPONENTS C CXX) diff --git a/Tests/RunCMake/FindOpenMP/RunCMakeTest.cmake b/Tests/RunCMake/FindOpenMP/RunCMakeTest.cmake new file mode 100644 index 0000000000..72073ca91d --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/RunCMakeTest.cmake @@ -0,0 +1,21 @@ +include(RunCMake) + +function(run_offload_build case) + run_cmake(${case}) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --verbose) +endfunction() + +run_offload_build(FlagsImplyOn) +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + run_offload_build(SwitchOn) +else() + run_cmake(NoDefault) +endif() +run_offload_build(Off) +run_offload_build(OffEmpty) +run_offload_build(Unset) +run_offload_build(WhitespaceFlags) +run_offload_build(RefindFlags) +run_offload_build(RefindOff) diff --git a/Tests/RunCMake/FindOpenMP/SwitchOn-build-check.cmake b/Tests/RunCMake/FindOpenMP/SwitchOn-build-check.cmake new file mode 100644 index 0000000000..0bd8e0409a --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/SwitchOn-build-check.cmake @@ -0,0 +1,2 @@ +set(link_omp exe static mixed) +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/SwitchOn.cmake b/Tests/RunCMake/FindOpenMP/SwitchOn.cmake new file mode 100644 index 0000000000..e098626228 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/SwitchOn.cmake @@ -0,0 +1,2 @@ +set(OpenMP_C_OFFLOAD ON) +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) diff --git a/Tests/RunCMake/FindOpenMP/Unset-build-check.cmake b/Tests/RunCMake/FindOpenMP/Unset-build-check.cmake new file mode 100644 index 0000000000..48ea2bd011 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/Unset-build-check.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/Unset.cmake b/Tests/RunCMake/FindOpenMP/Unset.cmake new file mode 100644 index 0000000000..c265ca1c27 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/Unset.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) diff --git a/Tests/RunCMake/FindOpenMP/WhitespaceFlags-build-check.cmake b/Tests/RunCMake/FindOpenMP/WhitespaceFlags-build-check.cmake new file mode 100644 index 0000000000..48ea2bd011 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/WhitespaceFlags-build-check.cmake @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/check-flags.cmake) diff --git a/Tests/RunCMake/FindOpenMP/WhitespaceFlags.cmake b/Tests/RunCMake/FindOpenMP/WhitespaceFlags.cmake new file mode 100644 index 0000000000..98b98500e3 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/WhitespaceFlags.cmake @@ -0,0 +1,2 @@ +set(OpenMP_C_OFFLOAD_FLAGS " ") +include(${CMAKE_CURRENT_LIST_DIR}/Offload-common.cmake) diff --git a/Tests/RunCMake/FindOpenMP/check-flags.cmake b/Tests/RunCMake/FindOpenMP/check-flags.cmake new file mode 100644 index 0000000000..d0d85e7182 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/check-flags.cmake @@ -0,0 +1,60 @@ +# Checks the verbose build output against these lists of targets: +# link_omp - link line has the OpenMP flag +# link_mark - link line has ${mark} +# compile_mark - compile line has ${mark} +# Other targets lack them, and no other marker appears. + +string(REPLACE ";" "," out "${actual_stdout}") +string(REPLACE "\n" ";" lines "${out}") + +function(check_line kind t line what pattern want) + list(FIND ${want} "${t}" i) + if(line MATCHES "${pattern}") + if(i EQUAL -1) + string(APPEND msg "${kind} line of '${t}' has ${what} but should not:\n ${line}\n") + endif() + elseif(NOT i EQUAL -1) + string(APPEND msg "${kind} line of '${t}' lacks ${what}:\n ${line}\n") + endif() + set(msg "${msg}" PARENT_SCOPE) +endfunction() + +set(msg "") +foreach(t IN ITEMS exe lib static mixed hostc host) + set(compile "") + set(link "") + foreach(l IN LISTS lines) + if(l MATCHES " -o CMakeFiles/${t}\\.dir/[^ ]+ -c ") + set(compile "${l}") + elseif(l MATCHES " -o ([^ ]*/)?${t}( |$)") + set(link "${l}") + endif() + endforeach() + if(compile STREQUAL "") + string(APPEND msg "No compile line for '${t}'.\n") + elseif(mark) + check_line(Compile ${t} "${compile}" "${mark}" "-D${mark}( |$)" compile_mark) + endif() + # The static library is archived, not linked. + if(t STREQUAL "lib") + continue() + endif() + if(link STREQUAL "") + string(APPEND msg "No link line for '${t}'.\n") + continue() + endif() + check_line(Link ${t} "${link}" "the OpenMP flag" "fopenmp" link_omp) + if(mark) + check_line(Link ${t} "${link}" "${mark}" "-D${mark}( |$)" link_mark) + endif() +endforeach() + +foreach(m IN ITEMS MARK_A MARK_B) + if(NOT m STREQUAL "${mark}" AND actual_stdout MATCHES "-D${m}") + string(APPEND msg "Unexpected ${m} in the build output.\n") + endif() +endforeach() + +if(msg) + set(RunCMake_TEST_FAILED "${msg}") +endif() diff --git a/Tests/RunCMake/FindOpenMP/lib.c b/Tests/RunCMake/FindOpenMP/lib.c new file mode 100644 index 0000000000..abe3b787c6 --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/lib.c @@ -0,0 +1,4 @@ +int lib(void) +{ + return 0; +} diff --git a/Tests/RunCMake/FindOpenMP/main.c b/Tests/RunCMake/FindOpenMP/main.c new file mode 100644 index 0000000000..8488f4e58f --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/FindOpenMP/main.cxx b/Tests/RunCMake/FindOpenMP/main.cxx new file mode 100644 index 0000000000..f8b643afbf --- /dev/null +++ b/Tests/RunCMake/FindOpenMP/main.cxx @@ -0,0 +1,4 @@ +int main() +{ + return 0; +}