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 # initialize arguments
00081 if (NOT COMMAND)
00082 message (FATAL_ERROR "No command specified for execute_process (): use -DCOMMAND='cmd'")
00083 endif ()
00084
00085 if (NOT ARGS_SEPARATOR)
00086 set (ARGS_SEPARATOR ";")
00087 endif ()
00088
00089 if (ARGS_FILE)
00090 include ("${ARGS_FILE}" OPTIONAL)
00091
00092 if (ARGS AND DEFINED ${ARGS})
00093 set (ARGS "${${ARGS}}")
00094 else ()
00095 set (ARGS "")
00096 endif ()
00097 endif ()
00098
00099 if ("${COMMAND}" MATCHES "ARGS")
00100 string (REPLACE ";" "${ARGS_SEPARATOR}" TMP "${ARGS}")
00101 string (REPLACE "ARGS" "${ARGS_SEPARATOR}${TMP}" COMMAND "${COMMAND}")
00102 set (ARGS)
00103 endif ()
00104
00105 set (EXECUTE_PROCESS_ARGS "COMMAND" "${COMMAND}")
00106
00107 if (ARGS)
00108 list (APPEND EXECUTE_PROCESS_ARGS "ARGS" "${ARGS}")
00109 endif ()
00110
00111 list (APPEND EXECUTE_PROCESS_ARGS "RESULT_VARIABLE" "RETVAL")
00112
00113 if (TIMEOUT)
00114 list (APPEND EXECUTE_PROCESS_ARGS "TIMEOUT" "${TIMEOUT}")
00115 endif ()
00116
00117 if (WORKING_DIRECTORY)
00118 list (APPEND EXECUTE_PROCESS_ARGS "WORKING_DIRECTORY" "${WORKING_DIRECTORY}")
00119 endif ()
00120
00121 if (OUTPUT_FILE)
00122 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_FILE" "${OUTPUT_FILE}")
00123 endif ()
00124
00125 if (ERROR_FILE)
00126 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_FILE" "${ERROR_FILE}")
00127 endif ()
00128
00129 if (OUTPUT_QUIET)
00130 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_QUIET")
00131 endif ()
00132
00133 if (ERROR_QUIET)
00134 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_QUIET")
00135 endif ()
00136
00137 if (OUTPUT_STRIP_TRAILING_WHITESPACE)
00138 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_STRIP_TRAILING_WHITESPACE")
00139 endif ()
00140
00141 if (ERROR_STRIP_TRAILING_WHITESPACE)
00142 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_STRIP_TRAILING_WHITESPACE")
00143 endif ()
00144
00145 if (NOT OUTPUT_FILE)
00146 list (APPEND EXECUTE_PROCESS_ARGS "OUTPUT_VARIABLE" "STDOUT")
00147 endif ()
00148
00149 if (NOT ERROR_FILE)
00150 list (APPEND EXECUTE_PROCESS_ARGS "ERROR_VARIABLE" "STDERR")
00151 endif ()
00152
00153 if (NOT RETRY_ATTEMPTS)
00154 set (RETRY_ATTEMPTS 0)
00155 endif ()
00156
00157 if (NOT RETRY_DELAY)
00158 set (RETRY_DELAY 60)
00159 endif ()
00160
00161 # --------------------------------------------------------------------------
00162 # verbose message of command to execute
00163 set (CMD)
00164 foreach (ARG ${COMMAND})
00165 if (CMD)
00166 set (CMD "${CMD} ")
00167 endif ()
00168 if (ARG MATCHES " ")
00169 set (CMD "${CMD}\"${ARG}\"")
00170 else ()
00171 set (CMD "${CMD}${ARG}")
00172 endif ()
00173 endforeach ()
00174
00175 if (VERBOSE)
00176 message ("${CMD}")
00177 endif ()
00178
00179 # ----------------------------------------------------------------------------
00180 # execute command
00181 set (RETRY TRUE) # execute process at least once
00182 while (RETRY)
00183 # --------------------------------------------------------------------------
00184 # whether retry is required is decided upon after process execution
00185 set (RETRY FALSE)
00186
00187 # --------------------------------------------------------------------------
00188 # execute process
00189 execute_process (${EXECUTE_PROCESS_ARGS})
00190
00191 # --------------------------------------------------------------------------
00192 # read in output from log files
00193 if (OUTPUT_FILE)
00194 file (READ "${OUTPUT_FILE}" STDOUT)
00195 endif ()
00196
00197 if (ERROR_FILE)
00198 file (READ "${ERROR_FILE}" STDERR)
00199 endif ()
00200
00201 # --------------------------------------------------------------------------
00202 # parse output for recoverable errors
00203 foreach (EXPR IN LISTS RETRY_EXPRESSION)
00204 if (STDOUT MATCHES "${EXPR}" OR STDERR MATCHES "${EXPR}")
00205 if (RETRY_ATTEMPTS GREATER 0)
00206 message ("Process output matches \"${EXPR}\", retry in ${RETRY_DELAY} seconds")
00207 # retry
00208 math (EXPR RETRY_ATTEMPTS "${RETRY_ATTEMPTS} - 1")
00209 set (RETRY TRUE)
00210 else ()
00211 # no retries left
00212 set (RETVAL 1)
00213 endif ()
00214 break ()
00215 endif ()
00216 endforeach ()
00217
00218 # --------------------------------------------------------------------------
00219 # sleep for given amount of seconds before retrying to execute process
00220 if (RETRY)
00221 # use sleep command if available, i.e., on Unix and also on Windows
00222 # if the Windows 2003 Resource Kit is installed
00223 find_program (SLEEP sleep)
00224 if (SLEEP)
00225 execute_process (
00226 COMMAND "${SLEEP}" ${RETRY_DELAY}
00227 TIMEOUT ${RETRY_DELAY}
00228 ERROR_QUIET OUTPUT_QUIET
00229 )
00230 else ()
00231 # work-around using ping command if sleep command not available, i.e.,
00232 # on Windows where the Windows 2003 Resource Kit is not installed
00233 # See http://malektips.com/dos0017.html
00234 find_program (PING ping)
00235 if (WINDOWS)
00236 execute_process (
00237 COMMAND ${PING} 127.0.0.1 -n ${RETRY_DELAY} -w 1000
00238 TIMEOUT ${RETRY_DELAY}
00239 ERROR_QUIET OUTPUT_QUIET
00240 )
00241 else ()
00242 # usually not required as sleep command should be available
00243 execute_process (
00244 COMMAND ${PING} 127.0.0.1 -c ${RETRY_DELAY} -W 1000
00245 TIMEOUT ${RETRY_DELAY}
00246 ERROR_QUIET OUTPUT_QUIET
00247 )
00248 endif ()
00249 else ()
00250 message (WARNING "Cannot delay retries as neither sleep nor ping command is available!")
00251 endif ()
00252 endif ()
00253 endwhile ()
00254
00255 # ----------------------------------------------------------------------------
00256 # parse output for errors
00257 foreach (EXPR IN LISTS ERROR_EXPRESSION)
00258 if (STDOUT MATCHES "${EXPR}" OR STDERR MATCHES "${EXPR}")
00259 set (RETVAL 1)
00260 break ()
00261 endif ()
00262 endforeach ()
00263
00264 # ----------------------------------------------------------------------------
00265 # prepand command to log file
00266 if (LOG_ARGS)
00267 if (OUTPUT_FILE)
00268 set (TMP "Command: ${CMD}\n\nWorking directory: ${WORKING_DIRECTORY}\n\n")
00269 set (TMP "${TMP}Timeout: ${TIMEOUT}\n\nOutput:\n\n${STDOUT}")
00270 file (WRITE "${OUTPUT_FILE}" "${TMP}")
00271 unset (TMP)
00272 endif ()
00273
00274 if (ERROR_FILE AND NOT "${ERROR_FILE}" STREQUAL "${OUTPUT_FILE}")
00275 set (TMP "Command: ${CMD}\n\nWorking directory: ${WORKING_DIRECTORY}\n\n")
00276 set (TMP "${TMP}Timeout: ${TIMEOUT}\n\nOutput:\n\n${STDERR}")
00277 file (WRITE "${ERROR_FILE}" "${TMP}")
00278 unset (TMP)
00279 endif ()
00280 endif ()
00281
00282 # ----------------------------------------------------------------------------
00283 # print error message (and exit with exit code 1) on error
00284 if (NOT RETVAL EQUAL 0)
00285 if ("${STDOUT}" STREQUAL "${STDERR}")
00286 message (
00287 FATAL_ERROR "
00288 Command: ${CMD}
00289 Working directory: ${WORKING_DIRECTORY}
00290 Timeout: ${TIMEOUT}
00291 Output:
00292 ${STDOUT}")
00293 else ()
00294 message (
00295 FATAL_ERROR "
00296 Command: ${CMD}
00297 Working directory: ${WORKING_DIRECTORY}
00298 Timeout: ${TIMEOUT}
00299 Output (stdout):
00300 ${STDOUT}
00301 Output (stderr):
00302 ${STDERR}")
00303 endif ()
00304 endif ()