Procházet zdrojové kódy

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++ ).
Robert Maynard před 9 roky
rodič
revize
44f3acb202

+ 1 - 0
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

+ 7 - 0
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 <CMake Language Lists>` of include directories provided
+by the CUDA Toolkit.  The value may be useful for C++ source files
+to include CUDA headers.

+ 2 - 0
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@")

+ 30 - 4
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

+ 1 - 0
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)

+ 11 - 0
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})

+ 8 - 0
Tests/Cuda/ToolkitInclude/main.cpp

@@ -0,0 +1,8 @@
+// Only thing we care about is that these headers are found
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+
+int main()
+{
+  return 0;
+}

+ 11 - 0
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()