From 44f3acb202c316bc6a863a1823aaafae486c899a Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Wed, 8 Feb 2017 16:51:18 -0500 Subject: CUDA: Detect the toolkit include directories The `nvcc -v` output provides what include directories need to be added to use the CUDA toolkit from other languages ( C/C++ ). --- Help/manual/cmake-variables.7.rst | 1 + .../CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst | 7 +++++ Modules/CMakeCUDACompiler.cmake.in | 2 ++ Modules/CMakeDetermineCUDACompiler.cmake | 34 +++++++++++++++++++--- Tests/Cuda/CMakeLists.txt | 1 + Tests/Cuda/ToolkitInclude/CMakeLists.txt | 11 +++++++ Tests/Cuda/ToolkitInclude/main.cpp | 8 +++++ Tests/CudaOnly/EnableStandard/CMakeLists.txt | 11 +++++++ 8 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst create mode 100644 Tests/Cuda/ToolkitInclude/CMakeLists.txt create mode 100644 Tests/Cuda/ToolkitInclude/main.cpp diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 95f780a..38444d1 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -353,6 +353,7 @@ Variables for Languages /variable/CMAKE_CUDA_EXTENSIONS /variable/CMAKE_CUDA_STANDARD /variable/CMAKE_CUDA_STANDARD_REQUIRED + /variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES /variable/CMAKE_CXX_COMPILE_FEATURES /variable/CMAKE_CXX_EXTENSIONS /variable/CMAKE_CXX_STANDARD diff --git a/Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst new file mode 100644 index 0000000..768f571 --- /dev/null +++ b/Help/variable/CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES.rst @@ -0,0 +1,7 @@ +CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES +-------------------------------------- + +When the ``CUDA`` language has been enabled, this provides a +:ref:`;-list ` of include directories provided +by the CUDA Toolkit. The value may be useful for C++ source files +to include CUDA headers. diff --git a/Modules/CMakeCUDACompiler.cmake.in b/Modules/CMakeCUDACompiler.cmake.in index 158d12b..f524e5f 100644 --- a/Modules/CMakeCUDACompiler.cmake.in +++ b/Modules/CMakeCUDACompiler.cmake.in @@ -16,6 +16,8 @@ set(CMAKE_CUDA_SOURCE_FILE_EXTENSIONS cu) set(CMAKE_CUDA_LINKER_PREFERENCE 15) set(CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES 1) +set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "@CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES@") + set(CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES "@CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES@") set(CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES "@CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES@") set(CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CUDA_HOST_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@") diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake index bef6d0e..7b6d17b 100644 --- a/Modules/CMakeDetermineCUDACompiler.cmake +++ b/Modules/CMakeDetermineCUDACompiler.cmake @@ -84,20 +84,20 @@ endif() #the compiler with cuda-fake-ld and pass too CMAKE_PARSE_IMPLICIT_LINK_INFO if(CMAKE_CUDA_COMPILER_ID STREQUAL NVIDIA) set(_nvcc_log "") - string(REPLACE "\r" "" _nvcc_output "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") - if(_nvcc_output MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n") + string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}") + if(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n") set(_nvcc_libraries "${CMAKE_MATCH_1}") string(APPEND _nvcc_log " found 'LIBRARIES=' string: [${_nvcc_libraries}]\n") else() set(_nvcc_libraries "") - string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output}") + string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}") string(APPEND _nvcc_log " no 'LIBRARIES=' string found in nvcc output:${_nvcc_output_log}\n") endif() set(_nvcc_link_line "") if(_nvcc_libraries) # Remove variable assignments. - string(REGEX REPLACE "#\\\$ *[^= ]+=[^\n]*\n" "" _nvcc_output "${_nvcc_output}") + string(REGEX REPLACE "#\\\$ *[^= ]+=[^\n]*\n" "" _nvcc_output "${_nvcc_output_orig}") # Split lines. string(REGEX REPLACE "\n+(#\\\$ )?" ";" _nvcc_output "${_nvcc_output}") foreach(line IN LISTS _nvcc_output) @@ -150,6 +150,32 @@ if(CMAKE_CUDA_COMPILER_ID STREQUAL NVIDIA) message(FATAL_ERROR "Failed to extract nvcc implicit link line.") endif() + set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES ) + if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n") + set(_nvcc_includes "${CMAKE_MATCH_1}") + string(APPEND _nvcc_log " found 'INCLUDES=' string: [${_nvcc_includes}]\n") + else() + set(_nvcc_includes "") + string(REPLACE "\n" "\n " _nvcc_output_log "\n${_nvcc_output_orig}") + string(APPEND _nvcc_log " no 'INCLUDES=' string found in nvcc output:${_nvcc_output_log}\n") + endif() + if(_nvcc_includes) + # across all operating system each include directory is prefixed with -I + separate_arguments(_nvcc_output UNIX_COMMAND "${_nvcc_includes}") + foreach(line IN LISTS _nvcc_output) + string(REGEX REPLACE "^-I" "" line "${line}") + get_filename_component(line "${line}" ABSOLUTE) + list(APPEND CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${line}") + endforeach() + + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Parsed CUDA nvcc include information from above output:\n${_nvcc_log}\n${log}\n\n") + else() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Failed to detect CUDA nvcc include information:\n${_nvcc_log}\n\n") + endif() + + endif() # configure all variables set in this file diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt index 40c9675..42b00e1 100644 --- a/Tests/Cuda/CMakeLists.txt +++ b/Tests/Cuda/CMakeLists.txt @@ -2,4 +2,5 @@ ADD_TEST_MACRO(Cuda.Complex CudaComplex) ADD_TEST_MACRO(Cuda.ConsumeCompileFeatures CudaConsumeCompileFeatures) ADD_TEST_MACRO(Cuda.ObjectLibrary CudaObjectLibrary) +ADD_TEST_MACRO(Cuda.ToolkitInclude CudaToolkitInclude) ADD_TEST_MACRO(Cuda.ProperLinkFlags ProperLinkFlags) diff --git a/Tests/Cuda/ToolkitInclude/CMakeLists.txt b/Tests/Cuda/ToolkitInclude/CMakeLists.txt new file mode 100644 index 0000000..f246b54 --- /dev/null +++ b/Tests/Cuda/ToolkitInclude/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.8) +project (ToolkitInclude CXX CUDA) + +#Goal for this example: +# Validate that between the CXX implicit include directories and the +# CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES directories we can find +# the cuda runtime headers + +add_executable(CudaToolkitInclude main.cpp) +target_include_directories(CudaToolkitInclude PRIVATE + ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) diff --git a/Tests/Cuda/ToolkitInclude/main.cpp b/Tests/Cuda/ToolkitInclude/main.cpp new file mode 100644 index 0000000..c8d5c6b --- /dev/null +++ b/Tests/Cuda/ToolkitInclude/main.cpp @@ -0,0 +1,8 @@ +// Only thing we care about is that these headers are found +#include +#include + +int main() +{ + return 0; +} diff --git a/Tests/CudaOnly/EnableStandard/CMakeLists.txt b/Tests/CudaOnly/EnableStandard/CMakeLists.txt index 53b9132..35a1deb 100644 --- a/Tests/CudaOnly/EnableStandard/CMakeLists.txt +++ b/Tests/CudaOnly/EnableStandard/CMakeLists.txt @@ -13,3 +13,14 @@ target_link_libraries(CudaOnlyEnableStandard PRIVATE CUDAStatic11 CUDADynamic11) set_target_properties(CUDAStatic11 CUDADynamic11 PROPERTIES CUDA_STANDARD 11) set_target_properties(CUDAStatic11 CUDADynamic11 PROPERTIES CUDA_STANDARD_REQUIRED TRUE) + +#Verify CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES +foreach(dir ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) + if(NOT IS_DIRECTORY "${dir}") + message(FATAL_ERROR + "CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES entry\n" + " ${dir}\n" + "is not an existing directory." + ) + endif() +endforeach() -- cgit v0.12