Search code examples
cmakecudanvidiabuild-automationcompute-capability

How can I get CMake to automatically detect the value for CUDA_ARCHITECTURES?


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?


Solution

  • CMake actually offers such autodetection capability, but:

    1. It's undocumented (and will probably be refactored at some point in the future).
    2. It's part of the deprecated FindCUDA mechanism, and is geared towards direct manipulation of CUDA_CMAKE_FLAGS (which isnt what we want).
    3. It doesn't "play nice", and hides its useful-form internal variables from us.

    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...