1#[=======================================================================[.rst:
2ExternalProject
3---------------
4
5Create custom targets to build projects in external trees
6
7.. command:: ExternalProject_Add
8
9  The ``ExternalProject_Add`` function creates a custom target to drive
10  download, update/patch, configure, build, install and test steps of an
11  external project::
12
13   ExternalProject_Add(<name> [<option>...])
14
15  General options are:
16
17  ``DEPENDS <projects>...``
18    Targets on which the project depends
19  ``PREFIX <dir>``
20    Root dir for entire project
21  ``LIST_SEPARATOR <sep>``
22    Sep to be replaced by ; in cmd lines
23  ``TMP_DIR <dir>``
24    Directory to store temporary files
25  ``STAMP_DIR <dir>``
26    Directory to store step timestamps
27  ``EXCLUDE_FROM_ALL 1``
28    The "all" target does not depend on this
29
30  Download step options are:
31
32  ``DOWNLOAD_NAME <fname>``
33    File name to store (if not end of URL)
34  ``DOWNLOAD_DIR <dir>``
35    Directory to store downloaded files
36  ``DOWNLOAD_COMMAND <cmd>...``
37    Command to download source tree
38  ``DOWNLOAD_NO_PROGRESS 1``
39    Disable download progress reports
40  ``CVS_REPOSITORY <cvsroot>``
41    CVSROOT of CVS repository
42  ``CVS_MODULE <mod>``
43    Module to checkout from CVS repo
44  ``CVS_TAG <tag>``
45    Tag to checkout from CVS repo
46  ``SVN_REPOSITORY <url>``
47    URL of Subversion repo
48  ``SVN_REVISION -r<rev>``
49    Revision to checkout from Subversion repo
50  ``SVN_USERNAME <username>``
51    Username for Subversion checkout and update
52  ``SVN_PASSWORD <password>``
53    Password for Subversion checkout and update
54  ``SVN_TRUST_CERT 1``
55    Trust the Subversion server site certificate
56  ``GIT_REPOSITORY <url>``
57    URL of git repo
58  ``GIT_TAG <tag>``
59    Git branch name, commit id or tag
60  ``GIT_REMOTE_NAME <name>``
61    The optional name of the remote, default to ``origin``
62  ``GIT_SUBMODULES <module>...``
63    Git submodules that shall be updated, all if empty
64  ``HG_REPOSITORY <url>``
65    URL of mercurial repo
66  ``HG_TAG <tag>``
67    Mercurial branch name, commit id or tag
68  ``URL /.../src.tgz``
69    Full path or URL of source
70  ``URL_HASH ALGO=value``
71    Hash of file at URL
72  ``URL_MD5 md5``
73    Equivalent to URL_HASH MD5=md5
74  ``TLS_VERIFY <bool>``
75    Should certificate for https be checked
76  ``TLS_CAINFO <file>``
77    Path to a certificate authority file
78  ``TIMEOUT <seconds>``
79    Time allowed for file download operations
80
81  Update/Patch step options are:
82
83  ``UPDATE_COMMAND <cmd>...``
84    Source work-tree update command
85  ``UPDATE_DISCONNECTED 1``
86    Never update automatically from the remote repository
87  ``PATCH_COMMAND <cmd>...``
88    Command to patch downloaded source
89
90  Configure step options are:
91
92  ``SOURCE_DIR <dir>``
93    Source dir to be used for build
94  ``CONFIGURE_COMMAND <cmd>...``
95    Build tree configuration command
96  ``CMAKE_COMMAND /.../cmake``
97    Specify alternative cmake executable
98  ``CMAKE_GENERATOR <gen>``
99    Specify generator for native build
100  ``CMAKE_GENERATOR_PLATFORM <platform>``
101    Generator-specific platform name
102  ``CMAKE_GENERATOR_TOOLSET <toolset>``
103    Generator-specific toolset name
104  ``CMAKE_ARGS <arg>...``
105    Arguments to CMake command line.
106    These arguments are passed to CMake command line, and can contain
107    arguments other than cache values, see also
108    :manual:`CMake Options <cmake(1)>`. Arguments in the form
109    ``-Dvar:string=on`` are always passed to the command line, and
110    therefore cannot be changed by the user.
111    Arguments may use
112    :manual:`generator expressions <cmake-generator-expressions(7)>`.
113  ``CMAKE_CACHE_ARGS <arg>...``
114    Initial cache arguments, of the form ``-Dvar:string=on``.
115    These arguments are written in a pre-load a script that populates
116    CMake cache, see also :manual:`cmake -C <cmake(1)>`. This allows to
117    overcome command line length limits.
118    These arguments are :command:`set` using the ``FORCE`` argument,
119    and therefore cannot be changed by the user.
120    Arguments may use
121    :manual:`generator expressions <cmake-generator-expressions(7)>`.
122  ``CMAKE_CACHE_DEFAULT_ARGS <arg>...``
123    Initial default cache arguments, of the form ``-Dvar:string=on``.
124    These arguments are written in a pre-load a script that populates
125    CMake cache, see also :manual:`cmake -C <cmake(1)>`. This allows to
126    overcome command line length limits.
127    These arguments can be used as default value that will be set if no
128    previous value is found in the cache, and that the user can change
129    later.
130    Arguments may use
131    :manual:`generator expressions <cmake-generator-expressions(7)>`.
132
133  Build step options are:
134
135  ``BINARY_DIR <dir>``
136    Specify build dir location
137  ``BUILD_COMMAND <cmd>...``
138    Command to drive the native build
139  ``BUILD_IN_SOURCE 1``
140    Use source dir for build dir
141  ``BUILD_ALWAYS 1``
142    No stamp file, build step always runs
143  ``BUILD_BYPRODUCTS <file>...``
144    Files that will be generated by the build command but may or may
145    not have their modification time updated by subsequent builds.
146
147  Install step options are:
148
149  ``INSTALL_DIR <dir>``
150    Installation prefix
151  ``INSTALL_COMMAND <cmd>...``
152    Command to drive install after build
153
154  Test step options are:
155
156  ``TEST_BEFORE_INSTALL 1``
157    Add test step executed before install step
158  ``TEST_AFTER_INSTALL 1``
159    Add test step executed after install step
160  ``TEST_EXCLUDE_FROM_MAIN 1``
161    Main target does not depend on the test step
162  ``TEST_COMMAND <cmd>...``
163    Command to drive test
164
165  Output logging options are:
166
167  ``LOG_DOWNLOAD 1``
168    Wrap download in script to log output
169  ``LOG_UPDATE 1``
170    Wrap update in script to log output
171  ``LOG_CONFIGURE 1``
172    Wrap configure in script to log output
173  ``LOG_BUILD 1``
174    Wrap build in script to log output
175  ``LOG_TEST 1``
176    Wrap test in script to log output
177  ``LOG_INSTALL 1``
178    Wrap install in script to log output
179
180  Steps can be given direct access to the terminal if possible.  With
181  the :generator:`Ninja` generator, this places the steps in the
182  ``console`` :prop_gbl:`pool <JOB_POOLS>`.  Options are:
183
184  ``USES_TERMINAL_DOWNLOAD 1``
185    Give download terminal access.
186  ``USES_TERMINAL_UPDATE 1``
187    Give update terminal access.
188  ``USES_TERMINAL_CONFIGURE 1``
189    Give configure terminal access.
190  ``USES_TERMINAL_BUILD 1``
191    Give build terminal access.
192  ``USES_TERMINAL_TEST 1``
193    Give test terminal access.
194  ``USES_TERMINAL_INSTALL 1``
195    Give install terminal access.
196
197  Other options are:
198
199  ``STEP_TARGETS <step-target>...``
200    Generate custom targets for these steps
201  ``INDEPENDENT_STEP_TARGETS <step-target>...``
202    Generate custom targets for these steps that do not depend on other
203    external projects even if a dependency is set
204
205  The ``*_DIR`` options specify directories for the project, with default
206  directories computed as follows.  If the ``PREFIX`` option is given to
207  ``ExternalProject_Add()`` or the ``EP_PREFIX`` directory property is set,
208  then an external project is built and installed under the specified prefix::
209
210   TMP_DIR      = <prefix>/tmp
211   STAMP_DIR    = <prefix>/src/<name>-stamp
212   DOWNLOAD_DIR = <prefix>/src
213   SOURCE_DIR   = <prefix>/src/<name>
214   BINARY_DIR   = <prefix>/src/<name>-build
215   INSTALL_DIR  = <prefix>
216
217  Otherwise, if the ``EP_BASE`` directory property is set then components
218  of an external project are stored under the specified base::
219
220   TMP_DIR      = <base>/tmp/<name>
221   STAMP_DIR    = <base>/Stamp/<name>
222   DOWNLOAD_DIR = <base>/Download/<name>
223   SOURCE_DIR   = <base>/Source/<name>
224   BINARY_DIR   = <base>/Build/<name>
225   INSTALL_DIR  = <base>/Install/<name>
226
227  If no ``PREFIX``, ``EP_PREFIX``, or ``EP_BASE`` is specified then the
228  default is to set ``PREFIX`` to ``<name>-prefix``.  Relative paths are
229  interpreted with respect to the build directory corresponding to the
230  source directory in which ``ExternalProject_Add`` is invoked.
231
232  If ``SOURCE_DIR`` is explicitly set to an existing directory the project
233  will be built from it.  Otherwise a download step must be specified
234  using one of the ``DOWNLOAD_COMMAND``, ``CVS_*``, ``SVN_*``, or ``URL``
235  options.  The ``URL`` option may refer locally to a directory or source
236  tarball, or refer to a remote tarball (e.g. ``http://.../src.tgz``).
237
238  If ``UPDATE_DISCONNECTED`` is set, the update step is not executed
239  automatically when building the main target. The update step can still
240  be added as a step target and called manually. This is useful if you
241  want to allow to build the project when you are disconnected from the
242  network (you might still need the network for the download step).
243  This is disabled by default.
244  The directory property ``EP_UPDATE_DISCONNECTED`` can be used to change
245  the default value for all the external projects in the current
246  directory and its subdirectories.
247
248.. command:: ExternalProject_Add_Step
249
250  The ``ExternalProject_Add_Step`` function adds a custom step to an
251  external project::
252
253   ExternalProject_Add_Step(<name> <step> [<option>...])
254
255  Options are:
256
257  ``COMMAND <cmd>...``
258    Command line invoked by this step
259  ``COMMENT "<text>..."``
260    Text printed when step executes
261  ``DEPENDEES <step>...``
262    Steps on which this step depends
263  ``DEPENDERS <step>...``
264    Steps that depend on this step
265  ``DEPENDS <file>...``
266    Files on which this step depends
267  ``BYPRODUCTS <file>...``
268    Files that will be generated by this step but may or may not
269    have their modification time updated by subsequent builds.
270  ``ALWAYS 1``
271    No stamp file, step always runs
272  ``EXCLUDE_FROM_MAIN 1``
273    Main target does not depend on this step
274  ``WORKING_DIRECTORY <dir>``
275    Working directory for command
276  ``LOG 1``
277    Wrap step in script to log output
278  ``USES_TERMINAL 1``
279    Give the step direct access to the terminal if possible.
280
281  The command line, comment, working directory, and byproducts of every
282  standard and custom step are processed to replace tokens ``<SOURCE_DIR>``,
283  ``<BINARY_DIR>``, ``<INSTALL_DIR>``, and ``<TMP_DIR>`` with
284  corresponding property values.
285
286Any builtin step that specifies a ``<step>_COMMAND cmd...`` or custom
287step that specifies a ``COMMAND cmd...`` may specify additional command
288lines using the form ``COMMAND cmd...``.  At build time the commands
289will be executed in order and aborted if any one fails.  For example::
290
291 ... BUILD_COMMAND make COMMAND echo done ...
292
293specifies to run ``make`` and then ``echo done`` during the build step.
294Whether the current working directory is preserved between commands is
295not defined.  Behavior of shell operators like ``&&`` is not defined.
296
297Arguments to ``<step>_COMMAND`` or ``COMMAND`` options may use
298:manual:`generator expressions <cmake-generator-expressions(7)>`.
299
300.. command:: ExternalProject_Get_Property
301
302  The ``ExternalProject_Get_Property`` function retrieves external project
303  target properties::
304
305    ExternalProject_Get_Property(<name> [prop1 [prop2 [...]]])
306
307  It stores property values in variables of the same name.  Property
308  names correspond to the keyword argument names of
309  ``ExternalProject_Add``.
310
311.. command:: ExternalProject_Add_StepTargets
312
313  The ``ExternalProject_Add_StepTargets`` function generates custom
314  targets for the steps listed::
315
316    ExternalProject_Add_StepTargets(<name> [NO_DEPENDS] [step1 [step2 [...]]])
317
318If ``NO_DEPENDS`` is set, the target will not depend on the
319dependencies of the complete project. This is usually safe to use for
320the download, update, and patch steps that do not require that all the
321dependencies are updated and built.  Using ``NO_DEPENDS`` for other
322of the default steps might break parallel builds, so you should avoid,
323it.  For custom steps, you should consider whether or not the custom
324commands requires that the dependencies are configured, built and
325installed.
326
327If ``STEP_TARGETS`` or ``INDEPENDENT_STEP_TARGETS`` is set then
328``ExternalProject_Add_StepTargets`` is automatically called at the end
329of matching calls to ``ExternalProject_Add_Step``.  Pass
330``STEP_TARGETS`` or ``INDEPENDENT_STEP_TARGETS`` explicitly to
331individual ``ExternalProject_Add`` calls, or implicitly to all
332``ExternalProject_Add`` calls by setting the directory properties
333``EP_STEP_TARGETS`` and ``EP_INDEPENDENT_STEP_TARGETS``.  The
334``INDEPENDENT`` version of the argument and of the property will call
335``ExternalProject_Add_StepTargets`` with the ``NO_DEPENDS`` argument.
336
337If ``STEP_TARGETS`` and ``INDEPENDENT_STEP_TARGETS`` are not set,
338clients may still manually call ``ExternalProject_Add_StepTargets``
339after calling ``ExternalProject_Add`` or ``ExternalProject_Add_Step``.
340
341This functionality is provided to make it easy to drive the steps
342independently of each other by specifying targets on build command
343lines.  For example, you may be submitting to a sub-project based
344dashboard, where you want to drive the configure portion of the build,
345then submit to the dashboard, followed by the build portion, followed
346by tests.  If you invoke a custom target that depends on a step
347halfway through the step dependency chain, then all the previous steps
348will also run to ensure everything is up to date.
349
350For example, to drive configure, build and test steps independently
351for each ``ExternalProject_Add`` call in your project, write the following
352line prior to any ``ExternalProject_Add`` calls in your ``CMakeLists.txt``
353file::
354
355 set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure build test)
356
357.. command:: ExternalProject_Add_StepDependencies
358
359  The ``ExternalProject_Add_StepDependencies`` function add some
360  dependencies for some external project step::
361
362    ExternalProject_Add_StepDependencies(<name> <step> [target1 [target2 [...]]])
363
364  This function takes care to set both target and file level
365  dependencies, and will ensure that parallel builds will not break.
366  It should be used instead of :command:`add_dependencies()` when adding
367  a dependency for some of the step targets generated by
368  ``ExternalProject``.
369#]=======================================================================]
370
371#=============================================================================
372# Copyright 2008-2013 Kitware, Inc.
373#
374# Distributed under the OSI-approved BSD License (the "License");
375# see accompanying file Copyright.txt for details.
376#
377# This software is distributed WITHOUT ANY WARRANTY; without even the
378# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
379# See the License for more information.
380#=============================================================================
381# (To distribute this file outside of CMake, substitute the full
382#  License text for the above reference.)
383
384# Pre-compute a regex to match documented keywords for each command.
385math(EXPR _ep_documentation_line_count "${CMAKE_CURRENT_LIST_LINE} - 16")
386file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines
387     LIMIT_COUNT ${_ep_documentation_line_count}
388     REGEX "^\\.\\. command:: [A-Za-z0-9_]+|^  ``[A-Z0-9_]+ .*``$")
389foreach(line IN LISTS lines)
390  if("${line}" MATCHES "^\\.\\. command:: ([A-Za-z0-9_]+)")
391    if(_ep_func)
392      set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
393    endif()
394    set(_ep_func "${CMAKE_MATCH_1}")
395    #message("function [${_ep_func}]")
396    set(_ep_keywords_${_ep_func} "^(")
397    set(_ep_keyword_sep)
398  elseif("${line}" MATCHES "^  ``([A-Z0-9_]+) .*``$")
399    set(_ep_key "${CMAKE_MATCH_1}")
400    #message("  keyword [${_ep_key}]")
401    set(_ep_keywords_${_ep_func}
402      "${_ep_keywords_${_ep_func}}${_ep_keyword_sep}${_ep_key}")
403    set(_ep_keyword_sep "|")
404  endif()
405endforeach()
406if(_ep_func)
407  set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
408endif()
409
410# Save regex matching supported hash algorithm names.
411set(_ep_hash_algos "MD5|SHA1|SHA224|SHA256|SHA384|SHA512")
412set(_ep_hash_regex "^(${_ep_hash_algos})=([0-9A-Fa-f]+)$")
413
414function(_ep_parse_arguments f name ns args)
415  # Transfer the arguments to this function into target properties for the
416  # new custom target we just added so that we can set up all the build steps
417  # correctly based on target properties.
418  #
419  # We loop through ARGN and consider the namespace starting with an
420  # upper-case letter followed by at least two more upper-case letters,
421  # numbers or underscores to be keywords.
422  set(key)
423
424  foreach(arg IN LISTS args)
425    set(is_value 1)
426
427    if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
428        NOT (("x${arg}x" STREQUAL "x${key}x") AND ("x${key}x" STREQUAL "xCOMMANDx")) AND
429        NOT arg MATCHES "^(TRUE|FALSE)$")
430      if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
431        set(is_value 0)
432      endif()
433    endif()
434
435    if(is_value)
436      if(key)
437        # Value
438        if(NOT arg STREQUAL "")
439          set_property(TARGET ${name} APPEND PROPERTY ${ns}${key} "${arg}")
440        else()
441          get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
442          if(have_key)
443            get_property(value TARGET ${name} PROPERTY ${ns}${key})
444            set_property(TARGET ${name} PROPERTY ${ns}${key} "${value};${arg}")
445          else()
446            set_property(TARGET ${name} PROPERTY ${ns}${key} "${arg}")
447          endif()
448        endif()
449      else()
450        # Missing Keyword
451        message(AUTHOR_WARNING "value '${arg}' with no previous keyword in ${f}")
452      endif()
453    else()
454      set(key "${arg}")
455    endif()
456  endforeach()
457endfunction()
458
459
460define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED
461  BRIEF_DOCS "Base directory for External Project storage."
462  FULL_DOCS
463  "See documentation of the ExternalProject_Add() function in the "
464  "ExternalProject module."
465  )
466
467define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
468  BRIEF_DOCS "Top prefix for External Project storage."
469  FULL_DOCS
470  "See documentation of the ExternalProject_Add() function in the "
471  "ExternalProject module."
472  )
473
474define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
475  BRIEF_DOCS
476  "List of ExternalProject steps that automatically get corresponding targets"
477  FULL_DOCS
478  "These targets will be dependent on the main target dependencies"
479  "See documentation of the ExternalProject_Add_StepTargets() function in the "
480  "ExternalProject module."
481  )
482
483define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED
484  BRIEF_DOCS
485  "List of ExternalProject steps that automatically get corresponding targets"
486  FULL_DOCS
487  "These targets will not be dependent on the main target dependencies"
488  "See documentation of the ExternalProject_Add_StepTargets() function in the "
489  "ExternalProject module."
490  )
491
492define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED
493  BRIEF_DOCS "Never update automatically from the remote repo."
494  FULL_DOCS
495  "See documentation of the ExternalProject_Add() function in the "
496  "ExternalProject module."
497  )
498
499function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name git_submodules src_name work_dir gitclone_infofile gitclone_stampfile)
500  file(WRITE ${script_filename}
501"if(\"${git_tag}\" STREQUAL \"\")
502  message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
503endif()
504
505set(run 0)
506
507if(\"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
508  set(run 1)
509endif()
510
511if(NOT run)
512  message(STATUS \"Avoiding repeated git clone, stamp file is up to date: '${gitclone_stampfile}'\")
513  return()
514endif()
515
516execute_process(
517  COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
518  RESULT_VARIABLE error_code
519  )
520if(error_code)
521  message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
522endif()
523
524# try the clone 3 times incase there is an odd git clone issue
525set(error_code 1)
526set(number_of_tries 0)
527while(error_code AND number_of_tries LESS 3)
528  execute_process(
529    COMMAND \"${git_EXECUTABLE}\" clone --origin \"${git_remote_name}\" \"${git_repository}\" \"${src_name}\"
530    WORKING_DIRECTORY \"${work_dir}\"
531    RESULT_VARIABLE error_code
532    )
533  math(EXPR number_of_tries \"\${number_of_tries} + 1\")
534endwhile()
535if(number_of_tries GREATER 1)
536  message(STATUS \"Had to git clone more than once:
537          \${number_of_tries} times.\")
538endif()
539if(error_code)
540  message(FATAL_ERROR \"Failed to clone repository: '${git_repository}'\")
541endif()
542
543execute_process(
544  COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag}
545  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
546  RESULT_VARIABLE error_code
547  )
548if(error_code)
549  message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
550endif()
551
552execute_process(
553  COMMAND \"${git_EXECUTABLE}\" submodule init ${git_submodules}
554  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
555  RESULT_VARIABLE error_code
556  )
557if(error_code)
558  message(FATAL_ERROR \"Failed to init submodules in: '${work_dir}/${src_name}'\")
559endif()
560
561execute_process(
562  COMMAND \"${git_EXECUTABLE}\" submodule update --recursive ${git_submodules}
563  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
564  RESULT_VARIABLE error_code
565  )
566if(error_code)
567  message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
568endif()
569
570# Complete success, update the script-last-run stamp file:
571#
572execute_process(
573  COMMAND \${CMAKE_COMMAND} -E copy
574    \"${gitclone_infofile}\"
575    \"${gitclone_stampfile}\"
576  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
577  RESULT_VARIABLE error_code
578  )
579if(error_code)
580  message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${gitclone_stampfile}'\")
581endif()
582
583"
584)
585
586endfunction()
587
588function(_ep_write_hgclone_script script_filename source_dir hg_EXECUTABLE hg_repository hg_tag src_name work_dir hgclone_infofile hgclone_stampfile)
589  file(WRITE ${script_filename}
590"if(\"${hg_tag}\" STREQUAL \"\")
591  message(FATAL_ERROR \"Tag for hg checkout should not be empty.\")
592endif()
593
594set(run 0)
595
596if(\"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
597  set(run 1)
598endif()
599
600if(NOT run)
601  message(STATUS \"Avoiding repeated hg clone, stamp file is up to date: '${hgclone_stampfile}'\")
602  return()
603endif()
604
605execute_process(
606  COMMAND \${CMAKE_COMMAND} -E remove_directory \"${source_dir}\"
607  RESULT_VARIABLE error_code
608  )
609if(error_code)
610  message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
611endif()
612
613execute_process(
614  COMMAND \"${hg_EXECUTABLE}\" clone -U \"${hg_repository}\" \"${src_name}\"
615  WORKING_DIRECTORY \"${work_dir}\"
616  RESULT_VARIABLE error_code
617  )
618if(error_code)
619  message(FATAL_ERROR \"Failed to clone repository: '${hg_repository}'\")
620endif()
621
622execute_process(
623  COMMAND \"${hg_EXECUTABLE}\" update ${hg_tag}
624  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
625  RESULT_VARIABLE error_code
626  )
627if(error_code)
628  message(FATAL_ERROR \"Failed to checkout tag: '${hg_tag}'\")
629endif()
630
631# Complete success, update the script-last-run stamp file:
632#
633execute_process(
634  COMMAND \${CMAKE_COMMAND} -E copy
635    \"${hgclone_infofile}\"
636    \"${hgclone_stampfile}\"
637  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
638  RESULT_VARIABLE error_code
639  )
640if(error_code)
641  message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${hgclone_stampfile}'\")
642endif()
643
644"
645)
646
647endfunction()
648
649
650function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name git_submodules git_repository work_dir)
651  if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.6)
652    set(git_stash_save_options --all --quiet)
653  else()
654    set(git_stash_save_options --quiet)
655  endif()
656  file(WRITE ${script_filename}
657"if(\"${git_tag}\" STREQUAL \"\")
658  message(FATAL_ERROR \"Tag for git checkout should not be empty.\")
659endif()
660
661execute_process(
662  COMMAND \"${git_EXECUTABLE}\" rev-list --max-count=1 HEAD
663  WORKING_DIRECTORY \"${work_dir}\"
664  RESULT_VARIABLE error_code
665  OUTPUT_VARIABLE head_sha
666  OUTPUT_STRIP_TRAILING_WHITESPACE
667  )
668if(error_code)
669  message(FATAL_ERROR \"Failed to get the hash for HEAD\")
670endif()
671
672execute_process(
673  COMMAND \"${git_EXECUTABLE}\" show-ref ${git_tag}
674  WORKING_DIRECTORY \"${work_dir}\"
675  OUTPUT_VARIABLE show_ref_output
676  )
677# If a remote ref is asked for, which can possibly move around,
678# we must always do a fetch and checkout.
679if(\"\${show_ref_output}\" MATCHES \"remotes\")
680  set(is_remote_ref 1)
681else()
682  set(is_remote_ref 0)
683endif()
684
685# Tag is in the form <remote>/<tag> (i.e. origin/master) we must strip
686# the remote from the tag.
687if(\"\${show_ref_output}\" MATCHES \"refs/remotes/${git_tag}\")
688  string(REGEX MATCH \"^([^/]+)/(.+)$\" _unused \"${git_tag}\")
689  set(git_remote \"\${CMAKE_MATCH_1}\")
690  set(git_tag \"\${CMAKE_MATCH_2}\")
691else()
692  set(git_remote \"${git_remote_name}\")
693  set(git_tag \"${git_tag}\")
694endif()
695
696# This will fail if the tag does not exist (it probably has not been fetched
697# yet).
698execute_process(
699  COMMAND \"${git_EXECUTABLE}\" rev-list --max-count=1 ${git_tag}
700  WORKING_DIRECTORY \"${work_dir}\"
701  RESULT_VARIABLE error_code
702  OUTPUT_VARIABLE tag_sha
703  OUTPUT_STRIP_TRAILING_WHITESPACE
704  )
705
706# Is the hash checkout out that we want?
707if(error_code OR is_remote_ref OR NOT (\"\${tag_sha}\" STREQUAL \"\${head_sha}\"))
708  execute_process(
709    COMMAND \"${git_EXECUTABLE}\" fetch
710    WORKING_DIRECTORY \"${work_dir}\"
711    RESULT_VARIABLE error_code
712    )
713  if(error_code)
714    message(FATAL_ERROR \"Failed to fetch repository '${git_repository}'\")
715  endif()
716
717  if(is_remote_ref)
718    # Check if stash is needed
719    execute_process(
720      COMMAND \"${git_EXECUTABLE}\" status --porcelain
721      WORKING_DIRECTORY \"${work_dir}\"
722      RESULT_VARIABLE error_code
723      OUTPUT_VARIABLE repo_status
724      )
725    if(error_code)
726      message(FATAL_ERROR \"Failed to get the status\")
727    endif()
728    string(LENGTH \"\${repo_status}\" need_stash)
729
730    # If not in clean state, stash changes in order to be able to be able to
731    # perform git pull --rebase
732    if(need_stash)
733      execute_process(
734        COMMAND \"${git_EXECUTABLE}\" stash save ${git_stash_save_options}
735        WORKING_DIRECTORY \"${work_dir}\"
736        RESULT_VARIABLE error_code
737        )
738      if(error_code)
739        message(FATAL_ERROR \"Failed to stash changes\")
740      endif()
741    endif()
742
743    # Pull changes from the remote branch
744    execute_process(
745      COMMAND \"${git_EXECUTABLE}\" rebase \${git_remote}/\${git_tag}
746      WORKING_DIRECTORY \"${work_dir}\"
747      RESULT_VARIABLE error_code
748      )
749    if(error_code)
750      # Rebase failed: Restore previous state.
751      execute_process(
752        COMMAND \"${git_EXECUTABLE}\" rebase --abort
753        WORKING_DIRECTORY \"${work_dir}\"
754      )
755      if(need_stash)
756        execute_process(
757          COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet
758          WORKING_DIRECTORY \"${work_dir}\"
759          )
760      endif()
761      message(FATAL_ERROR \"\\nFailed to rebase in: '${work_dir}/${src_name}'.\\nYou will have to resolve the conflicts manually\")
762    endif()
763
764    if(need_stash)
765      execute_process(
766        COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet
767        WORKING_DIRECTORY \"${work_dir}\"
768        RESULT_VARIABLE error_code
769        )
770      if(error_code)
771        # Stash pop --index failed: Try again dropping the index
772        execute_process(
773          COMMAND \"${git_EXECUTABLE}\" reset --hard --quiet
774          WORKING_DIRECTORY \"${work_dir}\"
775          RESULT_VARIABLE error_code
776          )
777        execute_process(
778          COMMAND \"${git_EXECUTABLE}\" stash pop --quiet
779          WORKING_DIRECTORY \"${work_dir}\"
780          RESULT_VARIABLE error_code
781          )
782        if(error_code)
783          # Stash pop failed: Restore previous state.
784          execute_process(
785            COMMAND \"${git_EXECUTABLE}\" reset --hard --quiet \${head_sha}
786            WORKING_DIRECTORY \"${work_dir}\"
787          )
788          execute_process(
789            COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet
790            WORKING_DIRECTORY \"${work_dir}\"
791          )
792          message(FATAL_ERROR \"\\nFailed to unstash changes in: '${work_dir}/${src_name}'.\\nYou will have to resolve the conflicts manually\")
793        endif()
794      endif()
795    endif()
796  else()
797    execute_process(
798      COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag}
799      WORKING_DIRECTORY \"${work_dir}\"
800      RESULT_VARIABLE error_code
801      )
802    if(error_code)
803      message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
804    endif()
805  endif()
806
807  execute_process(
808    COMMAND \"${git_EXECUTABLE}\" submodule update --recursive ${git_submodules}
809    WORKING_DIRECTORY \"${work_dir}/${src_name}\"
810    RESULT_VARIABLE error_code
811    )
812  if(error_code)
813    message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
814  endif()
815endif()
816
817"
818)
819
820endfunction(_ep_write_gitupdate_script)
821
822function(_ep_write_downloadfile_script script_filename remote local timeout no_progress hash tls_verify tls_cainfo)
823  if(timeout)
824    set(timeout_args TIMEOUT ${timeout})
825    set(timeout_msg "${timeout} seconds")
826  else()
827    set(timeout_args "# no TIMEOUT")
828    set(timeout_msg "none")
829  endif()
830
831  if(no_progress)
832    set(show_progress "")
833  else()
834    set(show_progress "SHOW_PROGRESS")
835  endif()
836
837  if("${hash}" MATCHES "${_ep_hash_regex}")
838    string(CONCAT hash_check
839      "if(EXISTS \"${local}\")\n"
840      "  file(\"${CMAKE_MATCH_1}\" \"${local}\" hash_value)\n"
841      "  if(\"x\${hash_value}\" STREQUAL \"x${CMAKE_MATCH_2}\")\n"
842      "    return()\n"
843      "  endif()\n"
844      "endif()\n"
845      )
846  else()
847    set(hash_check "")
848  endif()
849
850  # check for curl globals in the project
851  if(DEFINED CMAKE_TLS_VERIFY)
852    set(tls_verify "set(CMAKE_TLS_VERIFY ${CMAKE_TLS_VERIFY})")
853  endif()
854  if(DEFINED CMAKE_TLS_CAINFO)
855    set(tls_cainfo "set(CMAKE_TLS_CAINFO \"${CMAKE_TLS_CAINFO}\")")
856  endif()
857
858  # now check for curl locals so that the local values
859  # will override the globals
860
861  # check for tls_verify argument
862  string(LENGTH "${tls_verify}" tls_verify_len)
863  if(tls_verify_len GREATER 0)
864    set(tls_verify "set(CMAKE_TLS_VERIFY ${tls_verify})")
865  endif()
866  # check for tls_cainfo argument
867  string(LENGTH "${tls_cainfo}" tls_cainfo_len)
868  if(tls_cainfo_len GREATER 0)
869    set(tls_cainfo "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")")
870  endif()
871
872  file(WRITE ${script_filename}
873"${hash_check}message(STATUS \"downloading...
874     src='${remote}'
875     dst='${local}'
876     timeout='${timeout_msg}'\")
877
878${tls_verify}
879${tls_cainfo}
880
881file(DOWNLOAD
882  \"${remote}\"
883  \"${local}\"
884  ${show_progress}
885  ${timeout_args}
886  STATUS status
887  LOG log)
888
889list(GET status 0 status_code)
890list(GET status 1 status_string)
891
892if(NOT status_code EQUAL 0)
893  message(FATAL_ERROR \"error: downloading '${remote}' failed
894  status_code: \${status_code}
895  status_string: \${status_string}
896  log: \${log}
897\")
898endif()
899
900message(STATUS \"downloading... done\")
901"
902)
903
904endfunction()
905
906
907function(_ep_write_verifyfile_script script_filename local hash retries download_script)
908  if("${hash}" MATCHES "${_ep_hash_regex}")
909    set(algo "${CMAKE_MATCH_1}")
910    string(TOLOWER "${CMAKE_MATCH_2}" expect_value)
911    set(script_content "set(expect_value \"${expect_value}\")
912set(attempt 0)
913set(succeeded 0)
914while(\${attempt} LESS ${retries} OR \${attempt} EQUAL ${retries} AND NOT \${succeeded})
915  file(${algo} \"\${file}\" actual_value)
916  if(\"\${actual_value}\" STREQUAL \"\${expect_value}\")
917    set(succeeded 1)
918  elseif(\${attempt} LESS ${retries})
919    message(STATUS \"${algo} hash of \${file}
920does not match expected value
921  expected: \${expect_value}
922    actual: \${actual_value}
923Retrying download.
924\")
925    file(REMOVE \"\${file}\")
926    execute_process(COMMAND \${CMAKE_COMMAND} -P \"${download_script}\")
927  endif()
928  math(EXPR attempt \"\${attempt} + 1\")
929endwhile()
930
931if(\${succeeded})
932  message(STATUS \"verifying file... done\")
933else()
934  message(FATAL_ERROR \"error: ${algo} hash of
935  \${file}
936does not match expected value
937  expected: \${expect_value}
938    actual: \${actual_value}
939\")
940endif()")
941  else()
942    set(script_content "message(STATUS \"verifying file... warning: did not verify file - no URL_HASH specified?\")")
943  endif()
944  file(WRITE ${script_filename} "set(file \"${local}\")
945message(STATUS \"verifying file...
946     file='\${file}'\")
947${script_content}
948")
949endfunction()
950
951
952function(_ep_write_extractfile_script script_filename name filename directory)
953  set(args "")
954
955  if(filename MATCHES "(\\.|=)(7z|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$")
956    set(args xfz)
957  endif()
958
959  if(filename MATCHES "(\\.|=)tar$")
960    set(args xf)
961  endif()
962
963  if(args STREQUAL "")
964    message(SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .7z, .tar, .tar.bz2, .tar.gz, .tar.xz, .tbz2, .tgz, .txz and .zip")
965    return()
966  endif()
967
968  file(WRITE ${script_filename}
969"# Make file names absolute:
970#
971get_filename_component(filename \"${filename}\" ABSOLUTE)
972get_filename_component(directory \"${directory}\" ABSOLUTE)
973
974message(STATUS \"extracting...
975     src='\${filename}'
976     dst='\${directory}'\")
977
978if(NOT EXISTS \"\${filename}\")
979  message(FATAL_ERROR \"error: file to extract does not exist: '\${filename}'\")
980endif()
981
982# Prepare a space for extracting:
983#
984set(i 1234)
985while(EXISTS \"\${directory}/../ex-${name}\${i}\")
986  math(EXPR i \"\${i} + 1\")
987endwhile()
988set(ut_dir \"\${directory}/../ex-${name}\${i}\")
989file(MAKE_DIRECTORY \"\${ut_dir}\")
990
991# Extract it:
992#
993message(STATUS \"extracting... [tar ${args}]\")
994execute_process(COMMAND \${CMAKE_COMMAND} -E tar ${args} \${filename}
995  WORKING_DIRECTORY \${ut_dir}
996  RESULT_VARIABLE rv)
997
998if(NOT rv EQUAL 0)
999  message(STATUS \"extracting... [error clean up]\")
1000  file(REMOVE_RECURSE \"\${ut_dir}\")
1001  message(FATAL_ERROR \"error: extract of '\${filename}' failed\")
1002endif()
1003
1004# Analyze what came out of the tar file:
1005#
1006message(STATUS \"extracting... [analysis]\")
1007file(GLOB contents \"\${ut_dir}/*\")
1008list(LENGTH contents n)
1009if(NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\")
1010  set(contents \"\${ut_dir}\")
1011endif()
1012
1013# Move \"the one\" directory to the final directory:
1014#
1015message(STATUS \"extracting... [rename]\")
1016file(REMOVE_RECURSE \${directory})
1017get_filename_component(contents \${contents} ABSOLUTE)
1018file(RENAME \${contents} \${directory})
1019
1020# Clean up:
1021#
1022message(STATUS \"extracting... [clean up]\")
1023file(REMOVE_RECURSE \"\${ut_dir}\")
1024
1025message(STATUS \"extracting... done\")
1026"
1027)
1028
1029endfunction()
1030
1031
1032function(_ep_set_directories name)
1033  get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX)
1034  if(NOT prefix)
1035    get_property(prefix DIRECTORY PROPERTY EP_PREFIX)
1036    if(NOT prefix)
1037      get_property(base DIRECTORY PROPERTY EP_BASE)
1038      if(NOT base)
1039        set(prefix "${name}-prefix")
1040      endif()
1041    endif()
1042  endif()
1043  if(prefix)
1044    set(tmp_default "${prefix}/tmp")
1045    set(download_default "${prefix}/src")
1046    set(source_default "${prefix}/src/${name}")
1047    set(binary_default "${prefix}/src/${name}-build")
1048    set(stamp_default "${prefix}/src/${name}-stamp")
1049    set(install_default "${prefix}")
1050  else()
1051    set(tmp_default "${base}/tmp/${name}")
1052    set(download_default "${base}/Download/${name}")
1053    set(source_default "${base}/Source/${name}")
1054    set(binary_default "${base}/Build/${name}")
1055    set(stamp_default "${base}/Stamp/${name}")
1056    set(install_default "${base}/Install/${name}")
1057  endif()
1058  get_property(build_in_source TARGET ${name} PROPERTY _EP_BUILD_IN_SOURCE)
1059  if(build_in_source)
1060    get_property(have_binary_dir TARGET ${name} PROPERTY _EP_BINARY_DIR SET)
1061    if(have_binary_dir)
1062      message(FATAL_ERROR
1063        "External project ${name} has both BINARY_DIR and BUILD_IN_SOURCE!")
1064    endif()
1065  endif()
1066  set(top "${CMAKE_CURRENT_BINARY_DIR}")
1067  set(places stamp download source binary install tmp)
1068  foreach(var ${places})
1069    string(TOUPPER "${var}" VAR)
1070    get_property(${var}_dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
1071    if(NOT ${var}_dir)
1072      set(${var}_dir "${${var}_default}")
1073    endif()
1074    if(NOT IS_ABSOLUTE "${${var}_dir}")
1075      get_filename_component(${var}_dir "${top}/${${var}_dir}" ABSOLUTE)
1076    endif()
1077    set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
1078  endforeach()
1079  if(build_in_source)
1080    get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR)
1081    set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}")
1082  endif()
1083
1084  # Make the directories at CMake configure time *and* add a custom command
1085  # to make them at build time. They need to exist at makefile generation
1086  # time for Borland make and wmake so that CMake may generate makefiles
1087  # with "cd C:\short\paths\with\no\spaces" commands in them.
1088  #
1089  # Additionally, the add_custom_command is still used in case somebody
1090  # removes one of the necessary directories and tries to rebuild without
1091  # re-running cmake.
1092  foreach(var ${places})
1093    string(TOUPPER "${var}" VAR)
1094    get_property(dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
1095    file(MAKE_DIRECTORY "${dir}")
1096    if(NOT EXISTS "${dir}")
1097      message(FATAL_ERROR "dir '${dir}' does not exist after file(MAKE_DIRECTORY)")
1098    endif()
1099  endforeach()
1100endfunction()
1101
1102
1103# IMPORTANT: this MUST be a macro and not a function because of the
1104# in-place replacements that occur in each ${var}
1105#
1106macro(_ep_replace_location_tags target_name)
1107  set(vars ${ARGN})
1108  foreach(var ${vars})
1109    if(${var})
1110      foreach(dir SOURCE_DIR BINARY_DIR INSTALL_DIR TMP_DIR)
1111        get_property(val TARGET ${target_name} PROPERTY _EP_${dir})
1112        string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}")
1113      endforeach()
1114    endif()
1115  endforeach()
1116endmacro()
1117
1118
1119function(_ep_command_line_to_initial_cache var args force)
1120  set(script_initial_cache "")
1121  set(regex "^([^:]+):([^=]+)=(.*)$")
1122  set(setArg "")
1123  set(forceArg "")
1124  if(force)
1125    set(forceArg "FORCE")
1126  endif()
1127  foreach(line ${args})
1128    if("${line}" MATCHES "^-D(.*)")
1129      set(line "${CMAKE_MATCH_1}")
1130      if(setArg)
1131        # This is required to build up lists in variables, or complete an entry
1132        set(setArg "${setArg}${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})")
1133        set(script_initial_cache "${script_initial_cache}\n${setArg}")
1134        set(accumulator "")
1135        set(setArg "")
1136      endif()
1137      if("${line}" MATCHES "${regex}")
1138        set(name "${CMAKE_MATCH_1}")
1139        set(type "${CMAKE_MATCH_2}")
1140        set(value "${CMAKE_MATCH_3}")
1141        set(setArg "set(${name} \"${value}")
1142      else()
1143        message(WARNING "Line '${line}' does not match regex. Ignoring.")
1144      endif()
1145    else()
1146      # Assume this is a list to append to the last var
1147      set(accumulator "${accumulator};${line}")
1148    endif()
1149  endforeach()
1150  # Catch the final line of the args
1151  if(setArg)
1152    set(setArg "${setArg}${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})")
1153    set(script_initial_cache "${script_initial_cache}\n${setArg}")
1154  endif()
1155  set(${var} ${script_initial_cache} PARENT_SCOPE)
1156endfunction()
1157
1158
1159function(_ep_write_initial_cache target_name script_filename script_initial_cache)
1160  # Write out values into an initial cache, that will be passed to CMake with -C
1161  # Replace location tags.
1162  _ep_replace_location_tags(${target_name} script_initial_cache)
1163  # Write out the initial cache file to the location specified.
1164  file(GENERATE OUTPUT "${script_filename}" CONTENT "${script_initial_cache}")
1165endfunction()
1166
1167
1168function(ExternalProject_Get_Property name)
1169  foreach(var ${ARGN})
1170    string(TOUPPER "${var}" VAR)
1171    get_property(${var} TARGET ${name} PROPERTY _EP_${VAR})
1172    if(NOT ${var})
1173      message(FATAL_ERROR "External project \"${name}\" has no ${var}")
1174    endif()
1175    set(${var} "${${var}}" PARENT_SCOPE)
1176  endforeach()
1177endfunction()
1178
1179
1180function(_ep_get_configure_command_id name cfg_cmd_id_var)
1181  get_target_property(cmd ${name} _EP_CONFIGURE_COMMAND)
1182
1183  if(cmd STREQUAL "")
1184    # Explicit empty string means no configure step for this project
1185    set(${cfg_cmd_id_var} "none" PARENT_SCOPE)
1186  else()
1187    if(NOT cmd)
1188      # Default is "use cmake":
1189      set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
1190    else()
1191      # Otherwise we have to analyze the value:
1192      if(cmd MATCHES "^[^;]*/configure")
1193        set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
1194      elseif(cmd MATCHES "^[^;]*/cmake" AND NOT cmd MATCHES ";-[PE];")
1195        set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
1196      elseif(cmd MATCHES "config")
1197        set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
1198      else()
1199        set(${cfg_cmd_id_var} "unknown:${cmd}" PARENT_SCOPE)
1200      endif()
1201    endif()
1202  endif()
1203endfunction()
1204
1205
1206function(_ep_get_build_command name step cmd_var)
1207  set(cmd "${${cmd_var}}")
1208  if(NOT cmd)
1209    set(args)
1210    _ep_get_configure_command_id(${name} cfg_cmd_id)
1211    if(cfg_cmd_id STREQUAL "cmake")
1212      # CMake project.  Select build command based on generator.
1213      get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
1214      if("${CMAKE_GENERATOR}" MATCHES "Make" AND
1215         ("${cmake_generator}" MATCHES "Make" OR NOT cmake_generator))
1216        # The project uses the same Makefile generator.  Use recursive make.
1217        set(cmd "$(MAKE)")
1218        if(step STREQUAL "INSTALL")
1219          set(args install)
1220        endif()
1221        if("x${step}x" STREQUAL "xTESTx")
1222          set(args test)
1223        endif()
1224      else()
1225        # Drive the project with "cmake --build".
1226        get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
1227        if(cmake_command)
1228          set(cmd "${cmake_command}")
1229        else()
1230          set(cmd "${CMAKE_COMMAND}")
1231        endif()
1232        set(args --build ".")
1233        if(CMAKE_CONFIGURATION_TYPES)
1234          if (CMAKE_CFG_INTDIR AND
1235              NOT CMAKE_CFG_INTDIR STREQUAL "." AND
1236              NOT CMAKE_CFG_INTDIR MATCHES "\\$")
1237            # CMake 3.4 and below used the CMAKE_CFG_INTDIR placeholder value
1238            # provided by multi-configuration generators.  Some projects were
1239            # taking advantage of that undocumented implementation detail to
1240            # specify a specific configuration here.  They should use
1241            # BUILD_COMMAND to change the default command instead, but for
1242            # compatibility honor the value.
1243            set(config ${CMAKE_CFG_INTDIR})
1244            message(AUTHOR_WARNING "CMAKE_CFG_INTDIR should not be set by project code.\n"
1245              "To get a non-default build command, use the BUILD_COMMAND option.")
1246          else()
1247            set(config $<CONFIG>)
1248          endif()
1249          list(APPEND args --config ${config})
1250        endif()
1251        if(step STREQUAL "INSTALL")
1252          list(APPEND args --target install)
1253        endif()
1254        # But for "TEST" drive the project with corresponding "ctest".
1255        if("x${step}x" STREQUAL "xTESTx")
1256          string(REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}")
1257          set(args "")
1258          if(CMAKE_CONFIGURATION_TYPES)
1259            list(APPEND args -C ${config})
1260          endif()
1261        endif()
1262      endif()
1263    else()
1264      # Non-CMake project.  Guess "make" and "make install" and "make test".
1265      if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
1266        # Try to get the parallel arguments
1267        set(cmd "$(MAKE)")
1268      else()
1269        set(cmd "make")
1270      endif()
1271      if(step STREQUAL "INSTALL")
1272        set(args install)
1273      endif()
1274      if("x${step}x" STREQUAL "xTESTx")
1275        set(args test)
1276      endif()
1277    endif()
1278
1279    # Use user-specified arguments instead of default arguments, if any.
1280    get_property(have_args TARGET ${name} PROPERTY _EP_${step}_ARGS SET)
1281    if(have_args)
1282      get_target_property(args ${name} _EP_${step}_ARGS)
1283    endif()
1284
1285    list(APPEND cmd ${args})
1286  endif()
1287
1288  set(${cmd_var} "${cmd}" PARENT_SCOPE)
1289endfunction()
1290
1291function(_ep_write_log_script name step cmd_var)
1292  ExternalProject_Get_Property(${name} stamp_dir)
1293  set(command "${${cmd_var}}")
1294
1295  set(make "")
1296  set(code_cygpath_make "")
1297  if(command MATCHES "^\\$\\(MAKE\\)")
1298    # GNU make recognizes the string "$(MAKE)" as recursive make, so
1299    # ensure that it appears directly in the makefile.
1300    string(REGEX REPLACE "^\\$\\(MAKE\\)" "\${make}" command "${command}")
1301    set(make "-Dmake=$(MAKE)")
1302
1303    if(WIN32 AND NOT CYGWIN)
1304      set(code_cygpath_make "
1305if(\${make} MATCHES \"^/\")
1306  execute_process(
1307    COMMAND cygpath -w \${make}
1308    OUTPUT_VARIABLE cygpath_make
1309    ERROR_VARIABLE cygpath_make
1310    RESULT_VARIABLE cygpath_error
1311    OUTPUT_STRIP_TRAILING_WHITESPACE
1312  )
1313  if(NOT cygpath_error)
1314    set(make \${cygpath_make})
1315  endif()
1316endif()
1317")
1318    endif()
1319  endif()
1320
1321  set(config "")
1322  if("${CMAKE_CFG_INTDIR}" MATCHES "^\\$")
1323    string(REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}")
1324    set(config "-Dconfig=${CMAKE_CFG_INTDIR}")
1325  endif()
1326
1327  # Wrap multiple 'COMMAND' lines up into a second-level wrapper
1328  # script so all output can be sent to one log file.
1329  if(command MATCHES "(^|;)COMMAND;")
1330    set(code_execute_process "
1331${code_cygpath_make}
1332execute_process(COMMAND \${command} RESULT_VARIABLE result)
1333if(result)
1334  set(msg \"Command failed (\${result}):\\n\")
1335  foreach(arg IN LISTS command)
1336    set(msg \"\${msg} '\${arg}'\")
1337  endforeach()
1338  message(FATAL_ERROR \"\${msg}\")
1339endif()
1340")
1341    set(code "")
1342    set(cmd "")
1343    set(sep "")
1344    foreach(arg IN LISTS command)
1345      if("x${arg}" STREQUAL "xCOMMAND")
1346        if(NOT "x${cmd}" STREQUAL "x")
1347          set(code "${code}set(command \"${cmd}\")${code_execute_process}")
1348        endif()
1349        set(cmd "")
1350        set(sep "")
1351      else()
1352        set(cmd "${cmd}${sep}${arg}")
1353        set(sep ";")
1354      endif()
1355    endforeach()
1356    set(code "${code}set(command \"${cmd}\")${code_execute_process}")
1357    file(GENERATE OUTPUT "${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake" CONTENT "${code}")
1358    set(command ${CMAKE_COMMAND} "-Dmake=\${make}" "-Dconfig=\${config}" -P ${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake)
1359  endif()
1360
1361  # Wrap the command in a script to log output to files.
1362  set(script ${stamp_dir}/${name}-${step}-$<CONFIG>.cmake)
1363  set(logbase ${stamp_dir}/${name}-${step})
1364  set(code "
1365${code_cygpath_make}
1366set(command \"${command}\")
1367execute_process(
1368  COMMAND \${command}
1369  RESULT_VARIABLE result
1370  OUTPUT_FILE \"${logbase}-out.log\"
1371  ERROR_FILE \"${logbase}-err.log\"
1372  )
1373if(result)
1374  set(msg \"Command failed: \${result}\\n\")
1375  foreach(arg IN LISTS command)
1376    set(msg \"\${msg} '\${arg}'\")
1377  endforeach()
1378  set(msg \"\${msg}\\nSee also\\n  ${logbase}-*.log\")
1379  message(FATAL_ERROR \"\${msg}\")
1380else()
1381  set(msg \"${name} ${step} command succeeded.  See also ${logbase}-*.log\")
1382  message(STATUS \"\${msg}\")
1383endif()
1384")
1385  file(GENERATE OUTPUT "${script}" CONTENT "${code}")
1386  set(command ${CMAKE_COMMAND} ${make} ${config} -P ${script})
1387  set(${cmd_var} "${command}" PARENT_SCOPE)
1388endfunction()
1389
1390# This module used to use "/${CMAKE_CFG_INTDIR}" directly and produced
1391# makefiles with "/./" in paths for custom command dependencies. Which
1392# resulted in problems with parallel make -j invocations.
1393#
1394# This function was added so that the suffix (search below for ${cfgdir}) is
1395# only set to "/${CMAKE_CFG_INTDIR}" when ${CMAKE_CFG_INTDIR} is not going to
1396# be "." (multi-configuration build systems like Visual Studio and Xcode...)
1397#
1398function(_ep_get_configuration_subdir_suffix suffix_var)
1399  set(suffix "")
1400  if(CMAKE_CONFIGURATION_TYPES)
1401    set(suffix "/${CMAKE_CFG_INTDIR}")
1402  endif()
1403  set(${suffix_var} "${suffix}" PARENT_SCOPE)
1404endfunction()
1405
1406
1407function(_ep_get_step_stampfile name step stampfile_var)
1408  ExternalProject_Get_Property(${name} stamp_dir)
1409
1410  _ep_get_configuration_subdir_suffix(cfgdir)
1411  set(stampfile "${stamp_dir}${cfgdir}/${name}-${step}")
1412
1413  set(${stampfile_var} "${stampfile}" PARENT_SCOPE)
1414endfunction()
1415
1416
1417function(ExternalProject_Add_StepTargets name)
1418  set(steps ${ARGN})
1419  if(ARGC GREATER 1 AND "${ARGV1}" STREQUAL "NO_DEPENDS")
1420    set(no_deps 1)
1421    list(REMOVE_AT steps 0)
1422  endif()
1423  foreach(step ${steps})
1424    if(no_deps  AND  "${step}" MATCHES "^(configure|build|install|test)$")
1425      message(AUTHOR_WARNING "Using NO_DEPENDS for \"${step}\" step  might break parallel builds")
1426    endif()
1427    _ep_get_step_stampfile(${name} ${step} stamp_file)
1428    add_custom_target(${name}-${step}
1429      DEPENDS ${stamp_file})
1430    set_property(TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP 1)
1431    set_property(TARGET ${name}-${step} PROPERTY LABELS ${name})
1432    set_property(TARGET ${name}-${step} PROPERTY FOLDER "ExternalProjectTargets/${name}")
1433
1434    # Depend on other external projects (target-level).
1435    if(NOT no_deps)
1436      get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
1437      foreach(arg IN LISTS deps)
1438        add_dependencies(${name}-${step} ${arg})
1439      endforeach()
1440    endif()
1441  endforeach()
1442endfunction()
1443
1444
1445function(ExternalProject_Add_Step name step)
1446  set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
1447  _ep_get_configuration_subdir_suffix(cfgdir)
1448
1449  set(complete_stamp_file "${cmf_dir}${cfgdir}/${name}-complete")
1450  _ep_get_step_stampfile(${name} ${step} stamp_file)
1451
1452  _ep_parse_arguments(ExternalProject_Add_Step
1453                      ${name} _EP_${step}_ "${ARGN}")
1454
1455  get_property(exclude_from_main TARGET ${name} PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN)
1456  if(NOT exclude_from_main)
1457    add_custom_command(APPEND
1458      OUTPUT ${complete_stamp_file}
1459      DEPENDS ${stamp_file}
1460      )
1461  endif()
1462
1463  # Steps depending on this step.
1464  get_property(dependers TARGET ${name} PROPERTY _EP_${step}_DEPENDERS)
1465  foreach(depender IN LISTS dependers)
1466    _ep_get_step_stampfile(${name} ${depender} depender_stamp_file)
1467    add_custom_command(APPEND
1468      OUTPUT ${depender_stamp_file}
1469      DEPENDS ${stamp_file}
1470      )
1471  endforeach()
1472
1473  # Dependencies on files.
1474  get_property(depends TARGET ${name} PROPERTY _EP_${step}_DEPENDS)
1475
1476  # Byproducts of the step.
1477  get_property(byproducts TARGET ${name} PROPERTY _EP_${step}_BYPRODUCTS)
1478
1479  # Dependencies on steps.
1480  get_property(dependees TARGET ${name} PROPERTY _EP_${step}_DEPENDEES)
1481  foreach(dependee IN LISTS dependees)
1482    _ep_get_step_stampfile(${name} ${dependee} dependee_stamp_file)
1483    list(APPEND depends ${dependee_stamp_file})
1484  endforeach()
1485
1486  # The command to run.
1487  get_property(command TARGET ${name} PROPERTY _EP_${step}_COMMAND)
1488  if(command)
1489    set(comment "Performing ${step} step for '${name}'")
1490  else()
1491    set(comment "No ${step} step for '${name}'")
1492  endif()
1493  get_property(work_dir TARGET ${name} PROPERTY _EP_${step}_WORKING_DIRECTORY)
1494
1495  # Replace list separators.
1496  get_property(sep TARGET ${name} PROPERTY _EP_LIST_SEPARATOR)
1497  if(sep AND command)
1498    string(REPLACE "${sep}" "\\;" command "${command}")
1499  endif()
1500
1501  # Replace location tags.
1502  _ep_replace_location_tags(${name} comment command work_dir byproducts)
1503
1504  # Custom comment?
1505  get_property(comment_set TARGET ${name} PROPERTY _EP_${step}_COMMENT SET)
1506  if(comment_set)
1507    get_property(comment TARGET ${name} PROPERTY _EP_${step}_COMMENT)
1508  endif()
1509
1510  # Uses terminal?
1511  get_property(uses_terminal TARGET ${name} PROPERTY _EP_${step}_USES_TERMINAL)
1512  if(uses_terminal)
1513    set(uses_terminal USES_TERMINAL)
1514  else()
1515    set(uses_terminal "")
1516  endif()
1517
1518  # Run every time?
1519  get_property(always TARGET ${name} PROPERTY _EP_${step}_ALWAYS)
1520  if(always)
1521    set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
1522    set(touch)
1523    # Remove any existing stamp in case the option changed in an existing tree.
1524    if(CMAKE_CONFIGURATION_TYPES)
1525      foreach(cfg ${CMAKE_CONFIGURATION_TYPES})
1526        string(REPLACE "/${CMAKE_CFG_INTDIR}" "/${cfg}" stamp_file_config "${stamp_file}")
1527        file(REMOVE ${stamp_file_config})
1528      endforeach()
1529    else()
1530      file(REMOVE ${stamp_file})
1531    endif()
1532  else()
1533    set(touch ${CMAKE_COMMAND} -E touch ${stamp_file})
1534  endif()
1535
1536  # Wrap with log script?
1537  get_property(log TARGET ${name} PROPERTY _EP_${step}_LOG)
1538  if(command AND log)
1539    _ep_write_log_script(${name} ${step} command)
1540  endif()
1541
1542  if("${command}" STREQUAL "")
1543    # Some generators (i.e. Xcode) will not generate a file level target
1544    # if no command is set, and therefore the dependencies on this
1545    # target will be broken.
1546    # The empty command is replaced by an echo command here in order to
1547    # avoid this issue.
1548    set(command ${CMAKE_COMMAND} -E echo_append)
1549  endif()
1550
1551  add_custom_command(
1552    OUTPUT ${stamp_file}
1553    BYPRODUCTS ${byproducts}
1554    COMMENT ${comment}
1555    COMMAND ${command}
1556    COMMAND ${touch}
1557    DEPENDS ${depends}
1558    WORKING_DIRECTORY ${work_dir}
1559    VERBATIM
1560    ${uses_terminal}
1561    )
1562  set_property(TARGET ${name} APPEND PROPERTY _EP_STEPS ${step})
1563
1564  # Add custom "step target"?
1565  get_property(step_targets TARGET ${name} PROPERTY _EP_STEP_TARGETS)
1566  if(NOT step_targets)
1567    get_property(step_targets DIRECTORY PROPERTY EP_STEP_TARGETS)
1568  endif()
1569  foreach(st ${step_targets})
1570    if("${st}" STREQUAL "${step}")
1571      ExternalProject_Add_StepTargets(${name} ${step})
1572      break()
1573    endif()
1574  endforeach()
1575
1576  get_property(independent_step_targets TARGET ${name} PROPERTY _EP_INDEPENDENT_STEP_TARGETS)
1577  if(NOT independent_step_targets)
1578    get_property(independent_step_targets DIRECTORY PROPERTY EP_INDEPENDENT_STEP_TARGETS)
1579  endif()
1580  foreach(st ${independent_step_targets})
1581    if("${st}" STREQUAL "${step}")
1582      ExternalProject_Add_StepTargets(${name} NO_DEPENDS ${step})
1583      break()
1584    endif()
1585  endforeach()
1586endfunction()
1587
1588
1589function(ExternalProject_Add_StepDependencies name step)
1590  set(dependencies ${ARGN})
1591
1592  # Sanity checks on "name" and "step".
1593  if(NOT TARGET ${name})
1594    message(FATAL_ERROR "Cannot find target \"${name}\". Perhaps it has not yet been created using ExternalProject_Add.")
1595  endif()
1596
1597  get_property(type TARGET ${name} PROPERTY TYPE)
1598  if(NOT type STREQUAL "UTILITY")
1599    message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add.")
1600  endif()
1601
1602  get_property(is_ep TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT)
1603  if(NOT is_ep)
1604    message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add.")
1605  endif()
1606
1607  get_property(steps TARGET ${name} PROPERTY _EP_STEPS)
1608  list(FIND steps ${step} is_step)
1609  if(NOT is_step)
1610    message(FATAL_ERROR "External project \"${name}\" does not have a step \"${step}\".")
1611  endif()
1612
1613  if(TARGET ${name}-${step})
1614    get_property(type TARGET ${name}-${step} PROPERTY TYPE)
1615    if(NOT type STREQUAL "UTILITY")
1616      message(FATAL_ERROR "Target \"${name}-${step}\" was not generated by ExternalProject_Add_StepTargets.")
1617    endif()
1618    get_property(is_ep_step TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP)
1619    if(NOT is_ep_step)
1620      message(FATAL_ERROR "Target \"${name}-${step}\" was not generated by ExternalProject_Add_StepTargets.")
1621    endif()
1622  endif()
1623
1624  # Always add file-level dependency, but add target-level dependency
1625  # only if the target exists for that step.
1626  _ep_get_step_stampfile(${name} ${step} stamp_file)
1627  foreach(dep ${dependencies})
1628    add_custom_command(APPEND
1629      OUTPUT ${stamp_file}
1630      DEPENDS ${dep})
1631    if(TARGET ${name}-${step})
1632      foreach(dep ${dependencies})
1633        add_dependencies(${name}-${step} ${dep})
1634      endforeach()
1635    endif()
1636  endforeach()
1637
1638endfunction()
1639
1640
1641function(_ep_add_mkdir_command name)
1642  ExternalProject_Get_Property(${name}
1643    source_dir binary_dir install_dir stamp_dir download_dir tmp_dir)
1644
1645  _ep_get_configuration_subdir_suffix(cfgdir)
1646
1647  ExternalProject_Add_Step(${name} mkdir
1648    COMMENT "Creating directories for '${name}'"
1649    COMMAND ${CMAKE_COMMAND} -E make_directory ${source_dir}
1650    COMMAND ${CMAKE_COMMAND} -E make_directory ${binary_dir}
1651    COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}
1652    COMMAND ${CMAKE_COMMAND} -E make_directory ${tmp_dir}
1653    COMMAND ${CMAKE_COMMAND} -E make_directory ${stamp_dir}${cfgdir}
1654    COMMAND ${CMAKE_COMMAND} -E make_directory ${download_dir}
1655    )
1656endfunction()
1657
1658
1659function(_ep_is_dir_empty dir empty_var)
1660  file(GLOB gr "${dir}/*")
1661  if("${gr}" STREQUAL "")
1662    set(${empty_var} 1 PARENT_SCOPE)
1663  else()
1664    set(${empty_var} 0 PARENT_SCOPE)
1665  endif()
1666endfunction()
1667
1668
1669function(_ep_add_download_command name)
1670  ExternalProject_Get_Property(${name} source_dir stamp_dir download_dir tmp_dir)
1671
1672  get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
1673  get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
1674  get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
1675  get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
1676  get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
1677  get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
1678  get_property(url TARGET ${name} PROPERTY _EP_URL)
1679  get_property(fname TARGET ${name} PROPERTY _EP_DOWNLOAD_NAME)
1680
1681  # TODO: Perhaps file:// should be copied to download dir before extraction.
1682  string(REGEX REPLACE "^file://" "" url "${url}")
1683
1684  set(depends)
1685  set(comment)
1686  set(work_dir)
1687
1688  if(cmd_set)
1689    set(work_dir ${download_dir})
1690  elseif(cvs_repository)
1691    find_exthost_package(CVS QUIET)
1692    if(NOT CVS_EXECUTABLE)
1693      message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
1694    endif()
1695
1696    get_target_property(cvs_module ${name} _EP_CVS_MODULE)
1697    if(NOT cvs_module)
1698      message(FATAL_ERROR "error: no CVS_MODULE")
1699    endif()
1700
1701    get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
1702
1703    set(repository ${cvs_repository})
1704    set(module ${cvs_module})
1705    set(tag ${cvs_tag})
1706    configure_file(
1707      "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1708      "${stamp_dir}/${name}-cvsinfo.txt"
1709      @ONLY
1710      )
1711
1712    get_filename_component(src_name "${source_dir}" NAME)
1713    get_filename_component(work_dir "${source_dir}" PATH)
1714    set(comment "Performing download step (CVS checkout) for '${name}'")
1715    set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q co ${cvs_tag} -d ${src_name} ${cvs_module})
1716    list(APPEND depends ${stamp_dir}/${name}-cvsinfo.txt)
1717  elseif(svn_repository)
1718    find_exthost_package(Subversion QUIET)
1719    if(NOT Subversion_SVN_EXECUTABLE)
1720      message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
1721    endif()
1722
1723    get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
1724    get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
1725    get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
1726    get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
1727
1728    set(repository "${svn_repository} user=${svn_username} password=${svn_password}")
1729    set(module)
1730    set(tag ${svn_revision})
1731    configure_file(
1732      "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1733      "${stamp_dir}/${name}-svninfo.txt"
1734      @ONLY
1735      )
1736
1737    get_filename_component(src_name "${source_dir}" NAME)
1738    get_filename_component(work_dir "${source_dir}" PATH)
1739    set(comment "Performing download step (SVN checkout) for '${name}'")
1740    set(svn_user_pw_args "")
1741    if(DEFINED svn_username)
1742      set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
1743    endif()
1744    if(DEFINED svn_password)
1745      set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
1746    endif()
1747    if(svn_trust_cert)
1748      set(svn_trust_cert_args --trust-server-cert)
1749    endif()
1750    set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_revision}
1751      --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args} ${src_name})
1752    list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
1753  elseif(git_repository)
1754    unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
1755    find_exthost_package(Git QUIET)
1756    if(NOT GIT_EXECUTABLE)
1757      message(FATAL_ERROR "error: could not find git for clone of ${name}")
1758    endif()
1759
1760    # The git submodule update '--recursive' flag requires git >= v1.6.5
1761    #
1762    if(GIT_VERSION_STRING VERSION_LESS 1.6.5)
1763      message(FATAL_ERROR "error: git version 1.6.5 or later required for 'git submodule update --recursive': GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
1764    endif()
1765
1766    get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
1767    if(NOT git_tag)
1768      set(git_tag "master")
1769    endif()
1770    get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
1771
1772    get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
1773    if(NOT git_remote_name)
1774      set(git_remote_name "origin")
1775    endif()
1776
1777    # For the download step, and the git clone operation, only the repository
1778    # should be recorded in a configured RepositoryInfo file. If the repo
1779    # changes, the clone script should be run again. But if only the tag
1780    # changes, avoid running the clone script again. Let the 'always' running
1781    # update step checkout the new tag.
1782    #
1783    set(repository ${git_repository})
1784    set(module)
1785    set(tag)
1786    configure_file(
1787      "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1788      "${stamp_dir}/${name}-gitinfo.txt"
1789      @ONLY
1790      )
1791
1792    get_filename_component(src_name "${source_dir}" NAME)
1793    get_filename_component(work_dir "${source_dir}" PATH)
1794
1795    # Since git clone doesn't succeed if the non-empty source_dir exists,
1796    # create a cmake script to invoke as download command.
1797    # The script will delete the source directory and then call git clone.
1798    #
1799    _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
1800      ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${git_remote_name} "${git_submodules}" ${src_name} ${work_dir}
1801      ${stamp_dir}/${name}-gitinfo.txt ${stamp_dir}/${name}-gitclone-lastrun.txt
1802      )
1803    set(comment "Performing download step (git clone) for '${name}'")
1804    set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
1805    list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
1806  elseif(hg_repository)
1807    find_exthost_package(Hg QUIET)
1808    if(NOT HG_EXECUTABLE)
1809      message(FATAL_ERROR "error: could not find hg for clone of ${name}")
1810    endif()
1811
1812    get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
1813    if(NOT hg_tag)
1814      set(hg_tag "tip")
1815    endif()
1816
1817    # For the download step, and the hg clone operation, only the repository
1818    # should be recorded in a configured RepositoryInfo file. If the repo
1819    # changes, the clone script should be run again. But if only the tag
1820    # changes, avoid running the clone script again. Let the 'always' running
1821    # update step checkout the new tag.
1822    #
1823    set(repository ${hg_repository})
1824    set(module)
1825    set(tag)
1826    configure_file(
1827      "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1828      "${stamp_dir}/${name}-hginfo.txt"
1829      @ONLY
1830      )
1831
1832    get_filename_component(src_name "${source_dir}" NAME)
1833    get_filename_component(work_dir "${source_dir}" PATH)
1834
1835    # Since hg clone doesn't succeed if the non-empty source_dir exists,
1836    # create a cmake script to invoke as download command.
1837    # The script will delete the source directory and then call hg clone.
1838    #
1839    _ep_write_hgclone_script(${tmp_dir}/${name}-hgclone.cmake ${source_dir}
1840      ${HG_EXECUTABLE} ${hg_repository} ${hg_tag} ${src_name} ${work_dir}
1841      ${stamp_dir}/${name}-hginfo.txt ${stamp_dir}/${name}-hgclone-lastrun.txt
1842      )
1843    set(comment "Performing download step (hg clone) for '${name}'")
1844    set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake)
1845    list(APPEND depends ${stamp_dir}/${name}-hginfo.txt)
1846  elseif(url)
1847    get_filename_component(work_dir "${source_dir}" PATH)
1848    get_property(hash TARGET ${name} PROPERTY _EP_URL_HASH)
1849    if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
1850      message(FATAL_ERROR "URL_HASH is set to\n  ${hash}\n"
1851        "but must be ALGO=value where ALGO is\n  ${_ep_hash_algos}\n"
1852        "and value is a hex string.")
1853    endif()
1854    get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
1855    if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}")
1856      message(FATAL_ERROR "URL_MD5 is set to\n  ${md5}\nbut must be a hex string.")
1857    endif()
1858    if(md5 AND NOT hash)
1859      set(hash "MD5=${md5}")
1860    endif()
1861    set(repository "external project URL")
1862    set(module "${url}")
1863    set(tag "${hash}")
1864    set(retries 0)
1865    set(download_script "")
1866    configure_file(
1867      "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
1868      "${stamp_dir}/${name}-urlinfo.txt"
1869      @ONLY
1870      )
1871    list(APPEND depends ${stamp_dir}/${name}-urlinfo.txt)
1872    if(IS_DIRECTORY "${url}")
1873      get_filename_component(abs_dir "${url}" ABSOLUTE)
1874      set(comment "Performing download step (DIR copy) for '${name}'")
1875      set(cmd   ${CMAKE_COMMAND} -E remove_directory ${source_dir}
1876        COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir})
1877    else()
1878      if("${url}" MATCHES "^[a-z]+://")
1879        # TODO: Should download and extraction be different steps?
1880        if("x${fname}" STREQUAL "x")
1881          string(REGEX MATCH "[^/\\?]*$" fname "${url}")
1882        endif()
1883        if(NOT "${fname}" MATCHES "(\\.|=)(7z|tar|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$")
1884          string(REGEX MATCH "([^/\\?]+(\\.|=)(7z|tar|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip))/.*$" match_result "${url}")
1885          set(fname "${CMAKE_MATCH_1}")
1886        endif()
1887        if(NOT "${fname}" MATCHES "(\\.|=)(7z|tar|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$")
1888          message(FATAL_ERROR "Could not extract tarball filename from url:\n  ${url}")
1889        endif()
1890        string(REPLACE ";" "-" fname "${fname}")
1891        set(file ${download_dir}/${fname})
1892        get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
1893        get_property(no_progress TARGET ${name} PROPERTY _EP_DOWNLOAD_NO_PROGRESS)
1894        get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
1895        get_property(tls_cainfo TARGET ${name} PROPERTY _EP_TLS_CAINFO)
1896        set(download_script "${stamp_dir}/download-${name}.cmake")
1897        _ep_write_downloadfile_script("${download_script}" "${url}" "${file}" "${timeout}" "${no_progress}" "${hash}" "${tls_verify}" "${tls_cainfo}")
1898        set(cmd ${CMAKE_COMMAND} -P "${download_script}"
1899          COMMAND)
1900        set(retries 3)
1901        set(comment "Performing download step (download, verify and extract) for '${name}'")
1902      else()
1903        set(file "${url}")
1904        set(comment "Performing download step (verify and extract) for '${name}'")
1905      endif()
1906      _ep_write_verifyfile_script("${stamp_dir}/verify-${name}.cmake" "${file}" "${hash}" "${retries}" "${download_script}")
1907      list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake
1908        COMMAND)
1909      _ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${name}" "${file}" "${source_dir}")
1910      list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
1911    endif()
1912  else()
1913    _ep_is_dir_empty("${source_dir}" empty)
1914    if(${empty})
1915      message(SEND_ERROR
1916        "No download info given for '${name}' and its source directory:\n"
1917        " ${source_dir}\n"
1918        "is not an existing non-empty directory.  Please specify one of:\n"
1919        " * SOURCE_DIR with an existing non-empty directory\n"
1920        " * URL\n"
1921        " * GIT_REPOSITORY\n"
1922        " * HG_REPOSITORY\n"
1923        " * CVS_REPOSITORY and CVS_MODULE\n"
1924        " * SVN_REVISION\n"
1925        " * DOWNLOAD_COMMAND"
1926        )
1927    endif()
1928  endif()
1929
1930  get_property(log TARGET ${name} PROPERTY _EP_LOG_DOWNLOAD)
1931  if(log)
1932    set(log LOG 1)
1933  else()
1934    set(log "")
1935  endif()
1936
1937  get_property(uses_terminal TARGET ${name} PROPERTY
1938    _EP_USES_TERMINAL_DOWNLOAD)
1939  if(uses_terminal)
1940    set(uses_terminal USES_TERMINAL 1)
1941  else()
1942    set(uses_terminal "")
1943  endif()
1944
1945  ExternalProject_Add_Step(${name} download
1946    COMMENT ${comment}
1947    COMMAND ${cmd}
1948    WORKING_DIRECTORY ${work_dir}
1949    DEPENDS ${depends}
1950    DEPENDEES mkdir
1951    ${log}
1952    ${uses_terminal}
1953    )
1954endfunction()
1955
1956
1957function(_ep_add_update_command name)
1958  ExternalProject_Get_Property(${name} source_dir tmp_dir)
1959
1960  get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
1961  get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
1962  get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
1963  get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
1964  get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
1965  get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
1966  get_property(update_disconnected_set TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED SET)
1967  if(update_disconnected_set)
1968    get_property(update_disconnected TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED)
1969  else()
1970    get_property(update_disconnected DIRECTORY PROPERTY EP_UPDATE_DISCONNECTED)
1971  endif()
1972
1973  set(work_dir)
1974  set(comment)
1975  set(always)
1976
1977  if(cmd_set)
1978    set(work_dir ${source_dir})
1979  elseif(cvs_repository)
1980    if(NOT CVS_EXECUTABLE)
1981      message(FATAL_ERROR "error: could not find cvs for update of ${name}")
1982    endif()
1983    set(work_dir ${source_dir})
1984    set(comment "Performing update step (CVS update) for '${name}'")
1985    get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
1986    set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
1987    set(always 1)
1988  elseif(svn_repository)
1989    if(NOT Subversion_SVN_EXECUTABLE)
1990      message(FATAL_ERROR "error: could not find svn for update of ${name}")
1991    endif()
1992    set(work_dir ${source_dir})
1993    set(comment "Performing update step (SVN update) for '${name}'")
1994    get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
1995    get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
1996    get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
1997    get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
1998    set(svn_user_pw_args "")
1999    if(DEFINED svn_username)
2000      set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
2001    endif()
2002    if(DEFINED svn_password)
2003      set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
2004    endif()
2005    if(svn_trust_cert)
2006      set(svn_trust_cert_args --trust-server-cert)
2007    endif()
2008    set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_revision}
2009      --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args})
2010    set(always 1)
2011  elseif(git_repository)
2012    if(NOT GIT_EXECUTABLE)
2013      message(FATAL_ERROR "error: could not find git for fetch of ${name}")
2014    endif()
2015    set(work_dir ${source_dir})
2016    set(comment "Performing update step for '${name}'")
2017    get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
2018    if(NOT git_tag)
2019      set(git_tag "master")
2020    endif()
2021    get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
2022    if(NOT git_remote_name)
2023      set(git_remote_name "origin")
2024    endif()
2025    get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
2026    _ep_write_gitupdate_script(${tmp_dir}/${name}-gitupdate.cmake
2027      ${GIT_EXECUTABLE} ${git_tag} ${git_remote_name} "${git_submodules}" ${git_repository} ${work_dir}
2028      )
2029    set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake)
2030    set(always 1)
2031  elseif(hg_repository)
2032    if(NOT HG_EXECUTABLE)
2033      message(FATAL_ERROR "error: could not find hg for pull of ${name}")
2034    endif()
2035    set(work_dir ${source_dir})
2036    set(comment "Performing update step (hg pull) for '${name}'")
2037    get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
2038    if(NOT hg_tag)
2039      set(hg_tag "tip")
2040    endif()
2041    if("${HG_VERSION_STRING}" STREQUAL "2.1")
2042      message(WARNING "Mercurial 2.1 does not distinguish an empty pull from a failed pull:
2043 http://mercurial.selenic.com/wiki/UpgradeNotes#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X
2044 http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656
2045Update to Mercurial >= 2.1.1.
2046")
2047    endif()
2048    set(cmd ${HG_EXECUTABLE} pull
2049      COMMAND ${HG_EXECUTABLE} update ${hg_tag}
2050      )
2051    set(always 1)
2052  endif()
2053
2054  get_property(log TARGET ${name} PROPERTY _EP_LOG_UPDATE)
2055  if(log)
2056    set(log LOG 1)
2057  else()
2058    set(log "")
2059  endif()
2060
2061  get_property(uses_terminal TARGET ${name} PROPERTY
2062    _EP_USES_TERMINAL_UPDATE)
2063  if(uses_terminal)
2064    set(uses_terminal USES_TERMINAL 1)
2065  else()
2066    set(uses_terminal "")
2067  endif()
2068
2069  ExternalProject_Add_Step(${name} update
2070    COMMENT ${comment}
2071    COMMAND ${cmd}
2072    ALWAYS ${always}
2073    EXCLUDE_FROM_MAIN ${update_disconnected}
2074    WORKING_DIRECTORY ${work_dir}
2075    DEPENDEES download
2076    ${log}
2077    ${uses_terminal}
2078    )
2079
2080  if(always AND update_disconnected)
2081    _ep_get_step_stampfile(${name} skip-update skip-update_stamp_file)
2082    string(REPLACE "Performing" "Skipping" comment "${comment}")
2083    ExternalProject_Add_Step(${name} skip-update
2084      COMMENT ${comment}
2085      ALWAYS 1
2086      EXCLUDE_FROM_MAIN 1
2087      WORKING_DIRECTORY ${work_dir}
2088      DEPENDEES download
2089      ${log}
2090      ${uses_terminal}
2091    )
2092    set_property(SOURCE ${skip-update_stamp_file} PROPERTY SYMBOLIC 1)
2093  endif()
2094
2095endfunction()
2096
2097
2098function(_ep_add_patch_command name)
2099  ExternalProject_Get_Property(${name} source_dir)
2100
2101  get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
2102  get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
2103
2104  set(work_dir)
2105
2106  if(cmd_set)
2107    set(work_dir ${source_dir})
2108  endif()
2109
2110  ExternalProject_Add_Step(${name} patch
2111    COMMAND ${cmd}
2112    WORKING_DIRECTORY ${work_dir}
2113    DEPENDEES download
2114    )
2115endfunction()
2116
2117
2118# TODO: Make sure external projects use the proper compiler
2119function(_ep_add_configure_command name)
2120  ExternalProject_Get_Property(${name} source_dir binary_dir tmp_dir)
2121
2122  # Depend on other external projects (file-level).
2123  set(file_deps)
2124  get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
2125  foreach(dep IN LISTS deps)
2126    get_property(dep_type TARGET ${dep} PROPERTY TYPE)
2127    if(dep_type STREQUAL "UTILITY")
2128      get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
2129      if(is_ep)
2130        _ep_get_step_stampfile(${dep} "done" done_stamp_file)
2131        list(APPEND file_deps ${done_stamp_file})
2132      endif()
2133    endif()
2134  endforeach()
2135
2136  get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
2137  if(cmd_set)
2138    get_property(cmd TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND)
2139  else()
2140    get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
2141    if(cmake_command)
2142      set(cmd "${cmake_command}")
2143    else()
2144      set(cmd "${CMAKE_COMMAND}")
2145    endif()
2146
2147    get_property(cmake_args TARGET ${name} PROPERTY _EP_CMAKE_ARGS)
2148    list(APPEND cmd ${cmake_args})
2149
2150    # If there are any CMAKE_CACHE_ARGS or CMAKE_CACHE_DEFAULT_ARGS,
2151    # write an initial cache and use it
2152    get_property(cmake_cache_args TARGET ${name} PROPERTY _EP_CMAKE_CACHE_ARGS)
2153    get_property(cmake_cache_default_args TARGET ${name} PROPERTY _EP_CMAKE_CACHE_DEFAULT_ARGS)
2154
2155    if(cmake_cache_args OR cmake_cache_default_args)
2156      set(_ep_cache_args_script "${tmp_dir}/${name}-cache-$<CONFIG>.cmake")
2157      if(cmake_cache_args)
2158        _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
2159      endif()
2160      if(cmake_cache_default_args)
2161        _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
2162      endif()
2163      _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
2164      list(APPEND cmd "-C${_ep_cache_args_script}")
2165    endif()
2166
2167    get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
2168    get_target_property(cmake_generator_platform ${name} _EP_CMAKE_GENERATOR_PLATFORM)
2169    get_target_property(cmake_generator_toolset ${name} _EP_CMAKE_GENERATOR_TOOLSET)
2170    if(cmake_generator)
2171      list(APPEND cmd "-G${cmake_generator}")
2172      if(cmake_generator_platform)
2173        list(APPEND cmd "-A${cmake_generator_platform}")
2174      endif()
2175      if(cmake_generator_toolset)
2176        list(APPEND cmd "-T${cmake_generator_toolset}")
2177      endif()
2178    else()
2179      if(CMAKE_EXTRA_GENERATOR)
2180        list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
2181      else()
2182        list(APPEND cmd "-G${CMAKE_GENERATOR}")
2183      endif()
2184      if(cmake_generator_platform)
2185        message(FATAL_ERROR "Option CMAKE_GENERATOR_PLATFORM not allowed without CMAKE_GENERATOR.")
2186      endif()
2187      if(CMAKE_GENERATOR_PLATFORM)
2188        list(APPEND cmd "-A${CMAKE_GENERATOR_PLATFORM}")
2189      endif()
2190      if(cmake_generator_toolset)
2191        message(FATAL_ERROR "Option CMAKE_GENERATOR_TOOLSET not allowed without CMAKE_GENERATOR.")
2192      endif()
2193      if(CMAKE_GENERATOR_TOOLSET)
2194        list(APPEND cmd "-T${CMAKE_GENERATOR_TOOLSET}")
2195      endif()
2196    endif()
2197
2198    list(APPEND cmd "${source_dir}")
2199  endif()
2200
2201  # If anything about the configure command changes, (command itself, cmake
2202  # used, cmake args or cmake generator) then re-run the configure step.
2203  # Fixes issue http://public.kitware.com/Bug/view.php?id=10258
2204  #
2205  if(NOT EXISTS ${tmp_dir}/${name}-cfgcmd.txt.in)
2206    file(WRITE ${tmp_dir}/${name}-cfgcmd.txt.in "cmd='\@cmd\@'\n")
2207  endif()
2208  configure_file(${tmp_dir}/${name}-cfgcmd.txt.in ${tmp_dir}/${name}-cfgcmd.txt)
2209  list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt)
2210  list(APPEND file_deps ${_ep_cache_args_script})
2211
2212  get_property(log TARGET ${name} PROPERTY _EP_LOG_CONFIGURE)
2213  if(log)
2214    set(log LOG 1)
2215  else()
2216    set(log "")
2217  endif()
2218
2219  get_property(uses_terminal TARGET ${name} PROPERTY
2220    _EP_USES_TERMINAL_CONFIGURE)
2221  if(uses_terminal)
2222    set(uses_terminal USES_TERMINAL 1)
2223  else()
2224    set(uses_terminal "")
2225  endif()
2226
2227  get_property(update_disconnected_set TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED SET)
2228  if(update_disconnected_set)
2229    get_property(update_disconnected TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED)
2230  else()
2231    get_property(update_disconnected DIRECTORY PROPERTY EP_UPDATE_DISCONNECTED)
2232  endif()
2233  if(update_disconnected)
2234    set(update_dep skip-update)
2235  else()
2236    set(update_dep update)
2237  endif()
2238
2239  ExternalProject_Add_Step(${name} configure
2240    COMMAND ${cmd}
2241    WORKING_DIRECTORY ${binary_dir}
2242    DEPENDEES ${update_dep} patch
2243    DEPENDS ${file_deps}
2244    ${log}
2245    ${uses_terminal}
2246    )
2247endfunction()
2248
2249
2250function(_ep_add_build_command name)
2251  ExternalProject_Get_Property(${name} binary_dir)
2252
2253  get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
2254  if(cmd_set)
2255    get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
2256  else()
2257    _ep_get_build_command(${name} BUILD cmd)
2258  endif()
2259
2260  get_property(log TARGET ${name} PROPERTY _EP_LOG_BUILD)
2261  if(log)
2262    set(log LOG 1)
2263  else()
2264    set(log "")
2265  endif()
2266
2267  get_property(uses_terminal TARGET ${name} PROPERTY
2268    _EP_USES_TERMINAL_BUILD)
2269  if(uses_terminal)
2270    set(uses_terminal USES_TERMINAL 1)
2271  else()
2272    set(uses_terminal "")
2273  endif()
2274
2275  get_property(build_always TARGET ${name} PROPERTY _EP_BUILD_ALWAYS)
2276  if(build_always)
2277    set(always 1)
2278  else()
2279    set(always 0)
2280  endif()
2281
2282  get_property(build_byproducts TARGET ${name} PROPERTY _EP_BUILD_BYPRODUCTS)
2283
2284  ExternalProject_Add_Step(${name} build
2285    COMMAND ${cmd}
2286    BYPRODUCTS ${build_byproducts}
2287    WORKING_DIRECTORY ${binary_dir}
2288    #DEPENDEES configure
2289    ALWAYS ${always}
2290    ${log}
2291    ${uses_terminal}
2292    )
2293endfunction()
2294
2295
2296function(_ep_add_install_command name)
2297  ExternalProject_Get_Property(${name} binary_dir)
2298
2299  get_property(cmd_set TARGET ${name} PROPERTY _EP_INSTALL_COMMAND SET)
2300  if(cmd_set)
2301    get_property(cmd TARGET ${name} PROPERTY _EP_INSTALL_COMMAND)
2302  else()
2303    _ep_get_build_command(${name} INSTALL cmd)
2304  endif()
2305
2306  get_property(log TARGET ${name} PROPERTY _EP_LOG_INSTALL)
2307  if(log)
2308    set(log LOG 1)
2309  else()
2310    set(log "")
2311  endif()
2312
2313  get_property(uses_terminal TARGET ${name} PROPERTY
2314    _EP_USES_TERMINAL_INSTALL)
2315  if(uses_terminal)
2316    set(uses_terminal USES_TERMINAL 1)
2317  else()
2318    set(uses_terminal "")
2319  endif()
2320
2321  ExternalProject_Add_Step(${name} install
2322    COMMAND ${cmd}
2323    WORKING_DIRECTORY ${binary_dir}
2324    DEPENDEES build
2325    ${log}
2326    ${uses_terminal}
2327    )
2328endfunction()
2329
2330
2331function(_ep_add_test_command name)
2332  ExternalProject_Get_Property(${name} binary_dir)
2333
2334  get_property(before TARGET ${name} PROPERTY _EP_TEST_BEFORE_INSTALL)
2335  get_property(after TARGET ${name} PROPERTY _EP_TEST_AFTER_INSTALL)
2336  get_property(exclude TARGET ${name} PROPERTY _EP_TEST_EXCLUDE_FROM_MAIN)
2337  get_property(cmd_set TARGET ${name} PROPERTY _EP_TEST_COMMAND SET)
2338
2339  # Only actually add the test step if one of the test related properties is
2340  # explicitly set. (i.e. the test step is omitted unless requested...)
2341  #
2342  if(cmd_set OR before OR after OR exclude)
2343    if(cmd_set)
2344      get_property(cmd TARGET ${name} PROPERTY _EP_TEST_COMMAND)
2345    else()
2346      _ep_get_build_command(${name} TEST cmd)
2347    endif()
2348
2349    if(before)
2350      set(dependees_args DEPENDEES build)
2351    else()
2352      set(dependees_args DEPENDEES install)
2353    endif()
2354
2355    if(exclude)
2356      set(dependers_args "")
2357      set(exclude_args EXCLUDE_FROM_MAIN 1)
2358    else()
2359      if(before)
2360        set(dependers_args DEPENDERS install)
2361      else()
2362        set(dependers_args "")
2363      endif()
2364      set(exclude_args "")
2365    endif()
2366
2367    get_property(log TARGET ${name} PROPERTY _EP_LOG_TEST)
2368    if(log)
2369      set(log LOG 1)
2370    else()
2371      set(log "")
2372    endif()
2373
2374    get_property(uses_terminal TARGET ${name} PROPERTY
2375      _EP_USES_TERMINAL_TEST)
2376    if(uses_terminal)
2377      set(uses_terminal USES_TERMINAL 1)
2378    else()
2379      set(uses_terminal "")
2380    endif()
2381
2382    ExternalProject_Add_Step(${name} test
2383      COMMAND ${cmd}
2384      WORKING_DIRECTORY ${binary_dir}
2385      ${dependees_args}
2386      ${dependers_args}
2387      ${exclude_args}
2388      ${log}
2389      ${uses_terminal}
2390      )
2391  endif()
2392endfunction()
2393
2394
2395function(ExternalProject_Add name)
2396  _ep_get_configuration_subdir_suffix(cfgdir)
2397
2398  # Add a custom target for the external project.
2399  set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
2400  set(complete_stamp_file "${cmf_dir}${cfgdir}/${name}-complete")
2401
2402  # The "ALL" option to add_custom_target just tells it to not set the
2403  # EXCLUDE_FROM_ALL target property. Later, if the EXCLUDE_FROM_ALL
2404  # argument was passed, we explicitly set it for the target.
2405  add_custom_target(${name} ALL DEPENDS ${complete_stamp_file})
2406  set_property(TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT 1)
2407  set_property(TARGET ${name} PROPERTY LABELS ${name})
2408  set_property(TARGET ${name} PROPERTY FOLDER "ExternalProjectTargets/${name}")
2409
2410  _ep_parse_arguments(ExternalProject_Add ${name} _EP_ "${ARGN}")
2411  _ep_set_directories(${name})
2412  _ep_get_step_stampfile(${name} "done" done_stamp_file)
2413  _ep_get_step_stampfile(${name} "install" install_stamp_file)
2414
2415  # Set the EXCLUDE_FROM_ALL target property if required.
2416  get_property(exclude_from_all TARGET ${name} PROPERTY _EP_EXCLUDE_FROM_ALL)
2417  if(exclude_from_all)
2418    set_property(TARGET ${name} PROPERTY EXCLUDE_FROM_ALL TRUE)
2419  endif()
2420
2421  # The 'complete' step depends on all other steps and creates a
2422  # 'done' mark.  A dependent external project's 'configure' step
2423  # depends on the 'done' mark so that it rebuilds when this project
2424  # rebuilds.  It is important that 'done' is not the output of any
2425  # custom command so that CMake does not propagate build rules to
2426  # other external project targets, which may cause problems during
2427  # parallel builds.  However, the Ninja generator needs to see the entire
2428  # dependency graph, and can cope with custom commands belonging to
2429  # multiple targets, so we add the 'done' mark as an output for Ninja only.
2430  set(complete_outputs ${complete_stamp_file})
2431  if(${CMAKE_GENERATOR} MATCHES "Ninja")
2432    set(complete_outputs ${complete_outputs} ${done_stamp_file})
2433  endif()
2434
2435  add_custom_command(
2436    OUTPUT ${complete_outputs}
2437    COMMENT "Completed '${name}'"
2438    COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
2439    COMMAND ${CMAKE_COMMAND} -E touch ${complete_stamp_file}
2440    COMMAND ${CMAKE_COMMAND} -E touch ${done_stamp_file}
2441    DEPENDS ${install_stamp_file}
2442    VERBATIM
2443    )
2444
2445
2446  # Depend on other external projects (target-level).
2447  get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
2448  foreach(arg IN LISTS deps)
2449    add_dependencies(${name} ${arg})
2450  endforeach()
2451
2452  # Set up custom build steps based on the target properties.
2453  # Each step depends on the previous one.
2454  #
2455  # The target depends on the output of the final step.
2456  # (Already set up above in the DEPENDS of the add_custom_target command.)
2457  #
2458  _ep_add_mkdir_command(${name})
2459  ## _ep_add_download_command(${name})
2460  ## _ep_add_update_command(${name})
2461  ## _ep_add_patch_command(${name})
2462  ## _ep_add_configure_command(${name})
2463  _ep_add_build_command(${name})
2464  _ep_add_install_command(${name})
2465
2466  # Test is special in that it might depend on build, or it might depend
2467  # on install.
2468  #
2469  ## _ep_add_test_command(${name})
2470endfunction()
2471