CUDAToolkit: Detect CUDA SDK that don't have nvcc

When a CUDA sdk doesn't have nvcc, defer to the existence of
a version.txt file. When we do this fall back we also reconstruct
the CUDA version via version.txt

Fixes #20643
This commit is contained in:
Robert Maynard 2020-07-24 16:36:15 -04:00
parent 37e27aa552
commit 7cc815a2a6
2 changed files with 104 additions and 54 deletions

View File

@ -0,0 +1,5 @@
FindCUDAToolkit-no-nvcc
-----------------------
* The :module:`FindCUDAToolkit` module gained support for finding CUDA toolkits
that do not contain ``nvcc``.

View File

@ -14,8 +14,7 @@ module does not search for the NVIDIA CUDA Samples.
Search Behavior
^^^^^^^^^^^^^^^
Finding the CUDA Toolkit requires finding the ``nvcc`` executable, which is
searched for in the following order:
The CUDA Toolkit search behavior uses the following order:
1. If the ``CUDA`` language has been enabled we will use the directory
containing the compiler as the first search location for ``nvcc``.
@ -26,13 +25,12 @@ searched for in the following order:
configuration variable are specified, the *configuration* variable takes
precedence.
The directory specified here must be such that the executable ``nvcc`` can be
found underneath the directory specified by ``CUDAToolkit_ROOT``. If
``CUDAToolkit_ROOT`` is specified, but no ``nvcc`` is found underneath, this
package is marked as **not** found. No subsequent search attempts are
performed.
The directory specified here must be such that the executable ``nvcc`` or
the appropriate ``version.txt`` file can be found underneath the specified
directory.
3. If the CUDA_PATH environment variable is defined, it will be searched.
3. If the CUDA_PATH environment variable is defined, it will be searched
for ``nvcc``.
4. The user's path is searched for ``nvcc`` using :command:`find_program`. If
this is found, no subsequent search attempts are performed. Users are
@ -404,7 +402,7 @@ Result variables
``CUDAToolkit_VERSION``
The exact version of the CUDA Toolkit found (as reported by
``nvcc --version``).
``nvcc --version`` or ``version.txt``).
``CUDAToolkit_VERSION_MAJOR``
The major version of the CUDA Toolkit.
@ -434,7 +432,7 @@ Result variables
``CUDAToolkit_TARGET_DIR``
The path to the CUDA Toolkit directory including the target architecture
when cross-compiling. When not cross-compiling this will be equivalent to
``CUDAToolkit_ROOT_DIR``.
the parent directory of ``CUDAToolkit_BIN_DIR``.
``CUDAToolkit_NVCC_EXECUTABLE``
The path to the NVIDIA CUDA compiler ``nvcc``. Note that this path may
@ -493,31 +491,81 @@ if(CMAKE_CUDA_COMPILER_TOOLKIT_ROOT)
set(CUDAToolkit_BIN_DIR "${CUDAToolkit_ROOT_DIR}/bin")
set(CUDAToolkit_NVCC_EXECUTABLE "${CUDAToolkit_BIN_DIR}/nvcc${CMAKE_EXECUTABLE_SUFFIX}")
else()
function(_CUDAToolkit_find_root_dir )
cmake_parse_arguments(arg "" "" "SEARCH_PATHS;FIND_FLAGS" ${ARGN})
if(NOT CUDAToolkit_BIN_DIR)
if(NOT CUDAToolkit_SENTINEL_FILE)
find_program(CUDAToolkit_NVCC_EXECUTABLE
NAMES nvcc nvcc.exe
PATHS ${arg_SEARCH_PATHS}
${arg_FIND_FLAGS}
)
endif()
if(NOT CUDAToolkit_NVCC_EXECUTABLE)
find_file(CUDAToolkit_SENTINEL_FILE
NAMES version.txt
PATHS ${arg_SEARCH_PATHS}
NO_DEFAULT_PATH
)
endif()
if(CUDAToolkit_NVCC_EXECUTABLE)
get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
mark_as_advanced(CUDAToolkit_BIN_DIR)
elseif(CUDAToolkit_SENTINEL_FILE)
get_filename_component(CUDAToolkit_BIN_DIR ${CUDAToolkit_SENTINEL_FILE} DIRECTORY ABSOLUTE)
set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}/bin")
set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
mark_as_advanced(CUDAToolkit_BIN_DIR)
endif()
endif()
if(CUDAToolkit_BIN_DIR)
get_filename_component(CUDAToolkit_ROOT_DIR ${CUDAToolkit_BIN_DIR} DIRECTORY ABSOLUTE)
set(CUDAToolkit_ROOT_DIR "${CUDAToolkit_ROOT_DIR}" PARENT_SCOPE)
endif()
endfunction()
function(_CUDAToolkit_find_version_file result_variable)
# We first check for a non-scattered installation to prefer it over a scattered installation.
if(CUDAToolkit_ROOT AND EXISTS "${CUDAToolkit_ROOT}/version.txt")
set(${result_variable} "${CUDAToolkit_ROOT}/version.txt" PARENT_SCOPE)
elseif(CUDAToolkit_ROOT_DIR AND EXISTS "${CUDAToolkit_ROOT_DIR}/version.txt")
set(${result_variable} "${CUDAToolkit_ROOT_DIR}/version.txt" PARENT_SCOPE)
elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt")
set(${result_variable} "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt" PARENT_SCOPE)
elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt")
set(${result_variable} "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt" PARENT_SCOPE)
endif()
endfunction()
# For NVCC we can easily deduce the SDK binary directory from the compiler path.
if(CMAKE_CUDA_COMPILER_LOADED AND NOT CUDAToolkit_BIN_DIR AND CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
get_filename_component(CUDAToolkit_BIN_DIR "${CMAKE_CUDA_COMPILER}" DIRECTORY)
set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "")
# Try language provided path first.
_CUDAToolkit_find_root_dir(SEARCH_PATHS "${CUDAToolkit_BIN_DIR}" FIND_FLAGS NO_DEFAULT_PATH)
mark_as_advanced(CUDAToolkit_BIN_DIR)
endif()
# Try language- or user-provided path first.
if(CUDAToolkit_BIN_DIR)
find_program(CUDAToolkit_NVCC_EXECUTABLE
NAMES nvcc nvcc.exe
PATHS ${CUDAToolkit_BIN_DIR}
NO_DEFAULT_PATH
)
# Try user provided path
if(NOT CUDAToolkit_ROOT_DIR AND CUDAToolkit_ROOT)
_CUDAToolkit_find_root_dir(SEARCH_PATHS "${CUDAToolkit_ROOT}" FIND_FLAGS PATH_SUFFIXES bin NO_DEFAULT_PATH)
endif()
if(NOT CUDAToolkit_ROOT_DIR)
_CUDAToolkit_find_root_dir(FIND_FLAGS PATHS "ENV CUDA_PATH" PATH_SUFFIXES bin)
endif()
# Search using CUDAToolkit_ROOT
find_program(CUDAToolkit_NVCC_EXECUTABLE
NAMES nvcc nvcc.exe
PATHS ENV CUDA_PATH
PATH_SUFFIXES bin
)
# If the user specified CUDAToolkit_ROOT but nvcc could not be found, this is an error.
if(NOT CUDAToolkit_NVCC_EXECUTABLE AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT}))
# If the user specified CUDAToolkit_ROOT but the toolkit could not be found, this is an error.
if(NOT CUDAToolkit_ROOT_DIR AND (DEFINED CUDAToolkit_ROOT OR DEFINED ENV{CUDAToolkit_ROOT}))
# Declare error messages now, print later depending on find_package args.
set(fail_base "Could not find nvcc executable in path specified by")
set(cuda_root_fail "${fail_base} CUDAToolkit_ROOT=${CUDAToolkit_ROOT}")
@ -554,7 +602,7 @@ else()
# 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 CUDAToolkit_NVCC_EXECUTABLE)
if(NOT CUDAToolkit_ROOT_DIR)
if(UNIX)
if(NOT APPLE)
set(platform_base "/usr/local/cuda-")
@ -591,12 +639,8 @@ else()
list(INSERT search_paths 0 "/usr/local/cuda")
endif()
# Now search for nvcc again using the platform default search paths.
find_program(CUDAToolkit_NVCC_EXECUTABLE
NAMES nvcc nvcc.exe
PATHS ${search_paths}
PATH_SUFFIXES bin
)
# Now search for the toolkit again using the platform default search paths.
_CUDAToolkit_find_root_dir(SEARCH_PATHS "${search_paths}" FIND_FLAGS PATH_SUFFIXES bin)
# We are done with these variables now, cleanup for caller.
unset(platform_base)
@ -604,7 +648,7 @@ else()
unset(versions)
unset(search_paths)
if(NOT CUDAToolkit_NVCC_EXECUTABLE)
if(NOT CUDAToolkit_ROOT_DIR)
if(CUDAToolkit_FIND_REQUIRED)
message(FATAL_ERROR "Could not find nvcc, please set CUDAToolkit_ROOT.")
elseif(NOT CUDAToolkit_FIND_QUIETLY)
@ -616,24 +660,12 @@ else()
endif()
endif()
if(NOT CUDAToolkit_BIN_DIR AND CUDAToolkit_NVCC_EXECUTABLE)
get_filename_component(CUDAToolkit_BIN_DIR "${CUDAToolkit_NVCC_EXECUTABLE}" DIRECTORY)
set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE)
mark_as_advanced(CUDAToolkit_BIN_DIR)
endif()
get_filename_component(CUDAToolkit_ROOT_DIR ${CUDAToolkit_BIN_DIR} DIRECTORY ABSOLUTE)
# CUDAToolkit_LIBRARY_ROOT contains the device library and version file.
# In a non-scattered installation this is equivalent to CUDAToolkit_ROOT_DIR.
# We first check for a non-scattered installation to prefer it over a scattered installation.
if(EXISTS "${CUDAToolkit_ROOT_DIR}/version.txt")
set(CUDAToolkit_LIBRARY_ROOT "${CUDAToolkit_ROOT_DIR}")
elseif(CMAKE_SYSROOT_LINK AND EXISTS "${CMAKE_SYSROOT_LINK}/usr/lib/cuda/version.txt")
set(CUDAToolkit_LIBRARY_ROOT "${CMAKE_SYSROOT_LINK}/usr/lib/cuda")
elseif(EXISTS "${CMAKE_SYSROOT}/usr/lib/cuda/version.txt")
set(CUDAToolkit_LIBRARY_ROOT "${CMAKE_SYSROOT}/usr/lib/cuda")
_CUDAToolkit_find_version_file( _CUDAToolkit_version_file )
if(_CUDAToolkit_version_file)
# CUDAToolkit_LIBRARY_ROOT contains the device library and version file.
get_filename_component(CUDAToolkit_LIBRARY_ROOT "${_CUDAToolkit_version_file}" DIRECTORY ABSOLUTE)
endif()
unset(_CUDAToolkit_version_file)
endif()
# Handle cross compilation
@ -695,7 +727,7 @@ if(CUDAToolkit_NVCC_EXECUTABLE AND
set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}")
set(CUDAToolkit_VERSION "${CMAKE_CUDA_COMPILER_VERSION}")
endif()
else()
elseif(CUDAToolkit_NVCC_EXECUTABLE)
# Compute the version by invoking nvcc
execute_process(COMMAND ${CUDAToolkit_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT)
if(NVCC_OUT MATCHES [=[ V([0-9]+)\.([0-9]+)\.([0-9]+)]=])
@ -705,6 +737,17 @@ else()
set(CUDAToolkit_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
endif()
unset(NVCC_OUT)
else()
_CUDAToolkit_find_version_file(version_file)
if(version_file)
file(READ "${version_file}" VERSION_INFO)
if(VERSION_INFO MATCHES [=[CUDA Version ([0-9]+)\.([0-9]+)\.([0-9]+)]=])
set(CUDAToolkit_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(CUDAToolkit_VERSION_MINOR "${CMAKE_MATCH_2}")
set(CUDAToolkit_VERSION_PATCH "${CMAKE_MATCH_3}")
set(CUDAToolkit_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
endif()
endif()
endif()
# Find the CUDA Runtime Library libcudart
@ -721,7 +764,6 @@ if(NOT CUDA_CUDART AND NOT CUDAToolkit_FIND_QUIETLY)
message(STATUS "Unable to find cudart library.")
endif()
unset(CUDAToolkit_ROOT_DIR)
if(_CUDAToolkit_Pop_Prefix)
list(REMOVE_AT CMAKE_PREFIX_PATH -1)
unset(_CUDAToolkit_Pop_Prefix)
@ -734,13 +776,16 @@ find_package_handle_standard_args(CUDAToolkit
REQUIRED_VARS
CUDAToolkit_INCLUDE_DIR
CUDA_CUDART
CUDAToolkit_NVCC_EXECUTABLE
CUDAToolkit_BIN_DIR
VERSION_VAR
CUDAToolkit_VERSION
)
unset(CUDAToolkit_ROOT_DIR)
mark_as_advanced(CUDA_CUDART
CUDAToolkit_INCLUDE_DIR
CUDAToolkit_NVCC_EXECUTABLE
CUDAToolkit_SENTINEL_FILE
)
#-----------------------------------------------------------------------------