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

[Last updated on Feb 26, 2020]

The latest cmake 3.17 has just started to officially support a new module FindCUDAToolkit where NVML library is conveniently referenced by the target CUDA::nvml. With this new feature this article is now deprecated.

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 comment