mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-01 11:22:21 -06:00
This marks all `<PACKAGENAME>_FOUND` result variables as deprecated where possible (for `<PackageName>` find modules) to make it clearer which variable to use. In CMake 3.3, the FindPackageHandleStandardArgs module was refactored to set both `<PackageName>_FOUND` and uppercase `<PACKAGENAME>_FOUND` result variables to the same values. Before that, the FOUND_VAR argument could be used to set the result variable. * FindMatlab: Uppercased MATLAB_FOUND is not mentioned as it was never documented. * Documentation for FindPythonInterp and FindPythonLibs modules synced accordingly to their deprecation (3.12 instead of 4.2). * OPENGL_FOUND: deprecation version synced with other find modules. * DevIL_FOUND was introduced in CMake 3.8. The uppercased variant not mentioned as it was previously never documented. Fixes: #27242
385 lines
12 KiB
CMake
385 lines
12 KiB
CMake
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
# file LICENSE.rst or https://cmake.org/licensing for details.
|
|
|
|
#[=======================================================================[.rst:
|
|
FindEnvModules
|
|
--------------
|
|
|
|
.. versionadded:: 3.15
|
|
|
|
Finds an Environment Modules implementation and provides commands for use in
|
|
CMake scripts:
|
|
|
|
.. code-block:: cmake
|
|
|
|
find_package(EnvModules [...])
|
|
|
|
The Environment Modules system is a command-line tool that manages Unix-like
|
|
shell environments by dynamically modifying environment variables.
|
|
It is commonly used in High-Performance Computing (HPC) environments to
|
|
support multiple software versions or configurations.
|
|
|
|
This module is compatible with the two most common implementations:
|
|
|
|
* Lua-based Lmod
|
|
* TCL-based Environment Modules
|
|
|
|
This module is primarily intended for setting up compiler and library
|
|
environments within a :ref:`CTest Script <CTest Script>` (``ctest -S``).
|
|
It may also be used in a :ref:`CMake Script <Script Processing Mode>`
|
|
(``cmake -P``).
|
|
|
|
.. note::
|
|
|
|
The loaded environment will not persist beyond the end of the calling
|
|
process. Do not use this module in CMake project code (such as
|
|
``CMakeLists.txt``) to load compiler environments, as the environment
|
|
changes will not be available during the build phase. In such a case, load
|
|
the desired environment before invoking CMake or the generated build system.
|
|
|
|
Result Variables
|
|
^^^^^^^^^^^^^^^^
|
|
|
|
This module defines the following variables:
|
|
|
|
``EnvModules_FOUND``
|
|
Boolean indicating whether a compatible Environment Modules framework was
|
|
found.
|
|
|
|
Cache Variables
|
|
^^^^^^^^^^^^^^^
|
|
|
|
The following cache variables may also be set:
|
|
|
|
``EnvModules_COMMAND``
|
|
The path to a low level module command to use.
|
|
|
|
Hints
|
|
^^^^^
|
|
|
|
This module accepts the following variables before calling the
|
|
``find_package(EnvModules)``:
|
|
|
|
``ENV{MODULESHOME}``
|
|
This environment variable is usually set by the Environment Modules
|
|
implementation, and can be used as a hint to locate the module command to
|
|
execute.
|
|
|
|
Commands
|
|
^^^^^^^^
|
|
|
|
This module provides the following commands for interacting with the
|
|
Environment Modules system, if found:
|
|
|
|
.. command:: env_module
|
|
|
|
Executes an arbitrary module command:
|
|
|
|
.. code-block:: cmake
|
|
|
|
env_module(<command> <args>...)
|
|
env_module(
|
|
COMMAND <command> <args>...
|
|
[OUTPUT_VARIABLE <out-var>]
|
|
[RESULT_VARIABLE <ret-var>]
|
|
)
|
|
|
|
The options are:
|
|
|
|
``COMMAND <command> <args>...``
|
|
The module sub-command and arguments to execute as if passed directly to
|
|
the module command in the shell environment.
|
|
|
|
``OUTPUT_VARIABLE <out-var>``
|
|
Stores the standard output of the executed module command in the specified
|
|
variable.
|
|
|
|
``RESULT_VARIABLE <ret-var>``
|
|
Stores the return code of the executed module command in the specified
|
|
variable.
|
|
|
|
.. command:: env_module_swap
|
|
|
|
Swaps one module for another:
|
|
|
|
.. code-block:: cmake
|
|
|
|
env_module_swap(
|
|
<out-mod>
|
|
<in-mod>
|
|
[OUTPUT_VARIABLE <out-var>]
|
|
[RESULT_VARIABLE <ret-var>]
|
|
)
|
|
|
|
This is functionally equivalent to the ``module swap <out-mod> <in-mod>``
|
|
shell command.
|
|
|
|
The options are:
|
|
|
|
``OUTPUT_VARIABLE <out-var>``
|
|
Stores the standard output of the executed module command in the specified
|
|
variable.
|
|
|
|
``RESULT_VARIABLE <ret-var>``
|
|
Stores the return code of the executed module command in the specified
|
|
variable.
|
|
|
|
.. command:: env_module_list
|
|
|
|
Retrieves the list of currently loaded modules:
|
|
|
|
.. code-block:: cmake
|
|
|
|
env_module_list(<out-var>)
|
|
|
|
This is functionally equivalent to the ``module list`` shell command.
|
|
The result is stored in ``<out-var>`` as a properly formatted CMake
|
|
:ref:`semicolon-separated list <CMake Language Lists>` variable.
|
|
|
|
.. command:: env_module_avail
|
|
|
|
Retrieves the list of available modules:
|
|
|
|
.. code-block:: cmake
|
|
|
|
env_module_avail([<mod-prefix>] <out-var>)
|
|
|
|
This is functionally equivalent to the ``module avail <mod-prefix>`` shell
|
|
command. The result is stored in ``<out-var>`` as a properly formatted
|
|
CMake :ref:`semicolon-separated list <CMake Language Lists>` variable.
|
|
|
|
Examples
|
|
^^^^^^^^
|
|
|
|
In the following example, this module is used in a CTest script to configure
|
|
the compiler and libraries for a Cray Programming Environment.
|
|
After the Environment Modules system is found, the ``env_module()`` command is
|
|
used to load the necessary compiler, MPI, and scientific libraries to set up
|
|
the build environment. The ``CRAYPE_LINK_TYPE`` environment variable is set
|
|
to ``dynamic`` to specify dynamic linking. This instructs the Cray Linux
|
|
Environment compiler driver to link against dynamic libraries at runtime,
|
|
rather than linking static libraries at compile time. As a result, the
|
|
compiler produces dynamically linked executable files.
|
|
|
|
.. code-block:: cmake
|
|
:caption: ``example-script.cmake``
|
|
|
|
set(CTEST_BUILD_NAME "CrayLinux-CrayPE-Cray-dynamic")
|
|
set(CTEST_BUILD_CONFIGURATION Release)
|
|
set(CTEST_BUILD_FLAGS "-k -j8")
|
|
set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
|
|
|
|
# ...
|
|
|
|
find_package(EnvModules REQUIRED)
|
|
|
|
# Clear all currently loaded Environment Modules to start with a clean state
|
|
env_module(purge)
|
|
|
|
# Load the base module-handling system to use other modules
|
|
env_module(load modules)
|
|
|
|
# Load Cray Programming Environment (Cray PE) support, which manages
|
|
# platform-specific optimizations and architecture selection
|
|
env_module(load craype)
|
|
|
|
# Load the Cray programming environment
|
|
env_module(load PrgEnv-cray)
|
|
|
|
# Load settings targeting the Intel Knights Landing (KNL) CPU architecture
|
|
env_module(load craype-knl)
|
|
|
|
# Load the Cray MPI (Message Passing Interface) library, needed for
|
|
# distributed computing
|
|
env_module(load cray-mpich)
|
|
|
|
# Load Cray's scientific library package, which includes optimized math
|
|
# libraries (like BLAS, LAPACK)
|
|
env_module(load cray-libsci)
|
|
|
|
set(ENV{CRAYPE_LINK_TYPE} dynamic)
|
|
|
|
# ...
|
|
#]=======================================================================]
|
|
|
|
function(env_module)
|
|
if(NOT EnvModules_COMMAND)
|
|
message(FATAL_ERROR "Failed to process module command. EnvModules_COMMAND not found")
|
|
return()
|
|
endif()
|
|
|
|
set(options)
|
|
set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
|
|
set(multiValueArgs COMMAND)
|
|
cmake_parse_arguments(MOD_ARGS
|
|
"${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
|
|
)
|
|
if(NOT MOD_ARGS_COMMAND)
|
|
# If no explicit command argument was given, then treat the calling syntax
|
|
# as: module(cmd args...)
|
|
set(exec_cmd ${ARGV})
|
|
else()
|
|
set(exec_cmd ${MOD_ARGS_COMMAND})
|
|
endif()
|
|
|
|
if(MOD_ARGS_OUTPUT_VARIABLE)
|
|
set(err_var_args ERROR_VARIABLE err_var)
|
|
endif()
|
|
|
|
execute_process(
|
|
COMMAND mktemp -t module.cmake.XXXXXXXXXXXX
|
|
OUTPUT_VARIABLE tempfile_name
|
|
)
|
|
string(STRIP "${tempfile_name}" tempfile_name)
|
|
|
|
# If the $MODULESHOME/init/cmake file exists then assume that the CMake
|
|
# "shell" functionality exits
|
|
if(EXISTS "$ENV{MODULESHOME}/init/cmake")
|
|
execute_process(
|
|
COMMAND ${EnvModules_COMMAND} cmake ${exec_cmd}
|
|
OUTPUT_FILE ${tempfile_name}
|
|
${err_var_args}
|
|
RESULT_VARIABLE ret_var
|
|
)
|
|
|
|
else() # fallback to the sh shell and manually convert to CMake
|
|
execute_process(
|
|
COMMAND ${EnvModules_COMMAND} sh ${exec_cmd}
|
|
OUTPUT_VARIABLE out_var
|
|
${err_var_args}
|
|
RESULT_VARIABLE ret_var
|
|
)
|
|
endif()
|
|
|
|
# If we executed successfully then process and cleanup the temp file
|
|
if(ret_var EQUAL 0)
|
|
# No CMake shell so we need to process the sh output into CMake code
|
|
if(NOT EXISTS "$ENV{MODULESHOME}/init/cmake")
|
|
file(WRITE ${tempfile_name} "")
|
|
string(REPLACE "\n" ";" out_var "${out_var}")
|
|
foreach(sh_cmd IN LISTS out_var)
|
|
if(sh_cmd MATCHES "^ *unset *([^ ]*)")
|
|
set(cmake_cmd "unset(ENV{${CMAKE_MATCH_1}})")
|
|
elseif(sh_cmd MATCHES "^ *export *([^ ]*)")
|
|
set(cmake_cmd "set(ENV{${CMAKE_MATCH_1}} \"\${${CMAKE_MATCH_1}}\")")
|
|
elseif(sh_cmd MATCHES " *([^ =]*) *= *(.*)")
|
|
set(var_name "${CMAKE_MATCH_1}")
|
|
set(var_value "${CMAKE_MATCH_2}")
|
|
if(var_value MATCHES "^\"(.*[^\\])\"")
|
|
# If it's in quotes, take the value as is
|
|
set(var_value "${CMAKE_MATCH_1}")
|
|
else()
|
|
# Otherwise, strip trailing spaces
|
|
string(REGEX REPLACE "([^\\])? +$" "\\1" var_value "${var_value}")
|
|
endif()
|
|
string(REPLACE "\\ " " " var_value "${var_value}")
|
|
set(cmake_cmd "set(${var_name} \"${var_value}\")")
|
|
else()
|
|
continue()
|
|
endif()
|
|
file(APPEND ${tempfile_name} "${cmake_cmd}\n")
|
|
endforeach()
|
|
endif()
|
|
|
|
# Process the change in environment variables
|
|
include(${tempfile_name})
|
|
file(REMOVE ${tempfile_name})
|
|
endif()
|
|
|
|
# Push the output back out to the calling scope
|
|
if(MOD_ARGS_OUTPUT_VARIABLE)
|
|
set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE)
|
|
endif()
|
|
if(MOD_ARGS_RESULT_VARIABLE)
|
|
set(${MOD_ARGS_RESULT_VARIABLE} ${ret_var} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
#------------------------------------------------------------------------------
|
|
function(env_module_swap out_mod in_mod)
|
|
set(options)
|
|
set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE)
|
|
set(multiValueArgs)
|
|
|
|
cmake_parse_arguments(MOD_ARGS
|
|
"${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV}
|
|
)
|
|
|
|
env_module(COMMAND -t swap ${out_mod} ${in_mod}
|
|
OUTPUT_VARIABLE tmp_out
|
|
RETURN_VARIABLE tmp_ret
|
|
)
|
|
|
|
if(MOD_ARGS_OUTPUT_VARIABLE)
|
|
set(${MOD_ARGS_OUTPUT_VARIABLE} "${tmp_out}" PARENT_SCOPE)
|
|
endif()
|
|
if(MOD_ARGS_RESULT_VARIABLE)
|
|
set(${MOD_ARGS_RESULT_VARIABLE} ${tmp_ret} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
#------------------------------------------------------------------------------
|
|
function(env_module_list out_var)
|
|
env_module(COMMAND -t list OUTPUT_VARIABLE tmp_out)
|
|
|
|
# Convert output into a CMake list
|
|
string(REPLACE "\n" ";" ${out_var} "${tmp_out}")
|
|
|
|
# Remove title headers and empty entries
|
|
list(REMOVE_ITEM ${out_var} "No modules loaded")
|
|
if(${out_var})
|
|
list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
|
|
endif()
|
|
list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$")
|
|
|
|
set(${out_var} ${${out_var}} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
#------------------------------------------------------------------------------
|
|
function(env_module_avail)
|
|
if(ARGC EQUAL 1)
|
|
set(mod_prefix)
|
|
set(out_var ${ARGV0})
|
|
elseif(ARGC EQUAL 2)
|
|
set(mod_prefix ${ARGV0})
|
|
set(out_var ${ARGV1})
|
|
else()
|
|
message(FATAL_ERROR "Usage: env_module_avail([mod_prefix] out_var)")
|
|
endif()
|
|
env_module(COMMAND -t avail ${mod_prefix} OUTPUT_VARIABLE tmp_out)
|
|
|
|
# Convert output into a CMake list
|
|
string(REPLACE "\n" ";" tmp_out "${tmp_out}")
|
|
|
|
set(${out_var})
|
|
foreach(MOD IN LISTS tmp_out)
|
|
# Remove directory entries and empty values
|
|
if(MOD MATCHES "^(.*:)?$")
|
|
continue()
|
|
endif()
|
|
|
|
# Convert default modules
|
|
if(MOD MATCHES "^(.*)/$" ) # "foo/"
|
|
list(APPEND ${out_var} ${CMAKE_MATCH_1})
|
|
elseif(MOD MATCHES "^((.*)/.*)\\(default\\)$") # "foo/1.2.3(default)"
|
|
list(APPEND ${out_var} ${CMAKE_MATCH_2})
|
|
list(APPEND ${out_var} ${CMAKE_MATCH_1})
|
|
else()
|
|
list(APPEND ${out_var} ${MOD})
|
|
endif()
|
|
endforeach()
|
|
|
|
set(${out_var} ${${out_var}} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Make sure we know where the underlying module command is
|
|
find_program(EnvModules_COMMAND
|
|
NAMES lmod modulecmd
|
|
HINTS ENV MODULESHOME
|
|
PATH_SUFFIXES libexec
|
|
)
|
|
|
|
include(FindPackageHandleStandardArgs)
|
|
find_package_handle_standard_args(EnvModules DEFAULT_MSG EnvModules_COMMAND)
|