ExecuteProcess.cmake
Go to the documentation of this file.
00001 ############################################################################## 00002 # @file ExecuteProcess.cmake 00003 # @brief Execute process using CMake script mode. 00004 # 00005 # This CMake script can be used as argument for the -P option of cmake, when 00006 # another command shall be executed by CMake, for example, as custom build 00007 # command. The advantage of using this script is that all options of the 00008 # CMake command execute_process() can be used, i.e., a timeout can be 00009 # specified. 00010 # 00011 # The arguments of the execute_process() command have to specified via 00012 # the -D option on the command line of cmake before the -P \<this script\> 00013 # option is given. The name of the CMake variables must be equal the 00014 # name of the arguments to the execute_process() command. 00015 # 00016 # Arguments of execute_process() which are considered: 00017 # 00018 # - @b COMMAND 00019 # - @b WORKING_DIRECTORY 00020 # - @b TIMEOUT 00021 # - @b OUTPUT_FILE 00022 # - @b ERROR_FILE 00023 # - @b OUTPUT_QUIET 00024 # - @b ERROR_QUIET 00025 # - @b OUTPUT_STRIP_TRAILING_WHITESPACE 00026 # - @b ERROR_STRIP_TRAILING_WHITESPACE 00027 # 00028 # Additionally, matching expressions (separated by ';') to identify error messages 00029 # in the output streams stdout and stderr can be specified by the input argument 00030 # ERROR_EXPRESSION. When the output of the executed command matches one of 00031 # the error expressions, a fatal error message is displayed causing CMake to 00032 # return the exit code 1. 00033 # 00034 # Setting VERBOSE to true enables verbose output messages. 00035 # 00036 # When the input argument LOG_ARGS evaluates to true, the values of COMMAND, 00037 # WORKING_DIRECTORY, and TIMEOUT are added to the top of the output files 00038 # specified by OUTPUT_FILE and ERROR_FILE. 00039 # 00040 # The arguments ARGS and ARGS_FILE can be used to specify (additional) command 00041 # arguments. The content of the text file ARGS_FILE is read when it this file 00042 # exists. Separate lines of this file are considered single arguments. 00043 # The arguments specified by ARGS and ARGS_FILE are concatenated where the 00044 # arguments given by ARGS follow after the ones read from the ARGS_FILE. 00045 # All occurences of the string 'ARGS' in the COMMAND are replaced by these 00046 # arguments. If no such string is present, the arguments are simply passed 00047 # to the execute_process() command as its ARGS argument. 00048 # The argument ARGS_SEPARATOR specifies the separator used to separate the 00049 # arguments given by ARGS and ARGS_FILE when the 'ARGS' string in COMMAND 00050 # is replaced. By default, it is set to ';'. 00051 # 00052 # Example: 00053 # @code 00054 # cmake -DCOMMAND='ls;-l' -DWORKING_DIRECTORY='/' -DTIMEOUT=60 00055 # -P ExecuteProcess.cmake 00056 # @endcode 00057 # 00058 # The output of the executed process can further be searched for error expressions 00059 # specified by the ERROR_EXPRESSION variable. If the process output matches 00060 # this expression, a fatal CMake error is raised. 00061 # 00062 # Certain errors may be temporary such as in particular a license checkout 00063 # error of the MATLAB Compiler. Such errors can be filtered out using the 00064 # RETRY_EXPRESSION variable. If such error is detected, this script sleeps for 00065 # RETRY_DELAY seconds and then executes the process again. This is done 00066 # at maximum RETRY_ATTEMPTS times. If the retry attempts are exceeded, a 00067 # fatal CMake error is raised instead. 00068 # 00069 # @sa http://www.cmake.org/cmake/help/cmake2.6docs.html#command:execute_process 00070 # 00071 # Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br /> 00072 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file. 00073 # 00074 # Contact: SBIA Group <sbia-software at uphs.upenn.edu> 00075 # 00076 # @ingroup CMakeUtilities 00077 ############################################################################## 00078 00079 # ---------------------------------------------------------------------------- 00080 # unset environment variables that may cause problems otherwise 00081 unset (ENV{PYTHONHOME}) 00082 unset (ENV{PYTHONPATH}) 00083 00084 # ---------------------------------------------------------------------------- 00085 # initialize arguments 00086 set (CONFIGURED_COMMAND "@COMMAND@") 00087 if (CONFIGURED_COMMAND) 00088 set (COMMAND "${CONFIGURED_COMMAND}") 00089 elseif (NOT COMMAND) 00090 message (FATAL_ERROR "No command specified for execute_process(): use \"-DCOMMAND=cmd\"") 00091 endif () 00092 00093 if (NOT ARGS_SEPARATOR) 00094 set (ARGS_SEPARATOR ";") 00095 endif () 00096 00097 if (ARGS_FILE) 00098 include ("${ARGS_FILE}" OPTIONAL) 00099 00100 if (ARGS AND DEFINED ${ARGS}) 00101 set (ARGS "${${ARGS}}") 00102 else () 00103 set (ARGS "") 00104 endif () 00105 endif () 00106 00107 if ("${COMMAND}" MATCHES "ARGS") 00108 string (REPLACE ";" "${ARGS_SEPARATOR}" TMP "${ARGS}") 00109 string (REPLACE "ARGS" "${ARGS_SEPARATOR}${TMP}" COMMAND "${COMMAND}") 00110 set (ARGS) 00111 endif () 00112 00113 set (EXECUTE_PROCESS_ARGS "COMMAND" "${COMMAND}") 00114 00115 if (ARGS) 00116 list (APPEND EXECUTE_PROCESS_ARGS "ARGS" "${ARGS}") 00117 endif () 00118 00119 list (APPEND EXECUTE_PROCESS_ARGS "RESULT_VARIABLE" "RETVAL") 00120 00121 if (TIMEOUT) 00122 list (APPEND EXECUTE_PROCESS_ARGS "TIMEOUT" "${TIMEOUT}") 00123 endif () 00124 00125 if (WORKING_DIRECTORY) 00126 list (APPEND EXECUTE_PROCESS_ARGS "WORKING_DIRECTORY" "${WORKING_DIRECTORY}") 00127 endif () 00128 00129 if (OUTPUT_FILE) 00130 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_FILE" "${OUTPUT_FILE}") 00131 endif () 00132 00133 if (ERROR_FILE) 00134 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_FILE" "${ERROR_FILE}") 00135 endif () 00136 00137 if (OUTPUT_QUIET) 00138 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_QUIET") 00139 endif () 00140 00141 if (ERROR_QUIET) 00142 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_QUIET") 00143 endif () 00144 00145 if (OUTPUT_STRIP_TRAILING_WHITESPACE) 00146 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_STRIP_TRAILING_WHITESPACE") 00147 endif () 00148 00149 if (ERROR_STRIP_TRAILING_WHITESPACE) 00150 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_STRIP_TRAILING_WHITESPACE") 00151 endif () 00152 00153 if (NOT OUTPUT_FILE) 00154 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_VARIABLE" "STDOUT") 00155 endif () 00156 00157 if (NOT ERROR_FILE) 00158 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_VARIABLE" "STDERR") 00159 endif () 00160 00161 if (NOT RETRY_ATTEMPTS) 00162 set (RETRY_ATTEMPTS 0) 00163 endif () 00164 00165 if (NOT RETRY_DELAY) 00166 set (RETRY_DELAY 60) 00167 endif () 00168 00169 # -------------------------------------------------------------------------- 00170 # verbose message of command to execute 00171 set (CMD) 00172 foreach (ARG ${COMMAND}) 00173 if (CMD) 00174 set (CMD "${CMD} ") 00175 endif () 00176 if (ARG MATCHES " ") 00177 set (CMD "${CMD}\"${ARG}\"") 00178 else () 00179 set (CMD "${CMD}${ARG}") 00180 endif () 00181 endforeach () 00182 00183 if (VERBOSE) 00184 message ("${CMD}") 00185 endif () 00186 00187 # ---------------------------------------------------------------------------- 00188 # execute command 00189 set (RETRY TRUE) # execute process at least once 00190 while (RETRY) 00191 # -------------------------------------------------------------------------- 00192 # whether retry is required is decided upon after process execution 00193 set (RETRY FALSE) 00194 00195 # -------------------------------------------------------------------------- 00196 # execute process 00197 execute_process (${EXECUTE_PROCESS_ARGS}) 00198 00199 # -------------------------------------------------------------------------- 00200 # read in output from log files 00201 if (OUTPUT_FILE) 00202 file (READ "${OUTPUT_FILE}" STDOUT) 00203 endif () 00204 00205 if (ERROR_FILE) 00206 file (READ "${ERROR_FILE}" STDERR) 00207 endif () 00208 00209 # -------------------------------------------------------------------------- 00210 # parse output for recoverable errors 00211 foreach (EXPR IN LISTS RETRY_EXPRESSION) 00212 if (STDOUT MATCHES "${EXPR}" OR STDERR MATCHES "${EXPR}") 00213 if (RETRY_ATTEMPTS GREATER 0) 00214 message ("Process output matches \"${EXPR}\", retry in ${RETRY_DELAY} seconds") 00215 # retry 00216 math (EXPR RETRY_ATTEMPTS "${RETRY_ATTEMPTS} - 1") 00217 set (RETRY TRUE) 00218 else () 00219 # no retries left 00220 set (RETVAL 1) 00221 endif () 00222 break () 00223 endif () 00224 endforeach () 00225 00226 # -------------------------------------------------------------------------- 00227 # sleep for given amount of seconds before retrying to execute process 00228 if (RETRY) 00229 # use sleep command if available, i.e., on Unix and also on Windows 00230 # if the Windows 2003 Resource Kit is installed 00231 find_program (SLEEP sleep) 00232 if (SLEEP) 00233 execute_process ( 00234 COMMAND "${SLEEP}" ${RETRY_DELAY} 00235 TIMEOUT ${RETRY_DELAY} 00236 ERROR_QUIET OUTPUT_QUIET 00237 ) 00238 else () 00239 # work-around using ping command if sleep command not available, i.e., 00240 # on Windows where the Windows 2003 Resource Kit is not installed 00241 # See http://malektips.com/dos0017.html 00242 find_program (PING ping) 00243 if (WIN32) 00244 execute_process ( 00245 COMMAND ${PING} 127.0.0.1 -n ${RETRY_DELAY} -w 1000 00246 TIMEOUT ${RETRY_DELAY} 00247 ERROR_QUIET OUTPUT_QUIET 00248 ) 00249 else () 00250 # usually not required as sleep command should be available 00251 execute_process ( 00252 COMMAND ${PING} 127.0.0.1 -c ${RETRY_DELAY} -W 1000 00253 TIMEOUT ${RETRY_DELAY} 00254 ERROR_QUIET OUTPUT_QUIET 00255 ) 00256 endif () 00257 else () 00258 message (WARNING "Cannot delay retries as neither sleep nor ping command is available!") 00259 endif () 00260 endif () 00261 endwhile () 00262 00263 # ---------------------------------------------------------------------------- 00264 # parse output for errors 00265 foreach (EXPR IN LISTS ERROR_EXPRESSION) 00266 if (STDOUT MATCHES "${EXPR}" OR STDERR MATCHES "${EXPR}") 00267 set (RETVAL 1) 00268 break () 00269 endif () 00270 endforeach () 00271 00272 # ---------------------------------------------------------------------------- 00273 # give some hints for known error messages 00274 if (NOT RETVAL EQUAL 0) 00275 set (HINTS) 00276 # MATLAB Compiler 00277 if (CMD MATCHES "mcc") 00278 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.'") 00279 set (HINTS "${HINTS} 00280 00281 Note: The error that a MEX-file would shadow a M-file can be caused by a shared library that 00282 is required by the MEX-file but not found in the search path of the dynamic loader. 00283 ") 00284 endif () 00285 endif () 00286 # append hints to output 00287 if ("${STDOUT}" STREQUAL "${STDERR}") 00288 set (STDERR "${STDERR}${HINTS}") 00289 set (STDOUT "${STDOUT}${HINTS}") 00290 else () 00291 set (STDERR "${STDERR}${HINTS}") 00292 endif () 00293 endif () 00294 00295 # ---------------------------------------------------------------------------- 00296 # prepand command to log file 00297 if (LOG_ARGS) 00298 if (OUTPUT_FILE) 00299 set (TMP "Command: ${CMD}\n\nWorking directory: ${WORKING_DIRECTORY}\n\n") 00300 set (TMP "${TMP}Timeout: ${TIMEOUT}\n\nOutput:\n\n${STDOUT}") 00301 file (WRITE "${OUTPUT_FILE}" "${TMP}") 00302 unset (TMP) 00303 endif () 00304 00305 if (ERROR_FILE AND NOT "${ERROR_FILE}" STREQUAL "${OUTPUT_FILE}") 00306 set (TMP "Command: ${CMD}\n\nWorking directory: ${WORKING_DIRECTORY}\n\n") 00307 set (TMP "${TMP}Timeout: ${TIMEOUT}\n\nOutput:\n\n${STDERR}") 00308 file (WRITE "${ERROR_FILE}" "${TMP}") 00309 unset (TMP) 00310 endif () 00311 endif () 00312 00313 # ---------------------------------------------------------------------------- 00314 # print error message (and exit with exit code 1) on error 00315 if (NOT RETVAL EQUAL 0) 00316 00317 # print error 00318 if ("${STDOUT}" STREQUAL "${STDERR}") 00319 message ( 00320 FATAL_ERROR " 00321 Command: ${CMD} 00322 Working directory: ${WORKING_DIRECTORY} 00323 Timeout: ${TIMEOUT} 00324 Output: 00325 ${STDOUT}") 00326 else () 00327 message ( 00328 FATAL_ERROR " 00329 Command: ${CMD} 00330 Working directory: ${WORKING_DIRECTORY} 00331 Timeout: ${TIMEOUT} 00332 Output (stdout): 00333 ${STDOUT} 00334 Output (stderr): 00335 ${STDERR}") 00336 endif () 00337 endif ()