summaryrefslogtreecommitdiffstats
path: root/Modules/CMakeDetermineCUDACompiler.cmake
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2020-06-15 13:25:11 (GMT)
committerKitware Robot <kwrobot@kitware.com>2020-06-15 13:25:29 (GMT)
commit7fa5ea130b6f8b70d1c1ddef389ce9e47ac85b4b (patch)
tree966d34a004c446a70ed67e54573ad373ff160d2c /Modules/CMakeDetermineCUDACompiler.cmake
parenta3881d6313776aaf4c1d92b68c5064c9ac5cdcd3 (diff)
parentec59fb6c315f2797e72cab985110555c63ba65f8 (diff)
downloadCMake-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.cmake210
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")