SET(Kokkos_DEVICES @KOKKOS_ENABLED_DEVICES@) SET(Kokkos_OPTIONS @KOKKOS_ENABLED_OPTIONS@) SET(Kokkos_TPLS @KOKKOS_ENABLED_TPLS@) SET(Kokkos_ARCH @KOKKOS_ENABLED_ARCH_LIST@) SET(Kokkos_CXX_COMPILER "@CMAKE_CXX_COMPILER@") SET(Kokkos_CXX_COMPILER_ID "@KOKKOS_CXX_COMPILER_ID@") # These are needed by KokkosKernels FOREACH(DEV ${Kokkos_DEVICES}) SET(Kokkos_ENABLE_${DEV} ON) ENDFOREACH() IF(NOT Kokkos_FIND_QUIETLY) MESSAGE(STATUS "Enabled Kokkos devices: ${Kokkos_DEVICES}") ENDIF() IF (Kokkos_ENABLE_CUDA) # If we are building CUDA, we have tricked CMake because we declare a CXX project # If the default C++ standard for a given compiler matches the requested # standard, then CMake just omits the -std flag in later versions of CMake # This breaks CUDA compilation (CUDA compiler can have a different default # -std then the underlying host compiler by itself). Setting this variable # forces CMake to always add the -std flag even if it thinks it doesn't need it SET(CMAKE_CXX_STANDARD_DEFAULT 98 CACHE INTERNAL "" FORCE) ENDIF() SET(KOKKOS_USE_CXX_EXTENSIONS @KOKKOS_USE_CXX_EXTENSIONS@) IF (NOT DEFINED CMAKE_CXX_EXTENSIONS OR CMAKE_CXX_EXTENSIONS) IF (NOT KOKKOS_USE_CXX_EXTENSIONS) MESSAGE(WARNING "The installed Kokkos configuration does not support CXX extensions. Forcing -DCMAKE_CXX_EXTENSIONS=Off") SET(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "" FORCE) ENDIF() ENDIF() include(FindPackageHandleStandardArgs) # This function makes sure that Kokkos was built with the requested backends # and target architectures and generates a fatal error if it was not. # # kokkos_check( # [DEVICES ...] # Set of backends (e.g. "OpenMP" and/or "Cuda") # [ARCH ...] # Target architectures (e.g. "Power9" and/or "Volta70") # [OPTIONS ...] # Optional settings (e.g. "TUNING") # [TPLS ...] # Third party libraries # [RETURN_VALUE ] # Set a variable that indicates the result of the # # check instead of a fatal error # ) function(kokkos_check) set(ALLOWED_ARGS DEVICES ARCH OPTIONS TPLS) cmake_parse_arguments(KOKKOS_CHECK "" "RETURN_VALUE" "${ALLOWED_ARGS}" ${ARGN}) foreach(_arg ${KOKKOS_CHECK_UNPARSED_ARGUMENTS}) message(SEND_ERROR "Argument '${_arg}' passed to kokkos_check() was not recognized") endforeach() # Get the list of keywords that were actually passed to the function. set(REQUESTED_ARGS) foreach(arg ${ALLOWED_ARGS}) if(KOKKOS_CHECK_${arg}) list(APPEND REQUESTED_ARGS ${arg}) endif() endforeach() set(KOKKOS_CHECK_SUCCESS TRUE) foreach(arg ${REQUESTED_ARGS}) # Define variables named after the required arguments that are provided by # the Kokkos install. foreach(requested ${KOKKOS_CHECK_${arg}}) foreach(provided ${Kokkos_${arg}}) STRING(TOUPPER ${requested} REQUESTED_UC) STRING(TOUPPER ${provided} PROVIDED_UC) if(PROVIDED_UC STREQUAL REQUESTED_UC) string(REPLACE ";" " " ${requested} "${KOKKOS_CHECK_${arg}}") endif() endforeach() endforeach() # Somewhat divert the CMake function below from its original purpose and # use it to check that there are variables defined for all required # arguments. Success or failure messages will be displayed but we are # responsible for signaling failure and skip the build system generation. if (KOKKOS_CHECK_RETURN_VALUE) set(Kokkos_${arg}_FIND_QUIETLY ON) endif() find_package_handle_standard_args("Kokkos_${arg}" DEFAULT_MSG ${KOKKOS_CHECK_${arg}}) if(NOT Kokkos_${arg}_FOUND) set(KOKKOS_CHECK_SUCCESS FALSE) endif() endforeach() if(NOT KOKKOS_CHECK_SUCCESS AND NOT KOKKOS_CHECK_RETURN_VALUE) message(FATAL_ERROR "Kokkos does NOT provide all backends and/or architectures requested") else() set(${KOKKOS_CHECK_RETURN_VALUE} ${KOKKOS_CHECK_SUCCESS} PARENT_SCOPE) endif() endfunction() # A test to check whether a downstream project set the C++ compiler to NVCC or not # this is called only when Kokkos was installed with Kokkos_ENABLE_CUDA=ON FUNCTION(kokkos_compiler_is_nvcc VAR COMPILER) # Check if the compiler is nvcc (which really means nvcc_wrapper). EXECUTE_PROCESS(COMMAND ${COMPILER} ${ARGN} --version OUTPUT_VARIABLE INTERNAL_COMPILER_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE RET) # something went wrong IF(RET GREATER 0) SET(${VAR} false PARENT_SCOPE) ELSE() STRING(REPLACE "\n" " - " INTERNAL_COMPILER_VERSION_ONE_LINE ${INTERNAL_COMPILER_VERSION} ) STRING(FIND ${INTERNAL_COMPILER_VERSION_ONE_LINE} "nvcc" INTERNAL_COMPILER_VERSION_CONTAINS_NVCC) STRING(REGEX REPLACE "^ +" "" INTERNAL_HAVE_COMPILER_NVCC "${INTERNAL_HAVE_COMPILER_NVCC}") IF(${INTERNAL_COMPILER_VERSION_CONTAINS_NVCC} GREATER -1) SET(${VAR} true PARENT_SCOPE) ELSE() SET(${VAR} false PARENT_SCOPE) ENDIF() ENDIF() ENDFUNCTION() # this function checks whether the current CXX compiler supports building CUDA FUNCTION(kokkos_cxx_compiler_cuda_test _VAR _COMPILER) FILE(WRITE ${PROJECT_BINARY_DIR}/compile_tests/compiles_cuda.cu " #include #include __global__ void kernel(int sz, double* data) { int _beg = blockIdx.x * blockDim.x + threadIdx.x; for(int i = _beg; i < sz; ++i) data[i] += static_cast(i); } int main() { double* data = NULL; int blocks = 64; int grids = 64; int ret = cudaMalloc(&data, blocks * grids * sizeof(double)); if(ret != cudaSuccess) return EXIT_FAILURE; kernel<<>>(blocks * grids, data); cudaDeviceSynchronize(); return EXIT_SUCCESS; } ") # save the command for debugging SET(_COMMANDS "${_COMPILER} ${ARGN} -c ${PROJECT_BINARY_DIR}/compile_tests/compiles_cuda.cu") # use execute_process instead of try compile because we want to set custom compiler EXECUTE_PROCESS(COMMAND ${_COMPILER} ${ARGN} -c ${PROJECT_BINARY_DIR}/compile_tests/compiles_cuda.cu RESULT_VARIABLE _RET WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/compile_tests TIMEOUT 15 OUTPUT_QUIET ERROR_QUIET) IF(NOT _RET EQUAL 0) # save the command for debugging SET(_COMMANDS "${_COMMAND}\n${_COMPILER} --cuda-gpu-arch=sm_35 ${ARGN} -c ${PROJECT_BINARY_DIR}/compile_tests/compiles_cuda.cu") # try the compile test again with clang arguments EXECUTE_PROCESS(COMMAND ${_COMPILER} --cuda-gpu-arch=sm_35 -c ${PROJECT_BINARY_DIR}/compile_tests/compiles_cuda.cu RESULT_VARIABLE _RET WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/compile_tests TIMEOUT 15 OUTPUT_QUIET ERROR_QUIET) ENDIF() SET(${_VAR}_COMMANDS "${_COMMANDS}" PARENT_SCOPE) SET(${_VAR} ${_RET} PARENT_SCOPE) ENDFUNCTION() # this function is provided to easily select which files use the same compiler as Kokkos # when it was installed (or nvcc_wrapper): # # GLOBAL --> all files # TARGET --> all files in a target # SOURCE --> specific source files # DIRECTORY --> all files in directory # PROJECT --> all files/targets in a project/subproject # # Use the COMPILER argument to specify a compiler, if needed. By default, it will # set the values to ${Kokkos_CXX_COMPILER} unless Kokkos_ENABLE_CUDA=ON and # Kokkos_CXX_COMPILER_ID is NVIDIA, then it will set it to nvcc_wrapper # # Use CHECK_CUDA_COMPILES to run a check when CUDA is enabled # FUNCTION(kokkos_compilation) CMAKE_PARSE_ARGUMENTS(COMP "GLOBAL;PROJECT;CHECK_CUDA_COMPILES" "COMPILER" "DIRECTORY;TARGET;SOURCE;COMMAND_PREFIX" ${ARGN}) # if built w/o CUDA support, we want to basically make this a no-op SET(_Kokkos_ENABLE_CUDA @Kokkos_ENABLE_CUDA@) # search relative first and then absolute SET(_HINTS "${CMAKE_CURRENT_LIST_DIR}/../.." "@CMAKE_INSTALL_PREFIX@") # find kokkos_launch_compiler FIND_PROGRAM(Kokkos_COMPILE_LAUNCHER NAMES kokkos_launch_compiler HINTS ${_HINTS} PATHS ${_HINTS} PATH_SUFFIXES bin) IF(NOT Kokkos_COMPILE_LAUNCHER) MESSAGE(FATAL_ERROR "Kokkos could not find 'kokkos_launch_compiler'. Please set '-DKokkos_COMPILE_LAUNCHER=/path/to/launcher'") ENDIF() # if COMPILER was not specified, assume Kokkos_CXX_COMPILER IF(NOT COMP_COMPILER) SET(COMP_COMPILER ${Kokkos_CXX_COMPILER}) IF(_Kokkos_ENABLE_CUDA AND Kokkos_CXX_COMPILER_ID STREQUAL NVIDIA) # find nvcc_wrapper FIND_PROGRAM(Kokkos_NVCC_WRAPPER NAMES nvcc_wrapper HINTS ${_HINTS} PATHS ${_HINTS} PATH_SUFFIXES bin) # fatal if we can't nvcc_wrapper IF(NOT Kokkos_NVCC_WRAPPER) MESSAGE(FATAL_ERROR "Kokkos could not find nvcc_wrapper. Please set '-DKokkos_NVCC_WRAPPER=/path/to/nvcc_wrapper'") ENDIF() SET(COMP_COMPILER ${Kokkos_NVCC_WRAPPER}) ENDIF() ENDIF() # check that the original compiler still exists! IF(NOT EXISTS ${COMP_COMPILER}) MESSAGE(FATAL_ERROR "Kokkos could not find original compiler: '${COMP_COMPILER}'") ENDIF() # try to ensure that compiling cuda code works! IF(_Kokkos_ENABLE_CUDA AND COMP_CHECK_CUDA_COMPILES) # this may fail if kokkos_compiler launcher was used during install kokkos_cxx_compiler_cuda_test(_COMPILES_CUDA ${Kokkos_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}) # if above failed, throw an error IF(NOT _COMPILES_CUDA) MESSAGE(FATAL_ERROR "kokkos_cxx_compiler_cuda_test failed! Test commands:\n${_COMPILES_CUDA_COMMANDS}") ENDIF() ENDIF() IF(COMP_COMMAND_PREFIX) SET(_PREFIX "${COMP_COMMAND_PREFIX}") STRING(REPLACE ";" " " _PREFIX "${COMP_COMMAND_PREFIX}") SET(Kokkos_COMPILER_LAUNCHER "${_PREFIX} ${Kokkos_COMPILE_LAUNCHER}") ENDIF() IF(COMP_GLOBAL) # if global, don't bother setting others SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${Kokkos_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}") SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK "${Kokkos_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}") ELSE() FOREACH(_TYPE PROJECT DIRECTORY TARGET SOURCE) # make project/subproject scoping easy, e.g. KokkosCompilation(PROJECT) after project(...) IF("${_TYPE}" STREQUAL "PROJECT" AND COMP_${_TYPE}) LIST(APPEND COMP_DIRECTORY ${PROJECT_SOURCE_DIR}) UNSET(COMP_${_TYPE}) ENDIF() # set the properties if defined IF(COMP_${_TYPE}) # MESSAGE(STATUS "Using ${COMP_COMPILER} :: ${_TYPE} :: ${COMP_${_TYPE}}") SET_PROPERTY(${_TYPE} ${COMP_${_TYPE}} PROPERTY RULE_LAUNCH_COMPILE "${Kokkos_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}") SET_PROPERTY(${_TYPE} ${COMP_${_TYPE}} PROPERTY RULE_LAUNCH_LINK "${Kokkos_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}") ENDIF() ENDFOREACH() ENDIF() ENDFUNCTION()