FindNVML.cmake done correctly — how to have CMake find Nvidia Management Library (NVML) on Windows and Linux

Nvidia Management Library (NVML) is a powerful API to get and set GPU states. Currently there is a lack of official CMake support. The first couple of google search results point to a script on github, which unfortunately is only partially correct and does not work on Windows. Here we provide a working solution, tested on Scientific Linux 6 and Windows 10, with CUDA 9.1 and CMake 3.11.

The NVML API is spread across several locations:

  • Linux
    • Header: ${CUDA_INCLUDE_DIRS}/nvml.h
    • Shared library: ${CUDA_TOOLKIT_ROOT_DIR}/lib64/stubs/libnvidia-ml.so
  • Windows
    • Header: ${CUDA_INCLUDE_DIRS}/nvml.h
    • Shared library: C:/Program Files/NVIDIA Corporation/NVSMI/nvml.dll
    • Import library: ${CUDA_TOOLKIT_ROOT_DIR}/lib/x64/nvml.lib

It is critical to note that, on Windows a dynamic library (.dll) is accompanied by an import library (.lib), which is different from a static library (also .lib). In CMake the target binary should link to the import library (.lib) directly instead of the .dll file. With that, the correct FindNVML.cmake script is shown in listing 1.

Listing 1

# FindNVML.cmake

if(${CUDA_VERSION_STRING} VERSION_LESS "9.1")
    string(CONCAT ERROR_MSG "--> ARCHER: Current CUDA version "
                         ${CUDA_VERSION_STRING}
                         " is too old. Must upgrade it to 9.1 or newer.")
    message(FATAL_ERROR ${ERROR_MSG})
endif()

# windows, including both 32-bit and 64-bit
if(WIN32)
    set(NVML_NAMES nvml)
    set(NVML_LIB_DIR "${CUDA_TOOLKIT_ROOT_DIR}/lib/x64")
    set(NVML_INCLUDE_DIR ${CUDA_INCLUDE_DIRS})

    # .lib import library full path
    find_file(NVML_LIB_PATH
              NO_DEFAULT_PATH
              NAMES nvml.lib
              PATHS ${NVML_LIB_DIR})

    # .dll full path
    find_file(NVML_DLL_PATH
              NO_DEFAULT_PATH
              NAMES nvml.dll
              PATHS "C:/Program Files/NVIDIA Corporation/NVSMI")
# linux
elseif(UNIX AND NOT APPLE)
    set(NVML_NAMES nvidia-ml)
    set(NVML_LIB_DIR "${CUDA_TOOLKIT_ROOT_DIR}/lib64/stubs")
    set(NVML_INCLUDE_DIR ${CUDA_INCLUDE_DIRS})

    find_library(NVML_LIB_PATH
                 NO_DEFAULT_PATH
                 NAMES ${NVML_NAMES}
                 PATHS ${NVML_LIB_DIR})
else()
    message(FATAL_ERROR "Unsupported platform.")
endif()

find_path(NVML_INCLUDE_PATH
          NO_DEFAULT_PATH
          NAMES nvml.h
          PATHS ${NVML_INCLUDE_DIR})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(NVML DEFAULT_MSG NVML_LIB_PATH NVML_INCLUDE_PATH)

Once find_package(NVML) is called in user CMake code, two cache variables are generated: NVML_LIB_PATH and NVML_INCLUDE_PATH. For Windows, there is an additional NVML_DLL_PATH.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s