1 # ============================================================================ 2 # Copyright (c) 2011-2012 University of Pennsylvania 3 # Copyright (c) 2013-2016 Andreas Schuh 6 # See COPYING file for license information or visit 7 # https://cmake-basis.github.io/download.html#license 8 # ============================================================================ 10 ############################################################################## 11 # @file ExecuteProcess.cmake 12 # @brief Execute process using CMake script mode. 14 # This CMake script can be used as argument for the -P option of cmake, when 15 # another command shall be executed by CMake, for example, as custom build 16 # command. The advantage of using this script is that all options of the 17 # CMake command execute_process() can be used, i.e., a timeout can be 20 # The arguments of the execute_process() command have to be specified via 21 # the -D option on the command line of cmake before the -P \<this script\> 22 # option is given. The name of the CMake variables must be equal the 23 # name of the arguments to the execute_process() command. 25 # Arguments of execute_process() which are considered: 28 # - @b WORKING_DIRECTORY 34 # - @b OUTPUT_STRIP_TRAILING_WHITESPACE 35 # - @b ERROR_STRIP_TRAILING_WHITESPACE 37 # Additionally, matching expressions (separated by ';') to identify error messages 38 # in the output streams stdout and stderr can be specified by the input argument 39 # ERROR_EXPRESSION. When the output of the executed command matches one of 40 # the error expressions, a fatal error message is displayed causing CMake to 41 # return the exit code 1. 43 # Setting VERBOSE to true enables verbose output messages. 45 # When the input argument LOG_ARGS evaluates to true, the values of COMMAND, 46 # WORKING_DIRECTORY, and TIMEOUT are added to the top of the output files 47 # specified by OUTPUT_FILE and ERROR_FILE. 49 # The arguments ARGS and ARGS_FILE can be used to specify (additional) command 50 # arguments. The content of the text file ARGS_FILE is read when it this file 51 # exists. Separate lines of this file are considered single arguments. 52 # The arguments specified by ARGS and ARGS_FILE are concatenated where the 53 # arguments given by ARGS follow after the ones read from the ARGS_FILE. 54 # All occurences of the string 'ARGS' in the COMMAND are replaced by these 55 # arguments. If no such string is present, the arguments are simply passed 56 # to the execute_process() command as its ARGS argument. 57 # The argument ARGS_SEPARATOR specifies the separator used to separate the 58 # arguments given by ARGS and ARGS_FILE when the 'ARGS' string in COMMAND 59 # is replaced. By default, it is set to ';'. 63 # cmake -DCOMMAND='ls;-l' -DWORKING_DIRECTORY='/' -DTIMEOUT=60 64 # -P ExecuteProcess.cmake 67 # The output of the executed process can further be searched for error expressions 68 # specified by the ERROR_EXPRESSION variable. If the process output matches 69 # this expression, a fatal CMake error is raised. 71 # Certain errors may be temporary such as in particular a license checkout 72 # error of the MATLAB Compiler. Such errors can be filtered out using the 73 # RETRY_EXPRESSION variable. If such error is detected, this script sleeps for 74 # RETRY_DELAY seconds and then executes the process again. This is done 75 # at maximum RETRY_ATTEMPTS times. If the retry attempts are exceeded, a 76 # fatal CMake error is raised instead. 78 # @sa http://www.cmake.org/cmake/help/cmake2.6docs.html#command:execute_process 80 # @ingroup CMakeUtilities 81 ############################################################################## 84 cmake_policy (SET CMP0053 NEW)
87 # ---------------------------------------------------------------------------- 88 # unset environment variables that may cause problems otherwise 89 unset (ENV{PYTHONHOME})
90 unset (ENV{PYTHONPATH})
92 # ----------------------------------------------------------------------------
93 # initialize arguments
96 string (REPLACE
"#" "@" AT_BUILD_CMD_AT
"#BUILD_CMD#")
100 message (FATAL_ERROR
"No command specified for execute_process(): use \"-DCOMMAND=cmd\"")
108 include ("${ARGS_FILE}
" OPTIONAL) 110 if (ARGS AND DEFINED ${ARGS}) 117 if ("${COMMAND}
" MATCHES "ARGS") 123 set (EXECUTE_PROCESS_ARGS "COMMAND
" "${COMMAND}
") 126 list (APPEND EXECUTE_PROCESS_ARGS "ARGS
" "${ARGS}
") 129 list (APPEND EXECUTE_PROCESS_ARGS "RESULT_VARIABLE
" "RETVAL") 132 list (APPEND EXECUTE_PROCESS_ARGS "TIMEOUT
" "${TIMEOUT}
") 135 if (WORKING_DIRECTORY) 136 list (APPEND EXECUTE_PROCESS_ARGS "WORKING_DIRECTORY
" "${WORKING_DIRECTORY}
") 140 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_FILE
" "${OUTPUT_FILE}
") 144 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_FILE
" "${ERROR_FILE}
") 148 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_QUIET
") 152 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_QUIET
") 155 if (OUTPUT_STRIP_TRAILING_WHITESPACE) 156 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_STRIP_TRAILING_WHITESPACE
") 159 if (ERROR_STRIP_TRAILING_WHITESPACE) 160 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_STRIP_TRAILING_WHITESPACE
") 164 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_VARIABLE
" "STDOUT") 168 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_VARIABLE
" "STDERR") 171 if (NOT RETRY_ATTEMPTS) 172 set (RETRY_ATTEMPTS 0) 179 # -------------------------------------------------------------------------- 180 # verbose message of command to execute 182 foreach (ARG ${COMMAND}) 187 set (CMD "${
CMD}\
"${ARG}\"")
189 set (
CMD "${CMD}${ARG}")
197 # ---------------------------------------------------------------------------- 201 # -------------------------------------------------------------------------- 202 # whether retry is required is decided upon after process execution 205 # --------------------------------------------------------------------------
209 # --------------------------------------------------------------------------
210 # read in output from log files
212 file (READ
"${OUTPUT_FILE}" STDOUT)
216 file (READ
"${ERROR_FILE}" STDERR)
219 # -------------------------------------------------------------------------- 220 # parse output for recoverable errors 221 foreach (EXPR IN LISTS RETRY_EXPRESSION)
222 if (STDOUT MATCHES
"${EXPR}" OR STDERR MATCHES
"${EXPR}")
224 message (
"Process output matches \"${EXPR}\", retry in ${RETRY_DELAY} seconds")
236 # -------------------------------------------------------------------------- 237 # sleep for given amount of seconds before retrying to execute process 239 # use sleep command if available, i.e., on Unix and also on Windows 240 # if the Windows 2003 Resource Kit is installed 241 find_program (SLEEP sleep)
246 ERROR_QUIET OUTPUT_QUIET
249 # work-around using ping command if sleep command not available, i.e., 250 # on Windows where the Windows 2003 Resource Kit is not installed 251 # See http://malektips.com/dos0017.html 252 find_program (PING ping)
255 COMMAND ${PING} 127.0.0.1 -n ${
RETRY_DELAY} -w 1000
257 ERROR_QUIET OUTPUT_QUIET
260 # usually not required as sleep command should be available 262 COMMAND ${PING} 127.0.0.1 -c ${
RETRY_DELAY} -W 1000
264 ERROR_QUIET OUTPUT_QUIET
268 message (WARNING
"Cannot delay retries as neither sleep nor ping command is available!")
273 # ---------------------------------------------------------------------------- 274 # parse output for errors 275 foreach (EXPR IN LISTS ERROR_EXPRESSION)
276 if (STDOUT MATCHES
"${EXPR}" OR STDERR MATCHES
"${EXPR}")
282 # ---------------------------------------------------------------------------- 283 # give some hints for known error messages 287 if (
CMD MATCHES
"mcc")
288 if (STDERR MATCHES
"The file.*appears to be a MEX-file.[ ]+It shadows the M-file.*but will not execute properly at runtime, as it does not export a function.*named 'mexFunction.'")
291 Note: The error that a MEX-file would shadow a M-file can be caused by a shared library that 292 is required by the MEX-file but not found in the search path of the dynamic loader. 296 # append hints to output 297 if (
"${STDOUT}" STREQUAL
"${STDERR}")
298 set (STDERR
"${STDERR}${HINTS}")
299 set (STDOUT
"${STDOUT}${HINTS}")
301 set (STDERR
"${STDERR}${HINTS}")
305 # ---------------------------------------------------------------------------- 306 # prepand command to log file 309 set (
TMP "Command: ${CMD}\n\nWorking directory: ${WORKING_DIRECTORY}\n\n")
310 set (
TMP "${TMP}Timeout: ${TIMEOUT}\n\nOutput:\n\n${STDOUT}")
311 file (WRITE
"${OUTPUT_FILE}" "${TMP}")
315 if (ERROR_FILE AND NOT "${ERROR_FILE}
" STREQUAL "${OUTPUT_FILE}
") 316 set (TMP "Command: ${
CMD}\n\nWorking directory: ${WORKING_DIRECTORY}\n\n
") 317 set (TMP "${
TMP}Timeout: ${TIMEOUT}\n\nOutput:\n\n${STDERR}
") 318 file (WRITE "${ERROR_FILE}
" "${
TMP}
") 323 # ---------------------------------------------------------------------------- 324 # print error message (and exit with exit code 1) on error 325 if (NOT RETVAL EQUAL 0) 328 if ("${STDOUT}
" STREQUAL "${STDERR}
") 332 Working directory: ${WORKING_DIRECTORY}
340 Working directory: ${WORKING_DIRECTORY}
cmake EXECUTE_PROCESS_ARGS
function execute(in options, in cmd, in args)
Execute command as subprocess.