diff options
author | Brad King <brad.king@kitware.com> | 2020-06-15 13:25:11 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2020-06-15 13:25:29 (GMT) |
commit | 7fa5ea130b6f8b70d1c1ddef389ce9e47ac85b4b (patch) | |
tree | 966d34a004c446a70ed67e54573ad373ff160d2c /Modules/CMakeDetermineCUDACompiler.cmake | |
parent | a3881d6313776aaf4c1d92b68c5064c9ac5cdcd3 (diff) | |
parent | ec59fb6c315f2797e72cab985110555c63ba65f8 (diff) | |
download | CMake-7fa5ea130b6f8b70d1c1ddef389ce9e47ac85b4b.zip CMake-7fa5ea130b6f8b70d1c1ddef389ce9e47ac85b4b.tar.gz CMake-7fa5ea130b6f8b70d1c1ddef389ce9e47ac85b4b.tar.bz2 |
Merge topic 'cuda_clang_toolkit_path' into release-3.18
ec59fb6c31 CUDA: Determine CUDA toolkit location for NVCC
0a056246a1 CUDA: Pass toolkit path to Clang
9c43972127 FindCUDAToolkit: Avoid unnecessary temporary variable computing binary dir
9eebb5b8b2 FindCUDAToolkit: Remove unnecessary checks around searches
8f01fe7bf1 FindCUDAToolkit: Use list(SORT) to sort in natural order
8c144fe9ad FindCUDAToolkit: Compute CUDAToolkit_INCLUDE_DIR instead of searching
403f8d31e3 FindCUDAToolkit: Add CUDAToolkit_LIBRARY_ROOT
6636693134 FindCUDAToolkit: Re-unify with Internal/CUDAToolkit
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4828
Diffstat (limited to 'Modules/CMakeDetermineCUDACompiler.cmake')
-rw-r--r-- | Modules/CMakeDetermineCUDACompiler.cmake | 210 |
1 files changed, 195 insertions, 15 deletions
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake index 1273831..a0f7202 100644 --- a/Modules/CMakeDetermineCUDACompiler.cmake +++ b/Modules/CMakeDetermineCUDACompiler.cmake @@ -65,18 +65,144 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN) set(CMAKE_CXX_COMPILER_ID_TOOL_MATCH_INDEX 2) set(CMAKE_CUDA_COMPILER_ID_FLAGS_ALWAYS "-v") - # nvcc - set(nvcc_test_flags "--keep --keep-dir tmp") - if(CMAKE_CUDA_HOST_COMPILER) - string(APPEND nvcc_test_flags " -ccbin=${CMAKE_CUDA_HOST_COMPILER}") + # We determine the vendor to help with find the toolkit and use the right flags for detection right away. + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake) + CMAKE_DETERMINE_COMPILER_ID_VENDOR(CUDA "--version") + + # Find the CUDA toolkit. We store the CMAKE_CUDA_COMPILER_TOOLKIT_ROOT and CMAKE_CUDA_COMPILER_LIBRARY_ROOT + # in CMakeCUDACompiler.cmake, so FindCUDAToolkit can avoid searching on future runs and the toolkit stays the same. + # This is very similar to FindCUDAToolkit, but somewhat simplified since we can issue fatal errors + # if we fail to find things we need and we don't need to account for searching the libraries. + + # For NVCC we can easily deduce the SDK binary directory from the compiler path. + if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") + get_filename_component(_CUDA_BIN_DIR "${CMAKE_CUDA_COMPILER}" DIRECTORY) + find_program(CUDAToolkit_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATHS ${_CUDA_BIN_DIR} + NO_DEFAULT_PATH + ) + unset(_CUDA_BIN_DIR) endif() - # Clang - if(CMAKE_CROSSCOMPILING) - # Need to pass the host target and include directories if we're crosscompiling. - set(clang_test_flags "--sysroot=\"${CMAKE_SYSROOT}\" --target=${CMAKE_CUDA_COMPILER_TARGET}") - else() - set(clang_test_flags) + # Search using CUDAToolkit_ROOT and then CUDA_PATH for equivalence with FindCUDAToolkit. + # In FindCUDAToolkit CUDAToolkit_ROOT is searched automatically due to being in a find_package(). + # First we search candidate non-default paths to give them priority. + find_program(_CUDA_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATHS ${CUDAToolkit_ROOT} + ENV CUDAToolkit_ROOT + ENV CUDA_PATH + PATH_SUFFIXES bin + NO_DEFAULT_PATH + ) + + # If we didn't find NVCC, then try the default paths. + find_program(_CUDA_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATH_SUFFIXES bin + ) + + # If the user specified CUDAToolkit_ROOT but nvcc could not be found, this is an error. + if(NOT _CUDA_NVCC_EXECUTABLE AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT})) + set(fail_base "Could not find nvcc executable in path specified by") + + if(DEFINED CUDAToolkit_ROOT) + message(FATAL_ERROR "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}") + elseif(DEFINED ENV{CUDAToolkit_ROOT}) + message(FATAL_ERROR "${fail_base} environment variable CUDAToolkit_ROOT=$ENV{CUDAToolkit_ROOT}") + endif() + endif() + + # CUDAToolkit_ROOT cmake/env variable not specified, try platform defaults. + # + # - Linux: /usr/local/cuda-X.Y + # - macOS: /Developer/NVIDIA/CUDA-X.Y + # - Windows: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vX.Y + # + # We will also search the default symlink location /usr/local/cuda first since + # if CUDAToolkit_ROOT is not specified, it is assumed that the symlinked + # directory is the desired location. + if(NOT _CUDA_NVCC_EXECUTABLE) + if(UNIX) + if(NOT APPLE) + set(platform_base "/usr/local/cuda-") + else() + set(platform_base "/Developer/NVIDIA/CUDA-") + endif() + else() + set(platform_base "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v") + endif() + + # Build out a descending list of possible cuda installations, e.g. + file(GLOB possible_paths "${platform_base}*") + # Iterate the glob results and create a descending list. + set(versions) + foreach(p ${possible_paths}) + # Extract version number from end of string + string(REGEX MATCH "[0-9][0-9]?\\.[0-9]$" p_version ${p}) + if(IS_DIRECTORY ${p} AND p_version) + list(APPEND versions ${p_version}) + endif() + endforeach() + + # Sort numerically in descending order, so we try the newest versions first. + list(SORT versions COMPARE NATURAL ORDER DESCENDING) + + # With a descending list of versions, populate possible paths to search. + set(search_paths) + foreach(v ${versions}) + list(APPEND search_paths "${platform_base}${v}") + endforeach() + + # Force the global default /usr/local/cuda to the front on Unix. + if(UNIX) + list(INSERT search_paths 0 "/usr/local/cuda") + endif() + + # Now search for nvcc again using the platform default search paths. + find_program(_CUDA_NVCC_EXECUTABLE + NAMES nvcc nvcc.exe + PATHS ${search_paths} + PATH_SUFFIXES bin + ) + + # We are done with these variables now, cleanup. + unset(platform_base) + unset(possible_paths) + unset(versions) + unset(search_paths) + + if(NOT _CUDA_NVCC_EXECUTABLE) + message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.") + endif() + endif() + + get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${_CUDA_NVCC_EXECUTABLE}" DIRECTORY) + get_filename_component(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}" DIRECTORY ABSOLUTE) + + # CMAKE_CUDA_COMPILER_LIBRARY_ROOT contains the device library and version file. + # In a non-scattered installation this is equivalent to CMAKE_CUDA_COMPILER_TOOLKIT_ROOT. + # We first check for a non-scattered installation to prefer it over a scattered installation. + if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/version.txt") + set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") + elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt") + set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda") + elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt") + set(CMAKE_CUDA_COMPILER_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/cuda") + endif() + + if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") + set(nvcc_test_flags "--keep --keep-dir tmp") + if(CMAKE_CUDA_HOST_COMPILER) + string(APPEND nvcc_test_flags " -ccbin=${CMAKE_CUDA_HOST_COMPILER}") + endif() + elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang") + set(clang_test_flags "--cuda-path=\"${CMAKE_CUDA_COMPILER_LIBRARY_ROOT}\"") + if(CMAKE_CROSSCOMPILING) + # Need to pass the host target and include directories if we're crosscompiling. + string(APPEND clang_test_flags " --sysroot=\"${CMAKE_SYSROOT}\" --target=${CMAKE_CUDA_COMPILER_TARGET}") + endif() endif() # First try with the user-specified architectures. @@ -108,7 +234,12 @@ if(NOT CMAKE_CUDA_COMPILER_ID_RUN) # Finally also try the default. list(APPEND CMAKE_CUDA_COMPILER_ID_TEST_FLAGS_FIRST "${clang_test_flags}") - include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake) + # We perform compiler identification for a second time to extract implicit linking info and host compiler for NVCC. + # We also use it to verify that CMAKE_CUDA_ARCHITECTURES and additionaly on Clang that CUDA toolkit path works. + # The latter could be done during compiler testing in the future to avoid doing this for Clang. + # We need to unset the compiler ID otherwise CMAKE_DETERMINE_COMPILER_ID() doesn't work. + unset(CMAKE_CUDA_COMPILER_ID) + CMAKE_DETERMINE_COMPILER_ID(CUDA CUDAFLAGS CMakeCUDACompilerId.cu) _cmake_find_compiler_sysroot(CUDA) @@ -157,12 +288,54 @@ elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang") endforeach() endif() + # Find target directory. Account for crosscompiling. + if(CMAKE_CROSSCOMPILING) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a") + # Support for NVPACK + set(_CUDA_TARGET_NAME "armv7-linux-androideabi") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + set(_CUDA_TARGET_NAME "armv7-linux-gnueabihf") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + if(ANDROID_ARCH_NAME STREQUAL "arm64") + set(_CUDA_TARGET_NAME "aarch64-linux-androideabi") + else() + set(_CUDA_TARGET_NAME "aarch64-linux") + endif() + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(_CUDA_TARGET_NAME "x86_64-linux") + endif() + + if(EXISTS "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/targets/${_CUDA_TARGET_NAME}") + set(_CUDA_TARGET_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}/targets/${_CUDA_TARGET_NAME}") + endif() + else() + set(_CUDA_TARGET_DIR "${CMAKE_CUDA_COMPILER_TOOLKIT_ROOT}") + endif() + + # We can't use find_library() yet at this point, so try a few guesses. + if(EXISTS "${_CUDA_TARGET_DIR}/lib64") + set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib64") + elseif(EXISTS "${_CUDA_TARGET_DIR}/lib/x64") + set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib/x64") + elseif(EXISTS "${_CUDA_TARGET_DIR}/lib") + set(_CUDA_LIBRARY_DIR "${_CUDA_TARGET_DIR}/lib") + else() + message(FATAL_ERROR "Unable to find _CUDA_LIBRARY_DIR based on _CUDA_TARGET_DIR=${_CUDA_TARGET_DIR}") + endif() + + # _CUDA_TARGET_DIR always points to the directory containing the include directory. + # On a scattered installation /usr, on a non-scattered something like /usr/local/cuda or /usr/local/cuda-10.2/targets/aarch64-linux. + if(EXISTS "${_CUDA_TARGET_DIR}/include/cuda_runtime.h") + set(_CUDA_INCLUDE_DIR "${_CUDA_TARGET_DIR}/include") + else() + message(FATAL_ERROR "Unable to find cuda_runtime.h in \"${_CUDA_TARGET_DIR}/include\" for _CUDA_INCLUDE_DIR.") + endif() + # Clang does not add any CUDA SDK libraries or directories when invoking the host linker. # Add the CUDA toolkit library directory ourselves so that linking works. # The CUDA runtime libraries are handled elsewhere by CMAKE_CUDA_RUNTIME_LIBRARY. - include(Internal/CUDAToolkit) - set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${CUDAToolkit_INCLUDE_DIR}") - set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "${CUDAToolkit_LIBRARY_DIR}") + set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${_CUDA_INCLUDE_DIR}") + set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "${_CUDA_LIBRARY_DIR}") set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "") set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") @@ -382,7 +555,14 @@ endif() configure_file(${CMAKE_ROOT}/Modules/CMakeCUDACompiler.cmake.in ${CMAKE_PLATFORM_INFO_DIR}/CMakeCUDACompiler.cmake @ONLY - ) +) + +# Don't leak variables unnecessarily to user code. +unset(_CUDA_INCLUDE_DIR CACHE) +unset(_CUDA_NVCC_EXECUTABLE CACHE) +unset(_CUDA_LIBRARY_DIR) +unset(_CUDA_TARGET_DIR) +unset(_CUDA_TARGET_NAME) set(CMAKE_CUDA_COMPILER_ENV_VAR "CUDACXX") set(CMAKE_CUDA_HOST_COMPILER_ENV_VAR "CUDAHOSTCXX") |