Imported Upstream version 2.8.10.2
[platform/upstream/cmake.git] / Modules / ExternalProject.cmake
1 # - Create custom targets to build projects in external trees
2 # The 'ExternalProject_Add' function creates a custom target to drive
3 # download, update/patch, configure, build, install and test steps of an
4 # external project:
5 #  ExternalProject_Add(<name>    # Name for custom target
6 #    [DEPENDS projects...]       # Targets on which the project depends
7 #    [PREFIX dir]                # Root dir for entire project
8 #    [LIST_SEPARATOR sep]        # Sep to be replaced by ; in cmd lines
9 #    [TMP_DIR dir]               # Directory to store temporary files
10 #    [STAMP_DIR dir]             # Directory to store step timestamps
11 #   #--Download step--------------
12 #    [DOWNLOAD_NAME fname]       # File name to store (if not end of URL)
13 #    [DOWNLOAD_DIR dir]          # Directory to store downloaded files
14 #    [DOWNLOAD_COMMAND cmd...]   # Command to download source tree
15 #    [CVS_REPOSITORY cvsroot]    # CVSROOT of CVS repository
16 #    [CVS_MODULE mod]            # Module to checkout from CVS repo
17 #    [CVS_TAG tag]               # Tag to checkout from CVS repo
18 #    [SVN_REPOSITORY url]        # URL of Subversion repo
19 #    [SVN_REVISION rev]          # Revision to checkout from Subversion repo
20 #    [SVN_USERNAME john ]        # Username for Subversion checkout and update
21 #    [SVN_PASSWORD doe ]         # Password for Subversion checkout and update
22 #    [SVN_TRUST_CERT 1 ]         # Trust the Subversion server site certificate
23 #    [GIT_REPOSITORY url]        # URL of git repo
24 #    [GIT_TAG tag]               # Git branch name, commit id or tag
25 #    [HG_REPOSITORY url]         # URL of mercurial repo
26 #    [HG_TAG tag]                # Mercurial branch name, commit id or tag
27 #    [URL /.../src.tgz]          # Full path or URL of source
28 #    [URL_HASH ALGO=value]       # Hash of file at URL
29 #    [URL_MD5 md5]               # Equivalent to URL_HASH MD5=md5
30 #    [TLS_VERIFY bool]           # Should certificate for https be checked
31 #    [TLS_CAINFO file]           # Path to a certificate authority file
32 #    [TIMEOUT seconds]           # Time allowed for file download operations
33 #   #--Update/Patch step----------
34 #    [UPDATE_COMMAND cmd...]     # Source work-tree update command
35 #    [PATCH_COMMAND cmd...]      # Command to patch downloaded source
36 #   #--Configure step-------------
37 #    [SOURCE_DIR dir]            # Source dir to be used for build
38 #    [CONFIGURE_COMMAND cmd...]  # Build tree configuration command
39 #    [CMAKE_COMMAND /.../cmake]  # Specify alternative cmake executable
40 #    [CMAKE_GENERATOR gen]       # Specify generator for native build
41 #    [CMAKE_ARGS args...]        # Arguments to CMake command line
42 #    [CMAKE_CACHE_ARGS args...]  # Initial cache arguments, of the form -Dvar:string=on
43 #   #--Build step-----------------
44 #    [BINARY_DIR dir]            # Specify build dir location
45 #    [BUILD_COMMAND cmd...]      # Command to drive the native build
46 #    [BUILD_IN_SOURCE 1]         # Use source dir for build dir
47 #   #--Install step---------------
48 #    [INSTALL_DIR dir]           # Installation prefix
49 #    [INSTALL_COMMAND cmd...]    # Command to drive install after build
50 #   #--Test step------------------
51 #    [TEST_BEFORE_INSTALL 1]     # Add test step executed before install step
52 #    [TEST_AFTER_INSTALL 1]      # Add test step executed after install step
53 #    [TEST_COMMAND cmd...]       # Command to drive test
54 #   #--Output logging-------------
55 #    [LOG_DOWNLOAD 1]            # Wrap download in script to log output
56 #    [LOG_UPDATE 1]              # Wrap update in script to log output
57 #    [LOG_CONFIGURE 1]           # Wrap configure in script to log output
58 #    [LOG_BUILD 1]               # Wrap build in script to log output
59 #    [LOG_TEST 1]                # Wrap test in script to log output
60 #    [LOG_INSTALL 1]             # Wrap install in script to log output
61 #   #--Custom targets-------------
62 #    [STEP_TARGETS st1 st2 ...]  # Generate custom targets for these steps
63 #    )
64 # The *_DIR options specify directories for the project, with default
65 # directories computed as follows.
66 # If the PREFIX option is given to ExternalProject_Add() or the EP_PREFIX
67 # directory property is set, then an external project is built and installed
68 # under the specified prefix:
69 #   TMP_DIR      = <prefix>/tmp
70 #   STAMP_DIR    = <prefix>/src/<name>-stamp
71 #   DOWNLOAD_DIR = <prefix>/src
72 #   SOURCE_DIR   = <prefix>/src/<name>
73 #   BINARY_DIR   = <prefix>/src/<name>-build
74 #   INSTALL_DIR  = <prefix>
75 # Otherwise, if the EP_BASE directory property is set then components
76 # of an external project are stored under the specified base:
77 #   TMP_DIR      = <base>/tmp/<name>
78 #   STAMP_DIR    = <base>/Stamp/<name>
79 #   DOWNLOAD_DIR = <base>/Download/<name>
80 #   SOURCE_DIR   = <base>/Source/<name>
81 #   BINARY_DIR   = <base>/Build/<name>
82 #   INSTALL_DIR  = <base>/Install/<name>
83 # If no PREFIX, EP_PREFIX, or EP_BASE is specified then the default
84 # is to set PREFIX to "<name>-prefix".
85 # Relative paths are interpreted with respect to the build directory
86 # corresponding to the source directory in which ExternalProject_Add is
87 # invoked.
88 #
89 # If SOURCE_DIR is explicitly set to an existing directory the project
90 # will be built from it.
91 # Otherwise a download step must be specified using one of the
92 # DOWNLOAD_COMMAND, CVS_*, SVN_*, or URL options.
93 # The URL option may refer locally to a directory or source tarball,
94 # or refer to a remote tarball (e.g. http://.../src.tgz).
95 #
96 # The 'ExternalProject_Add_Step' function adds a custom step to an external
97 # project:
98 #  ExternalProject_Add_Step(<name> <step> # Names of project and custom step
99 #    [COMMAND cmd...]        # Command line invoked by this step
100 #    [COMMENT "text..."]     # Text printed when step executes
101 #    [DEPENDEES steps...]    # Steps on which this step depends
102 #    [DEPENDERS steps...]    # Steps that depend on this step
103 #    [DEPENDS files...]      # Files on which this step depends
104 #    [ALWAYS 1]              # No stamp file, step always runs
105 #    [WORKING_DIRECTORY dir] # Working directory for command
106 #    [LOG 1]                 # Wrap step in script to log output
107 #    )
108 # The command line, comment, and working directory of every standard
109 # and custom step is processed to replace tokens
110 # <SOURCE_DIR>,
111 # <BINARY_DIR>,
112 # <INSTALL_DIR>,
113 # and <TMP_DIR>
114 # with corresponding property values.
115 #
116 # The 'ExternalProject_Get_Property' function retrieves external project
117 # target properties:
118 #  ExternalProject_Get_Property(<name> [prop1 [prop2 [...]]])
119 # It stores property values in variables of the same name.
120 # Property names correspond to the keyword argument names of
121 # 'ExternalProject_Add'.
122 #
123 # The 'ExternalProject_Add_StepTargets' function generates custom targets for
124 # the steps listed:
125 #  ExternalProject_Add_StepTargets(<name> [step1 [step2 [...]]])
126 #
127 # If STEP_TARGETS is set then ExternalProject_Add_StepTargets is automatically
128 # called at the end of matching calls to ExternalProject_Add_Step. Pass
129 # STEP_TARGETS explicitly to individual ExternalProject_Add calls, or
130 # implicitly to all ExternalProject_Add calls by setting the directory property
131 # EP_STEP_TARGETS.
132 #
133 # If STEP_TARGETS is not set, clients may still manually call
134 # ExternalProject_Add_StepTargets after calling ExternalProject_Add or
135 # ExternalProject_Add_Step.
136 #
137 # This functionality is provided to make it easy to drive the steps
138 # independently of each other by specifying targets on build command lines.
139 # For example, you may be submitting to a sub-project based dashboard, where
140 # you want to drive the configure portion of the build, then submit to the
141 # dashboard, followed by the build portion, followed by tests. If you invoke
142 # a custom target that depends on a step halfway through the step dependency
143 # chain, then all the previous steps will also run to ensure everything is
144 # up to date.
145 #
146 # For example, to drive configure, build and test steps independently for each
147 # ExternalProject_Add call in your project, write the following line prior to
148 # any ExternalProject_Add calls in your CMakeLists file:
149 #
150 #   set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
151
152 #=============================================================================
153 # Copyright 2008-2012 Kitware, Inc.
154 #
155 # Distributed under the OSI-approved BSD License (the "License");
156 # see accompanying file Copyright.txt for details.
157 #
158 # This software is distributed WITHOUT ANY WARRANTY; without even the
159 # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
160 # See the License for more information.
161 #=============================================================================
162 # (To distribute this file outside of CMake, substitute the full
163 #  License text for the above reference.)
164
165 # Pre-compute a regex to match documented keywords for each command.
166 math(EXPR _ep_documentation_line_count "${CMAKE_CURRENT_LIST_LINE} - 16")
167 file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines
168      LIMIT_COUNT ${_ep_documentation_line_count}
169      REGEX "^#  (  \\[[A-Z0-9_]+ [^]]*\\] +#.*$|[A-Za-z0-9_]+\\()")
170 foreach(line IN LISTS lines)
171   if("${line}" MATCHES "^#  [A-Za-z0-9_]+\\(")
172     if(_ep_func)
173       set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
174     endif()
175     string(REGEX REPLACE "^#  ([A-Za-z0-9_]+)\\(.*" "\\1" _ep_func "${line}")
176     #message("function [${_ep_func}]")
177     set(_ep_keywords_${_ep_func} "^(")
178     set(_ep_keyword_sep)
179   else()
180     string(REGEX REPLACE "^#    \\[([A-Z0-9_]+) .*" "\\1" _ep_key "${line}")
181     #message("  keyword [${_ep_key}]")
182     set(_ep_keywords_${_ep_func}
183       "${_ep_keywords_${_ep_func}}${_ep_keyword_sep}${_ep_key}")
184     set(_ep_keyword_sep "|")
185   endif()
186 endforeach()
187 if(_ep_func)
188   set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
189 endif()
190
191 # Save regex matching supported hash algorithm names.
192 set(_ep_hash_algos "MD5|SHA1|SHA224|SHA256|SHA384|SHA512")
193 set(_ep_hash_regex "^(${_ep_hash_algos})=([0-9A-Fa-f]+)$")
194
195 function(_ep_parse_arguments f name ns args)
196   # Transfer the arguments to this function into target properties for the
197   # new custom target we just added so that we can set up all the build steps
198   # correctly based on target properties.
199   #
200   # We loop through ARGN and consider the namespace starting with an
201   # upper-case letter followed by at least two more upper-case letters,
202   # numbers or underscores to be keywords.
203   set(key)
204
205   foreach(arg IN LISTS args)
206     set(is_value 1)
207
208     if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
209         NOT ((arg STREQUAL "${key}") AND (key STREQUAL "COMMAND")) AND
210         NOT arg MATCHES "^(TRUE|FALSE)$")
211       if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
212         set(is_value 0)
213       endif()
214     endif()
215
216     if(is_value)
217       if(key)
218         # Value
219         if(NOT arg STREQUAL "")
220           set_property(TARGET ${name} APPEND PROPERTY ${ns}${key} "${arg}")
221         else()
222           get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
223           if(have_key)
224             get_property(value TARGET ${name} PROPERTY ${ns}${key})
225             set_property(TARGET ${name} PROPERTY ${ns}${key} "${value};${arg}")
226           else()
227             set_property(TARGET ${name} PROPERTY ${ns}${key} "${arg}")
228           endif()
229         endif()
230       else()
231         # Missing Keyword
232         message(AUTHOR_WARNING "value '${arg}' with no previous keyword in ${f}")
233       endif()
234     else()
235       set(key "${arg}")
236     endif()
237   endforeach()
238 endfunction()
239
240
241 define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED
242   BRIEF_DOCS "Base directory for External Project storage."
243   FULL_DOCS
244   "See documentation of the ExternalProject_Add() function in the "
245   "ExternalProject module."
246   )
247
248 define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
249   BRIEF_DOCS "Top prefix for External Project storage."
250   FULL_DOCS
251   "See documentation of the ExternalProject_Add() function in the "
252   "ExternalProject module."
253   )
254
255 define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
256   BRIEF_DOCS
257   "List of ExternalProject steps that automatically get corresponding targets"
258   FULL_DOCS
259   "See documentation of the ExternalProject_Add_StepTargets() function in the "
260   "ExternalProject module."
261   )
262
263
264 function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag src_name work_dir gitclone_infofile gitclone_stampfile)
265   file(WRITE ${script_filename}
266 "if(\"${git_tag}\" STREQUAL \"\")
267   message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
268 endif()
269
270 set(run 0)
271
272 if(\"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
273   set(run 1)
274 endif()
275
276 if(NOT run)
277   message(STATUS \"Avoiding repeated git clone, stamp file is up to date: '${gitclone_stampfile}'\")
278   return()
279 endif()
280
281 execute_process(
282   COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
283   RESULT_VARIABLE error_code
284   )
285 if(error_code)
286   message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
287 endif()
288
289 execute_process(
290   COMMAND \"${git_EXECUTABLE}\" clone \"${git_repository}\" \"${src_name}\"
291   WORKING_DIRECTORY \"${work_dir}\"
292   RESULT_VARIABLE error_code
293   )
294 if(error_code)
295   message(FATAL_ERROR \"Failed to clone repository: '${git_repository}'\")
296 endif()
297
298 execute_process(
299   COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag}
300   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
301   RESULT_VARIABLE error_code
302   )
303 if(error_code)
304   message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
305 endif()
306
307 execute_process(
308   COMMAND \"${git_EXECUTABLE}\" submodule init
309   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
310   RESULT_VARIABLE error_code
311   )
312 if(error_code)
313   message(FATAL_ERROR \"Failed to init submodules in: '${work_dir}/${src_name}'\")
314 endif()
315
316 execute_process(
317   COMMAND \"${git_EXECUTABLE}\" submodule update --recursive
318   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
319   RESULT_VARIABLE error_code
320   )
321 if(error_code)
322   message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
323 endif()
324
325 # Complete success, update the script-last-run stamp file:
326 #
327 execute_process(
328   COMMAND \${CMAKE_COMMAND} -E copy
329     \"${gitclone_infofile}\"
330     \"${gitclone_stampfile}\"
331   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
332   RESULT_VARIABLE error_code
333   )
334 if(error_code)
335   message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${gitclone_stampfile}'\")
336 endif()
337
338 "
339 )
340
341 endfunction()
342
343 function(_ep_write_hgclone_script script_filename source_dir hg_EXECUTABLE hg_repository hg_tag src_name work_dir hgclone_infofile hgclone_stampfile)
344   file(WRITE ${script_filename}
345 "if(\"${hg_tag}\" STREQUAL \"\")
346   message(FATAL_ERROR \"Tag for hg checkout should not be empty.\")
347 endif()
348
349 set(run 0)
350
351 if(\"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
352   set(run 1)
353 endif()
354
355 if(NOT run)
356   message(STATUS \"Avoiding repeated hg clone, stamp file is up to date: '${hgclone_stampfile}'\")
357   return()
358 endif()
359
360 execute_process(
361   COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
362   RESULT_VARIABLE error_code
363   )
364 if(error_code)
365   message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
366 endif()
367
368 execute_process(
369   COMMAND \"${hg_EXECUTABLE}\" clone \"${hg_repository}\" \"${src_name}\"
370   WORKING_DIRECTORY \"${work_dir}\"
371   RESULT_VARIABLE error_code
372   )
373 if(error_code)
374   message(FATAL_ERROR \"Failed to clone repository: '${hg_repository}'\")
375 endif()
376
377 execute_process(
378   COMMAND \"${hg_EXECUTABLE}\" update ${hg_tag}
379   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
380   RESULT_VARIABLE error_code
381   )
382 if(error_code)
383   message(FATAL_ERROR \"Failed to checkout tag: '${hg_tag}'\")
384 endif()
385
386 # Complete success, update the script-last-run stamp file:
387 #
388 execute_process(
389   COMMAND \${CMAKE_COMMAND} -E copy
390     \"${hgclone_infofile}\"
391     \"${hgclone_stampfile}\"
392   WORKING_DIRECTORY \"${work_dir}/${src_name}\"
393   RESULT_VARIABLE error_code
394   )
395 if(error_code)
396   message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${hgclone_stampfile}'\")
397 endif()
398
399 "
400 )
401
402 endfunction()
403
404
405 function(_ep_write_downloadfile_script script_filename remote local timeout hash tls_verify tls_cainfo)
406   if(timeout)
407     set(timeout_args TIMEOUT ${timeout})
408     set(timeout_msg "${timeout} seconds")
409   else()
410     set(timeout_args "# no TIMEOUT")
411     set(timeout_msg "none")
412   endif()
413
414   if("${hash}" MATCHES "${_ep_hash_regex}")
415     set(hash_args EXPECTED_HASH ${CMAKE_MATCH_1}=${CMAKE_MATCH_2})
416   else()
417     set(hash_args "# no EXPECTED_HASH")
418   endif()
419   # check for curl globals in the project
420   if(DEFINED CMAKE_TLS_VERIFY)
421     set(tls_verify "set(CMAKE_TLS_VERIFY ${CMAKE_TLS_VERIFY})")
422   endif()
423   if(DEFINED CMAKE_TLS_CAINFO)
424     set(tls_cainfo "set(CMAKE_TLS_CAINFO \"${CMAKE_TLS_CAINFO}\")")
425   endif()
426
427   # now check for curl locals so that the local values
428   # will override the globals
429
430   # check for tls_verify argument
431   string(LENGTH "${tls_verify}" tls_verify_len)
432   if(tls_verify_len GREATER 0)
433     set(tls_verify "set(CMAKE_TLS_VERIFY ${tls_verify})")
434   endif()
435   # check for tls_cainfo argument
436   string(LENGTH "${tls_cainfo}" tls_cainfo_len)
437   if(tls_cainfo_len GREATER 0)
438     set(tls_cainfo "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")")
439   endif()
440
441   file(WRITE ${script_filename}
442 "message(STATUS \"downloading...
443      src='${remote}'
444      dst='${local}'
445      timeout='${timeout_msg}'\")
446
447 ${tls_verify}
448 ${tls_cainfo}
449
450 file(DOWNLOAD
451   \"${remote}\"
452   \"${local}\"
453   SHOW_PROGRESS
454   ${hash_args}
455   ${timeout_args}
456   STATUS status
457   LOG log)
458
459 list(GET status 0 status_code)
460 list(GET status 1 status_string)
461
462 if(NOT status_code EQUAL 0)
463   message(FATAL_ERROR \"error: downloading '${remote}' failed
464   status_code: \${status_code}
465   status_string: \${status_string}
466   log: \${log}
467 \")
468 endif()
469
470 message(STATUS \"downloading... done\")
471 "
472 )
473
474 endfunction()
475
476
477 function(_ep_write_verifyfile_script script_filename local hash)
478   if("${hash}" MATCHES "${_ep_hash_regex}")
479     set(algo "${CMAKE_MATCH_1}")
480     string(TOLOWER "${CMAKE_MATCH_2}" expect_value)
481     set(script_content "set(expect_value \"${expect_value}\")
482 file(${algo} \"\${file}\" actual_value)
483 if(\"\${actual_value}\" STREQUAL \"\${expect_value}\")
484   message(STATUS \"verifying file... done\")
485 else()
486   message(FATAL_ERROR \"error: ${algo} hash of
487   \${file}
488 does not match expected value
489   expected: \${expect_value}
490     actual: \${actual_value}
491 \")
492 endif()")
493   else()
494     set(script_content "message(STATUS \"verifying file... warning: did not verify file - no URL_HASH specified?\")")
495   endif()
496   file(WRITE ${script_filename} "set(file \"${local}\")
497 message(STATUS \"verifying file...
498      file='\${file}'\")
499 ${script_content}
500 ")
501 endfunction()
502
503
504 function(_ep_write_extractfile_script script_filename name filename directory)
505   set(args "")
506
507   if(filename MATCHES "(\\.|=)(bz2|tar\\.gz|tgz|zip)$")
508     set(args xfz)
509   endif()
510
511   if(filename MATCHES "(\\.|=)tar$")
512     set(args xf)
513   endif()
514
515   if(args STREQUAL "")
516     message(SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .bz2, .tar, .tar.gz, .tgz and .zip")
517     return()
518   endif()
519
520   file(WRITE ${script_filename}
521 "# Make file names absolute:
522 #
523 get_filename_component(filename \"${filename}\" ABSOLUTE)
524 get_filename_component(directory \"${directory}\" ABSOLUTE)
525
526 message(STATUS \"extracting...
527      src='\${filename}'
528      dst='\${directory}'\")
529
530 if(NOT EXISTS \"\${filename}\")
531   message(FATAL_ERROR \"error: file to extract does not exist: '\${filename}'\")
532 endif()
533
534 # Prepare a space for extracting:
535 #
536 set(i 1234)
537 while(EXISTS \"\${directory}/../ex-${name}\${i}\")
538   math(EXPR i \"\${i} + 1\")
539 endwhile()
540 set(ut_dir \"\${directory}/../ex-${name}\${i}\")
541 file(MAKE_DIRECTORY \"\${ut_dir}\")
542
543 # Extract it:
544 #
545 message(STATUS \"extracting... [tar ${args}]\")
546 execute_process(COMMAND \${CMAKE_COMMAND} -E tar ${args} \${filename}
547   WORKING_DIRECTORY \${ut_dir}
548   RESULT_VARIABLE rv)
549
550 if(NOT rv EQUAL 0)
551   message(STATUS \"extracting... [error clean up]\")
552   file(REMOVE_RECURSE \"\${ut_dir}\")
553   message(FATAL_ERROR \"error: extract of '\${filename}' failed\")
554 endif()
555
556 # Analyze what came out of the tar file:
557 #
558 message(STATUS \"extracting... [analysis]\")
559 file(GLOB contents \"\${ut_dir}/*\")
560 list(LENGTH contents n)
561 if(NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\")
562   set(contents \"\${ut_dir}\")
563 endif()
564
565 # Move \"the one\" directory to the final directory:
566 #
567 message(STATUS \"extracting... [rename]\")
568 file(REMOVE_RECURSE \${directory})
569 get_filename_component(contents \${contents} ABSOLUTE)
570 file(RENAME \${contents} \${directory})
571
572 # Clean up:
573 #
574 message(STATUS \"extracting... [clean up]\")
575 file(REMOVE_RECURSE \"\${ut_dir}\")
576
577 message(STATUS \"extracting... done\")
578 "
579 )
580
581 endfunction()
582
583
584 function(_ep_set_directories name)
585   get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX)
586   if(NOT prefix)
587     get_property(prefix DIRECTORY PROPERTY EP_PREFIX)
588     if(NOT prefix)
589       get_property(base DIRECTORY PROPERTY EP_BASE)
590       if(NOT base)
591         set(prefix "${name}-prefix")
592       endif()
593     endif()
594   endif()
595   if(prefix)
596     set(tmp_default "${prefix}/tmp")
597     set(download_default "${prefix}/src")
598     set(source_default "${prefix}/src/${name}")
599     set(binary_default "${prefix}/src/${name}-build")
600     set(stamp_default "${prefix}/src/${name}-stamp")
601     set(install_default "${prefix}")
602   else()
603     set(tmp_default "${base}/tmp/${name}")
604     set(download_default "${base}/Download/${name}")
605     set(source_default "${base}/Source/${name}")
606     set(binary_default "${base}/Build/${name}")
607     set(stamp_default "${base}/Stamp/${name}")
608     set(install_default "${base}/Install/${name}")
609   endif()
610   get_property(build_in_source TARGET ${name} PROPERTY _EP_BUILD_IN_SOURCE)
611   if(build_in_source)
612     get_property(have_binary_dir TARGET ${name} PROPERTY _EP_BINARY_DIR SET)
613     if(have_binary_dir)
614       message(FATAL_ERROR
615         "External project ${name} has both BINARY_DIR and BUILD_IN_SOURCE!")
616     endif()
617   endif()
618   set(top "${CMAKE_CURRENT_BINARY_DIR}")
619   set(places stamp download source binary install tmp)
620   foreach(var ${places})
621     string(TOUPPER "${var}" VAR)
622     get_property(${var}_dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
623     if(NOT ${var}_dir)
624       set(${var}_dir "${${var}_default}")
625     endif()
626     if(NOT IS_ABSOLUTE "${${var}_dir}")
627       get_filename_component(${var}_dir "${top}/${${var}_dir}" ABSOLUTE)
628     endif()
629     set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
630   endforeach()
631   if(build_in_source)
632     get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR)
633     set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}")
634   endif()
635
636   # Make the directories at CMake configure time *and* add a custom command
637   # to make them at build time. They need to exist at makefile generation
638   # time for Borland make and wmake so that CMake may generate makefiles
639   # with "cd C:\short\paths\with\no\spaces" commands in them.
640   #
641   # Additionally, the add_custom_command is still used in case somebody
642   # removes one of the necessary directories and tries to rebuild without
643   # re-running cmake.
644   foreach(var ${places})
645     string(TOUPPER "${var}" VAR)
646     get_property(dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
647     file(MAKE_DIRECTORY "${dir}")
648     if(NOT EXISTS "${dir}")
649       message(FATAL_ERROR "dir '${dir}' does not exist after file(MAKE_DIRECTORY)")
650     endif()
651   endforeach()
652 endfunction()
653
654
655 # IMPORTANT: this MUST be a macro and not a function because of the
656 # in-place replacements that occur in each ${var}
657 #
658 macro(_ep_replace_location_tags target_name)
659   set(vars ${ARGN})
660   foreach(var ${vars})
661     if(${var})
662       foreach(dir SOURCE_DIR BINARY_DIR INSTALL_DIR TMP_DIR)
663         get_property(val TARGET ${target_name} PROPERTY _EP_${dir})
664         string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}")
665       endforeach()
666     endif()
667   endforeach()
668 endmacro()
669
670
671 function(_ep_write_initial_cache target_name script_filename args)
672   # Write out values into an initial cache, that will be passed to CMake with -C
673   set(script_initial_cache "")
674   set(regex "^([^:]+):([^=]+)=(.*)$")
675   set(setArg "")
676   foreach(line ${args})
677     if("${line}" MATCHES "^-D")
678       if(setArg)
679         # This is required to build up lists in variables, or complete an entry
680         set(setArg "${setArg}${accumulator}\" CACHE ${type} \"Initial cache\" FORCE)")
681         set(script_initial_cache "${script_initial_cache}\n${setArg}")
682         set(accumulator "")
683         set(setArg "")
684       endif()
685       string(REGEX REPLACE "^-D" "" line ${line})
686       if("${line}" MATCHES "${regex}")
687         string(REGEX MATCH "${regex}" match "${line}")
688         set(name "${CMAKE_MATCH_1}")
689         set(type "${CMAKE_MATCH_2}")
690         set(value "${CMAKE_MATCH_3}")
691         set(setArg "set(${name} \"${value}")
692       else()
693         message(WARNING "Line '${line}' does not match regex. Ignoring.")
694       endif()
695     else()
696       # Assume this is a list to append to the last var
697       set(accumulator "${accumulator};${line}")
698     endif()
699   endforeach()
700   # Catch the final line of the args
701   if(setArg)
702     set(setArg "${setArg}${accumulator}\" CACHE ${type} \"Initial cache\" FORCE)")
703     set(script_initial_cache "${script_initial_cache}\n${setArg}")
704   endif()
705   # Replace location tags.
706   _ep_replace_location_tags(${target_name} script_initial_cache)
707   # Write out the initial cache file to the location specified.
708   if(NOT EXISTS "${script_filename}.in")
709     file(WRITE "${script_filename}.in" "\@script_initial_cache\@\n")
710   endif()
711   configure_file("${script_filename}.in" "${script_filename}")
712 endfunction()
713
714
715 function(ExternalProject_Get_Property name)
716   foreach(var ${ARGN})
717     string(TOUPPER "${var}" VAR)
718     get_property(${var} TARGET ${name} PROPERTY _EP_${VAR})
719     if(NOT ${var})
720       message(FATAL_ERROR "External project \"${name}\" has no ${var}")
721     endif()
722     set(${var} "${${var}}" PARENT_SCOPE)
723   endforeach()
724 endfunction()
725
726
727 function(_ep_get_configure_command_id name cfg_cmd_id_var)
728   get_target_property(cmd ${name} _EP_CONFIGURE_COMMAND)
729
730   if(cmd STREQUAL "")
731     # Explicit empty string means no configure step for this project
732     set(${cfg_cmd_id_var} "none" PARENT_SCOPE)
733   else()
734     if(NOT cmd)
735       # Default is "use cmake":
736       set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
737     else()
738       # Otherwise we have to analyze the value:
739       if(cmd MATCHES "^[^;]*/configure")
740         set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
741       elseif(cmd MATCHES "^[^;]*/cmake" AND NOT cmd MATCHES ";-[PE];")
742         set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
743       elseif(cmd MATCHES "config")
744         set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
745       else()
746         set(${cfg_cmd_id_var} "unknown:${cmd}" PARENT_SCOPE)
747       endif()
748     endif()
749   endif()
750 endfunction()
751
752
753 function(_ep_get_build_command name step cmd_var)
754   set(cmd "${${cmd_var}}")
755   if(NOT cmd)
756     set(args)
757     _ep_get_configure_command_id(${name} cfg_cmd_id)
758     if(cfg_cmd_id STREQUAL "cmake")
759       # CMake project.  Select build command based on generator.
760       get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
761       if("${CMAKE_GENERATOR}" MATCHES "Make" AND
762          ("${cmake_generator}" MATCHES "Make" OR NOT cmake_generator))
763         # The project uses the same Makefile generator.  Use recursive make.
764         set(cmd "$(MAKE)")
765         if(step STREQUAL "INSTALL")
766           set(args install)
767         endif()
768         if(step STREQUAL "TEST")
769           set(args test)
770         endif()
771       else()
772         # Drive the project with "cmake --build".
773         get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
774         if(cmake_command)
775           set(cmd "${cmake_command}")
776         else()
777           set(cmd "${CMAKE_COMMAND}")
778         endif()
779         set(args --build ${binary_dir} --config ${CMAKE_CFG_INTDIR})
780         if(step STREQUAL "INSTALL")
781           list(APPEND args --target install)
782         endif()
783         # But for "TEST" drive the project with corresponding "ctest".
784         if(step STREQUAL "TEST")
785           string(REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}")
786           set(args "")
787         endif()
788       endif()
789     else()
790       # Non-CMake project.  Guess "make" and "make install" and "make test".
791       if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
792         # Try to get the parallel arguments
793         set(cmd "$(MAKE)")
794       else()
795         set(cmd "make")
796       endif()
797       if(step STREQUAL "INSTALL")
798         set(args install)
799       endif()
800       if(step STREQUAL "TEST")
801         set(args test)
802       endif()
803     endif()
804
805     # Use user-specified arguments instead of default arguments, if any.
806     get_property(have_args TARGET ${name} PROPERTY _EP_${step}_ARGS SET)
807     if(have_args)
808       get_target_property(args ${name} _EP_${step}_ARGS)
809     endif()
810
811     list(APPEND cmd ${args})
812   endif()
813
814   set(${cmd_var} "${cmd}" PARENT_SCOPE)
815 endfunction()
816
817 function(_ep_write_log_script name step cmd_var)
818   ExternalProject_Get_Property(${name} stamp_dir)
819   set(command "${${cmd_var}}")
820
821   set(make "")
822   set(code_cygpath_make "")
823   if("${command}" MATCHES "^\\$\\(MAKE\\)")
824     # GNU make recognizes the string "$(MAKE)" as recursive make, so
825     # ensure that it appears directly in the makefile.
826     string(REGEX REPLACE "^\\$\\(MAKE\\)" "\${make}" command "${command}")
827     set(make "-Dmake=$(MAKE)")
828
829     if(WIN32 AND NOT CYGWIN)
830       set(code_cygpath_make "
831 if(\${make} MATCHES \"^/\")
832   execute_process(
833     COMMAND cygpath -w \${make}
834     OUTPUT_VARIABLE cygpath_make
835     ERROR_VARIABLE cygpath_make
836     RESULT_VARIABLE cygpath_error
837     OUTPUT_STRIP_TRAILING_WHITESPACE
838   )
839   if(NOT cygpath_error)
840     set(make \${cygpath_make})
841   endif()
842 endif()
843 ")
844     endif()
845   endif()
846
847   set(config "")
848   if("${CMAKE_CFG_INTDIR}" MATCHES "^\\$")
849     string(REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}")
850     set(config "-Dconfig=${CMAKE_CFG_INTDIR}")
851   endif()
852
853   # Wrap multiple 'COMMAND' lines up into a second-level wrapper
854   # script so all output can be sent to one log file.
855   if("${command}" MATCHES ";COMMAND;")
856     set(code_execute_process "
857 ${code_cygpath_make}
858 execute_process(COMMAND \${command} RESULT_VARIABLE result)
859 if(result)
860   set(msg \"Command failed (\${result}):\\n\")
861   foreach(arg IN LISTS command)
862     set(msg \"\${msg} '\${arg}'\")
863   endforeach()
864   message(FATAL_ERROR \"\${msg}\")
865 endif()
866 ")
867     set(code "")
868     set(cmd "")
869     set(sep "")
870     foreach(arg IN LISTS command)
871       if("x${arg}" STREQUAL "xCOMMAND")
872         set(code "${code}set(command \"${cmd}\")${code_execute_process}")
873         set(cmd "")
874         set(sep "")
875       else()
876         set(cmd "${cmd}${sep}${arg}")
877         set(sep ";")
878       endif()
879     endforeach()
880     set(code "set(ENV{VS_UNICODE_OUTPUT} \"\")\n${code}set(command \"${cmd}\")${code_execute_process}")
881     file(WRITE ${stamp_dir}/${name}-${step}-impl.cmake "${code}")
882     set(command ${CMAKE_COMMAND} "-Dmake=\${make}" "-Dconfig=\${config}" -P ${stamp_dir}/${name}-${step}-impl.cmake)
883   endif()
884
885   # Wrap the command in a script to log output to files.
886   set(script ${stamp_dir}/${name}-${step}.cmake)
887   set(logbase ${stamp_dir}/${name}-${step})
888   file(WRITE ${script} "
889 ${code_cygpath_make}
890 set(ENV{VS_UNICODE_OUTPUT} \"\")
891 set(command \"${command}\")
892 execute_process(
893   COMMAND \${command}
894   RESULT_VARIABLE result
895   OUTPUT_FILE \"${logbase}-out.log\"
896   ERROR_FILE \"${logbase}-err.log\"
897   )
898 if(result)
899   set(msg \"Command failed: \${result}\\n\")
900   foreach(arg IN LISTS command)
901     set(msg \"\${msg} '\${arg}'\")
902   endforeach()
903   set(msg \"\${msg}\\nSee also\\n  ${logbase}-*.log\\n\")
904   message(FATAL_ERROR \"\${msg}\")
905 else()
906   set(msg \"${name} ${step} command succeeded.  See also ${logbase}-*.log\\n\")
907   message(STATUS \"\${msg}\")
908 endif()
909 ")
910   set(command ${CMAKE_COMMAND} ${make} ${config} -P ${script})
911   set(${cmd_var} "${command}" PARENT_SCOPE)
912 endfunction()
913
914 # This module used to use "/${CMAKE_CFG_INTDIR}" directly and produced
915 # makefiles with "/./" in paths for custom command dependencies. Which
916 # resulted in problems with parallel make -j invocations.
917 #
918 # This function was added so that the suffix (search below for ${cfgdir}) is
919 # only set to "/${CMAKE_CFG_INTDIR}" when ${CMAKE_CFG_INTDIR} is not going to
920 # be "." (multi-configuration build systems like Visual Studio and Xcode...)
921 #
922 function(_ep_get_configuration_subdir_suffix suffix_var)
923   set(suffix "")
924   if(CMAKE_CONFIGURATION_TYPES)
925     set(suffix "/${CMAKE_CFG_INTDIR}")
926   endif()
927   set(${suffix_var} "${suffix}" PARENT_SCOPE)
928 endfunction()
929
930
931 function(_ep_get_step_stampfile name step stampfile_var)
932   ExternalProject_Get_Property(${name} stamp_dir)
933
934   _ep_get_configuration_subdir_suffix(cfgdir)
935   set(stampfile "${stamp_dir}${cfgdir}/${name}-${step}")
936
937   set(${stampfile_var} "${stampfile}" PARENT_SCOPE)
938 endfunction()
939
940
941 function(ExternalProject_Add_StepTargets name)
942   set(steps ${ARGN})
943
944   foreach(step ${steps})
945     _ep_get_step_stampfile(${name} ${step} stamp_file)
946     add_custom_target(${name}-${step}
947       DEPENDS ${stamp_file})
948
949     # Depend on other external projects (target-level).
950     get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
951     foreach(arg IN LISTS deps)
952       add_dependencies(${name}-${step} ${arg})
953     endforeach()
954   endforeach()
955 endfunction()
956
957
958 function(ExternalProject_Add_Step name step)
959   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
960   _ep_get_configuration_subdir_suffix(cfgdir)
961
962   set(complete_stamp_file "${cmf_dir}${cfgdir}/${name}-complete")
963   _ep_get_step_stampfile(${name} ${step} stamp_file)
964
965   add_custom_command(APPEND
966     OUTPUT ${complete_stamp_file}
967     DEPENDS ${stamp_file}
968     )
969
970   _ep_parse_arguments(ExternalProject_Add_Step
971                       ${name} _EP_${step}_ "${ARGN}")
972
973   # Steps depending on this step.
974   get_property(dependers TARGET ${name} PROPERTY _EP_${step}_DEPENDERS)
975   foreach(depender IN LISTS dependers)
976     _ep_get_step_stampfile(${name} ${depender} depender_stamp_file)
977     add_custom_command(APPEND
978       OUTPUT ${depender_stamp_file}
979       DEPENDS ${stamp_file}
980       )
981   endforeach()
982
983   # Dependencies on files.
984   get_property(depends TARGET ${name} PROPERTY _EP_${step}_DEPENDS)
985
986   # Dependencies on steps.
987   get_property(dependees TARGET ${name} PROPERTY _EP_${step}_DEPENDEES)
988   foreach(dependee IN LISTS dependees)
989     _ep_get_step_stampfile(${name} ${dependee} dependee_stamp_file)
990     list(APPEND depends ${dependee_stamp_file})
991   endforeach()
992
993   # The command to run.
994   get_property(command TARGET ${name} PROPERTY _EP_${step}_COMMAND)
995   if(command)
996     set(comment "Performing ${step} step for '${name}'")
997   else()
998     set(comment "No ${step} step for '${name}'")
999   endif()
1000   get_property(work_dir TARGET ${name} PROPERTY _EP_${step}_WORKING_DIRECTORY)
1001
1002   # Replace list separators.
1003   get_property(sep TARGET ${name} PROPERTY _EP_LIST_SEPARATOR)
1004   if(sep AND command)
1005     string(REPLACE "${sep}" "\\;" command "${command}")
1006   endif()
1007
1008   # Replace location tags.
1009   _ep_replace_location_tags(${name} comment command work_dir)
1010
1011   # Custom comment?
1012   get_property(comment_set TARGET ${name} PROPERTY _EP_${step}_COMMENT SET)
1013   if(comment_set)
1014     get_property(comment TARGET ${name} PROPERTY _EP_${step}_COMMENT)
1015   endif()
1016
1017   # Run every time?
1018   get_property(always TARGET ${name} PROPERTY _EP_${step}_ALWAYS)
1019   if(always)
1020     set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
1021     set(touch)
1022   else()
1023     set(touch ${CMAKE_COMMAND} -E touch ${stamp_file})
1024   endif()
1025
1026   # Wrap with log script?
1027   get_property(log TARGET ${name} PROPERTY _EP_${step}_LOG)
1028   if(command AND log)
1029     _ep_write_log_script(${name} ${step} command)
1030   endif()
1031
1032   add_custom_command(
1033     OUTPUT ${stamp_file}
1034     COMMENT ${comment}
1035     COMMAND ${command}
1036     COMMAND ${touch}
1037     DEPENDS ${depends}
1038     WORKING_DIRECTORY ${work_dir}
1039     VERBATIM
1040     )
1041
1042   # Add custom "step target"?
1043   get_property(step_targets TARGET ${name} PROPERTY _EP_STEP_TARGETS)
1044   if(NOT step_targets)
1045     get_property(step_targets DIRECTORY PROPERTY EP_STEP_TARGETS)
1046   endif()
1047   foreach(st ${step_targets})
1048     if("${st}" STREQUAL "${step}")
1049       ExternalProject_Add_StepTargets(${name} ${step})
1050       break()
1051     endif()
1052   endforeach()
1053 endfunction()
1054
1055
1056 function(_ep_add_mkdir_command name)
1057   ExternalProject_Get_Property(${name}
1058     source_dir binary_dir install_dir stamp_dir download_dir tmp_dir)
1059
1060   _ep_get_configuration_subdir_suffix(cfgdir)
1061
1062   ExternalProject_Add_Step(${name} mkdir
1063     COMMENT "Creating directories for '${name}'"
1064     COMMAND ${CMAKE_COMMAND} -E make_directory ${source_dir}
1065     COMMAND ${CMAKE_COMMAND} -E make_directory ${binary_dir}
1066     COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}
1067     COMMAND ${CMAKE_COMMAND} -E make_directory ${tmp_dir}
1068     COMMAND ${CMAKE_COMMAND} -E make_directory ${stamp_dir}${cfgdir}
1069     COMMAND ${CMAKE_COMMAND} -E make_directory ${download_dir}
1070     )
1071 endfunction()
1072
1073
1074 function(_ep_get_git_version git_EXECUTABLE git_version_var)
1075   if(git_EXECUTABLE)
1076     execute_process(
1077       COMMAND "${git_EXECUTABLE}" --version
1078       OUTPUT_VARIABLE ov
1079       ERROR_VARIABLE ev
1080       OUTPUT_STRIP_TRAILING_WHITESPACE
1081       )
1082     string(REGEX REPLACE "^git version (.+)$" "\\1" version "${ov}")
1083     set(${git_version_var} "${version}" PARENT_SCOPE)
1084   endif()
1085 endfunction()
1086
1087
1088 function(_ep_is_dir_empty dir empty_var)
1089   file(GLOB gr "${dir}/*")
1090   if("${gr}" STREQUAL "")
1091     set(${empty_var} 1 PARENT_SCOPE)
1092   else()
1093     set(${empty_var} 0 PARENT_SCOPE)
1094   endif()
1095 endfunction()
1096
1097
1098 function(_ep_add_download_command name)
1099   ExternalProject_Get_Property(${name} source_dir stamp_dir download_dir tmp_dir)
1100
1101   get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
1102   get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
1103   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
1104   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
1105   get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
1106   get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
1107   get_property(url TARGET ${name} PROPERTY _EP_URL)
1108   get_property(fname TARGET ${name} PROPERTY _EP_DOWNLOAD_NAME)
1109
1110   # TODO: Perhaps file:// should be copied to download dir before extraction.
1111   string(REGEX REPLACE "^file://" "" url "${url}")
1112
1113   set(depends)
1114   set(comment)
1115   set(work_dir)
1116
1117   if(cmd_set)
1118     set(work_dir ${download_dir})
1119   elseif(cvs_repository)
1120     find_package(CVS)
1121     if(NOT CVS_EXECUTABLE)
1122       message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
1123     endif()
1124
1125     get_target_property(cvs_module ${name} _EP_CVS_MODULE)
1126     if(NOT cvs_module)
1127       message(FATAL_ERROR "error: no CVS_MODULE")
1128     endif()
1129
1130     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
1131
1132     set(repository ${cvs_repository})
1133     set(module ${cvs_module})
1134     set(tag ${cvs_tag})
1135     configure_file(
1136       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1137       "${stamp_dir}/${name}-cvsinfo.txt"
1138       @ONLY
1139       )
1140
1141     get_filename_component(src_name "${source_dir}" NAME)
1142     get_filename_component(work_dir "${source_dir}" PATH)
1143     set(comment "Performing download step (CVS checkout) for '${name}'")
1144     set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q co ${cvs_tag} -d ${src_name} ${cvs_module})
1145     list(APPEND depends ${stamp_dir}/${name}-cvsinfo.txt)
1146   elseif(svn_repository)
1147     find_package(Subversion)
1148     if(NOT Subversion_SVN_EXECUTABLE)
1149       message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
1150     endif()
1151
1152     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
1153     get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
1154     get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
1155     get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
1156
1157     set(repository "${svn_repository} user=${svn_username} password=${svn_password}")
1158     set(module)
1159     set(tag ${svn_revision})
1160     configure_file(
1161       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1162       "${stamp_dir}/${name}-svninfo.txt"
1163       @ONLY
1164       )
1165
1166     get_filename_component(src_name "${source_dir}" NAME)
1167     get_filename_component(work_dir "${source_dir}" PATH)
1168     set(comment "Performing download step (SVN checkout) for '${name}'")
1169     set(svn_user_pw_args "")
1170     if(svn_username)
1171       set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
1172     endif()
1173     if(svn_password)
1174       set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
1175     endif()
1176     if(svn_trust_cert)
1177       set(svn_trust_cert_args --trust-server-cert)
1178     endif()
1179     set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_revision}
1180       --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args} ${src_name})
1181     list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
1182   elseif(git_repository)
1183     find_package(Git)
1184     if(NOT GIT_EXECUTABLE)
1185       message(FATAL_ERROR "error: could not find git for clone of ${name}")
1186     endif()
1187
1188     # The git submodule update '--recursive' flag requires git >= v1.6.5
1189     #
1190     _ep_get_git_version("${GIT_EXECUTABLE}" git_version)
1191     if(git_version VERSION_LESS 1.6.5)
1192       message(FATAL_ERROR "error: git version 1.6.5 or later required for 'git submodule update --recursive': git_version='${git_version}'")
1193     endif()
1194
1195     get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
1196     if(NOT git_tag)
1197       set(git_tag "master")
1198     endif()
1199
1200     # For the download step, and the git clone operation, only the repository
1201     # should be recorded in a configured RepositoryInfo file. If the repo
1202     # changes, the clone script should be run again. But if only the tag
1203     # changes, avoid running the clone script again. Let the 'always' running
1204     # update step checkout the new tag.
1205     #
1206     set(repository ${git_repository})
1207     set(module)
1208     set(tag)
1209     configure_file(
1210       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1211       "${stamp_dir}/${name}-gitinfo.txt"
1212       @ONLY
1213       )
1214
1215     get_filename_component(src_name "${source_dir}" NAME)
1216     get_filename_component(work_dir "${source_dir}" PATH)
1217
1218     # Since git clone doesn't succeed if the non-empty source_dir exists,
1219     # create a cmake script to invoke as download command.
1220     # The script will delete the source directory and then call git clone.
1221     #
1222     _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
1223       ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${src_name} ${work_dir}
1224       ${stamp_dir}/${name}-gitinfo.txt ${stamp_dir}/${name}-gitclone-lastrun.txt
1225       )
1226     set(comment "Performing download step (git clone) for '${name}'")
1227     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
1228     list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
1229   elseif(hg_repository)
1230     find_package(Hg)
1231     if(NOT HG_EXECUTABLE)
1232       message(FATAL_ERROR "error: could not find hg for clone of ${name}")
1233     endif()
1234
1235     get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
1236     if(NOT hg_tag)
1237       set(hg_tag "tip")
1238     endif()
1239
1240     # For the download step, and the hg clone operation, only the repository
1241     # should be recorded in a configured RepositoryInfo file. If the repo
1242     # changes, the clone script should be run again. But if only the tag
1243     # changes, avoid running the clone script again. Let the 'always' running
1244     # update step checkout the new tag.
1245     #
1246     set(repository ${hg_repository})
1247     set(module)
1248     set(tag)
1249     configure_file(
1250       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1251       "${stamp_dir}/${name}-hginfo.txt"
1252       @ONLY
1253       )
1254
1255     get_filename_component(src_name "${source_dir}" NAME)
1256     get_filename_component(work_dir "${source_dir}" PATH)
1257
1258     # Since hg clone doesn't succeed if the non-empty source_dir exists,
1259     # create a cmake script to invoke as download command.
1260     # The script will delete the source directory and then call hg clone.
1261     #
1262     _ep_write_hgclone_script(${tmp_dir}/${name}-hgclone.cmake ${source_dir}
1263       ${HG_EXECUTABLE} ${hg_repository} ${hg_tag} ${src_name} ${work_dir}
1264       ${stamp_dir}/${name}-hginfo.txt ${stamp_dir}/${name}-hgclone-lastrun.txt
1265       )
1266     set(comment "Performing download step (hg clone) for '${name}'")
1267     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake)
1268     list(APPEND depends ${stamp_dir}/${name}-hginfo.txt)
1269   elseif(url)
1270     get_filename_component(work_dir "${source_dir}" PATH)
1271     get_property(hash TARGET ${name} PROPERTY _EP_URL_HASH)
1272     if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
1273       message(FATAL_ERROR "URL_HASH is set to\n  ${hash}\n"
1274         "but must be ALGO=value where ALGO is\n  ${_ep_hash_algos}\n"
1275         "and value is a hex string.")
1276     endif()
1277     get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
1278     if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}")
1279       message(FATAL_ERROR "URL_MD5 is set to\n  ${md5}\nbut must be a hex string.")
1280     endif()
1281     if(md5 AND NOT hash)
1282       set(hash "MD5=${md5}")
1283     endif()
1284     set(repository "external project URL")
1285     set(module "${url}")
1286     set(tag "${hash}")
1287     configure_file(
1288       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1289       "${stamp_dir}/${name}-urlinfo.txt"
1290       @ONLY
1291       )
1292     list(APPEND depends ${stamp_dir}/${name}-urlinfo.txt)
1293     if(IS_DIRECTORY "${url}")
1294       get_filename_component(abs_dir "${url}" ABSOLUTE)
1295       set(comment "Performing download step (DIR copy) for '${name}'")
1296       set(cmd   ${CMAKE_COMMAND} -E remove_directory ${source_dir}
1297         COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir})
1298     else()
1299       if("${url}" MATCHES "^[a-z]+://")
1300         # TODO: Should download and extraction be different steps?
1301         if("x${fname}" STREQUAL "x")
1302           string(REGEX MATCH "[^/\\?]*$" fname "${url}")
1303         endif()
1304         if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$")
1305           string(REGEX MATCH "([^/\\?]+(\\.|=)(bz2|tar|tgz|tar\\.gz|zip))/.*$" match_result "${url}")
1306           set(fname "${CMAKE_MATCH_1}")
1307         endif()
1308         if(NOT "${fname}" MATCHES "(\\.|=)(bz2|tar|tgz|tar\\.gz|zip)$")
1309           message(FATAL_ERROR "Could not extract tarball filename from url:\n  ${url}")
1310         endif()
1311         string(REPLACE ";" "-" fname "${fname}")
1312         set(file ${download_dir}/${fname})
1313         get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
1314         get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
1315         get_property(tls_cainfo TARGET ${name} PROPERTY _EP_TLS_CAINFO)
1316         _ep_write_downloadfile_script("${stamp_dir}/download-${name}.cmake"
1317           "${url}" "${file}" "${timeout}" "${hash}" "${tls_verify}" "${tls_cainfo}")
1318         set(cmd ${CMAKE_COMMAND} -P ${stamp_dir}/download-${name}.cmake
1319           COMMAND)
1320         set(comment "Performing download step (download, verify and extract) for '${name}'")
1321       else()
1322         set(file "${url}")
1323         set(comment "Performing download step (verify and extract) for '${name}'")
1324       endif()
1325       _ep_write_verifyfile_script("${stamp_dir}/verify-${name}.cmake" "${file}" "${hash}")
1326       list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake
1327         COMMAND)
1328       _ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${name}" "${file}" "${source_dir}")
1329       list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
1330     endif()
1331   else()
1332     _ep_is_dir_empty("${source_dir}" empty)
1333     if(${empty})
1334       message(SEND_ERROR "error: no download info for '${name}' -- please specify existing/non-empty SOURCE_DIR or one of URL, CVS_REPOSITORY and CVS_MODULE, SVN_REPOSITORY, GIT_REPOSITORY, HG_REPOSITORY or DOWNLOAD_COMMAND")
1335     endif()
1336   endif()
1337
1338   get_property(log TARGET ${name} PROPERTY _EP_LOG_DOWNLOAD)
1339   if(log)
1340     set(log LOG 1)
1341   else()
1342     set(log "")
1343   endif()
1344
1345   ExternalProject_Add_Step(${name} download
1346     COMMENT ${comment}
1347     COMMAND ${cmd}
1348     WORKING_DIRECTORY ${work_dir}
1349     DEPENDS ${depends}
1350     DEPENDEES mkdir
1351     ${log}
1352     )
1353 endfunction()
1354
1355
1356 function(_ep_add_update_command name)
1357   ExternalProject_Get_Property(${name} source_dir)
1358
1359   get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
1360   get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
1361   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
1362   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
1363   get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
1364   get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
1365
1366   set(work_dir)
1367   set(comment)
1368   set(always)
1369
1370   if(cmd_set)
1371     set(work_dir ${source_dir})
1372   elseif(cvs_repository)
1373     if(NOT CVS_EXECUTABLE)
1374       message(FATAL_ERROR "error: could not find cvs for update of ${name}")
1375     endif()
1376     set(work_dir ${source_dir})
1377     set(comment "Performing update step (CVS update) for '${name}'")
1378     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
1379     set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
1380     set(always 1)
1381   elseif(svn_repository)
1382     if(NOT Subversion_SVN_EXECUTABLE)
1383       message(FATAL_ERROR "error: could not find svn for update of ${name}")
1384     endif()
1385     set(work_dir ${source_dir})
1386     set(comment "Performing update step (SVN update) for '${name}'")
1387     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
1388     get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
1389     get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
1390     get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
1391     set(svn_user_pw_args "")
1392     if(svn_username)
1393       set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
1394     endif()
1395     if(svn_password)
1396       set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
1397     endif()
1398     if(svn_trust_cert)
1399       set(svn_trust_cert_args --trust-server-cert)
1400     endif()
1401     set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_revision}
1402       --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args})
1403     set(always 1)
1404   elseif(git_repository)
1405     if(NOT GIT_EXECUTABLE)
1406       message(FATAL_ERROR "error: could not find git for fetch of ${name}")
1407     endif()
1408     set(work_dir ${source_dir})
1409     set(comment "Performing update step (git fetch) for '${name}'")
1410     get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
1411     if(NOT git_tag)
1412       set(git_tag "master")
1413     endif()
1414     set(cmd ${GIT_EXECUTABLE} fetch
1415       COMMAND ${GIT_EXECUTABLE} checkout ${git_tag}
1416       COMMAND ${GIT_EXECUTABLE} submodule update --recursive
1417       )
1418     set(always 1)
1419   elseif(hg_repository)
1420     if(NOT HG_EXECUTABLE)
1421       message(FATAL_ERROR "error: could not find hg for pull of ${name}")
1422     endif()
1423     set(work_dir ${source_dir})
1424     set(comment "Performing update step (hg pull) for '${name}'")
1425     get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
1426     if(NOT hg_tag)
1427       set(hg_tag "tip")
1428     endif()
1429     if("${HG_VERSION_STRING}" STREQUAL "2.1")
1430       message(WARNING "Mercurial 2.1 does not distinguish an empty pull from a failed pull:
1431  http://mercurial.selenic.com/wiki/UpgradeNotes#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X
1432  http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656
1433 Update to Mercurial >= 2.1.1.
1434 ")
1435     endif()
1436     set(cmd ${HG_EXECUTABLE} pull
1437       COMMAND ${HG_EXECUTABLE} update ${hg_tag}
1438       )
1439     set(always 1)
1440   endif()
1441
1442   get_property(log TARGET ${name} PROPERTY _EP_LOG_UPDATE)
1443   if(log)
1444     set(log LOG 1)
1445   else()
1446     set(log "")
1447   endif()
1448
1449   ExternalProject_Add_Step(${name} update
1450     COMMENT ${comment}
1451     COMMAND ${cmd}
1452     ALWAYS ${always}
1453     WORKING_DIRECTORY ${work_dir}
1454     DEPENDEES download
1455     ${log}
1456     )
1457 endfunction()
1458
1459
1460 function(_ep_add_patch_command name)
1461   ExternalProject_Get_Property(${name} source_dir)
1462
1463   get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
1464   get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
1465
1466   set(work_dir)
1467
1468   if(cmd_set)
1469     set(work_dir ${source_dir})
1470   endif()
1471
1472   ExternalProject_Add_Step(${name} patch
1473     COMMAND ${cmd}
1474     WORKING_DIRECTORY ${work_dir}
1475     DEPENDEES download
1476     )
1477 endfunction()
1478
1479
1480 # TODO: Make sure external projects use the proper compiler
1481 function(_ep_add_configure_command name)
1482   ExternalProject_Get_Property(${name} source_dir binary_dir tmp_dir)
1483
1484   # Depend on other external projects (file-level).
1485   set(file_deps)
1486   get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
1487   foreach(dep IN LISTS deps)
1488     _ep_get_step_stampfile(${dep} "done" done_stamp_file)
1489     list(APPEND file_deps ${done_stamp_file})
1490   endforeach()
1491
1492   get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
1493   if(cmd_set)
1494     get_property(cmd TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND)
1495   else()
1496     get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
1497     if(cmake_command)
1498       set(cmd "${cmake_command}")
1499     else()
1500       set(cmd "${CMAKE_COMMAND}")
1501     endif()
1502
1503     get_property(cmake_args TARGET ${name} PROPERTY _EP_CMAKE_ARGS)
1504     list(APPEND cmd ${cmake_args})
1505
1506     # If there are any CMAKE_CACHE_ARGS, write an initial cache and use it
1507     get_property(cmake_cache_args TARGET ${name} PROPERTY _EP_CMAKE_CACHE_ARGS)
1508     if(cmake_cache_args)
1509       set(_ep_cache_args_script "${tmp_dir}/${name}-cache.cmake")
1510       _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${cmake_cache_args}")
1511       list(APPEND cmd "-C${_ep_cache_args_script}")
1512     endif()
1513
1514     get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
1515     if(cmake_generator)
1516       list(APPEND cmd "-G${cmake_generator}" "${source_dir}")
1517     else()
1518       if(CMAKE_EXTRA_GENERATOR)
1519         list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}"
1520           "${source_dir}")
1521       else()
1522         list(APPEND cmd "-G${CMAKE_GENERATOR}" "${source_dir}")
1523       endif()
1524     endif()
1525   endif()
1526
1527   # If anything about the configure command changes, (command itself, cmake
1528   # used, cmake args or cmake generator) then re-run the configure step.
1529   # Fixes issue http://public.kitware.com/Bug/view.php?id=10258
1530   #
1531   if(NOT EXISTS ${tmp_dir}/${name}-cfgcmd.txt.in)
1532     file(WRITE ${tmp_dir}/${name}-cfgcmd.txt.in "cmd='\@cmd\@'\n")
1533   endif()
1534   configure_file(${tmp_dir}/${name}-cfgcmd.txt.in ${tmp_dir}/${name}-cfgcmd.txt)
1535   list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt)
1536   list(APPEND file_deps ${_ep_cache_args_script})
1537
1538   get_property(log TARGET ${name} PROPERTY _EP_LOG_CONFIGURE)
1539   if(log)
1540     set(log LOG 1)
1541   else()
1542     set(log "")
1543   endif()
1544
1545   ExternalProject_Add_Step(${name} configure
1546     COMMAND ${cmd}
1547     WORKING_DIRECTORY ${binary_dir}
1548     DEPENDEES update patch
1549     DEPENDS ${file_deps}
1550     ${log}
1551     )
1552 endfunction()
1553
1554
1555 function(_ep_add_build_command name)
1556   ExternalProject_Get_Property(${name} binary_dir)
1557
1558   get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
1559   if(cmd_set)
1560     get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
1561   else()
1562     _ep_get_build_command(${name} BUILD cmd)
1563   endif()
1564
1565   get_property(log TARGET ${name} PROPERTY _EP_LOG_BUILD)
1566   if(log)
1567     set(log LOG 1)
1568   else()
1569     set(log "")
1570   endif()
1571
1572   ExternalProject_Add_Step(${name} build
1573     COMMAND ${cmd}
1574     WORKING_DIRECTORY ${binary_dir}
1575     DEPENDEES configure
1576     ${log}
1577     )
1578 endfunction()
1579
1580
1581 function(_ep_add_install_command name)
1582   ExternalProject_Get_Property(${name} binary_dir)
1583
1584   get_property(cmd_set TARGET ${name} PROPERTY _EP_INSTALL_COMMAND SET)
1585   if(cmd_set)
1586     get_property(cmd TARGET ${name} PROPERTY _EP_INSTALL_COMMAND)
1587   else()
1588     _ep_get_build_command(${name} INSTALL cmd)
1589   endif()
1590
1591   get_property(log TARGET ${name} PROPERTY _EP_LOG_INSTALL)
1592   if(log)
1593     set(log LOG 1)
1594   else()
1595     set(log "")
1596   endif()
1597
1598   ExternalProject_Add_Step(${name} install
1599     COMMAND ${cmd}
1600     WORKING_DIRECTORY ${binary_dir}
1601     DEPENDEES build
1602     ${log}
1603     )
1604 endfunction()
1605
1606
1607 function(_ep_add_test_command name)
1608   ExternalProject_Get_Property(${name} binary_dir)
1609
1610   get_property(before TARGET ${name} PROPERTY _EP_TEST_BEFORE_INSTALL)
1611   get_property(after TARGET ${name} PROPERTY _EP_TEST_AFTER_INSTALL)
1612   get_property(cmd_set TARGET ${name} PROPERTY _EP_TEST_COMMAND SET)
1613
1614   # Only actually add the test step if one of the test related properties is
1615   # explicitly set. (i.e. the test step is omitted unless requested...)
1616   #
1617   if(cmd_set OR before OR after)
1618     if(cmd_set)
1619       get_property(cmd TARGET ${name} PROPERTY _EP_TEST_COMMAND)
1620     else()
1621       _ep_get_build_command(${name} TEST cmd)
1622     endif()
1623
1624     if(before)
1625       set(dep_args DEPENDEES build DEPENDERS install)
1626     else()
1627       set(dep_args DEPENDEES install)
1628     endif()
1629
1630     get_property(log TARGET ${name} PROPERTY _EP_LOG_TEST)
1631     if(log)
1632       set(log LOG 1)
1633     else()
1634       set(log "")
1635     endif()
1636
1637     ExternalProject_Add_Step(${name} test
1638       COMMAND ${cmd}
1639       WORKING_DIRECTORY ${binary_dir}
1640       ${dep_args}
1641       ${log}
1642       )
1643   endif()
1644 endfunction()
1645
1646
1647 function(ExternalProject_Add name)
1648   _ep_get_configuration_subdir_suffix(cfgdir)
1649
1650   # Add a custom target for the external project.
1651   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
1652   set(complete_stamp_file "${cmf_dir}${cfgdir}/${name}-complete")
1653
1654   add_custom_target(${name} ALL DEPENDS ${complete_stamp_file})
1655   set_property(TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT 1)
1656   _ep_parse_arguments(ExternalProject_Add ${name} _EP_ "${ARGN}")
1657   _ep_set_directories(${name})
1658   _ep_get_step_stampfile(${name} "done" done_stamp_file)
1659   _ep_get_step_stampfile(${name} "install" install_stamp_file)
1660
1661   # The 'complete' step depends on all other steps and creates a
1662   # 'done' mark.  A dependent external project's 'configure' step
1663   # depends on the 'done' mark so that it rebuilds when this project
1664   # rebuilds.  It is important that 'done' is not the output of any
1665   # custom command so that CMake does not propagate build rules to
1666   # other external project targets, which may cause problems during
1667   # parallel builds.  However, the Ninja generator needs to see the entire
1668   # dependency graph, and can cope with custom commands belonging to
1669   # multiple targets, so we add the 'done' mark as an output for Ninja only.
1670   set(complete_outputs ${complete_stamp_file})
1671   if(${CMAKE_GENERATOR} MATCHES "Ninja")
1672     set(complete_outputs ${complete_outputs} ${done_stamp_file})
1673   endif()
1674
1675   add_custom_command(
1676     OUTPUT ${complete_outputs}
1677     COMMENT "Completed '${name}'"
1678     COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
1679     COMMAND ${CMAKE_COMMAND} -E touch ${complete_stamp_file}
1680     COMMAND ${CMAKE_COMMAND} -E touch ${done_stamp_file}
1681     DEPENDS ${install_stamp_file}
1682     VERBATIM
1683     )
1684
1685
1686   # Depend on other external projects (target-level).
1687   get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
1688   foreach(arg IN LISTS deps)
1689     add_dependencies(${name} ${arg})
1690   endforeach()
1691
1692   # Set up custom build steps based on the target properties.
1693   # Each step depends on the previous one.
1694   #
1695   # The target depends on the output of the final step.
1696   # (Already set up above in the DEPENDS of the add_custom_target command.)
1697   #
1698   _ep_add_mkdir_command(${name})
1699   _ep_add_download_command(${name})
1700   _ep_add_update_command(${name})
1701   _ep_add_patch_command(${name})
1702   _ep_add_configure_command(${name})
1703   _ep_add_build_command(${name})
1704   _ep_add_install_command(${name})
1705
1706   # Test is special in that it might depend on build, or it might depend
1707   # on install.
1708   #
1709   _ep_add_test_command(${name})
1710 endfunction()