CMakeDetermineCUDACompiler.cmake 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
  4. include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
  5. if( NOT ( ("${CMAKE_GENERATOR}" MATCHES "Make") OR
  6. ("${CMAKE_GENERATOR}" MATCHES "Ninja") OR
  7. ("${CMAKE_GENERATOR}" MATCHES "Visual Studio (1|[9][0-9])") ) )
  8. message(FATAL_ERROR "CUDA language not currently supported by \"${CMAKE_GENERATOR}\" generator")
  9. endif()
  10. if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
  11. else()
  12. if(NOT CMAKE_CUDA_COMPILER)
  13. set(CMAKE_CUDA_COMPILER_INIT NOTFOUND)
  14. # prefer the environment variable CUDACXX
  15. if(NOT $ENV{CUDACXX} STREQUAL "")
  16. get_filename_component(CMAKE_CUDA_COMPILER_INIT $ENV{CUDACXX} PROGRAM PROGRAM_ARGS CMAKE_CUDA_FLAGS_ENV_INIT)
  17. if(CMAKE_CUDA_FLAGS_ENV_INIT)
  18. set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "First argument to CXX compiler")
  19. endif()
  20. if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT})
  21. message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}")
  22. endif()
  23. endif()
  24. # finally list compilers to try
  25. if(NOT CMAKE_CUDA_COMPILER_INIT)
  26. set(CMAKE_CUDA_COMPILER_LIST nvcc)
  27. endif()
  28. _cmake_find_compiler(CUDA)
  29. else()
  30. _cmake_find_compiler_path(CUDA)
  31. endif()
  32. mark_as_advanced(CMAKE_CUDA_COMPILER)
  33. endif()
  34. #Allow the user to specify a host compiler
  35. if(NOT $ENV{CUDAHOSTCXX} STREQUAL "")
  36. get_filename_component(CMAKE_CUDA_HOST_COMPILER $ENV{CUDAHOSTCXX} PROGRAM)
  37. if(NOT EXISTS ${CMAKE_CUDA_HOST_COMPILER})
  38. message(FATAL_ERROR "Could not find compiler set in environment variable CUDAHOSTCXX:\n$ENV{CUDAHOSTCXX}.\n${CMAKE_CUDA_HOST_COMPILER}")
  39. endif()
  40. endif()
  41. # Build a small source file to identify the compiler.
  42. if(NOT CMAKE_CUDA_COMPILER_ID_RUN)
  43. set(CMAKE_CUDA_COMPILER_ID_RUN 1)
  44. # Try to identify the compiler.
  45. set(CMAKE_CUDA_COMPILER_ID)
  46. set(CMAKE_CUDA_PLATFORM_ID)
  47. file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in
  48. CMAKE_CUDA_COMPILER_ID_PLATFORM_CONTENT)
  49. list(APPEND CMAKE_CUDA_COMPILER_ID_VENDORS NVIDIA Clang)
  50. set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_NVIDIA "nvcc: NVIDIA \\(R\\) Cuda compiler driver")
  51. set(CMAKE_CUDA_COMPILER_ID_VENDOR_REGEX_Clang "(clang version)")
  52. set(CMAKE_CXX_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdCUDA/(\\./)?(CompilerIdCUDA.xctest/)?CompilerIdCUDA[ \t\n\\\"]")
  53. set(CMAKE_CXX_COMPILER_ID_TOOL_MATCH_INDEX 2)
  54. set(CMAKE_CUDA_COMPILER_ID_FLAGS_ALWAYS "-v")
  55. # nvcc
  56. set(nvcc_test_flags "--keep --keep-dir tmp")
  57. if(CMAKE_CUDA_HOST_COMPILER)
  58. string(APPEND nvcc_test_flags " -ccbin=${CMAKE_CUDA_HOST_COMPILER}")
  59. endif()
  60. list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST ${nvcc_test_flags})
  61. # Clang
  62. if(CMAKE_CROSSCOMPILING)
  63. # Need to pass the host target and include directories if we're crosscompiling.
  64. set(clang_test_flags "--sysroot=\"${CMAKE_SYSROOT}\" --target=${CMAKE_CUDA_COMPILER_TARGET}")
  65. else()
  66. set(clang_test_flags)
  67. endif()
  68. # Clang doesn't automatically select an architecture supported by the SDK.
  69. # Try in reverse order of deprecation with the most recent at front (i.e. the most likely to work for new setups).
  70. foreach(arch ${CMAKE_CUDA_ARCHITECTURES} "20" "30" "52")
  71. # Strip specifiers.
  72. string(REGEX MATCH "[0-9]+" arch_name "${arch}")
  73. list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${clang_test_flags} --cuda-gpu-arch=sm_${arch_name}")
  74. endforeach()
  75. # Finally also try the default.
  76. list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${clang_test_flags}")
  77. include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
  78. CMAKE_DETERMINE_COMPILER_ID(CUDA CUDAFLAGS CMakeCUDACompilerId.cu)
  79. _cmake_find_compiler_sysroot(CUDA)
  80. endif()
  81. set(_CMAKE_PROCESSING_LANGUAGE "CUDA")
  82. include(CMakeFindBinUtils)
  83. include(Compiler/${CMAKE_CUDA_COMPILER_ID}-FindBinUtils OPTIONAL)
  84. unset(_CMAKE_PROCESSING_LANGUAGE)
  85. if(MSVC_CUDA_ARCHITECTURE_ID)
  86. set(SET_MSVC_CUDA_ARCHITECTURE_ID
  87. "set(MSVC_CUDA_ARCHITECTURE_ID ${MSVC_CUDA_ARCHITECTURE_ID})")
  88. endif()
  89. if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
  90. set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_LINKER}")
  91. set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "")
  92. set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "")
  93. set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")
  94. # We do not currently detect CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES but we
  95. # do need to detect CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT from the compiler by
  96. # looking at which cudart library exists in the implicit link libraries passed
  97. # to the host linker.
  98. if(CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT MATCHES "link\\.exe [^\n]*cudart_static\\.lib")
  99. set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
  100. elseif(CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT MATCHES "link\\.exe [^\n]*cudart\\.lib")
  101. set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "SHARED")
  102. else()
  103. set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "NONE")
  104. endif()
  105. set(_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT
  106. "set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT \"${CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT}\")")
  107. elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
  108. # Parse default CUDA architecture.
  109. if(NOT CMAKE_CUDA_ARCHITECTURES)
  110. string(REGEX MATCH "-target-cpu sm_([0-9]+)" dont_care "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
  111. set(CMAKE_CUDA_ARCHITECTURES "${CMAKE_MATCH_1}" CACHE STRING "CUDA architectures")
  112. if(NOT CMAKE_CUDA_ARCHITECTURES)
  113. message(FATAL_ERROR "Failed to find default CUDA architecture.")
  114. endif()
  115. endif()
  116. # Parsing implicit host linker info is as simple as for regular Clang.
  117. CMAKE_PARSE_IMPLICIT_LINK_INFO("${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}"
  118. CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES
  119. CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES
  120. CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
  121. log
  122. "${CMAKE_CUDA_IMPLICIT_OBJECT_REGEX}")
  123. # Get SDK directory.
  124. string(REGEX MATCH "Found CUDA installation: (.+), version" dont_care "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
  125. set(__cuda_directory "${CMAKE_MATCH_1}")
  126. # Clang doesn't add the SDK library directory to the implicit link path. Do it ourselves, so stuff works.
  127. include(Internal/CUDAToolkit)
  128. set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${CUDAToolkit_INCLUDE_DIR}")
  129. list(APPEND CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "${CUDAToolkit_LIBRARY_DIR}")
  130. elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
  131. set(_nvcc_log "")
  132. string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
  133. if(_nvcc_output_orig MATCHES "#\\\$ +PATH= *([^\n]*)\n")
  134. set(_nvcc_path "${CMAKE_MATCH_1}")
  135. string(APPEND _nvcc_log " found 'PATH=' string: [${_nvcc_path}]\n")
  136. string(REPLACE ":" ";" _nvcc_path "${_nvcc_path}")
  137. else()
  138. set(_nvcc_path "")
  139. string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}")
  140. string(APPEND _nvcc_log " no 'PATH=' string found in nvcc output:${_nvcc_output_log}\n")
  141. endif()
  142. if(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n")
  143. set(_nvcc_libraries "${CMAKE_MATCH_1}")
  144. string(APPEND _nvcc_log " found 'LIBRARIES=' string: [${_nvcc_libraries}]\n")
  145. else()
  146. set(_nvcc_libraries "")
  147. string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}")
  148. string(APPEND _nvcc_log " no 'LIBRARIES=' string found in nvcc output:${_nvcc_output_log}\n")
  149. endif()
  150. set(_nvcc_link_line "")
  151. if(_nvcc_libraries)
  152. # Remove variable assignments.
  153. string(REGEX REPLACE "#\\\$ *[^= ]+=[^\n]*\n" "" _nvcc_output "${_nvcc_output_orig}")
  154. # Encode [] characters that break list expansion.
  155. string(REPLACE "[" "{==={" _nvcc_output "${_nvcc_output}")
  156. string(REPLACE "]" "}===}" _nvcc_output "${_nvcc_output}")
  157. # Split lines.
  158. string(REGEX REPLACE "\n+(#\\\$ )?" ";" _nvcc_output "${_nvcc_output}")
  159. foreach(line IN LISTS _nvcc_output)
  160. set(_nvcc_output_line "${line}")
  161. string(REPLACE "{==={" "[" _nvcc_output_line "${_nvcc_output_line}")
  162. string(REPLACE "}===}" "]" _nvcc_output_line "${_nvcc_output_line}")
  163. string(APPEND _nvcc_log " considering line: [${_nvcc_output_line}]\n")
  164. if("${_nvcc_output_line}" MATCHES "^ *nvlink")
  165. string(APPEND _nvcc_log " ignoring nvlink line\n")
  166. elseif(_nvcc_libraries)
  167. if("${_nvcc_output_line}" MATCHES "(@\"?tmp/a\\.exe\\.res\"?)")
  168. set(_nvcc_link_res_arg "${CMAKE_MATCH_1}")
  169. set(_nvcc_link_res "${CMAKE_PLATFORM_INFO_DIR}/CompilerIdCUDA/tmp/a.exe.res")
  170. if(EXISTS "${_nvcc_link_res}")
  171. file(READ "${_nvcc_link_res}" _nvcc_link_res_content)
  172. string(REPLACE "${_nvcc_link_res_arg}" "${_nvcc_link_res_content}" _nvcc_output_line "${_nvcc_output_line}")
  173. endif()
  174. endif()
  175. string(FIND "${_nvcc_output_line}" "${_nvcc_libraries}" _nvcc_libraries_pos)
  176. if(NOT _nvcc_libraries_pos EQUAL -1)
  177. set(_nvcc_link_line "${_nvcc_output_line}")
  178. string(APPEND _nvcc_log " extracted link line: [${_nvcc_link_line}]\n")
  179. endif()
  180. endif()
  181. endforeach()
  182. endif()
  183. if(_nvcc_link_line)
  184. if("x${CMAKE_CUDA_SIMULATE_ID}" STREQUAL "xMSVC")
  185. set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_LINKER}")
  186. else()
  187. #extract the compiler that is being used for linking
  188. separate_arguments(_nvcc_link_line_args UNIX_COMMAND "${_nvcc_link_line}")
  189. list(GET _nvcc_link_line_args 0 _nvcc_host_link_launcher)
  190. if(IS_ABSOLUTE "${_nvcc_host_link_launcher}")
  191. string(APPEND _nvcc_log " extracted link launcher absolute path: [${_nvcc_host_link_launcher}]\n")
  192. set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_host_link_launcher}")
  193. else()
  194. string(APPEND _nvcc_log " extracted link launcher name: [${_nvcc_host_link_launcher}]\n")
  195. find_program(_nvcc_find_host_link_launcher
  196. NAMES ${_nvcc_host_link_launcher}
  197. PATHS ${_nvcc_path} NO_DEFAULT_PATH)
  198. find_program(_nvcc_find_host_link_launcher
  199. NAMES ${_nvcc_host_link_launcher})
  200. if(_nvcc_find_host_link_launcher)
  201. string(APPEND _nvcc_log " found link launcher absolute path: [${_nvcc_find_host_link_launcher}]\n")
  202. set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_find_host_link_launcher}")
  203. else()
  204. string(APPEND _nvcc_log " could not find link launcher absolute path\n")
  205. set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${_nvcc_host_link_launcher}")
  206. endif()
  207. unset(_nvcc_find_host_link_launcher CACHE)
  208. endif()
  209. endif()
  210. #prefix the line with cuda-fake-ld so that implicit link info believes it is
  211. #a link line
  212. set(_nvcc_link_line "cuda-fake-ld ${_nvcc_link_line}")
  213. CMAKE_PARSE_IMPLICIT_LINK_INFO("${_nvcc_link_line}"
  214. CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES
  215. CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES
  216. CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES
  217. log
  218. "${CMAKE_CUDA_IMPLICIT_OBJECT_REGEX}")
  219. # Detect CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT from the compiler by looking at which
  220. # cudart library exists in the implicit link libraries passed to the host linker.
  221. # This is required when a project sets the cuda runtime library as part of the
  222. # initial flags.
  223. if(";${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES};" MATCHES [[;cudart_static(\.lib)?;]])
  224. set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
  225. elseif(";${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES};" MATCHES [[;cudart(\.lib)?;]])
  226. set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "SHARED")
  227. else()
  228. set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "NONE")
  229. endif()
  230. set(_SET_CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT
  231. "set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT \"${CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT}\")")
  232. file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
  233. "Parsed CUDA nvcc implicit link information from above output:\n${_nvcc_log}\n${log}\n\n")
  234. else()
  235. file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
  236. "Failed to parsed CUDA nvcc implicit link information:\n${_nvcc_log}\n\n")
  237. message(FATAL_ERROR "Failed to extract nvcc implicit link line.")
  238. endif()
  239. endif()
  240. if(CMAKE_CUDA_COMPILER_SYSROOT)
  241. string(CONCAT _SET_CMAKE_CUDA_COMPILER_SYSROOT
  242. "set(CMAKE_CUDA_COMPILER_SYSROOT \"${CMAKE_CUDA_COMPILER_SYSROOT}\")\n"
  243. "set(CMAKE_COMPILER_SYSROOT \"${CMAKE_CUDA_COMPILER_SYSROOT}\")")
  244. else()
  245. set(_SET_CMAKE_CUDA_COMPILER_SYSROOT "")
  246. endif()
  247. # Determine CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
  248. if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
  249. set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES)
  250. string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
  251. if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n")
  252. set(_nvcc_includes "${CMAKE_MATCH_1}")
  253. string(APPEND _nvcc_log " found 'INCLUDES=' string: [${_nvcc_includes}]\n")
  254. else()
  255. set(_nvcc_includes "")
  256. string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}")
  257. string(APPEND _nvcc_log " no 'INCLUDES=' string found in nvcc output:${_nvcc_output_log}\n")
  258. endif()
  259. if(_nvcc_includes)
  260. # across all operating system each include directory is prefixed with -I
  261. separate_arguments(_nvcc_output NATIVE_COMMAND "${_nvcc_includes}")
  262. foreach(line IN LISTS _nvcc_output)
  263. string(REGEX REPLACE "^-I" "" line "${line}")
  264. get_filename_component(line "${line}" ABSOLUTE)
  265. list(APPEND CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${line}")
  266. endforeach()
  267. file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
  268. "Parsed CUDA nvcc include information from above output:\n${_nvcc_log}\n${log}\n\n")
  269. else()
  270. file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
  271. "Failed to detect CUDA nvcc include information:\n${_nvcc_log}\n\n")
  272. endif()
  273. # Parse default CUDA architecture.
  274. cmake_policy(GET CMP0104 _CUDA_CMP0104)
  275. if(NOT CMAKE_CUDA_ARCHITECTURES AND _CUDA_CMP0104 STREQUAL "NEW")
  276. string(REGEX MATCH "arch[ =]compute_([0-9]+)" dont_care "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
  277. set(CMAKE_CUDA_ARCHITECTURES "${CMAKE_MATCH_1}" CACHE STRING "CUDA architectures")
  278. if(NOT CMAKE_CUDA_ARCHITECTURES)
  279. message(FATAL_ERROR "Failed to find default CUDA architecture.")
  280. endif()
  281. endif()
  282. endif()
  283. # configure all variables set in this file
  284. configure_file(${CMAKE_ROOT}/Modules/CMakeCUDACompiler.cmake.in
  285. ${CMAKE_PLATFORM_INFO_DIR}/CMakeCUDACompiler.cmake
  286. @ONLY
  287. )
  288. set(CMAKE_CUDA_COMPILER_ENV_VAR "CUDACXX")
  289. set(CMAKE_CUDA_HOST_COMPILER_ENV_VAR "CUDAHOSTCXX")