| # Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| # file Copyright.txt or https://cmake.org/licensing for details. |
| |
| #[=======================================================================[.rst: |
| FindEnvModules |
| -------------- |
| |
| .. versionadded:: 3.15 |
| |
| Locate an environment module implementation and make commands available to |
| CMake scripts to use them. This is compatible with both Lua-based Lmod |
| and TCL-based EnvironmentModules. |
| |
| This module is intended for the use case of setting up the compiler and library |
| environment within a :ref:`CTest Script <CTest Script>` (``ctest -S``). It can |
| also be used in a :ref:`CMake Script <Script Processing Mode>` (``cmake -P``). |
| |
| .. note:: |
| |
| The loaded environment will not survive past the end of the calling process. |
| Do not use this module in project code (``CMakeLists.txt`` files) to load |
| a compiler environment; it will not be available during the build. Instead |
| load the environment manually before running CMake or using the generated |
| build system. |
| |
| Example Usage |
| ^^^^^^^^^^^^^ |
| |
| .. code-block:: 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) |
| |
| env_module(purge) |
| env_module(load modules) |
| env_module(load craype) |
| env_module(load PrgEnv-cray) |
| env_module(load craype-knl) |
| env_module(load cray-mpich) |
| env_module(load cray-libsci) |
| |
| set(ENV{CRAYPE_LINK_TYPE} dynamic) |
| |
| ... |
| |
| Result Variables |
| ^^^^^^^^^^^^^^^^ |
| |
| This module will set the following variables in your project: |
| |
| ``EnvModules_FOUND`` |
| True if a compatible environment modules framework was found. |
| |
| Cache Variables |
| ^^^^^^^^^^^^^^^ |
| |
| The following cache variable will be set: |
| |
| ``EnvModules_COMMAND`` |
| The low level module command to use. Currently supported |
| implementations are the Lua based Lmod and TCL based EnvironmentModules. |
| |
| Environment Variables |
| ^^^^^^^^^^^^^^^^^^^^^ |
| |
| ``ENV{MODULESHOME}`` |
| Usually set by the module environment implementation, used as a hint to |
| locate the module command to execute. |
| |
| Provided Functions |
| ^^^^^^^^^^^^^^^^^^ |
| |
| This defines the following CMake functions for interacting with environment |
| modules: |
| |
| .. command:: env_module |
| |
| Execute an aribitrary module command: |
| |
| .. code-block:: cmake |
| |
| env_module(cmd arg1 ... argN) |
| env_module( |
| COMMAND cmd arg1 ... argN |
| [OUTPUT_VARIABLE <out-var>] |
| [RESULT_VARIABLE <ret-var>] |
| ) |
| |
| The options are: |
| |
| ``cmd arg1 ... argN`` |
| The module sub-command and arguments to execute as if they were |
| passed directly to the module command in your shell environment. |
| |
| ``OUTPUT_VARIABLE <out-var>`` |
| The standard output from executing the module command. |
| |
| ``RESULT_VARIABLE <ret-var>`` |
| The return code from executing the module command. |
| |
| .. command:: env_module_swap |
| |
| Swap 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>`` |
| The standard output from executing the module command. |
| |
| ``RESULT_VARIABLE <ret-var>`` |
| The return code from executing the module command. |
| |
| .. command:: env_module_list |
| |
| Retrieve 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 |
| |
| Retrieve 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. |
| |
| #]=======================================================================] |
| |
| 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(env_module) |
| |
| #------------------------------------------------------------------------------ |
| 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} "${err_var}" 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) |
| cmake_policy(SET CMP0007 NEW) |
| 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) |
| cmake_policy(SET CMP0007 NEW) |
| |
| 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(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) |
| find_package_handle_standard_args(EnvModules DEFAULT_MSG EnvModules_COMMAND) |