Home | History | Annotate | Download | only in FindCUDA
      1 #  James Bigler, NVIDIA Corp (nvidia.com - jbigler)
      2 #
      3 #  Copyright (c) 2008 - 2009 NVIDIA Corporation.  All rights reserved.
      4 #
      5 #  This code is licensed under the MIT License.  See the FindCUDA.cmake script
      6 #  for the text of the license.
      7 
      8 # The MIT License
      9 #
     10 # License for the specific language governing rights and limitations under
     11 # Permission is hereby granted, free of charge, to any person obtaining a
     12 # copy of this software and associated documentation files (the "Software"),
     13 # to deal in the Software without restriction, including without limitation
     14 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
     15 # and/or sell copies of the Software, and to permit persons to whom the
     16 # Software is furnished to do so, subject to the following conditions:
     17 #
     18 # The above copyright notice and this permission notice shall be included
     19 # in all copies or substantial portions of the Software.
     20 #
     21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     22 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     23 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     24 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     25 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     26 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     27 # DEALINGS IN THE SOFTWARE.
     28 
     29 
     30 ##########################################################################
     31 # This file runs the nvcc commands to produce the desired output file along with
     32 # the dependency file needed by CMake to compute dependencies.  In addition the
     33 # file checks the output of each command and if the command fails it deletes the
     34 # output files.
     35 
     36 # Input variables
     37 #
     38 # verbose:BOOL=<>          OFF: Be as quiet as possible (default)
     39 #                          ON : Describe each step
     40 #
     41 # build_configuration:STRING=<> Typically one of Debug, MinSizeRel, Release, or
     42 #                               RelWithDebInfo, but it should match one of the
     43 #                               entries in CUDA_HOST_FLAGS. This is the build
     44 #                               configuration used when compiling the code.  If
     45 #                               blank or unspecified Debug is assumed as this is
     46 #                               what CMake does.
     47 #
     48 # generated_file:STRING=<> File to generate.  This argument must be passed in.
     49 #
     50 # generated_cubin_file:STRING=<> File to generate.  This argument must be passed
     51 #                                                   in if build_cubin is true.
     52 
     53 if(NOT generated_file)
     54   message(FATAL_ERROR "You must specify generated_file on the command line")
     55 endif()
     56 
     57 # Set these up as variables to make reading the generated file easier
     58 set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path
     59 set(source_file "@source_file@") # path
     60 set(NVCC_generated_dependency_file "@NVCC_generated_dependency_file@") # path
     61 set(cmake_dependency_file "@cmake_dependency_file@") # path
     62 set(CUDA_make2cmake "@CUDA_make2cmake@") # path
     63 set(CUDA_parse_cubin "@CUDA_parse_cubin@") # path
     64 set(build_cubin @build_cubin@) # bool
     65 set(CUDA_HOST_COMPILER "@CUDA_HOST_COMPILER@") # path
     66 # We won't actually use these variables for now, but we need to set this, in
     67 # order to force this file to be run again if it changes.
     68 set(generated_file_path "@generated_file_path@") # path
     69 set(generated_file_internal "@generated_file@") # path
     70 set(generated_cubin_file_internal "@generated_cubin_file@") # path
     71 
     72 set(CUDA_NVCC_EXECUTABLE "@CUDA_NVCC_EXECUTABLE@") # path
     73 set(CUDA_NVCC_FLAGS @CUDA_NVCC_FLAGS@ ;; @CUDA_WRAP_OPTION_NVCC_FLAGS@) # list
     74 @CUDA_NVCC_FLAGS_CONFIG@
     75 set(nvcc_flags @nvcc_flags@) # list
     76 set(CUDA_NVCC_INCLUDE_ARGS "@CUDA_NVCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly).
     77 set(format_flag "@format_flag@") # string
     78 
     79 if(build_cubin AND NOT generated_cubin_file)
     80   message(FATAL_ERROR "You must specify generated_cubin_file on the command line")
     81 endif()
     82 
     83 # This is the list of host compilation flags.  It C or CXX should already have
     84 # been chosen by FindCUDA.cmake.
     85 @CUDA_HOST_FLAGS@
     86 
     87 # Take the compiler flags and package them up to be sent to the compiler via -Xcompiler
     88 set(nvcc_host_compiler_flags "")
     89 # If we weren't given a build_configuration, use Debug.
     90 if(NOT build_configuration)
     91   set(build_configuration Debug)
     92 endif()
     93 string(TOUPPER "${build_configuration}" build_configuration)
     94 #message("CUDA_NVCC_HOST_COMPILER_FLAGS = ${CUDA_NVCC_HOST_COMPILER_FLAGS}")
     95 foreach(flag ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}})
     96   # Extra quotes are added around each flag to help nvcc parse out flags with spaces.
     97   set(nvcc_host_compiler_flags "${nvcc_host_compiler_flags},\"${flag}\"")
     98 endforeach()
     99 if (nvcc_host_compiler_flags)
    100   set(nvcc_host_compiler_flags "-Xcompiler" ${nvcc_host_compiler_flags})
    101 endif()
    102 #message("nvcc_host_compiler_flags = \"${nvcc_host_compiler_flags}\"")
    103 # Add the build specific configuration flags
    104 list(APPEND CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS_${build_configuration}})
    105 
    106 # Any -ccbin existing in CUDA_NVCC_FLAGS gets highest priority
    107 list( FIND CUDA_NVCC_FLAGS "-ccbin" ccbin_found0 )
    108 list( FIND CUDA_NVCC_FLAGS "--compiler-bindir" ccbin_found1 )
    109 if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER )
    110   if (CUDA_HOST_COMPILER STREQUAL "$(VCInstallDir)bin" AND DEFINED CCBIN)
    111     set(CCBIN -ccbin "${CCBIN}")
    112   else()
    113     set(CCBIN -ccbin "${CUDA_HOST_COMPILER}")
    114   endif()
    115 endif()
    116 
    117 # cuda_execute_process - Executes a command with optional command echo and status message.
    118 #
    119 #   status  - Status message to print if verbose is true
    120 #   command - COMMAND argument from the usual execute_process argument structure
    121 #   ARGN    - Remaining arguments are the command with arguments
    122 #
    123 #   CUDA_result - return value from running the command
    124 #
    125 # Make this a macro instead of a function, so that things like RESULT_VARIABLE
    126 # and other return variables are present after executing the process.
    127 macro(cuda_execute_process status command)
    128   set(_command ${command})
    129   if(NOT "x${_command}" STREQUAL "xCOMMAND")
    130     message(FATAL_ERROR "Malformed call to cuda_execute_process.  Missing COMMAND as second argument. (command = ${command})")
    131   endif()
    132   if(verbose)
    133     execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status})
    134     # Now we need to build up our command string.  We are accounting for quotes
    135     # and spaces, anything else is left up to the user to fix if they want to
    136     # copy and paste a runnable command line.
    137     set(cuda_execute_process_string)
    138     foreach(arg ${ARGN})
    139       # If there are quotes, excape them, so they come through.
    140       string(REPLACE "\"" "\\\"" arg ${arg})
    141       # Args with spaces need quotes around them to get them to be parsed as a single argument.
    142       if(arg MATCHES " ")
    143         list(APPEND cuda_execute_process_string "\"${arg}\"")
    144       else()
    145         list(APPEND cuda_execute_process_string ${arg})
    146       endif()
    147     endforeach()
    148     # Echo the command
    149     execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${cuda_execute_process_string})
    150   endif()
    151   # Run the command
    152   execute_process(COMMAND ${ARGN} RESULT_VARIABLE CUDA_result )
    153 endmacro()
    154 
    155 # Delete the target file
    156 cuda_execute_process(
    157   "Removing ${generated_file}"
    158   COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
    159   )
    160 
    161 # For CUDA 2.3 and below, -G -M doesn't work, so remove the -G flag
    162 # for dependency generation and hope for the best.
    163 set(depends_CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}")
    164 set(CUDA_VERSION @CUDA_VERSION@)
    165 if(CUDA_VERSION VERSION_LESS "3.0")
    166   cmake_policy(PUSH)
    167   # CMake policy 0007 NEW states that empty list elements are not
    168   # ignored.  I'm just setting it to avoid the warning that's printed.
    169   cmake_policy(SET CMP0007 NEW)
    170   # Note that this will remove all occurances of -G.
    171   list(REMOVE_ITEM depends_CUDA_NVCC_FLAGS "-G")
    172   cmake_policy(POP)
    173 endif()
    174 
    175 # nvcc doesn't define __CUDACC__ for some reason when generating dependency files.  This
    176 # can cause incorrect dependencies when #including files based on this macro which is
    177 # defined in the generating passes of nvcc invokation.  We will go ahead and manually
    178 # define this for now until a future version fixes this bug.
    179 set(CUDACC_DEFINE -D__CUDACC__)
    180 
    181 # Generate the dependency file
    182 cuda_execute_process(
    183   "Generating dependency file: ${NVCC_generated_dependency_file}"
    184   COMMAND "${CUDA_NVCC_EXECUTABLE}"
    185   -M
    186   ${CUDACC_DEFINE}
    187   "${source_file}"
    188   -o "${NVCC_generated_dependency_file}"
    189   ${CCBIN}
    190   ${nvcc_flags}
    191   ${nvcc_host_compiler_flags}
    192   ${depends_CUDA_NVCC_FLAGS}
    193   -DNVCC
    194   ${CUDA_NVCC_INCLUDE_ARGS}
    195   )
    196 
    197 if(CUDA_result)
    198   message(FATAL_ERROR "Error generating ${generated_file}")
    199 endif()
    200 
    201 # Generate the cmake readable dependency file to a temp file.  Don't put the
    202 # quotes just around the filenames for the input_file and output_file variables.
    203 # CMake will pass the quotes through and not be able to find the file.
    204 cuda_execute_process(
    205   "Generating temporary cmake readable file: ${cmake_dependency_file}.tmp"
    206   COMMAND "${CMAKE_COMMAND}"
    207   -D "input_file:FILEPATH=${NVCC_generated_dependency_file}"
    208   -D "output_file:FILEPATH=${cmake_dependency_file}.tmp"
    209   -P "${CUDA_make2cmake}"
    210   )
    211 
    212 if(CUDA_result)
    213   message(FATAL_ERROR "Error generating ${generated_file}")
    214 endif()
    215 
    216 # Copy the file if it is different
    217 cuda_execute_process(
    218   "Copy if different ${cmake_dependency_file}.tmp to ${cmake_dependency_file}"
    219   COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${cmake_dependency_file}.tmp" "${cmake_dependency_file}"
    220   )
    221 
    222 if(CUDA_result)
    223   message(FATAL_ERROR "Error generating ${generated_file}")
    224 endif()
    225 
    226 # Delete the temporary file
    227 cuda_execute_process(
    228   "Removing ${cmake_dependency_file}.tmp and ${NVCC_generated_dependency_file}"
    229   COMMAND "${CMAKE_COMMAND}" -E remove "${cmake_dependency_file}.tmp" "${NVCC_generated_dependency_file}"
    230   )
    231 
    232 if(CUDA_result)
    233   message(FATAL_ERROR "Error generating ${generated_file}")
    234 endif()
    235 
    236 # Generate the code
    237 cuda_execute_process(
    238   "Generating ${generated_file}"
    239   COMMAND "${CUDA_NVCC_EXECUTABLE}"
    240   "${source_file}"
    241   ${format_flag} -o "${generated_file}"
    242   ${CCBIN}
    243   ${nvcc_flags}
    244   ${nvcc_host_compiler_flags}
    245   ${CUDA_NVCC_FLAGS}
    246   -DNVCC
    247   ${CUDA_NVCC_INCLUDE_ARGS}
    248   )
    249 
    250 if(CUDA_result)
    251   # Since nvcc can sometimes leave half done files make sure that we delete the output file.
    252   cuda_execute_process(
    253     "Removing ${generated_file}"
    254     COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
    255     )
    256   message(FATAL_ERROR "Error generating file ${generated_file}")
    257 else()
    258   if(verbose)
    259     message("Generated ${generated_file} successfully.")
    260   endif()
    261 endif()
    262 
    263 # Cubin resource report commands.
    264 if( build_cubin )
    265   # Run with -cubin to produce resource usage report.
    266   cuda_execute_process(
    267     "Generating ${generated_cubin_file}"
    268     COMMAND "${CUDA_NVCC_EXECUTABLE}"
    269     "${source_file}"
    270     ${CUDA_NVCC_FLAGS}
    271     ${nvcc_flags}
    272     ${CCBIN}
    273     ${nvcc_host_compiler_flags}
    274     -DNVCC
    275     -cubin
    276     -o "${generated_cubin_file}"
    277     ${CUDA_NVCC_INCLUDE_ARGS}
    278     )
    279 
    280   # Execute the parser script.
    281   cuda_execute_process(
    282     "Executing the parser script"
    283     COMMAND  "${CMAKE_COMMAND}"
    284     -D "input_file:STRING=${generated_cubin_file}"
    285     -P "${CUDA_parse_cubin}"
    286     )
    287 
    288 endif()
    289