1# Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2# file Copyright.txt or https://cmake.org/licensing for details. 3 4include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake) 5include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake) 6 7if( NOT ( ("${CMAKE_GENERATOR}" MATCHES "Make") OR 8 ("${CMAKE_GENERATOR}" MATCHES "Ninja") OR 9 ("${CMAKE_GENERATOR}" MATCHES "Visual Studio (1|[9][0-9])") ) ) 10 message(FATAL_ERROR "CUDA language not currently supported by \"${CMAKE_GENERATOR}\" generator") 11endif() 12 13if(${CMAKE_GENERATOR} MATCHES "Visual Studio") 14 if(DEFINED ENV{CUDAHOSTCXX} OR DEFINED CMAKE_CUDA_HOST_COMPILER) 15 message(WARNING "Visual Studio does not support specifying CUDAHOSTCXX or CMAKE_CUDA_HOST_COMPILER. Using the C++ compiler provided by Visual Studio.") 16 endif() 17else() 18 if(NOT CMAKE_CUDA_COMPILER) 19 set(CMAKE_CUDA_COMPILER_INIT NOTFOUND) 20 21 # prefer the environment variable CUDACXX 22 if(NOT $ENV{CUDACXX} STREQUAL "") 23 get_filename_component(CMAKE_CUDA_COMPILER_INIT $ENV{CUDACXX} PROGRAM PROGRAM_ARGS CMAKE_CUDA_FLAGS_ENV_INIT) 24 if(CMAKE_CUDA_FLAGS_ENV_INIT) 25 set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CXX compiler") 26 endif() 27 if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT}) 28 message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}") 29 endif() 30 endif() 31 32 # finally list compilers to try 33 if(NOT CMAKE_CUDA_COMPILER_INIT) 34 set(CMAKE_CUDA_COMPILER_LIST nvcc) 35 endif() 36 37 set(_CMAKE_CUDA_COMPILER_PATHS "$ENV{CUDA_PATH}/bin") 38 _cmake_find_compiler(CUDA) 39 unset(_CMAKE_CUDA_COMPILER_PATHS) 40 else() 41 _cmake_find_compiler_path(CUDA) 42 endif() 43 44 mark_as_advanced(CMAKE_CUDA_COMPILER) 45 46 #Allow the user to specify a host compiler except for Visual Studio 47 if(NOT $ENV{CUDAHOSTCXX} STREQUAL "") 48 get_filename_component(CMAKE_CUDA_HOST_COMPILER $ENV{CUDAHOSTCXX} PROGRAM) 49 if(NOT EXISTS ${CMAKE_CUDA_HOST_COMPILER}) 50 message(FATAL_ERROR "Could not find compiler set in environment variable CUDAHOSTCXX:\n$ENV{CUDAHOSTCXX}.\n${CMAKE_CUDA_HOST_COMPILER}") 51 endif() 52 endif() 53endif() 54 55if(NOT "$ENV{CUDAARCHS}" STREQUAL "") 56 set(CMAKE_CUDA_ARCHITECTURES "$ENV{CUDAARCHS}" CACHE STRING "CUDA architectures") 57endif() 58 59# Build a small source file to identify the compiler. 60if(NOT CMAKE_CUDA_COMPILER_ID_RUN) 61 set(CMAKE_CUDA_COMPILER_ID_RUN 1) 62 63 include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake) 64 65 if(${CMAKE_GENERATOR} MATCHES "Visual Studio") 66 # We will not know CMAKE_CUDA_COMPILER until the main compiler id step 67 # below extracts it, but we do know that the compiler id will be NVIDIA. 68 set(CMAKE_CUDA_COMPILER_ID "NVIDIA") 69 else() 70 # We determine the vendor to help with find the toolkit and use the right flags for detection right away. 71 # The main compiler identification is still needed below to extract other information. 72 list(APPEND CMAKE_CUDA_COMPILER_ID_VENDORS NVIDIA Clang) 73 set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_NVIDIA "nvcc: NVIDIA \\(R\\) Cuda compiler driver") 74 set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)") 75 CMAKE_DETERMINE_COMPILER_ID_VENDOR(CUDA "--version") 76 77 if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang" AND WIN32) 78 message(FATAL_ERROR "Clang with CUDA is not yet supported on Windows. See CMake issue #20776.") 79 endif() 80 81 # Find the CUDA toolkit. We store the CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT 82 # in CMakeCUDACompiler.cmake, so FindCUDAToolkit can avoid searching on future runs and the toolkit stays the same. 83 # This is very similar to FindCUDAToolkit, but somewhat simplified since we can issue fatal errors 84 # if we fail to find things we need and we don't need to account for searching the libraries. 85 86 # For NVCC we can easily deduce the SDK binary directory from the compiler path. 87 if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") 88 set(_CUDA_NVCC_EXECUTABLE "${CMAKE_CUDA_COMPILER}") 89 else() 90 # Search using CUDAToolkit_ROOT and then CUDA_PATH for equivalence with FindCUDAToolkit. 91 # In FindCUDAToolkit CUDAToolkit_ROOT is searched automatically due to being in a find_package(). 92 # First we search candidate non-default paths to give them priority. 93 find_program(_CUDA_NVCC_EXECUTABLE 94 NAMES nvcc nvcc.exe 95 PATHS ${CUDAToolkit_ROOT} 96 ENV CUDAToolkit_ROOT 97 ENV CUDA_PATH 98 PATH_SUFFIXES bin 99 NO_DEFAULT_PATH 100 ) 101 102 # If we didn't find NVCC, then try the default paths. 103 find_program(_CUDA_NVCC_EXECUTABLE 104 NAMES nvcc nvcc.exe 105 PATH_SUFFIXES bin 106 ) 107 108 # If the user specified CUDAToolkit_ROOT but nvcc could not be found, this is an error. 109 if(NOT _CUDA_NVCC_EXECUTABLE AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT})) 110 set(fail_base "Could not find nvcc executable in path specified by") 111 112 if(DEFINED CUDAToolkit_ROOT) 113 message(FATAL_ERROR "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}") 114 elseif(DEFINED ENV{CUDAToolkit_ROOT}) 115 message(FATAL_ERROR "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}") 116 endif() 117 endif() 118 119 # CUDAToolkit_ROOT cmake/env variable not specified, try platform defaults. 120 # 121 # - Linux: /usr/local/cuda-X.Y 122 # - macOS: /Developer/NVIDIA/CUDA-X.Y 123 # - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y 124 # 125 # We will also search the default symlink location /usr/local/cuda first since 126 # if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked 127 # directory is the desired location. 128 if(NOT _CUDA_NVCC_EXECUTABLE) 129 if(UNIX) 130 if(NOT APPLE) 131 set(platform_base "/usr/local/cuda-") 132 else() 133 set(platform_base "/Developer/NVIDIA/CUDA-") 134 endif() 135 else() 136 set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v") 137 endif() 138 139 # Build out a descending list of possible cuda installations, e.g. 140 file(GLOB possible_paths "${platform_base}*") 141 # Iterate the glob results and create a descending list. 142 set(versions) 143 foreach(p ${possible_paths}) 144 # Extract version number from end of string 145 string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p}) 146 if(IS_DIRECTORY ${p} AND p_version) 147 list(APPEND versions ${p_version}) 148 endif() 149 endforeach() 150 151 # Sort numerically in descending order, so we try the newest versions first. 152 list(SORT versions COMPARE NATURAL ORDER DESCENDING) 153 154 # With a descending list of versions, populate possible paths to search. 155 set(search_paths) 156 foreach(v ${versions}) 157 list(APPEND search_paths "${platform_base}${v}") 158 endforeach() 159 160 # Force the global default /usr/local/cuda to the front on Unix. 161 if(UNIX) 162 list(INSERT search_paths 0 "/usr/local/cuda") 163 endif() 164 165 # Now search for nvcc again using the platform default search paths. 166 find_program(_CUDA_NVCC_EXECUTABLE 167 NAMES nvcc nvcc.exe 168 PATHS ${search_paths} 169 PATH_SUFFIXES bin 170 ) 171 172 # We are done with these variables now, cleanup. 173 unset(platform_base) 174 unset(possible_paths) 175 unset(versions) 176 unset(search_paths) 177 178 if(NOT _CUDA_NVCC_EXECUTABLE) 179 message(FATAL_ERROR "Failed to find nvcc.\nCompiler ${CMAKE_CUDA_COMPILER_ID} requires the CUDA toolkit. Please set the CUDAToolkit_ROOT variable.") 180 endif() 181 endif() 182 endif() 183 184 # Given that NVCC can be provided by multiple different sources (NVIDIA HPC SDK, CUDA Toolkit, distro) 185 # each of which has a different layout, we need to extract the CUDA toolkit root from the compiler 186 # itself, allowing us to support numerous different scattered toolkit layouts 187 execute_process(COMMAND ${_CUDA_NVCC_EXECUTABLE} "-v" "__cmake_determine_cuda" 188 OUTPUT_VARIABLE _CUDA_NVCC_OUT ERROR_VARIABLE _CUDA_NVCC_OUT) 189 if(_CUDA_NVCC_OUT MATCHES "\\#\\$ TOP=([^\r\n]*)") 190 get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_MATCH_1}" ABSOLUTE) 191 else() 192 get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY) 193 get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY) 194 endif() 195 196 if(_CUDA_NVCC_OUT MATCHES "\\#\\$ NVVMIR_LIBRARY_DIR=([^\r\n]*)") 197 get_filename_component(_CUDA_NVVMIR_LIBRARY_DIR "${CMAKE_MATCH_1}" ABSOLUTE) 198 199 #We require the path to end in `/nvvm/libdevice' 200 if(_CUDA_NVVMIR_LIBRARY_DIR MATCHES "nvvm/libdevice$") 201 get_filename_component(_CUDA_NVVMIR_LIBRARY_DIR "${_CUDA_NVVMIR_LIBRARY_DIR}/../.." ABSOLUTE) 202 set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR "${_CUDA_NVVMIR_LIBRARY_DIR}") 203 endif() 204 205 unset(_CUDA_NVVMIR_LIBRARY_DIR) 206 unset(_cuda_nvvmir_dir_name) 207 endif() 208 unset(_CUDA_NVCC_OUT) 209 210 set(CMAKE_CUDA_DEVICE_LINKER "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/nvlink${CMAKE_EXECUTABLE_SUFFIX}") 211 set(CMAKE_CUDA_FATBINARY "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/bin/fatbinary${CMAKE_EXECUTABLE_SUFFIX}") 212 213 # In a non-scattered installation the following are equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT. 214 # We first check for a non-scattered installation to prefer it over a scattered installation. 215 216 # CMAKE_CUDA_COMPILER_LIBRARY_ROOT contains the device library. 217 if(DEFINED CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR) 218 set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR}") 219 elseif(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/nvvm/libdevice") 220 set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") 221 elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/nvvm/libdevice") 222 set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda") 223 elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/nvvm/libdevice") 224 set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/cuda") 225 else() 226 message(FATAL_ERROR "Couldn't find CUDA library root.") 227 endif() 228 unset(CMAKE_CUDA_COMPILER_LIBRARY_ROOT_FROM_NVVMIR_LIBRARY_DIR) 229 230 # CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT contains the linking stubs necessary for device linking and other low-level library files. 231 if(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/nvidia-cuda-toolkit/bin/crt/link.stub") 232 set(CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/nvidia-cuda-toolkit") 233 elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/nvidia-cuda-toolkit/bin/crt/link.stub") 234 set(CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/nvidia-cuda-toolkit") 235 else() 236 set(CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") 237 endif() 238 endif() 239 240 set(CMAKE_CUDA_COMPILER_ID_FLAGS_ALWAYS "-v") 241 242 if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") 243 set(nvcc_test_flags "--keep --keep-dir tmp") 244 if(CMAKE_CUDA_HOST_COMPILER) 245 string(APPEND nvcc_test_flags " -ccbin=\"${CMAKE_CUDA_HOST_COMPILER}\"") 246 247 # If the user has specified a host compiler we should fail instead of trying without. 248 # Succeeding detection without may result in confusing errors later on, see #21076. 249 set(CMAKE_CUDA_COMPILER_ID_REQUIRE_SUCCESS ON) 250 endif() 251 elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang") 252 set(clang_test_flags "--cuda-path=\"${CMAKE_CUDA_COMPILER_LIBRARY_ROOT}\"") 253 if(CMAKE_CROSSCOMPILING) 254 # Need to pass the host target and include directories if we're crosscompiling. 255 string(APPEND clang_test_flags " --sysroot=\"${CMAKE_SYSROOT}\" --target=${CMAKE_CUDA_COMPILER_TARGET}") 256 endif() 257 endif() 258 259 # Append user-specified architectures. 260 if(CMAKE_CUDA_ARCHITECTURES) 261 foreach(arch ${CMAKE_CUDA_ARCHITECTURES}) 262 # Strip specifiers as PTX vs binary doesn't matter. 263 string(REGEX MATCH "[0-9]+" arch_name "${arch}") 264 string(APPEND clang_test_flags " --cuda-gpu-arch=sm_${arch_name}") 265 string(APPEND nvcc_test_flags " -gencode=arch=compute_${arch_name},code=sm_${arch_name}") 266 list(APPEND tested_architectures "${arch_name}") 267 endforeach() 268 269 # If the user has specified architectures we'll want to fail during compiler detection if they don't work. 270 set(CMAKE_CUDA_COMPILER_ID_REQUIRE_SUCCESS ON) 271 endif() 272 273 if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang") 274 if(NOT CMAKE_CUDA_ARCHITECTURES) 275 # Clang doesn't automatically select an architecture supported by the SDK. 276 # Try in reverse order of deprecation with the most recent at front (i.e. the most likely to work for new setups). 277 foreach(arch "20" "30" "52") 278 list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${clang_test_flags} --cuda-gpu-arch=sm_${arch}") 279 endforeach() 280 endif() 281 282 # If the user specified CMAKE_CUDA_ARCHITECTURES this will include all the architecture flags. 283 # Otherwise this won't include any architecture flags and we'll fallback to Clang's defaults. 284 list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${clang_test_flags}") 285 elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") 286 list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${nvcc_test_flags}") 287 endif() 288 289 # We perform compiler identification for a second time to extract implicit linking info and host compiler for NVCC. 290 # We also use it to verify that CMAKE_CUDA_ARCHITECTURES and additionally on Clang that CUDA toolkit path works. 291 # The latter could be done during compiler testing in the future to avoid doing this for Clang. 292 # We need to unset the compiler ID otherwise CMAKE_DETERMINE_COMPILER_ID() doesn't work. 293 set(CMAKE_CUDA_COMPILER_ID) 294 set(CMAKE_CUDA_PLATFORM_ID) 295 file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in 296 CMAKE_CUDA_COMPILER_ID_PLATFORM_CONTENT) 297 298 CMAKE_DETERMINE_COMPILER_ID(CUDA CUDAFLAGS CMakeCUDACompilerId.cu) 299 300 if(${CMAKE_GENERATOR} MATCHES "Visual Studio") 301 # Now that we have the path to nvcc, we can compute the toolkit root. 302 get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER}" DIRECTORY) 303 get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY) 304 set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") 305 endif() 306 307 _cmake_find_compiler_sysroot(CUDA) 308endif() 309 310set(_CMAKE_PROCESSING_LANGUAGE "CUDA") 311include(CMakeFindBinUtils) 312include(Compiler/${CMAKE_CUDA_COMPILER_ID}-FindBinUtils OPTIONAL) 313unset(_CMAKE_PROCESSING_LANGUAGE) 314 315if(MSVC_CUDA_ARCHITECTURE_ID) 316 set(SET_MSVC_CUDA_ARCHITECTURE_ID 317 "set(MSVC_CUDA_ARCHITECTURE_ID ${MSVC_CUDA_ARCHITECTURE_ID})") 318endif() 319 320if(${CMAKE_GENERATOR} MATCHES "Visual Studio") 321 set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_LINKER}") 322 set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "") 323 set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "") 324 set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") 325 326 # We do not currently detect CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES but we 327 # do need to detect CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT from the compiler by 328 # looking at which cudart library exists in the implicit link libraries passed 329 # to the host linker. 330 if(CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT MATCHES "link\\.exe [^\n]*cudart_static\\.lib") 331 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC") 332 elseif(CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT MATCHES "link\\.exe [^\n]*cudart\\.lib") 333 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "SHARED") 334 else() 335 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "NONE") 336 endif() 337 set(_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT 338 "set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT \"${CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT}\")") 339elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang") 340 if(NOT CMAKE_CUDA_ARCHITECTURES) 341 # Find the architecture that we successfully compiled using and set it as the default. 342 string(REGEX MATCH "-target-cpu sm_([0-9]+)" dont_care "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") 343 set(detected_architecture "${CMAKE_MATCH_1}") 344 else() 345 string(REGEX MATCHALL "-target-cpu sm_([0-9]+)" target_cpus "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") 346 347 foreach(cpu ${target_cpus}) 348 string(REGEX MATCH "-target-cpu sm_([0-9]+)" dont_care "${cpu}") 349 list(APPEND architectures "${CMAKE_MATCH_1}") 350 endforeach() 351 endif() 352 353 # Find target directory when crosscompiling. 354 if(CMAKE_CROSSCOMPILING) 355 if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a") 356 # Support for NVPACK 357 set(_CUDA_TARGET_NAME "armv7-linux-androideabi") 358 elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") 359 set(_CUDA_TARGET_NAME "armv7-linux-gnueabihf") 360 elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") 361 if(ANDROID_ARCH_NAME STREQUAL "arm64") 362 set(_CUDA_TARGET_NAME "aarch64-linux-androideabi") 363 else() 364 set(_CUDA_TARGET_NAME "aarch64-linux") 365 endif() 366 elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") 367 set(_CUDA_TARGET_NAME "x86_64-linux") 368 endif() 369 370 if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/targets/${_CUDA_TARGET_NAME}") 371 set(_CUDA_TARGET_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/targets/${_CUDA_TARGET_NAME}") 372 endif() 373 endif() 374 375 # If not already set we can simply use the toolkit root or it's a scattered installation. 376 if(NOT _CUDA_TARGET_DIR) 377 set(_CUDA_TARGET_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") 378 endif() 379 380 # We can't use find_library() yet at this point, so try a few guesses. 381 if(EXISTS "${_CUDA_TARGET_DIR}/lib64") 382 set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib64") 383 elseif(EXISTS "${_CUDA_TARGET_DIR}/lib/x64") 384 set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib/x64") 385 elseif(EXISTS "${_CUDA_TARGET_DIR}/lib") 386 set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib") 387 else() 388 message(FATAL_ERROR "Unable to find _CUDA_LIBRARY_DIR based on _CUDA_TARGET_DIR=${_CUDA_TARGET_DIR}") 389 endif() 390 391 # _CUDA_TARGET_DIR always points to the directory containing the include directory. 392 # On a scattered installation /usr, on a non-scattered something like /usr/local/cuda or /usr/local/cuda-10.2/targets/aarch64-linux. 393 if(EXISTS "${_CUDA_TARGET_DIR}/include/cuda_runtime.h") 394 set(_CUDA_INCLUDE_DIR "${_CUDA_TARGET_DIR}/include") 395 else() 396 message(FATAL_ERROR "Unable to find cuda_runtime.h in \"${_CUDA_TARGET_DIR}/include\" for _CUDA_INCLUDE_DIR.") 397 endif() 398 399 # Clang does not add any CUDA SDK libraries or directories when invoking the host linker. 400 # Add the CUDA toolkit library directory ourselves so that linking works. 401 # The CUDA runtime libraries are handled elsewhere by CMAKE_CUDA_RUNTIME_LIBRARY. 402 set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${_CUDA_INCLUDE_DIR}") 403 set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "${_CUDA_LIBRARY_DIR}") 404 set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "") 405 set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") 406elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") 407 set(_nvcc_log "") 408 string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") 409 if(_nvcc_output_orig MATCHES "#\\\$ +PATH= *([^\n]*)\n") 410 set(_nvcc_path "${CMAKE_MATCH_1}") 411 string(APPEND _nvcc_log " found 'PATH=' string: [${_nvcc_path}]\n") 412 string(REPLACE ":" ";" _nvcc_path "${_nvcc_path}") 413 else() 414 set(_nvcc_path "") 415 string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}") 416 string(APPEND _nvcc_log " no 'PATH=' string found in nvcc output:${_nvcc_output_log}\n") 417 endif() 418 if(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n") 419 set(_nvcc_libraries "${CMAKE_MATCH_1}") 420 string(APPEND _nvcc_log " found 'LIBRARIES=' string: [${_nvcc_libraries}]\n") 421 else() 422 set(_nvcc_libraries "") 423 string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}") 424 string(APPEND _nvcc_log " no 'LIBRARIES=' string found in nvcc output:${_nvcc_output_log}\n") 425 endif() 426 427 set(_nvcc_link_line "") 428 if(_nvcc_libraries) 429 # Remove variable assignments. 430 string(REGEX REPLACE "#\\\$ *[^= ]+=[^\n]*\n" "" _nvcc_output "${_nvcc_output_orig}") 431 # Encode [] characters that break list expansion. 432 string(REPLACE "[" "{==={" _nvcc_output "${_nvcc_output}") 433 string(REPLACE "]" "}===}" _nvcc_output "${_nvcc_output}") 434 # Split lines. 435 string(REGEX REPLACE "\n+(#\\\$ )?" ";" _nvcc_output "${_nvcc_output}") 436 foreach(line IN LISTS _nvcc_output) 437 set(_nvcc_output_line "${line}") 438 string(REPLACE "{==={" "[" _nvcc_output_line "${_nvcc_output_line}") 439 string(REPLACE "}===}" "]" _nvcc_output_line "${_nvcc_output_line}") 440 string(APPEND _nvcc_log " considering line: [${_nvcc_output_line}]\n") 441 if("${_nvcc_output_line}" MATCHES "^ *nvlink") 442 string(APPEND _nvcc_log " ignoring nvlink line\n") 443 elseif(_nvcc_libraries) 444 if("${_nvcc_output_line}" MATCHES "(@\"?((tmp/)?a\\.exe\\.res)\"?)") 445 set(_nvcc_link_res_arg "${CMAKE_MATCH_1}") 446 set(_nvcc_link_res_file "${CMAKE_MATCH_2}") 447 set(_nvcc_link_res "${CMAKE_PLATFORM_INFO_DIR}/CompilerIdCUDA/${_nvcc_link_res_file}") 448 if(EXISTS "${_nvcc_link_res}") 449 file(READ "${_nvcc_link_res}" _nvcc_link_res_content) 450 string(REPLACE "${_nvcc_link_res_arg}" "${_nvcc_link_res_content}" _nvcc_output_line "${_nvcc_output_line}") 451 endif() 452 endif() 453 string(FIND "${_nvcc_output_line}" "${_nvcc_libraries}" _nvcc_libraries_pos) 454 if(NOT _nvcc_libraries_pos EQUAL -1) 455 set(_nvcc_link_line "${_nvcc_output_line}") 456 string(APPEND _nvcc_log " extracted link line: [${_nvcc_link_line}]\n") 457 endif() 458 endif() 459 endforeach() 460 endif() 461 462 if(_nvcc_link_line) 463 if("x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC") 464 set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_LINKER}") 465 else() 466 #extract the compiler that is being used for linking 467 separate_arguments(_nvcc_link_line_args UNIX_COMMAND "${_nvcc_link_line}") 468 list(GET _nvcc_link_line_args 0 _nvcc_host_link_launcher) 469 if(IS_ABSOLUTE "${_nvcc_host_link_launcher}") 470 string(APPEND _nvcc_log " extracted link launcher absolute path: [${_nvcc_host_link_launcher}]\n") 471 set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_host_link_launcher}") 472 else() 473 string(APPEND _nvcc_log " extracted link launcher name: [${_nvcc_host_link_launcher}]\n") 474 find_program(_nvcc_find_host_link_launcher 475 NAMES ${_nvcc_host_link_launcher} 476 PATHS ${_nvcc_path} NO_DEFAULT_PATH) 477 find_program(_nvcc_find_host_link_launcher 478 NAMES ${_nvcc_host_link_launcher}) 479 if(_nvcc_find_host_link_launcher) 480 string(APPEND _nvcc_log " found link launcher absolute path: [${_nvcc_find_host_link_launcher}]\n") 481 set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_find_host_link_launcher}") 482 else() 483 string(APPEND _nvcc_log " could not find link launcher absolute path\n") 484 set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_host_link_launcher}") 485 endif() 486 unset(_nvcc_find_host_link_launcher CACHE) 487 endif() 488 endif() 489 490 #prefix the line with cuda-fake-ld so that implicit link info believes it is 491 #a link line 492 set(_nvcc_link_line "cuda-fake-ld ${_nvcc_link_line}") 493 CMAKE_PARSE_IMPLICIT_LINK_INFO("${_nvcc_link_line}" 494 CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES 495 CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES 496 CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES 497 log 498 "${CMAKE_CUDA_IMPLICIT_OBJECT_REGEX}") 499 500 # Detect CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT from the compiler by looking at which 501 # cudart library exists in the implicit link libraries passed to the host linker. 502 # This is required when a project sets the cuda runtime library as part of the 503 # initial flags. 504 if(";${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES};" MATCHES [[;cudart_static(\.lib)?;]]) 505 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC") 506 elseif(";${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES};" MATCHES [[;cudart(\.lib)?;]]) 507 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "SHARED") 508 else() 509 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "NONE") 510 endif() 511 set(_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT 512 "set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT \"${CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT}\")") 513 514 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 515 "Parsed CUDA nvcc implicit link information from above output:\n${_nvcc_log}\n${log}\n\n") 516 else() 517 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 518 "Failed to parse CUDA nvcc implicit link information:\n${_nvcc_log}\n\n") 519 message(FATAL_ERROR "Failed to extract nvcc implicit link line.") 520 endif() 521endif() 522 523# CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES is detected above as the list of 524# libraries that the CUDA compiler implicitly passes to the host linker. 525# CMake invokes the host linker directly and so needs to pass these libraries. 526# We filter out those that should not be passed unconditionally both here 527# and from CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES in CMakeTestCUDACompiler. 528set(CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES_EXCLUDE 529 # The CUDA runtime libraries are controlled by CMAKE_CUDA_RUNTIME_LIBRARY. 530 cudart cudart.lib 531 cudart_static cudart_static.lib 532 cudadevrt cudadevrt.lib 533 534 # Dependencies of the CUDA static runtime library on Linux hosts. 535 rt 536 pthread 537 dl 538 ) 539list(REMOVE_ITEM CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES ${CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES_EXCLUDE}) 540 541if(CMAKE_CUDA_COMPILER_SYSROOT) 542 string(CONCAT _SET_CMAKE_CUDA_COMPILER_SYSROOT 543 "set(CMAKE_CUDA_COMPILER_SYSROOT \"${CMAKE_CUDA_COMPILER_SYSROOT}\")\n" 544 "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_CUDA_COMPILER_SYSROOT}\")") 545else() 546 set(_SET_CMAKE_CUDA_COMPILER_SYSROOT "") 547endif() 548 549# Determine CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES 550if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") 551 set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES) 552 string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") 553 if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n") 554 set(_nvcc_includes "${CMAKE_MATCH_1}") 555 string(APPEND _nvcc_log " found 'INCLUDES=' string: [${_nvcc_includes}]\n") 556 else() 557 set(_nvcc_includes "") 558 string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}") 559 string(APPEND _nvcc_log " no 'INCLUDES=' string found in nvcc output:${_nvcc_output_log}\n") 560 endif() 561 if(_nvcc_includes) 562 # across all operating system each include directory is prefixed with -I 563 separate_arguments(_nvcc_output NATIVE_COMMAND "${_nvcc_includes}") 564 foreach(line IN LISTS _nvcc_output) 565 string(REGEX REPLACE "^-I" "" line "${line}") 566 get_filename_component(line "${line}" ABSOLUTE) 567 list(APPEND CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${line}") 568 endforeach() 569 570 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 571 "Parsed CUDA nvcc include information from above output:\n${_nvcc_log}\n${log}\n\n") 572 else() 573 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 574 "Failed to detect CUDA nvcc include information:\n${_nvcc_log}\n\n") 575 endif() 576 577 # Parse default CUDA architecture. 578 cmake_policy(GET CMP0104 _CUDA_CMP0104) 579 if(NOT CMAKE_CUDA_ARCHITECTURES AND _CUDA_CMP0104 STREQUAL "NEW") 580 string(REGEX MATCH "arch[ =]compute_([0-9]+)" dont_care "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") 581 set(detected_architecture "${CMAKE_MATCH_1}") 582 elseif(CMAKE_CUDA_ARCHITECTURES) 583 string(REGEX MATCHALL "-arch compute_([0-9]+)" target_cpus "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") 584 585 foreach(cpu ${target_cpus}) 586 string(REGEX MATCH "-arch compute_([0-9]+)" dont_care "${cpu}") 587 list(APPEND architectures "${CMAKE_MATCH_1}") 588 endforeach() 589 endif() 590endif() 591 592# If the user didn't set the architectures, then set them to a default. 593# If the user did, then make sure those architectures worked. 594if(DEFINED detected_architecture AND "${CMAKE_CUDA_ARCHITECTURES}" STREQUAL "") 595 set(CMAKE_CUDA_ARCHITECTURES "${detected_architecture}" CACHE STRING "CUDA architectures") 596 597 if(NOT CMAKE_CUDA_ARCHITECTURES) 598 message(FATAL_ERROR "Failed to find a working CUDA architecture.") 599 endif() 600elseif(architectures) 601 # Sort since order mustn't matter. 602 list(SORT architectures) 603 list(SORT tested_architectures) 604 605 # We don't distinguish real/virtual architectures during testing. 606 # For "70-real;70-virtual" we detect "70" as working and tested_architectures is "70;70". 607 # Thus we need to remove duplicates before checking if they're equal. 608 list(REMOVE_DUPLICATES tested_architectures) 609 610 if(NOT "${architectures}" STREQUAL "${tested_architectures}") 611 message(FATAL_ERROR 612 "The CMAKE_CUDA_ARCHITECTURES:\n" 613 " ${CMAKE_CUDA_ARCHITECTURES}\n" 614 "do not all work with this compiler. Try:\n" 615 " ${architectures}\n" 616 "instead.") 617 endif() 618endif() 619 620# configure all variables set in this file 621configure_file(${CMAKE_ROOT}/Modules/CMakeCUDACompiler.cmake.in 622 ${CMAKE_PLATFORM_INFO_DIR}/CMakeCUDACompiler.cmake 623 @ONLY 624) 625 626# Don't leak variables unnecessarily to user code. 627unset(_CUDA_INCLUDE_DIR CACHE) 628unset(_CUDA_NVCC_EXECUTABLE CACHE) 629unset(_CUDA_LIBRARY_DIR) 630unset(_CUDA_TARGET_DIR) 631unset(_CUDA_TARGET_NAME) 632 633set(CMAKE_CUDA_COMPILER_ENV_VAR "CUDACXX") 634set(CMAKE_CUDA_HOST_COMPILER_ENV_VAR "CUDAHOSTCXX") 635