CMake file bug in Optix 5.x can cause incorrectly formatted nvcc command

This bug happens when using the CUDA_WRAP_SRCS macro on Windows with Visual Studio if the CUDA_HOST_COMPILER variable is left blank, and here’s why:

In FindCUDA.cmake @ line 1378 (inside the CUDA_WRAP_SRCS definition) exists the following code:

# This needs to be passed in at this stage, because VS needs to fill out the
  # value of VCInstallDir from within VS.  Note that CCBIN is only used if
  # -ccbin or --compiler-bindir isn't used and CUDA_HOST_COMPILER matches
  # $(VCInstallDir)/bin.
  if(CMAKE_GENERATOR MATCHES "Visual Studio")
    set(ccbin_flags -D "\"CCBIN:PATH=$(VCInstallDir)bin\"" )
  else()
    set(ccbin_flags)
  endif()

The comment notes that the CCBIN variable is only used if -ccbin or --compiler-bindir isn’t used and CUDA_HOST_COMPILER matches $(VCInstallDir)/bin. However this is not true.

The CCBIN variable is used in the run_nvcc.cmake file (which is a configure file used to run nvcc), however the variable is used regardless of the above situtation. It is checked in that situation by the following code @ line 125:

# Any -ccbin existing in CUDA_NVCC_FLAGS gets highest priority
list( FIND CUDA_NVCC_FLAGS "-ccbin" ccbin_found0 )
list( FIND CUDA_NVCC_FLAGS "--compiler-bindir" ccbin_found1 )
if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER )
  if (CUDA_HOST_COMPILER STREQUAL "$(VCInstallDir)bin" AND DEFINED CCBIN)
    set(CCBIN -ccbin "${CCBIN}")
  else()
    set(CCBIN -ccbin "${CUDA_HOST_COMPILER}")
  endif()
endif()

However if none of the conditionals pass, for instance if CUDA_HOST_COMPILER is blank, then the variable CCBIN is left unchanged, this is a problem because FindCUDA.cmake sets it to various path values:

FindCUDA.cmake @ line 1715 onwards:

if (CUDA_HOST_COMPILER STREQUAL "$(VCInstallDir)bin")
          if (CUDA_VS_DIR)
            set(_cuda_dependency_ccbin -D "CCBIN:PATH=${CUDA_VS_DIR}/VC/bin")
          endif()
        elseif(ccbin_flags)
          # The CUDA_HOST_COMPILER is set to something interesting, so use the
          # ccbin_flags as-is.
          set(_cuda_dependency_ccbin ${ccbin_flags})
        endif()

This results in the CCBIN variable being set to a path and added to the nvcc command which nvcc interprets as another file giving the error:

A single input file is required for a non-link phase when an outputfile is specified

Now the easiest fix for this is to change run_nvcc.cmake to obey the comment in FindCUDA.cmake and not use the CCBIN variable if the conditions aren’t met, this can easily be done by clearing the CCBIN variable like so:

# Any -ccbin existing in CUDA_NVCC_FLAGS gets highest priority
list( FIND CUDA_NVCC_FLAGS "-ccbin" ccbin_found0 )
list( FIND CUDA_NVCC_FLAGS "--compiler-bindir" ccbin_found1 )
if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER )
  if (CUDA_HOST_COMPILER STREQUAL "$(VCInstallDir)bin" AND DEFINED CCBIN)
    set(CCBIN -ccbin "${CCBIN}")
  else()
    set(CCBIN -ccbin "${CUDA_HOST_COMPILER}")
  endif()
else()
	# Need to ensure here that ccbin is cleared as FindCUDA.cmake sets this to something non-executable on Windows
	set(CCBIN "")
endif()

That’s the fix I have locally and it works fine, I know those cmake files are only distributed along with the samples but I imagine quite a few people like myself port them to actual projects.

Cheers