Newer versions of CMake (3.18 and later), are "aware" of the choice of CUDA architectures which compilation of CUDA code targets. Targets have a CUDA_ARCHITECTURES
property, which, when set, generates the appropriate -gencode arch=whatever,code=whatever
compilation options for you. You will even get a warning if you don't set this value:
CMake Error in CMakeLists.txt:
CUDA_ARCHITECTURES is empty for target "my_cuda_app".
by default, this target property is initialized to CMAKE_CUDA_ARCHITECTURES
. But CMAKE_CUDA_ARCHITECTURES
itself is not initialized to anything (!)
How can we have CMake auto-detect an appropriate value for CUDA_ARCHITECTURES
or the global CMAKD_CUDA_ARCHITECTURES
? That is, use the architectures of GPUs installed on the system?
CMake actually offers such autodetection capability, but:
CUDA_CMAKE_FLAGS
(which isnt what we want).Still, with a little elbow grease, we can make it work.
First, its location: It's in a module, FindCUDA/select_compute_arch
(which, on a Linux system, will be located in /path/to/cmake/root/share/cmake-X.YY/Modules/FindCUDA/select_compute_arch.cmake
).
Now here's how you use it:
include(FindCUDA/select_compute_arch)
CUDA_DETECT_INSTALLED_GPUS(INSTALLED_GPU_CCS_1)
string(STRIP "${INSTALLED_GPU_CCS_1}" INSTALLED_GPU_CCS_2)
string(REPLACE " " ";" INSTALLED_GPU_CCS_3 "${INSTALLED_GPU_CCS_2}")
string(REPLACE "." "" CUDA_ARCH_LIST "${INSTALLED_GPU_CCS_3}")
SET(CMAKE_CUDA_ARCHITECTURES ${CUDA_ARCH_LIST})
If you only want this for a single target, you would replace the last line with:
set_property(TARGET my_target PROPERTY "${CUDA_ARCH_LIST}")
Notes:
When there are no GPUs on your system you may get a result such as: 3.5;5.0;5.3;6.0;6.1;7.0;7.5;7.5+PTX
.
This is an issue with CMake which will not be resolved, since the submodule we're using here is not officially supported. So, if you need to compile on systems with no GPUs, either avoid this call or parse your results for the "+PTX" entry.
The select_compute_arch
submodule has existed for much longer, but in the past you would use it differently, and would include it through include(FindCUDA)
.
I wonder if LIST(APPEND CMAKE_CUDA_ARCHITECTURES
might not be more appropriate than SET(CMAKE_CUDA_ARCHITECTURES
.
See CMake issues 22375 and 19199 for where CMake might go with this in the future. Caveat: I filed those bugs...