FindOpenMP: Add support for CUDA when supported by the toolchain

NVCC supports OpenMP on the host when the host compiler does.
This commit is contained in:
Brad King
2024-09-27 16:38:44 -04:00
parent f8ed4d7c21
commit 8f4cea94da
5 changed files with 56 additions and 14 deletions

View File

@@ -1,5 +1,7 @@
set(CMake_TEST_CUDA "NVIDIA" CACHE STRING "") set(CMake_TEST_CUDA "NVIDIA" CACHE STRING "")
set(CMake_TEST_CUDA_CUPTI "ON" CACHE STRING "") set(CMake_TEST_CUDA_CUPTI "ON" CACHE STRING "")
set(CMake_TEST_CUDA_STANDARDS "03;11;14;17;20" CACHE STRING "") set(CMake_TEST_CUDA_STANDARDS "03;11;14;17;20" CACHE STRING "")
set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
set(CMake_TEST_FindOpenMP_CUDA "ON" CACHE BOOL "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake") include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

View File

@@ -0,0 +1,5 @@
FindOpenMP-CUDA
---------------
* The :module:`FindOpenMP` module gained support for ``CUDA`` when using
a CUDA compiler that supports OpenMP on the host.

View File

@@ -37,6 +37,10 @@ Result Variables
The module exposes the components ``C``, ``CXX``, and ``Fortran``. The module exposes the components ``C``, ``CXX``, and ``Fortran``.
Each of these controls the various languages to search OpenMP support for. Each of these controls the various languages to search OpenMP support for.
.. versionadded:: 3.31
The ``CUDA`` language component is supported when using a CUDA compiler
that supports OpenMP on the host.
Depending on the enabled components the following variables will be set: Depending on the enabled components the following variables will be set:
``OpenMP_FOUND`` ``OpenMP_FOUND``
@@ -48,7 +52,7 @@ Depending on the enabled components the following variables will be set:
or all enabled languages if no components were specified. or all enabled languages if no components were specified.
This module will set the following variables per language in your This module will set the following variables per language in your
project, where ``<lang>`` is one of C, CXX, or Fortran: project, where ``<lang>`` is one of C, CXX, CUDA, or Fortran:
``OpenMP_<lang>_FOUND`` ``OpenMP_<lang>_FOUND``
Variable indicating if OpenMP support for ``<lang>`` was detected. Variable indicating if OpenMP support for ``<lang>`` was detected.
@@ -153,7 +157,11 @@ function(_OPENMP_FLAG_CANDIDATES LANG)
set(OMP_FLAG_Fujitsu "-Kopenmp" "-KOMP") set(OMP_FLAG_Fujitsu "-Kopenmp" "-KOMP")
set(OMP_FLAG_FujitsuClang "-fopenmp" "-Kopenmp") set(OMP_FLAG_FujitsuClang "-fopenmp" "-Kopenmp")
set(compiler_id "${CMAKE_${LANG}_COMPILER_ID}") if(CMAKE_${LANG}_COMPILER_ID STREQUAL "NVIDIA" AND CMAKE_${LANG}_HOST_COMPILER_ID)
set(compiler_id "${CMAKE_${LANG}_HOST_COMPILER_ID}")
else()
set(compiler_id "${CMAKE_${LANG}_COMPILER_ID}")
endif()
# If we know the correct flags, use those # If we know the correct flags, use those
if(DEFINED OMP_FLAG_${compiler_id}) if(DEFINED OMP_FLAG_${compiler_id})
@@ -206,6 +214,9 @@ macro(_OPENMP_PREPARE_SOURCE LANG CONTENT_ID NAME_PREFIX FULLNAME_VAR CONTENT_VA
elseif("${LANG}" STREQUAL "CXX") elseif("${LANG}" STREQUAL "CXX")
set(${FULLNAME_VAR} "${NAME_PREFIX}.cpp") set(${FULLNAME_VAR} "${NAME_PREFIX}.cpp")
set(${CONTENT_VAR} "${OpenMP_C_CXX_${CONTENT_ID}}") set(${CONTENT_VAR} "${OpenMP_C_CXX_${CONTENT_ID}}")
elseif("${LANG}" STREQUAL "CUDA")
set(${FULLNAME_VAR} "${NAME_PREFIX}.cu")
set(${CONTENT_VAR} "${OpenMP_C_CXX_${CONTENT_ID}}")
elseif("${LANG}" STREQUAL "Fortran") elseif("${LANG}" STREQUAL "Fortran")
set(${FULLNAME_VAR} "${NAME_PREFIX}.F90") set(${FULLNAME_VAR} "${NAME_PREFIX}.F90")
string(CONFIGURE "${OpenMP_Fortran_${CONTENT_ID}}" ${CONTENT_VAR} @ONLY) string(CONFIGURE "${OpenMP_Fortran_${CONTENT_ID}}" ${CONTENT_VAR} @ONLY)
@@ -227,11 +238,24 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
if(OpenMP_${LANG}_INCLUDE_DIR) if(OpenMP_${LANG}_INCLUDE_DIR)
set(_includeDirFlags "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}") set(_includeDirFlags "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}")
endif() endif()
if(CMAKE_${LANG}_COMPILER_ID STREQUAL "NVIDIA")
# With NVCC we drive linking directly through the host compiler, but
# without language-wide flags since they may be specific to nvcc.
# Pass the candidate OpenMP flag to the host compiler when linking.
set(_OpenMP_LINK_OPTIONS "${OPENMP_FLAG}")
# Exclude CUDA runtime libraries that we may add ourselves.
# See the Compiler/NVIDIA module. Do not exclude pthread,
# as that is typically a dependency of OpenMP too.
set(_OpenMP_EXCLUDE_IMPLICIT_LIBS cudart cudart_static cudadevrt rt dl)
else()
set(_OpenMP_LINK_OPTIONS "")
set(_OpenMP_EXCLUDE_IMPLICIT_LIBS "")
endif()
try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}
SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT SOURCE_FROM_VAR "${_OPENMP_TEST_SRC_NAME}" _OPENMP_TEST_SRC_CONTENT
LOG_DESCRIPTION "Detecting ${LANG} OpenMP compiler info" LOG_DESCRIPTION "Detecting ${LANG} OpenMP compiler info"
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAG}" ${_includeDirFlags} CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAG}" ${_includeDirFlags}
LINK_OPTIONS ${OpenMP_VERBOSE_OPTIONS} LINK_OPTIONS ${OpenMP_VERBOSE_OPTIONS} ${_OpenMP_LINK_OPTIONS}
OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT
) )
@@ -282,6 +306,7 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}") string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}")
string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}") string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}")
if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES
OR "${_OPENMP_IMPLICIT_LIB}" IN_LIST _OpenMP_EXCLUDE_IMPLICIT_LIBS
OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)"
OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) ) OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) )
if(_OPENMP_IMPLICIT_LIB_DIR) if(_OPENMP_IMPLICIT_LIB_DIR)
@@ -302,6 +327,9 @@ function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR)
list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN}) list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN})
endif() endif()
endforeach() endforeach()
list(REVERSE _OPENMP_LIB_NAMES)
list(REMOVE_DUPLICATES _OPENMP_LIB_NAMES)
list(REVERSE _OPENMP_LIB_NAMES)
set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE) set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE)
else() else()
# We do not know how to extract implicit OpenMP libraries for this compiler. # We do not know how to extract implicit OpenMP libraries for this compiler.
@@ -489,7 +517,7 @@ macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG)
unset(OpenMP_SPEC_DATE_MAP) unset(OpenMP_SPEC_DATE_MAP)
endmacro() endmacro()
foreach(LANG IN ITEMS C CXX) foreach(LANG IN ITEMS C CXX CUDA)
if(CMAKE_${LANG}_COMPILER_LOADED) if(CMAKE_${LANG}_COMPILER_LOADED)
if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND" if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND"
OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND") OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND")
@@ -555,7 +583,7 @@ if(CMAKE_Fortran_COMPILER_LOADED)
endif() endif()
if(NOT OpenMP_FIND_COMPONENTS) if(NOT OpenMP_FIND_COMPONENTS)
set(OpenMP_FINDLIST C CXX Fortran) set(OpenMP_FINDLIST C CXX CUDA Fortran)
else() else()
set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS}) set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS})
endif() endif()
@@ -634,7 +662,7 @@ foreach(LANG IN LISTS OpenMP_FINDLIST)
endforeach() endforeach()
unset(_OpenMP_REQ_VARS) unset(_OpenMP_REQ_VARS)
foreach(LANG IN ITEMS C CXX Fortran) foreach(LANG IN ITEMS C CXX CUDA Fortran)
if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS) if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS)
list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND") list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND")
endif() endif()
@@ -656,8 +684,8 @@ if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND)
endif() endif()
endif() endif()
if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED )) if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_CUDA_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED ))
message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled") message(SEND_ERROR "FindOpenMP requires the C, CXX, CUDA, or Fortran languages to be enabled")
endif() endif()
unset(OpenMP_C_CXX_TEST_SOURCE) unset(OpenMP_C_CXX_TEST_SOURCE)

View File

@@ -1,4 +1,4 @@
foreach(c C CXX Fortran) foreach(c C CXX CUDA Fortran)
if(CMake_TEST_FindOpenMP_${c}) if(CMake_TEST_FindOpenMP_${c})
set(CMake_TEST_FindOpenMP_FLAG_${c} 1) set(CMake_TEST_FindOpenMP_FLAG_${c} 1)
else() else()
@@ -16,9 +16,13 @@ add_test(NAME FindOpenMP.Test COMMAND
--build-options ${build_options} --build-options ${build_options}
-DOpenMP_TEST_C=${CMake_TEST_FindOpenMP_FLAG_C} -DOpenMP_TEST_C=${CMake_TEST_FindOpenMP_FLAG_C}
-DOpenMP_TEST_CXX=${CMake_TEST_FindOpenMP_FLAG_CXX} -DOpenMP_TEST_CXX=${CMake_TEST_FindOpenMP_FLAG_CXX}
-DOpenMP_TEST_CUDA=${CMake_TEST_FindOpenMP_FLAG_CUDA}
-DOpenMP_TEST_Fortran=${CMake_TEST_FindOpenMP_FLAG_Fortran} -DOpenMP_TEST_Fortran=${CMake_TEST_FindOpenMP_FLAG_Fortran}
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
) )
if(CMake_TEST_FindOpenMP_FLAG_CUDA)
set_property(TEST FindOpenMP.Test APPEND PROPERTY LABELS "CUDA")
endif()
if(CMake_TEST_FindOpenMP_FLAG_Fortran) if(CMake_TEST_FindOpenMP_FLAG_Fortran)
set_property(TEST FindOpenMP.Test APPEND PROPERTY LABELS "Fortran") set_property(TEST FindOpenMP.Test APPEND PROPERTY LABELS "Fortran")
endif() endif()

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12) cmake_minimum_required(VERSION 3.30)
project(TestFindOpenMP NONE) project(TestFindOpenMP NONE)
include(CTest) include(CTest)
@@ -8,6 +8,9 @@ macro(source_code_mapper_helper LANG_NAME SRC_FILE_NAME)
elseif("${LANG_NAME}" STREQUAL "CXX") elseif("${LANG_NAME}" STREQUAL "CXX")
configure_file("${SRC_FILE_NAME}.c" "${SRC_FILE_NAME}.cxx" COPYONLY) configure_file("${SRC_FILE_NAME}.c" "${SRC_FILE_NAME}.cxx" COPYONLY)
set(OpenMPTEST_SOURCE_FILE "${SRC_FILE_NAME}.cxx") set(OpenMPTEST_SOURCE_FILE "${SRC_FILE_NAME}.cxx")
elseif("${LANG_NAME}" STREQUAL "CUDA")
configure_file("${SRC_FILE_NAME}.c" "${SRC_FILE_NAME}.cu" COPYONLY)
set(OpenMPTEST_SOURCE_FILE "${SRC_FILE_NAME}.cu")
elseif("${LANG_NAME}" STREQUAL "Fortran") elseif("${LANG_NAME}" STREQUAL "Fortran")
set(OpenMPTEST_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE_NAME}.f90") set(OpenMPTEST_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE_NAME}.f90")
if(OpenMP_Fortran_HAVE_OMPLIB_MODULE) if(OpenMP_Fortran_HAVE_OMPLIB_MODULE)
@@ -19,7 +22,7 @@ macro(source_code_mapper_helper LANG_NAME SRC_FILE_NAME)
endif() endif()
endmacro() endmacro()
foreach(c C CXX Fortran) foreach(c C CXX CUDA Fortran)
if("${OpenMP_TEST_${c}}") if("${OpenMP_TEST_${c}}")
message("Testing ${c}") message("Testing ${c}")
enable_language(${c}) enable_language(${c})
@@ -41,7 +44,7 @@ if(test_msvc_runtime)
endif() endif()
endif() endif()
foreach(c C CXX Fortran) foreach(c C CXX CUDA Fortran)
if(NOT "${OpenMP_TEST_${c}}") if(NOT "${OpenMP_TEST_${c}}")
continue() continue()
endif() endif()
@@ -65,11 +68,11 @@ foreach(c C CXX Fortran)
set_property(TARGET scalprod_${c} PROPERTY LINKER_LANGUAGE ${c}) set_property(TARGET scalprod_${c} PROPERTY LINKER_LANGUAGE ${c})
endforeach() endforeach()
foreach(c C CXX Fortran) foreach(c C CXX CUDA Fortran)
if(NOT "${OpenMP_TEST_${c}}") if(NOT "${OpenMP_TEST_${c}}")
continue() continue()
endif() endif()
foreach(d C CXX Fortran) foreach(d C CXX CUDA Fortran)
if(NOT "${OpenMP_TEST_${d}}") if(NOT "${OpenMP_TEST_${d}}")
continue() continue()
endif() endif()