Building Cross-Platform CUDA Applications with CMake

Thank you for the link will check it out. BTW I think I narrow down the problem. When setting PROJECT(myProject LANGUAGES CUDA CXX) will everything be compiled with nvcc? What I mean is that my main file is a main.cpp which I don't know if it goes through nvcc or directly through cl, could it be the problem? How to set main.cpp to be treated by nvcc so that device linker resolves whatever it needs to resolve?

Only .cu files will be handled by nvcc. Any .cpp/cxx/c++ files will be handled by cl.exe . If you have .cpp files that should be compiled with nvcc you will want to set the LANGUAGE property on that file to CUDA ( https://gitlab.kitware.com/... )

And so that implies that if my .exe links to a .lib which has been compiled with separable_compilation=on I have to tell CMake to compile my main.cpp with NVCC and activate also separable_compilation and all should be good to go, right?

Yes.

In CMake version 3.11.1, CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES does not use absolute paths (I think).

You are correct they are relative paths. I don't know why I said absolute.

Hi!
Thanks so much for this. I am running into problems pretty early in the process. I upgraded to CUDA 10.0 and downloaded VS2017 with cmake 3.12.2.
Trying to run the github code i get different errors when opening via visual studio or through the cmake.
when opening the cmake via VS i get:
1> Command line: C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2017\COMMUNITY\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe -G "Ninja" -DCMAKE_INSTALL_PREFIX:PATH="C:\Users\bensr\CMakeBuilds\205fdb7c-dc35-3038-9b74-9f4be7ba3cf4\install\x86-Debug" -DCMAKE_CXX_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.15.26726/bin/HostX86/x86/cl.exe" -DCMAKE_C_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.15.26726/bin/HostX86/x86/cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_MAKE_PROGRAM="C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2017\COMMUNITY\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\Ninja\ninja.exe" "C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake"
1> Working directory: C:\Users\bensr\CMakeBuilds\205fdb7c-dc35-3038-9b74-9f4be7ba3cf4\build\x86-Debug
1> -- The CUDA compiler identification is unknown
1> -- Check for working CUDA compiler: C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.0/bin/nvcc.exe
1> -- Check for working CUDA compiler: C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.0/bin/nvcc.exe -- broken
1> CMake Error at C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-3.11/Modules/CMakeTestCUDACompiler.cmake:46 (message):
1> The CUDA compiler
1>
1> "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.0/bin/nvcc.exe"
1>
1> is not able to compile a simple test program.
1>
1> It fails with the following output:
1>
1> Change Dir: C:/Users/bensr/CMakeBuilds/205fdb7c-dc35-3038-9b74-9f4be7ba3cf4/build/x86-Debug/CMakeFiles/CMakeTmp
1>
1> Run Build Command:"C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe" "cmTC_25c6c"
1> [1/3] Building CUDA object CMakeFiles\cmTC_25c6c.dir\main.cu.obj
1> FAILED: CMakeFiles/cmTC_25c6c.dir/main.cu.obj
1> cmd.exe /C "C:\PROGRA~1\NVIDIA~2\CUDA\v10.0\bin\nvcc.exe -x cu -c main.cu -o CMakeFiles\cmTC_25c6c.dir\main.cu.obj && C:\PROGRA~1\NVIDIA~2\CUDA\v10.0\bin\nvcc.exe -x cu -M main.cu -MT CMakeFiles\cmTC_25c6c.dir\main.cu.obj -o CMakeFiles\cmTC_25c6c.dir\main.cu.obj.d"
1> C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\include\vcruntime.h(184): error: invalid redeclaration of type name "size_t"
1>
1> C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\include\vcruntime_new.h(66): error: first parameter of allocation function must be of type "size_t"

and many more of this kinde
###############################################end of visual studio error##############################################33

When running through the cmake application it says

The CUDA compiler identification is unknown
Check for working CUDA compiler: C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.0/bin/nvcc.exe
Check for working CUDA compiler: C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.0/bin/nvcc.exe -- broken
CMake Error at C:/Program Files/CMake/share/cmake-3.12/Modules/CMakeTestCUDACompiler.cmake:46 (message):
The CUDA compiler

"C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v10.0/bin/nvcc.exe"

is not able to compile a simple test program.

It fails with the following output:

Change Dir: C:/Users/bensr/Documents/GitHub/code-samples/posts/cmake_build/CMakeFiles/CMakeTmp

Run Build Command:"C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/MSBuild/15.0/Bin/MSBuild.exe" "cmTC_71df4.vcxproj" "/p:Configuration=Debug" "/p:VisualStudioVersion=15.0"
Microsoft (R) Build Engine version 15.8.169+g1ccb72aefa for .NET Framework

Copyright (C) Microsoft Corporation. All rights reserved.

Build started 10/2/2018 11:01:22 PM.

Project "C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp\cmTC_71df4.vcxproj" on node 1 (default targets).

PrepareForBuild:

Creating directory "cmTC_71df4.dir\Debug\".

Creating directory "C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp\Debug\".

Creating directory "cmTC_71df4.dir\Debug\cmTC_71df4.tlog\".

InitializeBuildStatus:

Creating "cmTC_71df4.dir\Debug\cmTC_71df4.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.

AddCudaCompileDeps:

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\bin\HostX86\x86\cl.exe /E /nologo /showIncludes /TP /D__CUDACC__ /DCMAKE_INTDIR="Debug" /DCMAKE_INTDIR="Debug" /D_MBCS /I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\bin" /I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\include" /I. /FIcuda_runtime.h /c C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp\main.cu

Project "C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp\cmTC_71df4.vcxproj" (1) is building "C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp\cmTC_71df4.vcxproj" (1:2) on node 1 (CudaBuildCore target(s)).

CudaBuildCore:

Compiling CUDA source file main.cu...

cmd.exe /C "C:\Users\bensr\AppData\Local\Temp\tmp6e2fda3fa9c44f3584da74512023f7e9.cmd"

"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\bin\nvcc.exe" -gencode=arch=compute_35,code=\"sm_35,compute_35\" --use-local-env -ccbin "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\bin\HostX86\x86" -x cu -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\include" --keep-dir Debug -maxrregcount=0 --machine 32 --compile -cudart static -g -D"CMAKE_INTDIR=\"Debug\"" -D"CMAKE_INTDIR=\"Debug\"" -D_MBCS -Xcompiler "/EHsc /W1 /nologo /O2 /FdcmTC_71df4.dir\Debug\vc141.pdb /FS /Zi /MD " -o cmTC_71df4.dir\Debug\main.obj "C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp\main.cu"

C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp>"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\bin\nvcc.exe" -gencode=arch=compute_35,code=\"sm_35,compute_35\" --use-local-env -ccbin "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\bin\HostX86\x86" -x cu -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\include" --keep-dir Debug -maxrregcount=0 --machine 32 --compile -cudart static -g -D"CMAKE_INTDIR=\"Debug\"" -D"CMAKE_INTDIR=\"Debug\"" -D_MBCS -Xcompiler "/EHsc /W1 /nologo /O2 /FdcmTC_71df4.dir\Debug\vc141.pdb /FS /Zi /MD " -o cmTC_71df4.dir\Debug\main.obj "C:\Users\bensr\Documents\GitHub\code-samples\posts\cmake_build\CMakeFiles\CMakeTmp\main.cu"

nvcc fatal : 32 bit compilation is only supported for Microsoft Visual Studio 2013 and earlier

Please help!!!

The problem is that you are asking CMake to build a 32bit application which isn't supported by CUDA anymore.

To fix this issue you should run Ninja from a shell with the 64bit environment setup ( something like "C:\<path>\vcvarsall.bat" amd64).

I pulled down your github example here and tried it on my Macbook Pro (my trusty old one with nvidia graphics) and it builds just fine, but upon running I get:
0 CUDA driver version is insufficient for CUDA runtime version

I have older CUDA projects (that used the old cuda_add_executable from old CMake) that build and run just fine, so my setup is good (also deviceQuery passes). I'm on CUDA 10.0, OSX 10.13. I've been trying to make a new project with your modern CMake usage, but I'm hitting this same version error. Any idea why?

I expect the problem is related to setting up RPATH. This is a fairly common issue on OSX with CUDA. Add the following logic to the CMakeLists.txt and it should fix the problem


if(APPLE)
# Help the static cuda runtime find the driver (libcuda.dyllib) at runtime.
set_property(TARGET <target_name> PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
endif()

The trouble is that I pulled down your example verbatim (which already includes those lines) and I get this result. So I think there must be a little more to it.

Okay, after downgrading to CUDA 9.2 and CMake 3.12 I got your sample to build and run. My old code also works (though oddly the Nvidia samples now fail to build saying ld: library not found for -lnvrtc)

However, my new cmake project is still failing with the same old error when I try to run any part of it that accesses the GPU. I decided to query the versions and it output driver version = 0 and runtime version = 203845632, while I put the same query in your sample and got driver version = 9020 and runtime version = 9020. Mine is obviously wrong, but I can't imagine why.

The primary difference between my test and yours is that your test file is .cu, while mine is .cpp and I'm using the pimpl idiom to wrap up the cuda code so I can link against it from a .cpp. Is that somehow not allowed?

You most likely need to tell CMake that the .cpp file should be compiled with the cuda compiler by using:
set_source_files_properties(${sources} PROPERTIES LANGUAGE "CUDA")

A sample small example project would be help track down the issue.

The advice to make a small example to track down the issue was a good one (always is...). Your first thought about BUILD_RPATH was indeed the issue; I had missed a library that needed that specified. Thanks!

Hi, I found this new methods of using CUDA in cmake does not handle Mac framework as external library very well. For example if I added OpenGL to the project and trying to wrap all OpenGL dependencies in the particle lib with the target_link_libraries(particles ${OPENGL_LIBRARIES}) command. It will report
nvcc fatal : Don't know what to do with 'OpenGL'
The ${OPENGL_LIBRARIES} under Mac would be "/System/Library/Frameworks/OpenGL.framework". But somehow while doing the device linking, "OpenGL" was passed to nvcc instead of "-lOpenGL", hence the unknown option.
Here is the minimal patch file applied to the particle example to replicate the problem.

diff --git a/posts/cmake/CMakeLists.txt b/posts/cmake/CMakeLists.txt
index 0e39e4c..a485ed4 100644
--- a/posts/cmake/CMakeLists.txt
+++ b/posts/cmake/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(cmake_and_cuda LANGUAGES CXX CUDA)
-
+find_package(OpenGL REQUIRED)
include(CTest)
add_library(particles STATIC
@@ -24,6 +24,7 @@ target_compile_features(particles PUBLIC cxx_std_11)
set_target_properties( particles
PROPERTIES CUDA_SEPARABLE_COMPILATION ON
)
+target_link_libraries(particles ${OPENGL_LIBRARIES})
if(BUILD_TESTING)

This looks to be an issue with how CMake constructs the link line when doing device linking.

You can track the issue at: https://gitlab.kitware.com/...

The quick workaround is to use the `OpenGL::GL` target instead of `${OPENGL_LIBRARIES}`.

I knew I should have tried latest CMake first :) . I fixed this issue starting in 3.12.4 with the new rules on what libraries we pass to the device linker.

My recommendation is to bump your minimum required to CMake 3.12.4 ( and use 3.13+ ) and this will work with no modifications to your code.

I have tried using CMake 3.13.4 with ${OPENGL_LIBRARIES}, but it is still not working. I think the reason is .framework suffix is not properly handled. I have moved the discuss to the issue tracker https://gitlab.kitware.com/cmake/cmake/issues/18911

I’m trying to build this with CMake 3.19.8, CUDA 11.4.2, and Visual Studio 16.9.6. CMake generates and builds the project, but Visual Studio fails to build. I’m getting MSB3721 errors for the CUDA 11.4.targets file on lines 785 and 874. It says that nvcc.exe exited with code 1.

Any tips?

To understand why nvcc is returning an error code of 1, it’s necessary to increase the verbosity of VS output so that it shows the actual invocation of nvcc and the actual error. If you increase the VS verbosity what is the exact error message?