995265803be241f10467e539eb86b17e5e7fe19d
[platform/upstream/cmake.git] / Modules / ExternalProject.cmake
1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
3
4 include_guard(GLOBAL)
5
6 #[=======================================================================[.rst:
7 ExternalProject
8 ---------------
9
10 .. only:: html
11
12    .. contents::
13
14 Commands
15 ^^^^^^^^
16
17 External Project Definition
18 """""""""""""""""""""""""""
19
20 .. command:: ExternalProject_Add
21
22   The ``ExternalProject_Add()`` function creates a custom target to drive
23   download, update/patch, configure, build, install and test steps of an
24   external project:
25
26   .. code-block:: cmake
27
28     ExternalProject_Add(<name> [<option>...])
29
30   The individual steps within the process can be driven independently if
31   required (e.g. for CDash submission) and extra custom steps can be defined,
32   along with the ability to control the step dependencies. The directory
33   structure used for the management of the external project can also be
34   customized. The function supports a large number of options which can be used
35   to tailor the external project behavior.
36
37   **Directory Options:**
38     Most of the time, the default directory layout is sufficient. It is largely
39     an implementation detail that the main project usually doesn't need to
40     change. In some circumstances, however, control over the directory layout
41     can be useful or necessary. The directory options are potentially more
42     useful from the point of view that the main build can use the
43     :command:`ExternalProject_Get_Property` command to retrieve their values,
44     thereby allowing the main project to refer to build artifacts of the
45     external project.
46
47     ``PREFIX <dir>``
48       Root directory for the external project. Unless otherwise noted below,
49       all other directories associated with the external project will be
50       created under here.
51
52     ``TMP_DIR <dir>``
53       Directory in which to store temporary files.
54
55     ``STAMP_DIR <dir>``
56       Directory in which to store the timestamps of each step. Log files from
57       individual steps are also created in here unless overridden by LOG_DIR
58       (see *Logging Options* below).
59
60     ``LOG_DIR <dir>``
61       .. versionadded:: 3.14
62
63       Directory in which to store the logs of each step.
64
65     ``DOWNLOAD_DIR <dir>``
66       Directory in which to store downloaded files before unpacking them. This
67       directory is only used by the URL download method, all other download
68       methods use ``SOURCE_DIR`` directly instead.
69
70     ``SOURCE_DIR <dir>``
71       Source directory into which downloaded contents will be unpacked, or for
72       non-URL download methods, the directory in which the repository should be
73       checked out, cloned, etc. If no download method is specified, this must
74       point to an existing directory where the external project has already
75       been unpacked or cloned/checked out.
76
77       .. note::
78          If a download method is specified, any existing contents of the source
79          directory may be deleted. Only the URL download method checks whether
80          this directory is either missing or empty before initiating the
81          download, stopping with an error if it is not empty. All other
82          download methods silently discard any previous contents of the source
83          directory.
84
85     ``BINARY_DIR <dir>``
86       Specify the build directory location. This option is ignored if
87       ``BUILD_IN_SOURCE`` is enabled.
88
89     ``INSTALL_DIR <dir>``
90       Installation prefix to be placed in the ``<INSTALL_DIR>`` placeholder.
91       This does not actually configure the external project to install to
92       the given prefix. That must be done by passing appropriate arguments
93       to the external project configuration step, e.g. using ``<INSTALL_DIR>``.
94
95     If any of the above ``..._DIR`` options are not specified, their defaults
96     are computed as follows. If the ``PREFIX`` option is given or the
97     ``EP_PREFIX`` directory property is set, then an external project is built
98     and installed under the specified prefix::
99
100       TMP_DIR      = <prefix>/tmp
101       STAMP_DIR    = <prefix>/src/<name>-stamp
102       DOWNLOAD_DIR = <prefix>/src
103       SOURCE_DIR   = <prefix>/src/<name>
104       BINARY_DIR   = <prefix>/src/<name>-build
105       INSTALL_DIR  = <prefix>
106       LOG_DIR      = <STAMP_DIR>
107
108     Otherwise, if the ``EP_BASE`` directory property is set then components
109     of an external project are stored under the specified base::
110
111       TMP_DIR      = <base>/tmp/<name>
112       STAMP_DIR    = <base>/Stamp/<name>
113       DOWNLOAD_DIR = <base>/Download/<name>
114       SOURCE_DIR   = <base>/Source/<name>
115       BINARY_DIR   = <base>/Build/<name>
116       INSTALL_DIR  = <base>/Install/<name>
117       LOG_DIR      = <STAMP_DIR>
118
119     If no ``PREFIX``, ``EP_PREFIX``, or ``EP_BASE`` is specified, then the
120     default is to set ``PREFIX`` to ``<name>-prefix``. Relative paths are
121     interpreted with respect to :variable:`CMAKE_CURRENT_BINARY_DIR` at the
122     point where ``ExternalProject_Add()`` is called.
123
124   **Download Step Options:**
125     A download method can be omitted if the ``SOURCE_DIR`` option is used to
126     point to an existing non-empty directory. Otherwise, one of the download
127     methods below must be specified (multiple download methods should not be
128     given) or a custom ``DOWNLOAD_COMMAND`` provided.
129
130     ``DOWNLOAD_COMMAND <cmd>...``
131       Overrides the command used for the download step
132       (:manual:`generator expressions <cmake-generator-expressions(7)>` are
133       supported). If this option is specified, all other download options will
134       be ignored. Providing an empty string for ``<cmd>`` effectively disables
135       the download step.
136
137     *URL Download*
138       ``URL <url1> [<url2>...]``
139         List of paths and/or URL(s) of the external project's source. When more
140         than one URL is given, they are tried in turn until one succeeds. A URL
141         may be an ordinary path in the local file system (in which case it
142         must be the only URL provided) or any downloadable URL supported by the
143         :command:`file(DOWNLOAD)` command. A local filesystem path may refer to
144         either an existing directory or to an archive file, whereas a URL is
145         expected to point to a file which can be treated as an archive. When an
146         archive is used, it will be unpacked automatically unless the
147         ``DOWNLOAD_NO_EXTRACT`` option is set to prevent it. The archive type
148         is determined by inspecting the actual content rather than using logic
149         based on the file extension.
150
151         .. versionchanged:: 3.7
152           Multiple URLs are allowed.
153
154       ``URL_HASH <algo>=<hashValue>``
155         Hash of the archive file to be downloaded. The argument should be of
156         the form ``<algo>=<hashValue>`` where ``algo`` can be any of the hashing
157         algorithms supported by the :command:`file()` command. Specifying this
158         option is strongly recommended for URL downloads, as it ensures the
159         integrity of the downloaded content. It is also used as a check for a
160         previously downloaded file, allowing connection to the remote location
161         to be avoided altogether if the local directory already has a file from
162         an earlier download that matches the specified hash.
163
164       ``URL_MD5 <md5>``
165         Equivalent to ``URL_HASH MD5=<md5>``.
166
167       ``DOWNLOAD_NAME <fname>``
168         File name to use for the downloaded file. If not given, the end of the
169         URL is used to determine the file name. This option is rarely needed,
170         the default name is generally suitable and is not normally used outside
171         of code internal to the ``ExternalProject`` module.
172
173       ``DOWNLOAD_EXTRACT_TIMESTAMP <bool>``
174         .. versionadded:: 3.24
175
176         When specified with a true value, the timestamps of the extracted
177         files will match those in the archive. When false, the timestamps of
178         the extracted files will reflect the time at which the extraction
179         was performed. If the download URL changes, timestamps based off
180         those in the archive can result in dependent targets not being rebuilt
181         when they potentially should have been. Therefore, unless the file
182         timestamps are significant to the project in some way, use a false
183         value for this option. If ``DOWNLOAD_EXTRACT_TIMESTAMP`` is not given,
184         the default is false. See policy :policy:`CMP0135`.
185
186       ``DOWNLOAD_NO_EXTRACT <bool>``
187         .. versionadded:: 3.6
188
189         Allows the extraction part of the download step to be disabled by
190         passing a boolean true value for this option. If this option is not
191         given, the downloaded contents will be unpacked automatically if
192         required. If extraction has been disabled, the full path to the
193         downloaded file is available as ``<DOWNLOADED_FILE>`` in subsequent
194         steps or as the property ``DOWNLOADED_FILE`` with the
195         :command:`ExternalProject_Get_Property` command.
196
197       ``DOWNLOAD_NO_PROGRESS <bool>``
198         Can be used to disable logging the download progress. If this option is
199         not given, download progress messages will be logged.
200
201       ``TIMEOUT <seconds>``
202         Maximum time allowed for file download operations.
203
204       ``INACTIVITY_TIMEOUT <seconds>``
205         .. versionadded:: 3.19
206
207         Terminate the operation after a period of inactivity.
208
209       ``HTTP_USERNAME <username>``
210         .. versionadded:: 3.7
211
212         Username for the download operation if authentication is required.
213
214       ``HTTP_PASSWORD <password>``
215         .. versionadded:: 3.7
216
217         Password for the download operation if authentication is required.
218
219       ``HTTP_HEADER <header1> [<header2>...]``
220         .. versionadded:: 3.7
221
222         Provides an arbitrary list of HTTP headers for the download operation.
223         This can be useful for accessing content in systems like AWS, etc.
224
225       ``TLS_VERIFY <bool>``
226         Specifies whether certificate verification should be performed for
227         https URLs. If this option is not provided, the default behavior is
228         determined by the :variable:`CMAKE_TLS_VERIFY` variable (see
229         :command:`file(DOWNLOAD)`). If that is also not set, certificate
230         verification will not be performed. In situations where ``URL_HASH``
231         cannot be provided, this option can be an alternative verification
232         measure.
233
234         .. versionchanged:: 3.6
235           This option also applies to ``git clone`` invocations.
236
237       ``TLS_CAINFO <file>``
238         Specify a custom certificate authority file to use if ``TLS_VERIFY``
239         is enabled. If this option is not specified, the value of the
240         :variable:`CMAKE_TLS_CAINFO` variable will be used instead (see
241         :command:`file(DOWNLOAD)`)
242
243       ``NETRC <level>``
244         .. versionadded:: 3.11
245
246         Specify whether the ``.netrc`` file is to be used for operation.
247         If this option is not specified, the value of the
248         :variable:`CMAKE_NETRC` variable will be used instead
249         (see :command:`file(DOWNLOAD)`).  Valid levels are:
250
251         ``IGNORED``
252           The ``.netrc`` file is ignored.
253           This is the default.
254         ``OPTIONAL``
255           The ``.netrc`` file is optional, and information in the URL
256           is preferred.  The file will be scanned to find which ever
257           information is not specified in the URL.
258         ``REQUIRED``
259           The ``.netrc`` file is required, and information in the URL
260           is ignored.
261
262       ``NETRC_FILE <file>``
263         .. versionadded:: 3.11
264
265         Specify an alternative ``.netrc`` file to the one in your home directory
266         if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option
267         is not specified, the value of the :variable:`CMAKE_NETRC_FILE` variable
268         will be used instead (see :command:`file(DOWNLOAD)`)
269
270       .. versionadded:: 3.1
271         Added support for `tbz2`, `.tar.xz`, `.txz`, and `.7z` extensions.
272
273     *Git*
274       NOTE: A git version of 1.6.5 or later is required if this download method
275       is used.
276
277       ``GIT_REPOSITORY <url>``
278         URL of the git repository. Any URL understood by the ``git`` command
279         may be used.
280
281       ``GIT_TAG <tag>``
282         Git branch name, tag or commit hash. Note that branch names and tags
283         should generally be specified as remote names (i.e. ``origin/myBranch``
284         rather than simply ``myBranch``). This ensures that if the remote end
285         has its tag moved or branch rebased or history rewritten, the local
286         clone will still be updated correctly. In general, however, specifying
287         a commit hash should be preferred for a number of reasons:
288
289         - If the local clone already has the commit corresponding to the hash,
290           no ``git fetch`` needs to be performed to check for changes each time
291           CMake is re-run. This can result in a significant speed up if many
292           external projects are being used.
293         - Using a specific git hash ensures that the main project's own history
294           is fully traceable to a specific point in the external project's
295           evolution. If a branch or tag name is used instead, then checking out
296           a specific commit of the main project doesn't necessarily pin the
297           whole build to a specific point in the life of the external project.
298           The lack of such deterministic behavior makes the main project lose
299           traceability and repeatability.
300
301         If ``GIT_SHALLOW`` is enabled then ``GIT_TAG`` works only with
302         branch names and tags.  A commit hash is not allowed.
303
304         Note that if not provided, ``GIT_TAG`` defaults to ``master``, not the
305         default Git branch name.
306
307       ``GIT_REMOTE_NAME <name>``
308         The optional name of the remote. If this option is not specified, it
309         defaults to ``origin``.
310
311       ``GIT_SUBMODULES <module>...``
312         Specific git submodules that should also be updated. If this option is
313         not provided, all git submodules will be updated.
314
315         .. versionchanged:: 3.16
316           When :policy:`CMP0097` is set to ``NEW``, if this value is set
317           to an empty string then no submodules are initialized or updated.
318
319       ``GIT_SUBMODULES_RECURSE <bool>``
320         .. versionadded:: 3.17
321
322         Specify whether git submodules (if any) should update recursively by
323         passing the ``--recursive`` flag to ``git submodule update``.
324         If not specified, the default is on.
325
326       ``GIT_SHALLOW <bool>``
327         .. versionadded:: 3.6
328
329         When this option is enabled, the ``git clone`` operation will be given
330         the ``--depth 1`` option. This performs a shallow clone, which avoids
331         downloading the whole history and instead retrieves just the commit
332         denoted by the ``GIT_TAG`` option.
333
334       ``GIT_PROGRESS <bool>``
335         .. versionadded:: 3.8
336
337         When enabled, this option instructs the ``git clone`` operation to
338         report its progress by passing it the ``--progress`` option. Without
339         this option, the clone step for large projects may appear to make the
340         build stall, since nothing will be logged until the clone operation
341         finishes. While this option can be used to provide progress to prevent
342         the appearance of the build having stalled, it may also make the build
343         overly noisy if lots of external projects are used.
344
345       ``GIT_CONFIG <option1> [<option2>...]``
346         .. versionadded:: 3.8
347
348         Specify a list of config options to pass to ``git clone``. Each option
349         listed will be transformed into its own ``--config <option>`` on the
350         ``git clone`` command line, with each option required to be in the
351         form ``key=value``.
352
353       ``GIT_REMOTE_UPDATE_STRATEGY <strategy>``
354         .. versionadded:: 3.18
355
356         When ``GIT_TAG`` refers to a remote branch, this option can be used to
357         specify how the update step behaves.  The ``<strategy>`` must be one of
358         the following:
359
360         ``CHECKOUT``
361           Ignore the local branch and always checkout the branch specified by
362           ``GIT_TAG``.
363
364         ``REBASE``
365           Try to rebase the current branch to the one specified by ``GIT_TAG``.
366           If there are local uncommitted changes, they will be stashed first
367           and popped again after rebasing.  If rebasing or popping stashed
368           changes fail, abort the rebase and halt with an error.
369           When ``GIT_REMOTE_UPDATE_STRATEGY`` is not present, this is the
370           default strategy unless the default has been overridden with
371           ``CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY`` (see below).
372           Note that if the branch specified in ``GIT_TAG`` is different to
373           the upstream branch currently being tracked, it is not safe to
374           perform a rebase. In that situation, ``REBASE`` will silently be
375           treated as ``CHECKOUT`` instead.
376
377         ``REBASE_CHECKOUT``
378           Same as ``REBASE`` except if the rebase fails, an annotated tag will
379           be created at the original ``HEAD`` position from before the rebase
380           and then checkout ``GIT_TAG`` just like the ``CHECKOUT`` strategy.
381           The message stored on the annotated tag will give information about
382           what was attempted and the tag name will include a timestamp so that
383           each failed run will add a new tag.  This strategy ensures no changes
384           will be lost, but updates should always succeed if ``GIT_TAG`` refers
385           to a valid ref unless there are uncommitted changes that cannot be
386           popped successfully.
387
388         The variable ``CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY`` can be set to
389         override the default strategy.  This variable should not be set by a
390         project, it is intended for the user to set.  It is primarily intended
391         for use in continuous integration scripts to ensure that when history
392         is rewritten on a remote branch, the build doesn't end up with
393         unintended changes or failed builds resulting from conflicts during
394         rebase operations.
395
396     *Subversion*
397       ``SVN_REPOSITORY <url>``
398         URL of the Subversion repository.
399
400       ``SVN_REVISION -r<rev>``
401         Revision to checkout from the Subversion repository.
402
403       ``SVN_USERNAME <username>``
404         Username for the Subversion checkout and update.
405
406       ``SVN_PASSWORD <password>``
407         Password for the Subversion checkout and update.
408
409       ``SVN_TRUST_CERT <bool>``
410         Specifies whether to trust the Subversion server site certificate. If
411         enabled, the ``--trust-server-cert`` option is passed to the ``svn``
412         checkout and update commands.
413
414     *Mercurial*
415       ``HG_REPOSITORY <url>``
416         URL of the mercurial repository.
417
418       ``HG_TAG <tag>``
419         Mercurial branch name, tag or commit id.
420
421     *CVS*
422       ``CVS_REPOSITORY <cvsroot>``
423         CVSROOT of the CVS repository.
424
425       ``CVS_MODULE <mod>``
426         Module to checkout from the CVS repository.
427
428       ``CVS_TAG <tag>``
429         Tag to checkout from the CVS repository.
430
431   **Update Step Options:**
432     Whenever CMake is re-run, by default the external project's sources will be
433     updated if the download method supports updates (e.g. a git repository
434     would be checked if the ``GIT_TAG`` does not refer to a specific commit).
435
436     ``UPDATE_COMMAND <cmd>...``
437       Overrides the download method's update step with a custom command.
438       The command may use
439       :manual:`generator expressions <cmake-generator-expressions(7)>`.
440
441     ``UPDATE_DISCONNECTED <bool>``
442       .. versionadded:: 3.2
443
444       When enabled, this option causes the update step to be skipped. It does
445       not, however, prevent the download step. The update step can still be
446       added as a step target (see :command:`ExternalProject_Add_StepTargets`)
447       and called manually. This is useful if you want to allow developers to
448       build the project when disconnected from the network (the network may
449       still be needed for the download step though).
450
451       When this option is present, it is generally advisable to make the value
452       a cache variable under the developer's control rather than hard-coding
453       it. If this option is not present, the default value is taken from the
454       ``EP_UPDATE_DISCONNECTED`` directory property. If that is also not
455       defined, updates are performed as normal. The ``EP_UPDATE_DISCONNECTED``
456       directory property is intended as a convenience for controlling the
457       ``UPDATE_DISCONNECTED`` behavior for an entire section of a project's
458       directory hierarchy and may be a more convenient method of giving
459       developers control over whether or not to perform updates (assuming the
460       project also provides a cache variable or some other convenient method
461       for setting the directory property).
462
463       This may cause a step target to be created automatically for the
464       ``download`` step.  See policy :policy:`CMP0114`.
465
466   **Patch Step Options:**
467     ``PATCH_COMMAND <cmd>...``
468       Specifies a custom command to patch the sources after an update. By
469       default, no patch command is defined. Note that it can be quite difficult
470       to define an appropriate patch command that performs robustly, especially
471       for download methods such as git where changing the ``GIT_TAG`` will not
472       discard changes from a previous patch, but the patch command will be
473       called again after updating to the new tag.
474
475   **Configure Step Options:**
476     The configure step is run after the download and update steps. By default,
477     the external project is assumed to be a CMake project, but this can be
478     overridden if required.
479
480     ``CONFIGURE_COMMAND <cmd>...``
481       The default configure command runs CMake with a few options based on
482       the main project.  The options added are typically only those needed to
483       use the same generator as the main project, but the ``CMAKE_GENERATOR``
484       option can be given to override this.  The project is responsible for
485       adding any toolchain details, flags or other settings it wants to
486       re-use from the main project or otherwise specify (see ``CMAKE_ARGS``,
487       ``CMAKE_CACHE_ARGS`` and ``CMAKE_CACHE_DEFAULT_ARGS`` below).
488
489       For non-CMake external projects, the ``CONFIGURE_COMMAND`` option must
490       be used to override the default configure command
491       (:manual:`generator expressions <cmake-generator-expressions(7)>` are
492       supported). For projects that require no configure step, specify this
493       option with an empty string as the command to execute.
494
495     ``CMAKE_COMMAND /.../cmake``
496       Specify an alternative cmake executable for the configure step (use an
497       absolute path). This is generally not recommended, since it is
498       usually desirable to use the same CMake version throughout the whole
499       build. This option is ignored if a custom configure command has been
500       specified with ``CONFIGURE_COMMAND``.
501
502     ``CMAKE_GENERATOR <gen>``
503       Override the CMake generator used for the configure step. Without this
504       option, the same generator as the main build will be used. This option is
505       ignored if a custom configure command has been specified with the
506       ``CONFIGURE_COMMAND`` option.
507
508     ``CMAKE_GENERATOR_PLATFORM <platform>``
509       .. versionadded:: 3.1
510
511       Pass a generator-specific platform name to the CMake command (see
512       :variable:`CMAKE_GENERATOR_PLATFORM`). It is an error to provide this
513       option without the ``CMAKE_GENERATOR`` option.
514
515     ``CMAKE_GENERATOR_TOOLSET <toolset>``
516       Pass a generator-specific toolset name to the CMake command (see
517       :variable:`CMAKE_GENERATOR_TOOLSET`). It is an error to provide this
518       option without the ``CMAKE_GENERATOR`` option.
519
520     ``CMAKE_GENERATOR_INSTANCE <instance>``
521       .. versionadded:: 3.11
522
523       Pass a generator-specific instance selection to the CMake command (see
524       :variable:`CMAKE_GENERATOR_INSTANCE`). It is an error to provide this
525       option without the ``CMAKE_GENERATOR`` option.
526
527     ``CMAKE_ARGS <arg>...``
528       The specified arguments are passed to the ``cmake`` command line. They
529       can be any argument the ``cmake`` command understands, not just cache
530       values defined by ``-D...`` arguments (see also
531       :manual:`CMake Options <cmake(1)>`).
532
533       .. versionadded:: 3.3
534         Arguments may use
535         :manual:`generator expressions <cmake-generator-expressions(7)>`.
536
537     ``CMAKE_CACHE_ARGS <arg>...``
538       This is an alternate way of specifying cache variables where command line
539       length issues may become a problem. The arguments are expected to be in
540       the form ``-Dvar:STRING=value``, which are then transformed into
541       CMake :command:`set` commands with the ``FORCE`` option used. These
542       ``set()`` commands are written to a pre-load script which is then applied
543       using the :manual:`cmake -C <cmake(1)>` command line option.
544
545       .. versionadded:: 3.3
546         Arguments may use
547         :manual:`generator expressions <cmake-generator-expressions(7)>`.
548
549     ``CMAKE_CACHE_DEFAULT_ARGS <arg>...``
550       .. versionadded:: 3.2
551
552       This is the same as the ``CMAKE_CACHE_ARGS`` option except the ``set()``
553       commands do not include the ``FORCE`` keyword. This means the values act
554       as initial defaults only and will not override any variables already set
555       from a previous run. Use this option with care, as it can lead to
556       different behavior depending on whether the build starts from a fresh
557       build directory or re-uses previous build contents.
558
559       .. versionadded:: 3.15
560         If the CMake generator is the ``Green Hills MULTI`` and not overridden,
561         the original project's settings for the GHS toolset and target system
562         customization cache variables are propagated into the external project.
563
564     ``SOURCE_SUBDIR <dir>``
565       .. versionadded:: 3.7
566
567       When no ``CONFIGURE_COMMAND`` option is specified, the configure step
568       assumes the external project has a ``CMakeLists.txt`` file at the top of
569       its source tree (i.e. in ``SOURCE_DIR``). The ``SOURCE_SUBDIR`` option
570       can be used to point to an alternative directory within the source tree
571       to use as the top of the CMake source tree instead. This must be a
572       relative path and it will be interpreted as being relative to
573       ``SOURCE_DIR``.
574
575       .. versionadded:: 3.14
576         When ``BUILD_IN_SOURCE`` option is enabled, the ``BUILD_COMMAND``
577         is used to point to an alternative directory within the source tree.
578
579     ``CONFIGURE_HANDLED_BY_BUILD <bool>``
580       .. versionadded:: 3.20
581
582       Enabling this option relaxes the dependencies of the configure step on
583       other external projects to order-only. This means the configure step will
584       be executed after its external project dependencies are built but it will
585       not be marked dirty when one of its external project dependencies is
586       rebuilt. This option can be enabled when the build step is smart enough
587       to figure out if the configure step needs to be rerun. CMake and Meson are
588       examples of build systems whose build step is smart enough to know if the
589       configure step needs to be rerun.
590
591   **Build Step Options:**
592     If the configure step assumed the external project uses CMake as its build
593     system, the build step will also. Otherwise, the build step will assume a
594     Makefile-based build and simply run ``make`` with no arguments as the
595     default build step. This can be overridden with custom build commands if
596     required.
597
598     If both the main project and the external project use make as their build
599     tool, the build step of the external project is invoked as a recursive
600     make using ``$(MAKE)``.  This will communicate some build tool settings
601     from the main project to the external project.  If either the main project
602     or external project is not using make, no build tool settings will be
603     passed to the external project other than those established by the
604     configure step (i.e. running ``ninja -v`` in the main project will not
605     pass ``-v`` to the external project's build step, even if it also uses
606     ``ninja`` as its build tool).
607
608     ``BUILD_COMMAND <cmd>...``
609       Overrides the default build command
610       (:manual:`generator expressions <cmake-generator-expressions(7)>` are
611       supported). If this option is not given, the default build command will
612       be chosen to integrate with the main build in the most appropriate way
613       (e.g. using recursive ``make`` for Makefile generators or
614       ``cmake --build`` if the project uses a CMake build). This option can be
615       specified with an empty string as the command to make the build step do
616       nothing.
617
618     ``BUILD_IN_SOURCE <bool>``
619       When this option is enabled, the build will be done directly within the
620       external project's source tree. This should generally be avoided, the use
621       of a separate build directory is usually preferred, but it can be useful
622       when the external project assumes an in-source build. The ``BINARY_DIR``
623       option should not be specified if building in-source.
624
625     ``BUILD_ALWAYS <bool>``
626       Enabling this option forces the build step to always be run. This can be
627       the easiest way to robustly ensure that the external project's own build
628       dependencies are evaluated rather than relying on the default
629       success timestamp-based method. This option is not normally needed unless
630       developers are expected to modify something the external project's build
631       depends on in a way that is not detectable via the step target
632       dependencies (e.g. ``SOURCE_DIR`` is used without a download method and
633       developers might modify the sources in ``SOURCE_DIR``).
634
635     ``BUILD_BYPRODUCTS <file>...``
636       .. versionadded:: 3.2
637
638       Specifies files that will be generated by the build command but which
639       might or might not have their modification time updated by subsequent
640       builds. These ultimately get passed through as ``BYPRODUCTS`` to the
641       build step's own underlying call to :command:`add_custom_command`.
642
643   **Install Step Options:**
644     If the configure step assumed the external project uses CMake as its build
645     system, the install step will also. Otherwise, the install step will assume
646     a Makefile-based build and simply run ``make install`` as the default build
647     step. This can be overridden with custom install commands if required.
648
649     ``INSTALL_COMMAND <cmd>...``
650       The external project's own install step is invoked as part of the main
651       project's *build*. It is done after the external project's build step
652       and may be before or after the external project's test step (see the
653       ``TEST_BEFORE_INSTALL`` option below). The external project's install
654       rules are not part of the main project's install rules, so if anything
655       from the external project should be installed as part of the main build,
656       these need to be specified in the main build as additional
657       :command:`install` commands. The default install step builds the
658       ``install`` target of the external project, but this can be overridden
659       with a custom command using this option
660       (:manual:`generator expressions <cmake-generator-expressions(7)>` are
661       supported). Passing an empty string as the ``<cmd>`` makes the install
662       step do nothing.
663
664     .. note::
665       If the :envvar:`CMAKE_INSTALL_MODE` environment variable is set when the
666       main project is built, it will only have an effect if the following
667       conditions are met:
668
669       * The main project's configure step assumed the external project uses
670         CMake as its build system.
671       * The external project's install command actually runs. Note that due
672         to the way ``ExternalProject`` may use timestamps internally, if
673         nothing the install step depends on needs to be re-executed, the
674         install command might also not need to run.
675
676       Note also that ``ExternalProject`` does not check whether the
677       :envvar:`CMAKE_INSTALL_MODE` environment variable changes from one run
678       to another.
679
680   **Test Step Options:**
681     The test step is only defined if at least one of the following ``TEST_...``
682     options are provided.
683
684     ``TEST_COMMAND <cmd>...``
685       Overrides the default test command
686       (:manual:`generator expressions <cmake-generator-expressions(7)>` are
687       supported). If this option is not given, the default behavior of the test
688       step is to build the external project's own ``test`` target. This option
689       can be specified with ``<cmd>`` as an empty string, which allows the test
690       step to still be defined, but it will do nothing. Do not specify any of
691       the other ``TEST_...`` options if providing an empty string as the test
692       command, but prefer to omit all ``TEST_...`` options altogether if the
693       test step target is not needed.
694
695     ``TEST_BEFORE_INSTALL <bool>``
696       When this option is enabled, the test step will be executed before the
697       install step. The default behavior is for the test step to run after the
698       install step.
699
700     ``TEST_AFTER_INSTALL <bool>``
701       This option is mainly useful as a way to indicate that the test step is
702       desired but all default behavior is sufficient. Specifying this option
703       with a boolean true value ensures the test step is defined and that it
704       comes after the install step. If both ``TEST_BEFORE_INSTALL`` and
705       ``TEST_AFTER_INSTALL`` are enabled, the latter is silently ignored.
706
707     ``TEST_EXCLUDE_FROM_MAIN <bool>``
708       .. versionadded:: 3.2
709
710       If enabled, the main build's default ALL target will not depend on the
711       test step. This can be a useful way of ensuring the test step is defined
712       but only gets invoked when manually requested.
713       This may cause a step target to be created automatically for either
714       the ``install`` or ``build`` step.  See policy :policy:`CMP0114`.
715
716   **Output Logging Options:**
717     Each of the following ``LOG_...`` options can be used to wrap the relevant
718     step in a script to capture its output to files. The log files will be
719     created in ``LOG_DIR`` if supplied or otherwise the ``STAMP_DIR``
720     directory with step-specific file names.
721
722     ``LOG_DOWNLOAD <bool>``
723       When enabled, the output of the download step is logged to files.
724
725     ``LOG_UPDATE <bool>``
726       When enabled, the output of the update step is logged to files.
727
728     ``LOG_PATCH <bool>``
729       .. versionadded:: 3.14
730
731       When enabled, the output of the patch step is logged to files.
732
733     ``LOG_CONFIGURE <bool>``
734       When enabled, the output of the configure step is logged to files.
735
736     ``LOG_BUILD <bool>``
737       When enabled, the output of the build step is logged to files.
738
739     ``LOG_INSTALL <bool>``
740       When enabled, the output of the install step is logged to files.
741
742     ``LOG_TEST <bool>``
743       When enabled, the output of the test step is logged to files.
744
745     ``LOG_MERGED_STDOUTERR <bool>``
746       .. versionadded:: 3.14
747
748       When enabled, stdout and stderr will be merged for any step whose
749       output is being logged to files.
750
751     ``LOG_OUTPUT_ON_FAILURE <bool>``
752       .. versionadded:: 3.14
753
754       This option only has an effect if at least one of the other ``LOG_<step>``
755       options is enabled.  If an error occurs for a step which has logging to
756       file enabled, that step's output will be printed to the console if
757       ``LOG_OUTPUT_ON_FAILURE`` is set to true.  For cases where a large amount
758       of output is recorded, just the end of that output may be printed to the
759       console.
760
761   **Terminal Access Options:**
762     .. versionadded:: 3.4
763
764     Steps can be given direct access to the terminal in some cases. Giving a
765     step access to the terminal may allow it to receive terminal input if
766     required, such as for authentication details not provided by other options.
767     With the :generator:`Ninja` generator, these options place the steps in the
768     ``console`` :prop_gbl:`job pool <JOB_POOLS>`. Each step can be given access
769     to the terminal individually via the following options:
770
771     ``USES_TERMINAL_DOWNLOAD <bool>``
772       Give the download step access to the terminal.
773
774     ``USES_TERMINAL_UPDATE <bool>``
775       Give the update step access to the terminal.
776
777     ``USES_TERMINAL_PATCH <bool>``
778       .. versionadded:: 3.23
779
780       Give the patch step access to the terminal.
781
782     ``USES_TERMINAL_CONFIGURE <bool>``
783       Give the configure step access to the terminal.
784
785     ``USES_TERMINAL_BUILD <bool>``
786       Give the build step access to the terminal.
787
788     ``USES_TERMINAL_INSTALL <bool>``
789       Give the install step access to the terminal.
790
791     ``USES_TERMINAL_TEST <bool>``
792       Give the test step access to the terminal.
793
794   **Target Options:**
795     ``DEPENDS <targets>...``
796       Specify other targets on which the external project depends. The other
797       targets will be brought up to date before any of the external project's
798       steps are executed. Because the external project uses additional custom
799       targets internally for each step, the ``DEPENDS`` option is the most
800       convenient way to ensure all of those steps depend on the other targets.
801       Simply doing
802       :command:`add_dependencies(\<name\> \<targets\>) <add_dependencies>` will
803       not make any of the steps dependent on ``<targets>``.
804
805     ``EXCLUDE_FROM_ALL <bool>``
806       When enabled, this option excludes the external project from the default
807       ALL target of the main build.
808
809     ``STEP_TARGETS <step-target>...``
810       Generate custom targets for the specified steps. This is required if the
811       steps need to be triggered manually or if they need to be used as
812       dependencies of other targets. If this option is not specified, the
813       default value is taken from the ``EP_STEP_TARGETS`` directory property.
814       See :command:`ExternalProject_Add_StepTargets` below for further
815       discussion of the effects of this option.
816
817     ``INDEPENDENT_STEP_TARGETS <step-target>...``
818       .. deprecated:: 3.19
819         This is allowed only if policy :policy:`CMP0114` is not set to ``NEW``.
820
821       Generates custom targets for the specified steps and prevent these targets
822       from having the usual dependencies applied to them. If this option is not
823       specified, the default value is taken from the
824       ``EP_INDEPENDENT_STEP_TARGETS`` directory property. This option is mostly
825       useful for allowing individual steps to be driven independently, such as
826       for a CDash setup where each step should be initiated and reported
827       individually rather than as one whole build. See
828       :command:`ExternalProject_Add_StepTargets` below for further discussion
829       of the effects of this option.
830
831   **Miscellaneous Options:**
832     ``LIST_SEPARATOR <sep>``
833       For any of the various ``..._COMMAND`` options, and ``CMAKE_ARGS``,
834       replace ``;`` with ``<sep>`` in the specified command lines.
835       This can be useful where list variables may be given in commands where
836       they should end up as space-separated arguments (``<sep>`` would be a
837       single space character string in this case).
838
839     ``COMMAND <cmd>...``
840       Any of the other ``..._COMMAND`` options can have additional commands
841       appended to them by following them with as many ``COMMAND ...`` options
842       as needed
843       (:manual:`generator expressions <cmake-generator-expressions(7)>` are
844       supported). For example:
845
846       .. code-block:: cmake
847
848         ExternalProject_Add(example
849           ... # Download options, etc.
850           BUILD_COMMAND ${CMAKE_COMMAND} -E echo "Starting $<CONFIG> build"
851           COMMAND       ${CMAKE_COMMAND} --build <BINARY_DIR> --config $<CONFIG>
852           COMMAND       ${CMAKE_COMMAND} -E echo "$<CONFIG> build complete"
853         )
854
855   It should also be noted that each build step is created via a call to
856   :command:`ExternalProject_Add_Step`. See that command's documentation for the
857   automatic substitutions that are supported for some options.
858
859 Obtaining Project Properties
860 """"""""""""""""""""""""""""
861
862 .. command:: ExternalProject_Get_Property
863
864   The ``ExternalProject_Get_Property()`` function retrieves external project
865   target properties:
866
867   .. code-block:: cmake
868
869     ExternalProject_Get_Property(<name> <prop1> [<prop2>...])
870
871   The function stores property values in variables of the same name. Property
872   names correspond to the keyword argument names of ``ExternalProject_Add()``.
873   For example, the source directory might be retrieved like so:
874
875   .. code-block:: cmake
876
877     ExternalProject_Get_property(myExtProj SOURCE_DIR)
878     message("Source dir of myExtProj = ${SOURCE_DIR}")
879
880 Explicit Step Management
881 """"""""""""""""""""""""
882
883 The ``ExternalProject_Add()`` function on its own is often sufficient for
884 incorporating an external project into the main build. Certain scenarios
885 require additional work to implement desired behavior, such as adding in a
886 custom step or making steps available as manually triggerable targets. The
887 ``ExternalProject_Add_Step()``, ``ExternalProject_Add_StepTargets()`` and
888 ``ExternalProject_Add_StepDependencies`` functions provide the lower level
889 control needed to implement such step-level capabilities.
890
891 .. command:: ExternalProject_Add_Step
892
893   The ``ExternalProject_Add_Step()`` function specifies an additional custom
894   step for an external project defined by an earlier call to
895   :command:`ExternalProject_Add`:
896
897   .. code-block:: cmake
898
899     ExternalProject_Add_Step(<name> <step> [<option>...])
900
901   ``<name>`` is the same as the name passed to the original call to
902   :command:`ExternalProject_Add`. The specified ``<step>`` must not be one of
903   the pre-defined steps (``mkdir``, ``download``, ``update``,
904   ``patch``, ``configure``, ``build``, ``install`` or ``test``). The supported
905   options are:
906
907   ``COMMAND <cmd>...``
908     The command line to be executed by this custom step
909     (:manual:`generator expressions <cmake-generator-expressions(7)>` are
910     supported). This option can be repeated multiple times to specify multiple
911     commands to be executed in order.
912
913   ``COMMENT "<text>..."``
914     Text to be printed when the custom step executes.
915
916   ``DEPENDEES <step>...``
917     Other steps (custom or pre-defined) on which this step depends.
918
919   ``DEPENDERS <step>...``
920     Other steps (custom or pre-defined) that depend on this new custom step.
921
922   ``DEPENDS <file>...``
923     Files on which this custom step depends.
924
925   ``INDEPENDENT <bool>``
926     .. versionadded:: 3.19
927
928     Specifies whether this step is independent of the external dependencies
929     specified by the :command:`ExternalProject_Add`'s ``DEPENDS`` option.
930     The default is ``FALSE``.  Steps marked as independent may depend only
931     on other steps marked independent.  See policy :policy:`CMP0114`.
932
933     Note that this use of the term "independent" refers only to independence
934     from external targets specified by the ``DEPENDS`` option and is
935     orthogonal to a step's dependencies on other steps.
936
937     If a step target is created for an independent step by the
938     :command:`ExternalProject_Add` ``STEP_TARGETS`` option or by the
939     :command:`ExternalProject_Add_StepTargets` function, it will not depend
940     on the external targets, but may depend on targets for other steps.
941
942   ``BYPRODUCTS <file>...``
943     .. versionadded:: 3.2
944
945     Files that will be generated by this custom step but which might or might
946     not have their modification time updated by subsequent builds. This list of
947     files will ultimately be passed through as the ``BYPRODUCTS`` option to the
948     :command:`add_custom_command` used to implement the custom step internally.
949
950   ``ALWAYS <bool>``
951     When enabled, this option specifies that the custom step should always be
952     run (i.e. that it is always considered out of date).
953
954   ``EXCLUDE_FROM_MAIN <bool>``
955     When enabled, this option specifies that the external project's main target
956     does not depend on the custom step.
957     This may cause step targets to be created automatically for the steps on
958     which this step depends.  See policy :policy:`CMP0114`.
959
960   ``WORKING_DIRECTORY <dir>``
961     Specifies the working directory to set before running the custom step's
962     command. If this option is not specified, the directory will be the value
963     of the :variable:`CMAKE_CURRENT_BINARY_DIR` at the point where
964     ``ExternalProject_Add_Step()`` was called.
965
966   ``LOG <bool>``
967     If set, this causes the output from the custom step to be captured to files
968     in the external project's ``LOG_DIR`` if supplied or ``STAMP_DIR``.
969
970   ``USES_TERMINAL <bool>``
971     If enabled, this gives the custom step direct access to the terminal if
972     possible.
973
974   The command line, comment, working directory and byproducts of every
975   standard and custom step are processed to replace the tokens
976   ``<SOURCE_DIR>``, ``<SOURCE_SUBDIR>``, ``<BINARY_DIR>``, ``<INSTALL_DIR>``
977   ``<TMP_DIR>``, ``<DOWNLOAD_DIR>`` and ``<DOWNLOADED_FILE>`` with their
978   corresponding property values defined in the original call to
979   :command:`ExternalProject_Add`.
980
981   .. versionadded:: 3.3
982     Token replacement is extended to byproducts.
983
984   .. versionadded:: 3.11
985     The ``<DOWNLOAD_DIR>`` substitution token.
986
987 .. command:: ExternalProject_Add_StepTargets
988
989   The ``ExternalProject_Add_StepTargets()`` function generates targets for the
990   steps listed. The name of each created target will be of the form
991   ``<name>-<step>``:
992
993   .. code-block:: cmake
994
995     ExternalProject_Add_StepTargets(<name> <step1> [<step2>...])
996
997   Creating a target for a step allows it to be used as a dependency of another
998   target or to be triggered manually. Having targets for specific steps also
999   allows them to be driven independently of each other by specifying targets on
1000   build command lines. For example, you may be submitting to a sub-project
1001   based dashboard where you want to drive the configure portion of the build,
1002   then submit to the dashboard, followed by the build portion, followed
1003   by tests. If you invoke a custom target that depends on a step halfway
1004   through the step dependency chain, then all the previous steps will also run
1005   to ensure everything is up to date.
1006
1007   Internally, :command:`ExternalProject_Add` calls
1008   :command:`ExternalProject_Add_Step` to create each step. If any
1009   ``STEP_TARGETS`` were specified, then ``ExternalProject_Add_StepTargets()``
1010   will also be called after :command:`ExternalProject_Add_Step`.  Even if a
1011   step is not mentioned in the ``STEP_TARGETS`` option,
1012   ``ExternalProject_Add_StepTargets()`` can still be called later to manually
1013   define a target for the step.
1014
1015   The ``STEP_TARGETS`` option for :command:`ExternalProject_Add` is generally
1016   the easiest way to ensure targets are created for specific steps of interest.
1017   For custom steps, ``ExternalProject_Add_StepTargets()`` must be called
1018   explicitly if a target should also be created for that custom step.
1019   An alternative to these two options is to populate the ``EP_STEP_TARGETS``
1020   directory property.  It acts as a default for the step target options and
1021   can save having to repeatedly specify the same set of step targets when
1022   multiple external projects are being defined.
1023
1024   .. versionadded:: 3.19
1025     If :policy:`CMP0114` is set to ``NEW``, step targets are fully responsible
1026     for holding the custom commands implementing their steps.  The primary
1027     target created by ``ExternalProject_Add`` depends on the step targets, and
1028     the step targets depend on each other.  The target-level dependencies match
1029     the file-level dependencies used by the custom commands for each step.
1030     The targets for steps created with :command:`ExternalProject_Add_Step`'s
1031     ``INDEPENDENT`` option do not depend on the external targets specified
1032     by :command:`ExternalProject_Add`'s ``DEPENDS`` option.  The predefined
1033     steps ``mkdir``, ``download``, ``update``, and ``patch`` are independent.
1034
1035   If :policy:`CMP0114` is not ``NEW``, the following deprecated behavior
1036   is available:
1037
1038   * A deprecated ``NO_DEPENDS`` option may be specified immediately after the
1039     ``<name>`` and before the first step.
1040     If the ``NO_DEPENDS`` option is specified, the step target will not depend
1041     on the dependencies of the external project (i.e. on any dependencies of the
1042     ``<name>`` custom target created by :command:`ExternalProject_Add`). This is
1043     usually safe for the ``download``, ``update`` and ``patch`` steps, since
1044     they do not typically require that the dependencies are updated and built.
1045     Using ``NO_DEPENDS`` for any of the other pre-defined steps, however, may
1046     break parallel builds. Only use ``NO_DEPENDS`` where it is certain that the
1047     named steps genuinely do not have dependencies. For custom steps, consider
1048     whether or not the custom commands require the dependencies to be
1049     configured, built and installed.
1050
1051   * The ``INDEPENDENT_STEP_TARGETS`` option for :command:`ExternalProject_Add`,
1052     or the ``EP_INDEPENDENT_STEP_TARGETS`` directory property, tells the
1053     function to call ``ExternalProject_Add_StepTargets()`` internally
1054     using the ``NO_DEPENDS`` option for the specified steps.
1055
1056 .. command:: ExternalProject_Add_StepDependencies
1057
1058   .. versionadded:: 3.2
1059
1060   The ``ExternalProject_Add_StepDependencies()`` function can be used to add
1061   dependencies to a step. The dependencies added must be targets CMake already
1062   knows about (these can be ordinary executable or library targets, custom
1063   targets or even step targets of another external project):
1064
1065   .. code-block:: cmake
1066
1067     ExternalProject_Add_StepDependencies(<name> <step> <target1> [<target2>...])
1068
1069   This function takes care to set both target and file level dependencies and
1070   will ensure that parallel builds will not break. It should be used instead of
1071   :command:`add_dependencies` whenever adding a dependency for some of the step
1072   targets generated by the ``ExternalProject`` module.
1073
1074 Examples
1075 ^^^^^^^^
1076
1077 The following example shows how to download and build a hypothetical project
1078 called *FooBar* from github:
1079
1080 .. code-block:: cmake
1081
1082   include(ExternalProject)
1083   ExternalProject_Add(foobar
1084     GIT_REPOSITORY    git@github.com:FooCo/FooBar.git
1085     GIT_TAG           origin/release/1.2.3
1086   )
1087
1088 For the sake of the example, also define a second hypothetical external project
1089 called *SecretSauce*, which is downloaded from a web server. Two URLs are given
1090 to take advantage of a faster internal network if available, with a fallback to
1091 a slower external server. The project is a typical ``Makefile`` project with no
1092 configure step, so some of the default commands are overridden. The build is
1093 only required to build the *sauce* target:
1094
1095 .. code-block:: cmake
1096
1097   find_program(MAKE_EXE NAMES gmake nmake make)
1098   ExternalProject_Add(secretsauce
1099     URL               http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
1100                       https://www.somecompany.com/downloads/sauce-2.7.zip
1101     URL_HASH          MD5=d41d8cd98f00b204e9800998ecf8427e
1102     CONFIGURE_COMMAND ""
1103     BUILD_COMMAND     ${MAKE_EXE} sauce
1104   )
1105
1106 Suppose the build step of ``secretsauce`` requires that ``foobar`` must already
1107 be built. This could be enforced like so:
1108
1109 .. code-block:: cmake
1110
1111   ExternalProject_Add_StepDependencies(secretsauce build foobar)
1112
1113 Another alternative would be to create a custom target for ``foobar``'s build
1114 step and make ``secretsauce`` depend on that rather than the whole ``foobar``
1115 project. This would mean ``foobar`` only needs to be built, it doesn't need to
1116 run its install or test steps before ``secretsauce`` can be built. The
1117 dependency can also be defined along with the ``secretsauce`` project:
1118
1119 .. code-block:: cmake
1120
1121   ExternalProject_Add_StepTargets(foobar build)
1122   ExternalProject_Add(secretsauce
1123     URL               http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
1124                       https://www.somecompany.com/downloads/sauce-2.7.zip
1125     URL_HASH          MD5=d41d8cd98f00b204e9800998ecf8427e
1126     CONFIGURE_COMMAND ""
1127     BUILD_COMMAND     ${MAKE_EXE} sauce
1128     DEPENDS           foobar-build
1129   )
1130
1131 Instead of calling :command:`ExternalProject_Add_StepTargets`, the target could
1132 be defined along with the ``foobar`` project itself:
1133
1134 .. code-block:: cmake
1135
1136   ExternalProject_Add(foobar
1137     GIT_REPOSITORY git@github.com:FooCo/FooBar.git
1138     GIT_TAG        origin/release/1.2.3
1139     STEP_TARGETS   build
1140   )
1141
1142 If many external projects should have the same set of step targets, setting a
1143 directory property may be more convenient. The ``build`` step target could be
1144 created automatically by setting the ``EP_STEP_TARGETS`` directory property
1145 before creating the external projects with :command:`ExternalProject_Add`:
1146
1147 .. code-block:: cmake
1148
1149   set_property(DIRECTORY PROPERTY EP_STEP_TARGETS build)
1150
1151 Lastly, suppose that ``secretsauce`` provides a script called ``makedoc`` which
1152 can be used to generate its own documentation. Further suppose that the script
1153 expects the output directory to be provided as the only parameter and that it
1154 should be run from the ``secretsauce`` source directory. A custom step and a
1155 custom target to trigger the script can be defined like so:
1156
1157 .. code-block:: cmake
1158
1159   ExternalProject_Add_Step(secretsauce docs
1160     COMMAND           <SOURCE_DIR>/makedoc <BINARY_DIR>
1161     WORKING_DIRECTORY <SOURCE_DIR>
1162     COMMENT           "Building secretsauce docs"
1163     ALWAYS            TRUE
1164     EXCLUDE_FROM_MAIN TRUE
1165   )
1166   ExternalProject_Add_StepTargets(secretsauce docs)
1167
1168 The custom step could then be triggered from the main build like so::
1169
1170   cmake --build . --target secretsauce-docs
1171
1172 #]=======================================================================]
1173
1174 cmake_policy(PUSH)
1175 cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
1176 cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST
1177
1178 macro(_ep_get_hash_algos out_var)
1179   set(${out_var}
1180     MD5
1181     SHA1
1182     SHA224
1183     SHA256
1184     SHA384
1185     SHA512
1186     SHA3_224
1187     SHA3_256
1188     SHA3_384
1189     SHA3_512
1190   )
1191 endmacro()
1192
1193 macro(_ep_get_hash_regex out_var)
1194   _ep_get_hash_algos(${out_var})
1195   list(JOIN ${out_var} "|" ${out_var})
1196   set(${out_var} "^(${${out_var}})=([0-9A-Fa-f]+)$")
1197 endmacro()
1198
1199 function(_ep_parse_arguments
1200   f
1201   keywords
1202   name
1203   ns
1204   args
1205 )
1206   # Transfer the arguments to this function into target properties for the
1207   # new custom target we just added so that we can set up all the build steps
1208   # correctly based on target properties.
1209   #
1210   # Because some keywords can be repeated, we can't use cmake_parse_arguments().
1211   # Instead, we loop through ARGN and consider the namespace starting with an
1212   # upper-case letter followed by at least two more upper-case letters,
1213   # numbers or underscores to be keywords.
1214
1215   set(key)
1216
1217   foreach(arg IN LISTS args)
1218     set(is_value 1)
1219
1220     if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
1221         NOT (("x${arg}x" STREQUAL "x${key}x") AND
1222              ("x${key}x" STREQUAL "xCOMMANDx")) AND
1223         NOT arg MATCHES "^(TRUE|FALSE)$")
1224       if(arg IN_LIST keywords)
1225         set(is_value 0)
1226       endif()
1227     endif()
1228
1229     if(is_value)
1230       if(key)
1231         # Value
1232         if(NOT arg STREQUAL "")
1233           set_property(TARGET ${name} APPEND PROPERTY ${ns}${key} "${arg}")
1234         else()
1235           get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
1236           if(have_key)
1237             get_property(value TARGET ${name} PROPERTY ${ns}${key})
1238             set_property(TARGET ${name} PROPERTY ${ns}${key} "${value};${arg}")
1239           else()
1240             set_property(TARGET ${name} PROPERTY ${ns}${key} "${arg}")
1241           endif()
1242         endif()
1243       else()
1244         # Missing Keyword
1245         message(AUTHOR_WARNING
1246           "value '${arg}' with no previous keyword in ${f}"
1247         )
1248       endif()
1249     else()
1250       set(key "${arg}")
1251     endif()
1252   endforeach()
1253 endfunction()
1254
1255
1256 define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED)
1257 define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED)
1258 define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED)
1259 define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED)
1260 define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED)
1261
1262 function(_ep_write_gitclone_script
1263   script_filename
1264   source_dir
1265   git_EXECUTABLE
1266   git_repository
1267   git_tag
1268   git_remote_name
1269   init_submodules
1270   git_submodules_recurse
1271   git_submodules
1272   git_shallow
1273   git_progress
1274   git_config
1275   src_name
1276   work_dir
1277   gitclone_infofile
1278   gitclone_stampfile
1279   tls_verify
1280 )
1281
1282   if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
1283     # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
1284     set(git_checkout_explicit-- "--")
1285   else()
1286     # Use `git checkout <branch>` even though this risks ambiguity with a
1287     # local path.  Unfortunately we cannot use `git checkout <tree-ish> --`
1288     # because that will not search for remote branch names, a common use case.
1289     set(git_checkout_explicit-- "")
1290   endif()
1291   if("${git_tag}" STREQUAL "")
1292     message(FATAL_ERROR "Tag for git checkout should not be empty.")
1293   endif()
1294
1295   if(GIT_VERSION_STRING VERSION_LESS 2.20 OR
1296      2.21 VERSION_LESS_EQUAL GIT_VERSION_STRING)
1297     set(git_clone_options "--no-checkout")
1298   else()
1299     set(git_clone_options)
1300   endif()
1301   if(git_shallow)
1302     if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
1303       list(APPEND git_clone_options "--depth 1 --no-single-branch")
1304     else()
1305       list(APPEND git_clone_options "--depth 1")
1306     endif()
1307   endif()
1308   if(git_progress)
1309     list(APPEND git_clone_options --progress)
1310   endif()
1311   foreach(config IN LISTS git_config)
1312     list(APPEND git_clone_options --config \"${config}\")
1313   endforeach()
1314   if(NOT ${git_remote_name} STREQUAL "origin")
1315     list(APPEND git_clone_options --origin \"${git_remote_name}\")
1316   endif()
1317
1318   string (REPLACE ";" " " git_clone_options "${git_clone_options}")
1319
1320   set(git_options)
1321   # disable cert checking if explicitly told not to do it
1322   if(NOT "x${tls_verify}" STREQUAL "x" AND NOT tls_verify)
1323     set(git_options
1324       -c http.sslVerify=false
1325     )
1326   endif()
1327   string (REPLACE ";" " " git_options "${git_options}")
1328
1329   configure_file(
1330     ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/gitclone.cmake.in
1331     ${script_filename}
1332     @ONLY
1333   )
1334 endfunction()
1335
1336 function(_ep_write_hgclone_script
1337   script_filename
1338   source_dir
1339   hg_EXECUTABLE
1340   hg_repository
1341   hg_tag
1342   src_name
1343   work_dir
1344   hgclone_infofile
1345   hgclone_stampfile
1346 )
1347
1348   if("${hg_tag}" STREQUAL "")
1349     message(FATAL_ERROR "Tag for hg checkout should not be empty.")
1350   endif()
1351
1352   configure_file(
1353     ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/hgclone.cmake.in
1354     ${script_filename}
1355     @ONLY
1356   )
1357 endfunction()
1358
1359
1360 function(_ep_write_gitupdate_script
1361   script_filename
1362   git_EXECUTABLE
1363   git_tag
1364   git_remote_name
1365   init_submodules
1366   git_submodules_recurse
1367   git_submodules
1368   git_repository
1369   work_dir
1370   git_update_strategy
1371 )
1372
1373   if("${git_tag}" STREQUAL "")
1374     message(FATAL_ERROR "Tag for git checkout should not be empty.")
1375   endif()
1376   set(git_stash_save_options --quiet)
1377   if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7)
1378     # This avoids stashing files covered by .gitignore
1379     list(APPEND git_stash_save_options --include-untracked)
1380   elseif(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.6)
1381     # Untracked files, but also ignored files, so potentially slower
1382     list(APPEND git_stash_save_options --all)
1383   endif()
1384
1385   configure_file(
1386       "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/gitupdate.cmake.in"
1387       "${script_filename}"
1388       @ONLY
1389   )
1390 endfunction()
1391
1392 function(_ep_write_downloadfile_script
1393   script_filename
1394   REMOTE
1395   LOCAL
1396   timeout
1397   inactivity_timeout
1398   no_progress
1399   hash
1400   tls_verify
1401   tls_cainfo
1402   userpwd
1403   http_headers
1404   netrc
1405   netrc_file
1406 )
1407   if(timeout)
1408     set(TIMEOUT_ARGS TIMEOUT ${timeout})
1409     set(TIMEOUT_MSG "${timeout} seconds")
1410   else()
1411     set(TIMEOUT_ARGS "# no TIMEOUT")
1412     set(TIMEOUT_MSG "none")
1413   endif()
1414   if(inactivity_timeout)
1415     set(INACTIVITY_TIMEOUT_ARGS INACTIVITY_TIMEOUT ${inactivity_timeout})
1416     set(INACTIVITY_TIMEOUT_MSG "${inactivity_timeout} seconds")
1417   else()
1418     set(INACTIVITY_TIMEOUT_ARGS "# no INACTIVITY_TIMEOUT")
1419     set(INACTIVITY_TIMEOUT_MSG "none")
1420   endif()
1421
1422   if(no_progress)
1423     set(SHOW_PROGRESS "")
1424   else()
1425     set(SHOW_PROGRESS "SHOW_PROGRESS")
1426   endif()
1427
1428   _ep_get_hash_regex(_ep_hash_regex)
1429   if("${hash}" MATCHES "${_ep_hash_regex}")
1430     set(ALGO "${CMAKE_MATCH_1}")
1431     string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
1432   else()
1433     set(ALGO "")
1434     set(EXPECT_VALUE "")
1435   endif()
1436
1437   set(TLS_VERIFY_CODE "")
1438   set(TLS_CAINFO_CODE "")
1439   set(NETRC_CODE "")
1440   set(NETRC_FILE_CODE "")
1441
1442   # check for curl globals in the project
1443   if(DEFINED CMAKE_TLS_VERIFY)
1444     set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY ${CMAKE_TLS_VERIFY})")
1445   endif()
1446   if(DEFINED CMAKE_TLS_CAINFO)
1447     set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${CMAKE_TLS_CAINFO}\")")
1448   endif()
1449   if(DEFINED CMAKE_NETRC)
1450     set(NETRC_CODE "set(CMAKE_NETRC \"${CMAKE_NETRC}\")")
1451   endif()
1452   if(DEFINED CMAKE_NETRC_FILE)
1453     set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${CMAKE_NETRC_FILE}\")")
1454   endif()
1455
1456   # now check for curl locals so that the local values
1457   # will override the globals
1458
1459   # check for tls_verify argument
1460   string(LENGTH "${tls_verify}" tls_verify_len)
1461   if(tls_verify_len GREATER 0)
1462     set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY ${tls_verify})")
1463   endif()
1464   # check for tls_cainfo argument
1465   string(LENGTH "${tls_cainfo}" tls_cainfo_len)
1466   if(tls_cainfo_len GREATER 0)
1467     set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")")
1468   endif()
1469   # check for netrc argument
1470   string(LENGTH "${netrc}" netrc_len)
1471   if(netrc_len GREATER 0)
1472     set(NETRC_CODE "set(CMAKE_NETRC \"${netrc}\")")
1473   endif()
1474   # check for netrc_file argument
1475   string(LENGTH "${netrc_file}" netrc_file_len)
1476   if(netrc_file_len GREATER 0)
1477     set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${netrc_file}\")")
1478   endif()
1479
1480   if(userpwd STREQUAL ":")
1481     set(USERPWD_ARGS)
1482   else()
1483     set(USERPWD_ARGS USERPWD "${userpwd}")
1484   endif()
1485
1486   set(HTTP_HEADERS_ARGS "")
1487   if(NOT http_headers STREQUAL "")
1488     foreach(header ${http_headers})
1489       string(PREPEND HTTP_HEADERS_ARGS
1490         "HTTPHEADER \"${header}\"\n        "
1491       )
1492     endforeach()
1493   endif()
1494
1495   # Used variables:
1496   # * TLS_VERIFY_CODE
1497   # * TLS_CAINFO_CODE
1498   # * ALGO
1499   # * EXPECT_VALUE
1500   # * REMOTE
1501   # * LOCAL
1502   # * SHOW_PROGRESS
1503   # * TIMEOUT_ARGS
1504   # * TIMEOUT_MSG
1505   # * USERPWD_ARGS
1506   # * HTTP_HEADERS_ARGS
1507   configure_file(
1508     "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/download.cmake.in"
1509     "${script_filename}"
1510     @ONLY
1511   )
1512 endfunction()
1513
1514 function(_ep_write_verifyfile_script
1515   script_filename
1516   LOCAL
1517   hash
1518 )
1519   _ep_get_hash_regex(_ep_hash_regex)
1520   if("${hash}" MATCHES "${_ep_hash_regex}")
1521     set(ALGO "${CMAKE_MATCH_1}")
1522     string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
1523   else()
1524     set(ALGO "")
1525     set(EXPECT_VALUE "")
1526   endif()
1527
1528   # Used variables:
1529   # * ALGO
1530   # * EXPECT_VALUE
1531   # * LOCAL
1532   configure_file(
1533     "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/verify.cmake.in"
1534     "${script_filename}"
1535     @ONLY
1536   )
1537 endfunction()
1538
1539
1540 function(_ep_write_extractfile_script
1541   script_filename
1542   name
1543   filename
1544   directory options
1545 )
1546   set(args "")
1547
1548   if(filename MATCHES
1549      "(\\.|=)(7z|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$")
1550     set(args xfz)
1551   endif()
1552
1553   if(filename MATCHES "(\\.|=)tar$")
1554     set(args xf)
1555   endif()
1556
1557   if(args STREQUAL "")
1558     message(FATAL_ERROR
1559       "Do not know how to extract '${filename}' -- known types are: "
1560       ".7z, .tar, .tar.bz2, .tar.gz, .tar.xz, .tbz2, .tgz, .txz and .zip"
1561     )
1562   endif()
1563
1564   configure_file(
1565     "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/extractfile.cmake.in"
1566     "${script_filename}"
1567     @ONLY
1568   )
1569 endfunction()
1570
1571
1572 function(_ep_set_directories name)
1573   get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX)
1574   if(NOT prefix)
1575     get_property(prefix DIRECTORY PROPERTY EP_PREFIX)
1576     if(NOT prefix)
1577       get_property(base DIRECTORY PROPERTY EP_BASE)
1578       if(NOT base)
1579         set(prefix "${name}-prefix")
1580       endif()
1581     endif()
1582   endif()
1583   if(prefix)
1584     file(TO_CMAKE_PATH "${prefix}" prefix)
1585     set(tmp_default "${prefix}/tmp")
1586     set(download_default "${prefix}/src")
1587     set(source_default "${prefix}/src/${name}")
1588     set(binary_default "${prefix}/src/${name}-build")
1589     set(stamp_default "${prefix}/src/${name}-stamp")
1590     set(install_default "${prefix}")
1591   else()
1592     file(TO_CMAKE_PATH "${base}" base)
1593     set(tmp_default "${base}/tmp/${name}")
1594     set(download_default "${base}/Download/${name}")
1595     set(source_default "${base}/Source/${name}")
1596     set(binary_default "${base}/Build/${name}")
1597     set(stamp_default "${base}/Stamp/${name}")
1598     set(install_default "${base}/Install/${name}")
1599   endif()
1600   get_property(build_in_source TARGET ${name} PROPERTY _EP_BUILD_IN_SOURCE)
1601   if(build_in_source)
1602     get_property(have_binary_dir TARGET ${name} PROPERTY _EP_BINARY_DIR SET)
1603     if(have_binary_dir)
1604       message(FATAL_ERROR
1605         "External project ${name} has both BINARY_DIR and BUILD_IN_SOURCE!"
1606       )
1607     endif()
1608   endif()
1609   set(top "${CMAKE_CURRENT_BINARY_DIR}")
1610
1611   # Apply defaults and convert to absolute paths.
1612   set(places stamp download source binary install tmp)
1613   foreach(var ${places})
1614     string(TOUPPER "${var}" VAR)
1615     get_property(${var}_dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
1616     if(NOT ${var}_dir)
1617       set(${var}_dir "${${var}_default}")
1618     endif()
1619     if(NOT IS_ABSOLUTE "${${var}_dir}")
1620       get_filename_component(${var}_dir "${top}/${${var}_dir}" ABSOLUTE)
1621     endif()
1622     file(TO_CMAKE_PATH "${${var}_dir}" ${var}_dir)
1623     set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
1624   endforeach()
1625
1626   # Special case for default log directory based on stamp directory.
1627   get_property(log_dir TARGET ${name} PROPERTY _EP_LOG_DIR)
1628   if(NOT log_dir)
1629     get_property(log_dir TARGET ${name} PROPERTY _EP_STAMP_DIR)
1630   endif()
1631   if(NOT IS_ABSOLUTE "${log_dir}")
1632     get_filename_component(log_dir "${top}/${log_dir}" ABSOLUTE)
1633   endif()
1634   file(TO_CMAKE_PATH "${log_dir}" log_dir)
1635   set_property(TARGET ${name} PROPERTY _EP_LOG_DIR "${log_dir}")
1636
1637   get_property(source_subdir TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR)
1638   if(NOT source_subdir)
1639     set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "")
1640   elseif(IS_ABSOLUTE "${source_subdir}")
1641     message(FATAL_ERROR
1642       "External project ${name} has non-relative SOURCE_SUBDIR!"
1643     )
1644   else()
1645     # Prefix with a slash so that when appended to the source directory, it
1646     # behaves as expected.
1647     file(TO_CMAKE_PATH "${source_subdir}" source_subdir)
1648     set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "/${source_subdir}")
1649   endif()
1650   if(build_in_source)
1651     get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR)
1652     if(source_subdir)
1653       set_property(TARGET ${name} PROPERTY
1654         _EP_BINARY_DIR "${source_dir}/${source_subdir}"
1655       )
1656     else()
1657       set_property(TARGET ${name} PROPERTY
1658         _EP_BINARY_DIR "${source_dir}"
1659       )
1660     endif()
1661   endif()
1662
1663   # This script will be used both here and by the mkdir step. We create the
1664   # directories now at configure time and ensure they exist again at build
1665   # time (since somebody might remove one of the required directories and try
1666   # to rebuild without re-running cmake). They need to exist now at makefile
1667   # generation time for Borland make and wmake so that CMake may generate
1668   # makefiles with "cd C:\short\paths\with\no\spaces" commands in them.
1669   set(script_filename "${tmp_dir}/${name}-mkdirs.cmake")
1670   configure_file(
1671     ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/mkdirs.cmake.in
1672     ${script_filename}
1673     @ONLY
1674   )
1675   unset(cfgdir) # do not leak into mkdirs.cmake script
1676   include(${script_filename})
1677 endfunction()
1678
1679
1680 # IMPORTANT: this MUST be a macro and not a function because of the
1681 # in-place replacements that occur in each ${var}
1682 #
1683 macro(_ep_replace_location_tags target_name)
1684   set(vars ${ARGN})
1685   foreach(var ${vars})
1686     if(${var})
1687       foreach(dir
1688         SOURCE_DIR
1689         SOURCE_SUBDIR
1690         BINARY_DIR
1691         INSTALL_DIR
1692         TMP_DIR
1693         DOWNLOAD_DIR
1694         DOWNLOADED_FILE
1695         LOG_DIR
1696       )
1697         get_property(val TARGET ${target_name} PROPERTY _EP_${dir})
1698         string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}")
1699       endforeach()
1700     endif()
1701   endforeach()
1702 endmacro()
1703
1704
1705 function(_ep_command_line_to_initial_cache
1706   var
1707   args
1708   force
1709 )
1710   set(script_initial_cache "")
1711   set(regex "^([^:]+):([^=]+)=(.*)$")
1712   set(setArg "")
1713   set(forceArg "")
1714   if(force)
1715     set(forceArg "FORCE")
1716   endif()
1717   foreach(line ${args})
1718     if("${line}" MATCHES "^-D(.*)")
1719       set(line "${CMAKE_MATCH_1}")
1720       if(NOT "${setArg}" STREQUAL "")
1721         # This is required to build up lists in variables, or complete an entry
1722         string(APPEND setArg
1723           "${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})"
1724         )
1725         string(APPEND script_initial_cache "\n${setArg}")
1726         set(accumulator "")
1727         set(setArg "")
1728       endif()
1729       if("${line}" MATCHES "${regex}")
1730         set(name "${CMAKE_MATCH_1}")
1731         set(type "${CMAKE_MATCH_2}")
1732         set(value "${CMAKE_MATCH_3}")
1733         set(setArg "set(${name} \"${value}")
1734       else()
1735         message(WARNING "Line '${line}' does not match regex. Ignoring.")
1736       endif()
1737     else()
1738       # Assume this is a list to append to the last var
1739       string(APPEND accumulator ";${line}")
1740     endif()
1741   endforeach()
1742   # Catch the final line of the args
1743   if(NOT "${setArg}" STREQUAL "")
1744     string(APPEND setArg
1745       "${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})"
1746     )
1747     string(APPEND script_initial_cache "\n${setArg}")
1748   endif()
1749   set(${var} ${script_initial_cache} PARENT_SCOPE)
1750 endfunction()
1751
1752
1753 function(_ep_write_initial_cache
1754   target_name
1755   script_filename
1756   script_initial_cache
1757 )
1758   # Write out values into an initial cache, that will be passed to CMake with -C
1759   # Replace location tags.
1760   _ep_replace_location_tags(${target_name} script_initial_cache)
1761   _ep_replace_location_tags(${target_name} script_filename)
1762   # Replace list separators.
1763   get_property(sep TARGET ${target_name} PROPERTY _EP_LIST_SEPARATOR)
1764   if(sep AND script_initial_cache)
1765     string(REPLACE "${sep}" ";" script_initial_cache "${script_initial_cache}")
1766   endif()
1767   # Write out the initial cache file to the location specified.
1768   file(GENERATE OUTPUT "${script_filename}" CONTENT "${script_initial_cache}")
1769 endfunction()
1770
1771
1772 function(ExternalProject_Get_Property name)
1773   foreach(var ${ARGN})
1774     string(TOUPPER "${var}" VAR)
1775     get_property(is_set TARGET ${name} PROPERTY _EP_${VAR} SET)
1776     if(NOT is_set)
1777       message(FATAL_ERROR "External project \"${name}\" has no ${var}")
1778     endif()
1779     get_property(${var} TARGET ${name} PROPERTY _EP_${VAR})
1780     set(${var} "${${var}}" PARENT_SCOPE)
1781   endforeach()
1782 endfunction()
1783
1784
1785 function(_ep_get_configure_command_id
1786   name
1787   cfg_cmd_id_var
1788 )
1789   get_target_property(cmd ${name} _EP_CONFIGURE_COMMAND)
1790
1791   if(cmd STREQUAL "")
1792     # Explicit empty string means no configure step for this project
1793     set(${cfg_cmd_id_var} "none" PARENT_SCOPE)
1794   else()
1795     if(NOT cmd)
1796       # Default is "use cmake":
1797       set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
1798     else()
1799       # Otherwise we have to analyze the value:
1800       if(cmd MATCHES "^[^;]*/configure")
1801         set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
1802       elseif(cmd MATCHES "^[^;]*/cmake" AND NOT cmd MATCHES ";-[PE];")
1803         set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
1804       elseif(cmd MATCHES "config")
1805         set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
1806       else()
1807         set(${cfg_cmd_id_var} "unknown:${cmd}" PARENT_SCOPE)
1808       endif()
1809     endif()
1810   endif()
1811 endfunction()
1812
1813
1814 function(_ep_get_build_command
1815   name
1816   step
1817   cmd_var
1818 )
1819   set(cmd "")
1820   set(args)
1821   _ep_get_configure_command_id(${name} cfg_cmd_id)
1822   if(cfg_cmd_id STREQUAL "cmake")
1823     # CMake project.  Select build command based on generator.
1824     get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
1825     if("${CMAKE_GENERATOR}" MATCHES "Make" AND
1826        ("${cmake_generator}" MATCHES "Make" OR NOT cmake_generator))
1827       # The project uses the same Makefile generator.  Use recursive make.
1828       set(cmd "$(MAKE)")
1829       if(step STREQUAL "INSTALL")
1830         set(args install)
1831       endif()
1832       if("x${step}x" STREQUAL "xTESTx")
1833         set(args test)
1834       endif()
1835     else()
1836       # Drive the project with "cmake --build".
1837       get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
1838       if(cmake_command)
1839         set(cmd "${cmake_command}")
1840       else()
1841         set(cmd "${CMAKE_COMMAND}")
1842       endif()
1843       set(args --build ".")
1844       get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
1845       if(_isMultiConfig)
1846         if (CMAKE_CFG_INTDIR AND
1847             NOT CMAKE_CFG_INTDIR STREQUAL "." AND
1848             NOT CMAKE_CFG_INTDIR MATCHES "\\$")
1849           # CMake 3.4 and below used the CMAKE_CFG_INTDIR placeholder value
1850           # provided by multi-configuration generators.  Some projects were
1851           # taking advantage of that undocumented implementation detail to
1852           # specify a specific configuration here.  They should use
1853           # BUILD_COMMAND to change the default command instead, but for
1854           # compatibility honor the value.
1855           set(config ${CMAKE_CFG_INTDIR})
1856           message(AUTHOR_WARNING
1857             "CMAKE_CFG_INTDIR should not be set by project code.\n"
1858             "To get a non-default build command, use the BUILD_COMMAND option."
1859           )
1860         else()
1861           set(config $<CONFIG>)
1862         endif()
1863         list(APPEND args --config ${config})
1864       endif()
1865       if(step STREQUAL "INSTALL")
1866         list(APPEND args --target install)
1867       endif()
1868       # But for "TEST" drive the project with corresponding "ctest".
1869       if("x${step}x" STREQUAL "xTESTx")
1870         string(REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}")
1871         set(args "")
1872         if(_isMultiConfig)
1873           list(APPEND args -C ${config})
1874         endif()
1875       endif()
1876     endif()
1877   else()
1878     # Non-CMake project.  Guess "make" and "make install" and "make test".
1879     if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
1880       # Try to get the parallel arguments
1881       set(cmd "$(MAKE)")
1882     else()
1883       set(cmd "make")
1884     endif()
1885     if(step STREQUAL "INSTALL")
1886       set(args install)
1887     endif()
1888     if("x${step}x" STREQUAL "xTESTx")
1889       set(args test)
1890     endif()
1891   endif()
1892
1893   # Use user-specified arguments instead of default arguments, if any.
1894   get_property(have_args TARGET ${name} PROPERTY _EP_${step}_ARGS SET)
1895   if(have_args)
1896     get_target_property(args ${name} _EP_${step}_ARGS)
1897   endif()
1898
1899   if(NOT "${args}" STREQUAL "")
1900     # args could have empty items, so we must quote it to prevent them
1901     # from being silently removed
1902     list(APPEND cmd "${args}")
1903   endif()
1904   set(${cmd_var} "${cmd}" PARENT_SCOPE)
1905 endfunction()
1906
1907 function(_ep_write_log_script
1908   name
1909   step
1910   cmd_var
1911 )
1912   ExternalProject_Get_Property(${name} log_dir)
1913   ExternalProject_Get_Property(${name} stamp_dir)
1914   set(command "${${cmd_var}}")
1915
1916   set(make "")
1917   set(code_cygpath_make "")
1918   if(command MATCHES "^\\$\\(MAKE\\)")
1919     # GNU make recognizes the string "$(MAKE)" as recursive make, so
1920     # ensure that it appears directly in the makefile.
1921     string(REGEX REPLACE "^\\$\\(MAKE\\)" "\${make}" command "${command}")
1922     set(make "-Dmake=$(MAKE)")
1923
1924     if(WIN32 AND NOT CYGWIN)
1925       set(code_cygpath_make "
1926 if(\${make} MATCHES \"^/\")
1927   execute_process(
1928     COMMAND cygpath -w \${make}
1929     OUTPUT_VARIABLE cygpath_make
1930     ERROR_VARIABLE cygpath_make
1931     RESULT_VARIABLE cygpath_error
1932     OUTPUT_STRIP_TRAILING_WHITESPACE
1933   )
1934   if(NOT cygpath_error)
1935     set(make \${cygpath_make})
1936   endif()
1937 endif()
1938 ")
1939     endif()
1940   endif()
1941
1942   set(config "")
1943   if("${CMAKE_CFG_INTDIR}" MATCHES "^\\$")
1944     string(REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}")
1945     set(config "-Dconfig=${CMAKE_CFG_INTDIR}")
1946   endif()
1947
1948   # Wrap multiple 'COMMAND' lines up into a second-level wrapper
1949   # script so all output can be sent to one log file.
1950   if(command MATCHES "(^|;)COMMAND;")
1951     set(code_execute_process "
1952 ${code_cygpath_make}
1953 execute_process(COMMAND \${command} RESULT_VARIABLE result)
1954 if(result)
1955   set(msg \"Command failed (\${result}):\\n\")
1956   foreach(arg IN LISTS command)
1957     set(msg \"\${msg} '\${arg}'\")
1958   endforeach()
1959   message(FATAL_ERROR \"\${msg}\")
1960 endif()
1961 ")
1962     set(code "")
1963     set(cmd "")
1964     set(sep "")
1965     foreach(arg IN LISTS command)
1966       if("x${arg}" STREQUAL "xCOMMAND")
1967         if(NOT "x${cmd}" STREQUAL "x")
1968           string(APPEND code "set(command \"${cmd}\")${code_execute_process}")
1969         endif()
1970         set(cmd "")
1971         set(sep "")
1972       else()
1973         string(APPEND cmd "${sep}${arg}")
1974         set(sep ";")
1975       endif()
1976     endforeach()
1977     string(APPEND code "set(command \"${cmd}\")${code_execute_process}")
1978     file(GENERATE
1979       OUTPUT "${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake"
1980       CONTENT "${code}"
1981     )
1982     set(command
1983       ${CMAKE_COMMAND}
1984       "-Dmake=\${make}"
1985       "-Dconfig=\${config}"
1986       -P ${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake
1987     )
1988   endif()
1989
1990   # Wrap the command in a script to log output to files.
1991   set(script ${stamp_dir}/${name}-${step}-$<CONFIG>.cmake)
1992   set(logbase ${log_dir}/${name}-${step})
1993   get_property(log_merged
1994     TARGET ${name}
1995     PROPERTY _EP_LOG_MERGED_STDOUTERR
1996   )
1997   get_property(log_output_on_failure
1998     TARGET ${name}
1999     PROPERTY _EP_LOG_OUTPUT_ON_FAILURE
2000   )
2001   if (log_merged)
2002     set(stdout_log "${logbase}.log")
2003     set(stderr_log "${logbase}.log")
2004   else()
2005     set(stdout_log "${logbase}-out.log")
2006     set(stderr_log "${logbase}-err.log")
2007   endif()
2008   set(code "
2009 cmake_minimum_required(VERSION 3.15)
2010 ${code_cygpath_make}
2011 set(command \"${command}\")
2012 set(log_merged \"${log_merged}\")
2013 set(log_output_on_failure \"${log_output_on_failure}\")
2014 set(stdout_log \"${stdout_log}\")
2015 set(stderr_log \"${stderr_log}\")
2016 execute_process(
2017   COMMAND \${command}
2018   RESULT_VARIABLE result
2019   OUTPUT_FILE \"\${stdout_log}\"
2020   ERROR_FILE \"\${stderr_log}\"
2021 )
2022 macro(read_up_to_max_size log_file output_var)
2023   file(SIZE \${log_file} determined_size)
2024   set(max_size 10240)
2025   if (determined_size GREATER max_size)
2026     math(EXPR seek_position \"\${determined_size} - \${max_size}\")
2027     file(READ \${log_file} \${output_var} OFFSET \${seek_position})
2028     set(\${output_var} \"...skipping to end...\\n\${\${output_var}}\")
2029   else()
2030     file(READ \${log_file} \${output_var})
2031   endif()
2032 endmacro()
2033 if(result)
2034   set(msg \"Command failed: \${result}\\n\")
2035   foreach(arg IN LISTS command)
2036     set(msg \"\${msg} '\${arg}'\")
2037   endforeach()
2038   if (\${log_merged})
2039     set(msg \"\${msg}\\nSee also\\n  \${stderr_log}\")
2040   else()
2041     set(msg \"\${msg}\\nSee also\\n  ${logbase}-*.log\")
2042   endif()
2043   if (\${log_output_on_failure})
2044     message(SEND_ERROR \"\${msg}\")
2045     if (\${log_merged})
2046       read_up_to_max_size(\"\${stderr_log}\" error_log_contents)
2047       message(STATUS \"Log output is:\\n\${error_log_contents}\")
2048     else()
2049       read_up_to_max_size(\"\${stdout_log}\" out_log_contents)
2050       read_up_to_max_size(\"\${stderr_log}\" err_log_contents)
2051       message(STATUS \"stdout output is:\\n\${out_log_contents}\")
2052       message(STATUS \"stderr output is:\\n\${err_log_contents}\")
2053     endif()
2054     message(FATAL_ERROR \"Stopping after outputting logs.\")
2055   else()
2056     message(FATAL_ERROR \"\${msg}\")
2057   endif()
2058 else()
2059   if(NOT \"${CMAKE_GENERATOR}\" MATCHES \"Ninja\")
2060     set(msg \"${name} ${step} command succeeded.  See also ${logbase}-*.log\")
2061     message(STATUS \"\${msg}\")
2062   endif()
2063 endif()
2064 ")
2065   file(GENERATE OUTPUT "${script}" CONTENT "${code}")
2066   set(command ${CMAKE_COMMAND} ${make} ${config} -P ${script})
2067   set(${cmd_var} "${command}" PARENT_SCOPE)
2068 endfunction()
2069
2070 # On multi-config generators, provide a placeholder for a per-config subdir.
2071 # On single-config generators, this is empty.
2072 function(_ep_get_configuration_subdir_genex suffix_var)
2073   set(suffix "")
2074   get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
2075   if(_isMultiConfig)
2076     if(CMAKE_GENERATOR STREQUAL "Xcode")
2077       # The Xcode generator does not support per-config sources,
2078       # so use the underlying build system's placeholder instead.
2079       set(suffix "/${CMAKE_CFG_INTDIR}")
2080     else()
2081       set(suffix "/$<CONFIG>")
2082     endif()
2083   endif()
2084   set(${suffix_var} "${suffix}" PARENT_SCOPE)
2085 endfunction()
2086
2087
2088 function(_ep_get_step_stampfile
2089   name
2090   step
2091   stampfile_var
2092 )
2093   ExternalProject_Get_Property(${name} stamp_dir)
2094
2095   _ep_get_configuration_subdir_genex(cfgdir)
2096   set(stampfile "${stamp_dir}${cfgdir}/${name}-${step}")
2097
2098   set(${stampfile_var} "${stampfile}" PARENT_SCOPE)
2099 endfunction()
2100
2101
2102 function(_ep_get_complete_stampfile
2103   name
2104   stampfile_var
2105 )
2106   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
2107   _ep_get_configuration_subdir_genex(cfgdir)
2108   set(stampfile "${cmf_dir}${cfgdir}/${name}-complete")
2109
2110   set(${stampfile_var} ${stampfile} PARENT_SCOPE)
2111 endfunction()
2112
2113
2114 function(_ep_step_add_target
2115   name
2116   step
2117   no_deps
2118 )
2119   if(TARGET ${name}-${step})
2120     return()
2121   endif()
2122   get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
2123   _ep_get_step_stampfile(${name} ${step} stamp_file)
2124   cmake_policy(PUSH)
2125   if(cmp0114 STREQUAL "NEW")
2126     # To implement CMP0114 NEW behavior with Makefile generators,
2127     # we need CMP0113 NEW behavior.
2128     cmake_policy(SET CMP0113 NEW)
2129   endif()
2130   add_custom_target(${name}-${step} DEPENDS ${stamp_file})
2131   cmake_policy(POP)
2132   set_target_properties(${name}-${step} PROPERTIES
2133     _EP_IS_EXTERNAL_PROJECT_STEP 1
2134     LABELS "${name}"
2135     FOLDER "ExternalProjectTargets/${name}"
2136   )
2137
2138   if(cmp0114 STREQUAL "NEW")
2139     # Add target-level dependencies for the step.
2140     get_property(exclude_from_main
2141       TARGET ${name}
2142       PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN
2143     )
2144     if(NOT exclude_from_main)
2145       add_dependencies(${name} ${name}-${step})
2146     endif()
2147     _ep_step_add_target_dependencies(${name} ${step} ${step})
2148     _ep_step_add_target_dependents(${name} ${step} ${step})
2149
2150     get_property(independent TARGET ${name} PROPERTY _EP_${step}_INDEPENDENT)
2151   else()
2152     if(no_deps AND "${step}" MATCHES "^(configure|build|install|test)$")
2153       message(AUTHOR_WARNING
2154         "Using NO_DEPENDS for \"${step}\" step  might break parallel builds"
2155       )
2156     endif()
2157     set(independent ${no_deps})
2158   endif()
2159
2160   # Depend on other external projects (target-level).
2161   if(NOT independent)
2162     get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
2163     foreach(arg IN LISTS deps)
2164       add_dependencies(${name}-${step} ${arg})
2165     endforeach()
2166   endif()
2167 endfunction()
2168
2169
2170 function(_ep_step_add_target_dependencies
2171   name
2172   step
2173   node
2174 )
2175   get_property(dependees
2176     TARGET ${name}
2177     PROPERTY _EP_${node}_INTERNAL_DEPENDEES
2178   )
2179   list(REMOVE_DUPLICATES dependees)
2180   foreach(dependee IN LISTS dependees)
2181     get_property(exclude_from_main
2182       TARGET ${name}
2183       PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN
2184     )
2185     get_property(dependee_dependers
2186       TARGET ${name}
2187       PROPERTY _EP_${dependee}_INTERNAL_DEPENDERS
2188     )
2189     if(exclude_from_main OR dependee_dependers MATCHES ";")
2190       # The step on which our step target depends itself has
2191       # dependents in multiple targes.  It needs a step target too
2192       # so that there is a unique place for its custom command.
2193       _ep_step_add_target("${name}" "${dependee}" "FALSE")
2194     endif()
2195
2196     if(TARGET ${name}-${dependee})
2197       add_dependencies(${name}-${step} ${name}-${dependee})
2198     else()
2199       _ep_step_add_target_dependencies(${name} ${step} ${dependee})
2200     endif()
2201   endforeach()
2202 endfunction()
2203
2204
2205 function(_ep_step_add_target_dependents
2206   name
2207   step
2208   node
2209 )
2210   get_property(dependers
2211     TARGET ${name}
2212     PROPERTY _EP_${node}_INTERNAL_DEPENDERS
2213   )
2214   list(REMOVE_DUPLICATES dependers)
2215   foreach(depender IN LISTS dependers)
2216     if(TARGET ${name}-${depender})
2217       add_dependencies(${name}-${depender} ${name}-${step})
2218     else()
2219       _ep_step_add_target_dependents(${name} ${step} ${depender})
2220     endif()
2221   endforeach()
2222 endfunction()
2223
2224
2225 function(ExternalProject_Add_StepTargets name)
2226   get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
2227   set(steps ${ARGN})
2228   if(ARGC GREATER 1 AND "${ARGV1}" STREQUAL "NO_DEPENDS")
2229     set(no_deps 1)
2230     list(REMOVE_AT steps 0)
2231   else()
2232     set(no_deps 0)
2233   endif()
2234   if(cmp0114 STREQUAL "NEW")
2235     if(no_deps)
2236       message(FATAL_ERROR
2237         "The 'NO_DEPENDS' option is no longer allowed.  "
2238         "It has been superseded by the per-step 'INDEPENDENT' option.  "
2239         "See policy CMP0114."
2240       )
2241     endif()
2242   elseif(cmp0114 STREQUAL "")
2243     cmake_policy(GET_WARNING CMP0114 _cmp0114_warning)
2244     string(APPEND _cmp0114_warning "\n"
2245       "ExternalProject target '${name}' would depend on the targets for "
2246       "step(s) '${steps}' under policy CMP0114, but this is being left out "
2247       "for compatibility since the policy is not set."
2248     )
2249     if(no_deps)
2250       string(APPEND _cmp0114_warning "  "
2251         "Also, the NO_DEPENDS option is deprecated in favor of policy CMP0114."
2252       )
2253     endif()
2254     message(AUTHOR_WARNING "${_cmp0114_warning}")
2255   endif()
2256   foreach(step ${steps})
2257     _ep_step_add_target("${name}" "${step}" "${no_deps}")
2258   endforeach()
2259 endfunction()
2260
2261
2262 function(ExternalProject_Add_Step name step)
2263   get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
2264   _ep_get_complete_stampfile(${name} complete_stamp_file)
2265   _ep_get_step_stampfile(${name} ${step} stamp_file)
2266
2267   set(keywords
2268     COMMAND
2269     COMMENT
2270     DEPENDEES
2271     DEPENDERS
2272     DEPENDS
2273     INDEPENDENT
2274     BYPRODUCTS
2275     ALWAYS
2276     EXCLUDE_FROM_MAIN
2277     WORKING_DIRECTORY
2278     LOG
2279     USES_TERMINAL
2280   )
2281   _ep_parse_arguments(
2282     ExternalProject_Add_Step
2283     "${keywords}"
2284     ${name}
2285     _EP_${step}_
2286     "${ARGN}"
2287   )
2288
2289   get_property(independent
2290     TARGET ${name}
2291     PROPERTY _EP_${step}_INDEPENDENT
2292   )
2293   if(independent STREQUAL "")
2294     set(independent FALSE)
2295     set_property(TARGET ${name} PROPERTY
2296       _EP_${step}_INDEPENDENT "${independent}"
2297     )
2298   endif()
2299
2300   get_property(exclude_from_main
2301     TARGET ${name}
2302     PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN
2303   )
2304   if(NOT exclude_from_main)
2305     add_custom_command(APPEND
2306       OUTPUT ${complete_stamp_file}
2307       DEPENDS ${stamp_file}
2308     )
2309   endif()
2310
2311   # Steps depending on this step.
2312   get_property(dependers TARGET ${name} PROPERTY _EP_${step}_DEPENDERS)
2313   set_property(TARGET ${name} APPEND PROPERTY
2314     _EP_${step}_INTERNAL_DEPENDERS ${dependers}
2315   )
2316   foreach(depender IN LISTS dependers)
2317     set_property(TARGET ${name} APPEND PROPERTY
2318       _EP_${depender}_INTERNAL_DEPENDEES ${step}
2319     )
2320     _ep_get_step_stampfile(${name} ${depender} depender_stamp_file)
2321     add_custom_command(APPEND
2322       OUTPUT ${depender_stamp_file}
2323       DEPENDS ${stamp_file}
2324     )
2325     if(cmp0114 STREQUAL "NEW" AND NOT independent)
2326       get_property(dep_independent
2327         TARGET ${name}
2328         PROPERTY _EP_${depender}_INDEPENDENT
2329       )
2330       if(dep_independent)
2331         message(FATAL_ERROR
2332           "ExternalProject '${name}' step '${depender}' is marked INDEPENDENT "
2333           "but depends on step '${step}' that is not marked INDEPENDENT."
2334         )
2335       endif()
2336     endif()
2337   endforeach()
2338
2339   # Dependencies on files.
2340   get_property(depends TARGET ${name} PROPERTY _EP_${step}_DEPENDS)
2341
2342   # Byproducts of the step.
2343   get_property(byproducts TARGET ${name} PROPERTY _EP_${step}_BYPRODUCTS)
2344
2345   # Dependencies on steps.
2346   get_property(dependees TARGET ${name} PROPERTY _EP_${step}_DEPENDEES)
2347   set_property(TARGET ${name} APPEND PROPERTY
2348     _EP_${step}_INTERNAL_DEPENDEES ${dependees}
2349   )
2350   foreach(dependee IN LISTS dependees)
2351     set_property(TARGET ${name} APPEND PROPERTY
2352       _EP_${dependee}_INTERNAL_DEPENDERS ${step}
2353     )
2354     _ep_get_step_stampfile(${name} ${dependee} dependee_stamp_file)
2355     list(APPEND depends ${dependee_stamp_file})
2356     if(cmp0114 STREQUAL "NEW" AND independent)
2357       get_property(dep_independent
2358         TARGET ${name}
2359         PROPERTY _EP_${dependee}_INDEPENDENT
2360       )
2361       if(NOT dep_independent)
2362         message(FATAL_ERROR
2363           "ExternalProject '${name}' step '${step}' is marked INDEPENDENT "
2364           "but depends on step '${dependee}' that is not marked INDEPENDENT."
2365         )
2366       endif()
2367     endif()
2368   endforeach()
2369
2370   # The command to run.
2371   get_property(command TARGET ${name} PROPERTY _EP_${step}_COMMAND)
2372   if(command)
2373     set(comment "Performing ${step} step for '${name}'")
2374   else()
2375     set(comment "No ${step} step for '${name}'")
2376   endif()
2377   get_property(work_dir
2378     TARGET ${name}
2379     PROPERTY _EP_${step}_WORKING_DIRECTORY
2380   )
2381
2382   # Replace list separators.
2383   get_property(sep
2384     TARGET ${name}
2385     PROPERTY _EP_LIST_SEPARATOR
2386   )
2387   if(sep AND command)
2388     string(REPLACE "${sep}" "\\;" command "${command}")
2389   endif()
2390
2391   # Replace location tags.
2392   _ep_replace_location_tags(
2393     ${name}
2394     comment
2395     command
2396     work_dir
2397     byproducts
2398   )
2399
2400   # Custom comment?
2401   get_property(comment_set
2402     TARGET ${name}
2403     PROPERTY _EP_${step}_COMMENT
2404     SET
2405   )
2406   if(comment_set)
2407     get_property(comment
2408       TARGET ${name}
2409       PROPERTY _EP_${step}_COMMENT
2410     )
2411   endif()
2412
2413   # Uses terminal?
2414   get_property(uses_terminal
2415     TARGET ${name}
2416     PROPERTY _EP_${step}_USES_TERMINAL
2417   )
2418   if(uses_terminal)
2419     set(uses_terminal USES_TERMINAL)
2420   else()
2421     set(uses_terminal "")
2422   endif()
2423
2424   # Run every time?
2425   get_property(always
2426     TARGET ${name}
2427     PROPERTY _EP_${step}_ALWAYS
2428   )
2429   if(always)
2430     set(touch)
2431     # Mark stamp files for all configs as SYMBOLIC since we do not create them.
2432     # Remove any existing stamp in case the option changed in an existing tree.
2433     get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
2434     if(_isMultiConfig)
2435       _ep_get_configuration_subdir_genex(cfgdir)
2436       foreach(cfg ${CMAKE_CONFIGURATION_TYPES})
2437         string(REPLACE "${cfgdir}" "/${cfg}"
2438           stamp_file_config "${stamp_file}"
2439         )
2440         set_property(SOURCE ${stamp_file_config} PROPERTY SYMBOLIC 1)
2441         file(REMOVE ${stamp_file_config})
2442       endforeach()
2443       if(CMAKE_GENERATOR STREQUAL "Xcode")
2444         # See Xcode case in _ep_get_configuration_subdir_genex.
2445         set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
2446       endif()
2447     else()
2448       set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
2449       file(REMOVE ${stamp_file})
2450     endif()
2451   else()
2452     set(touch ${CMAKE_COMMAND} -E touch ${stamp_file})
2453   endif()
2454
2455   # Wrap with log script?
2456   get_property(log TARGET ${name} PROPERTY _EP_${step}_LOG)
2457   if(command AND log)
2458     _ep_write_log_script(${name} ${step} command)
2459   endif()
2460
2461   if("${command}" STREQUAL "")
2462     # Some generators (i.e. Xcode) will not generate a file level target
2463     # if no command is set, and therefore the dependencies on this
2464     # target will be broken.
2465     # The empty command is replaced by an echo command here in order to
2466     # avoid this issue.
2467     set(command ${CMAKE_COMMAND} -E echo_append)
2468   endif()
2469
2470   set(__cmdQuoted)
2471   foreach(__item IN LISTS command)
2472     string(APPEND __cmdQuoted " [==[${__item}]==]")
2473   endforeach()
2474   cmake_language(EVAL CODE "
2475     add_custom_command(
2476       OUTPUT \${stamp_file}
2477       BYPRODUCTS \${byproducts}
2478       COMMENT \${comment}
2479       COMMAND ${__cmdQuoted}
2480       COMMAND \${touch}
2481       DEPENDS \${depends}
2482       WORKING_DIRECTORY \${work_dir}
2483       VERBATIM
2484       ${uses_terminal}
2485     )"
2486   )
2487   set_property(TARGET ${name} APPEND PROPERTY _EP_STEPS ${step})
2488
2489   # Add custom "step target"?
2490   get_property(step_targets
2491     TARGET ${name}
2492     PROPERTY _EP_STEP_TARGETS
2493   )
2494   if(NOT step_targets)
2495     get_property(step_targets
2496       DIRECTORY
2497       PROPERTY EP_STEP_TARGETS
2498     )
2499   endif()
2500   foreach(st ${step_targets})
2501     if("${st}" STREQUAL "${step}")
2502       _ep_step_add_target("${name}" "${step}" "FALSE")
2503       break()
2504     endif()
2505   endforeach()
2506
2507   get_property(independent_step_targets
2508     TARGET ${name} PROPERTY
2509     _EP_INDEPENDENT_STEP_TARGETS
2510   )
2511   if(NOT independent_step_targets)
2512     get_property(independent_step_targets
2513       DIRECTORY
2514       PROPERTY EP_INDEPENDENT_STEP_TARGETS
2515     )
2516   endif()
2517   if(cmp0114 STREQUAL "NEW")
2518     if(independent_step_targets)
2519       message(FATAL_ERROR
2520         "ExternalProject '${name}' option 'INDEPENDENT_STEP_TARGETS' is set to"
2521         "\n  ${independent_step_targets}\n"
2522         "but the option is no longer allowed.  "
2523         "It has been superseded by the per-step 'INDEPENDENT' option.  "
2524         "See policy CMP0114."
2525       )
2526     endif()
2527   else()
2528     if(independent_step_targets AND cmp0114 STREQUAL "")
2529       get_property(warned
2530         TARGET ${name}
2531         PROPERTY _EP_CMP0114_WARNED_INDEPENDENT_STEP_TARGETS
2532       )
2533       if(NOT warned)
2534         set_property(TARGET ${name} PROPERTY
2535           _EP_CMP0114_WARNED_INDEPENDENT_STEP_TARGETS 1
2536         )
2537         cmake_policy(GET_WARNING CMP0114 _cmp0114_warning)
2538         string(APPEND _cmp0114_warning
2539           "\n"
2540           "ExternalProject '${name}' option INDEPENDENT_STEP_TARGETS is set to"
2541           "\n  ${independent_step_targets}\n"
2542           "but the option is deprecated in favor of policy CMP0114."
2543         )
2544         message(AUTHOR_WARNING "${_cmp0114_warning}")
2545       endif()
2546     endif()
2547     foreach(st ${independent_step_targets})
2548       if("${st}" STREQUAL "${step}")
2549         _ep_step_add_target("${name}" "${step}" "TRUE")
2550         break()
2551       endif()
2552     endforeach()
2553   endif()
2554 endfunction()
2555
2556
2557 function(ExternalProject_Add_StepDependencies name step)
2558   set(dependencies ${ARGN})
2559
2560   # Sanity checks on "name" and "step".
2561   if(NOT TARGET ${name})
2562     message(FATAL_ERROR
2563       "Cannot find target \"${name}\". Perhaps it has not yet been created "
2564       "using ExternalProject_Add."
2565     )
2566   endif()
2567
2568   get_property(type TARGET ${name} PROPERTY TYPE)
2569   if(NOT type STREQUAL "UTILITY")
2570     message(FATAL_ERROR
2571       "Target \"${name}\" was not generated by ExternalProject_Add."
2572     )
2573   endif()
2574
2575   get_property(is_ep TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT)
2576   if(NOT is_ep)
2577     message(FATAL_ERROR
2578       "Target \"${name}\" was not generated by ExternalProject_Add."
2579     )
2580   endif()
2581
2582   get_property(steps TARGET ${name} PROPERTY _EP_STEPS)
2583   list(FIND steps ${step} is_step)
2584   if(is_step LESS 0)
2585     message(FATAL_ERROR
2586       "External project \"${name}\" does not have a step \"${step}\"."
2587     )
2588   endif()
2589
2590   if(TARGET ${name}-${step})
2591     get_property(type TARGET ${name}-${step} PROPERTY TYPE)
2592     if(NOT type STREQUAL "UTILITY")
2593       message(FATAL_ERROR
2594         "Target \"${name}-${step}\" was not generated by "
2595         "ExternalProject_Add_StepTargets."
2596       )
2597     endif()
2598     get_property(is_ep_step
2599       TARGET ${name}-${step}
2600       PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP
2601     )
2602     if(NOT is_ep_step)
2603       message(FATAL_ERROR
2604         "Target \"${name}-${step}\" was not generated by "
2605         "ExternalProject_Add_StepTargets."
2606       )
2607     endif()
2608   endif()
2609
2610   # Always add file-level dependency, but add target-level dependency
2611   # only if the target exists for that step.
2612   _ep_get_step_stampfile(${name} ${step} stamp_file)
2613   foreach(dep ${dependencies})
2614     add_custom_command(APPEND
2615       OUTPUT ${stamp_file}
2616       DEPENDS ${dep}
2617     )
2618     if(TARGET ${name}-${step})
2619       foreach(dep ${dependencies})
2620         add_dependencies(${name}-${step} ${dep})
2621       endforeach()
2622     endif()
2623   endforeach()
2624
2625 endfunction()
2626
2627
2628 function(_ep_add_mkdir_command name)
2629   ExternalProject_Get_Property(${name} tmp_dir)
2630   set(script_filename "${tmp_dir}/${name}-mkdirs.cmake")
2631   _ep_get_configuration_subdir_genex(cfgdir)
2632
2633   ExternalProject_Add_Step(${name} mkdir
2634     INDEPENDENT TRUE
2635     COMMENT "Creating directories for '${name}'"
2636     COMMAND ${CMAKE_COMMAND} -Dcfgdir=${cfgdir} -P ${script_filename}
2637   )
2638 endfunction()
2639
2640
2641 function(_ep_is_dir_empty dir empty_var)
2642   file(GLOB gr "${dir}/*")
2643   if("${gr}" STREQUAL "")
2644     set(${empty_var} 1 PARENT_SCOPE)
2645   else()
2646     set(${empty_var} 0 PARENT_SCOPE)
2647   endif()
2648 endfunction()
2649
2650 function(_ep_get_git_submodules_recurse git_submodules_recurse)
2651   # Checks for GIT_SUBMODULES_RECURSE property. Default is ON, which sets
2652   # git_submodules_recurse output variable to "--recursive". Otherwise, the
2653   # output variable is set to an empty value "".
2654   get_property(git_submodules_recurse_set
2655     TARGET ${name}
2656     PROPERTY _EP_GIT_SUBMODULES_RECURSE
2657     SET
2658   )
2659   if(NOT git_submodules_recurse_set)
2660     set(recurseFlag "--recursive")
2661   else()
2662     get_property(git_submodules_recurse_value
2663       TARGET ${name}
2664       PROPERTY _EP_GIT_SUBMODULES_RECURSE
2665     )
2666     if(git_submodules_recurse_value)
2667       set(recurseFlag "--recursive")
2668     else()
2669       set(recurseFlag "")
2670     endif()
2671   endif()
2672   set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE)
2673
2674   # The git submodule update '--recursive' flag requires git >= v1.6.5
2675   if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5)
2676     message(FATAL_ERROR
2677       "git version 1.6.5 or later required for --recursive flag with "
2678       "'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'"
2679     )
2680   endif()
2681 endfunction()
2682
2683
2684 function(_ep_add_download_command name)
2685   ExternalProject_Get_Property(${name}
2686     source_dir
2687     stamp_dir
2688     download_dir
2689     tmp_dir
2690   )
2691
2692   get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
2693   get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
2694   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
2695   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
2696   get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
2697   get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
2698   get_property(url TARGET ${name} PROPERTY _EP_URL)
2699   get_property(fname TARGET ${name} PROPERTY _EP_DOWNLOAD_NAME)
2700
2701   # TODO: Perhaps file:// should be copied to download dir before extraction.
2702   string(REGEX REPLACE "file://" "" url "${url}")
2703
2704   set(depends)
2705   set(comment)
2706   set(work_dir)
2707   set(extra_repo_info)
2708
2709   if(cmd_set)
2710     set(work_dir ${download_dir})
2711     set(method custom)
2712   elseif(cvs_repository)
2713     set(method cvs)
2714     find_package(CVS QUIET)
2715     if(NOT CVS_EXECUTABLE)
2716       message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
2717     endif()
2718
2719     get_target_property(cvs_module ${name} _EP_CVS_MODULE)
2720     if(NOT cvs_module)
2721       message(FATAL_ERROR "error: no CVS_MODULE")
2722     endif()
2723
2724     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
2725     get_filename_component(src_name "${source_dir}" NAME)
2726     get_filename_component(work_dir "${source_dir}" PATH)
2727     set(comment "Performing download step (CVS checkout) for '${name}'")
2728     set(cmd
2729       ${CVS_EXECUTABLE}
2730       -d ${cvs_repository}
2731       -q
2732       co ${cvs_tag}
2733       -d ${src_name}
2734       ${cvs_module}
2735     )
2736
2737   elseif(svn_repository)
2738     set(method svn)
2739     find_package(Subversion QUIET)
2740     if(NOT Subversion_SVN_EXECUTABLE)
2741       message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
2742     endif()
2743
2744     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
2745     get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
2746     get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
2747     get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
2748     get_property(uses_terminal
2749       TARGET ${name}
2750       PROPERTY _EP_USES_TERMINAL_DOWNLOAD
2751     )
2752     if(uses_terminal)
2753       set(svn_interactive_args "")
2754     else()
2755       set(svn_interactive_args "--non-interactive")
2756     endif()
2757
2758     get_filename_component(src_name "${source_dir}" NAME)
2759     get_filename_component(work_dir "${source_dir}" PATH)
2760     set(comment "Performing download step (SVN checkout) for '${name}'")
2761     set(svn_user_pw_args "")
2762     if(DEFINED svn_username)
2763       set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
2764     endif()
2765     if(DEFINED svn_password)
2766       set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
2767     endif()
2768     if(svn_trust_cert)
2769       set(svn_trust_cert_args --trust-server-cert)
2770     endif()
2771     set(cmd
2772       ${Subversion_SVN_EXECUTABLE}
2773       co
2774       ${svn_repository}
2775       ${svn_revision}
2776       ${svn_interactive_args}
2777       ${svn_trust_cert_args}
2778       ${svn_user_pw_args}
2779       ${src_name}
2780     )
2781
2782   elseif(git_repository)
2783     set(method git)
2784     # FetchContent gives us these directly, so don't try to recompute them
2785     if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
2786       unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
2787       find_package(Git QUIET)
2788       if(NOT GIT_EXECUTABLE)
2789         message(FATAL_ERROR "error: could not find git for clone of ${name}")
2790       endif()
2791     endif()
2792
2793     _ep_get_git_submodules_recurse(git_submodules_recurse)
2794
2795     get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
2796     if(NOT git_tag)
2797       set(git_tag "master")
2798     endif()
2799
2800     set(git_init_submodules TRUE)
2801     get_property(git_submodules_set
2802       TARGET ${name}
2803       PROPERTY _EP_GIT_SUBMODULES SET
2804     )
2805     if(git_submodules_set)
2806       get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
2807       if(git_submodules  STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
2808         set(git_init_submodules FALSE)
2809       endif()
2810     endif()
2811
2812     get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
2813     if(NOT git_remote_name)
2814       set(git_remote_name "origin")
2815     endif()
2816
2817     get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
2818     if("x${tls_verify}" STREQUAL "x" AND DEFINED CMAKE_TLS_VERIFY)
2819       set(tls_verify "${CMAKE_TLS_VERIFY}")
2820     endif()
2821     get_property(git_shallow TARGET ${name} PROPERTY _EP_GIT_SHALLOW)
2822     get_property(git_progress TARGET ${name} PROPERTY _EP_GIT_PROGRESS)
2823     get_property(git_config TARGET ${name} PROPERTY _EP_GIT_CONFIG)
2824
2825     # If git supports it, make checkouts quiet when checking out a git hash.
2826     # This avoids the very noisy detached head message.
2827     if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7)
2828       list(PREPEND git_config advice.detachedHead=false)
2829     endif()
2830
2831     # The command doesn't expose any details, so we need to record additional
2832     # information in the RepositoryInfo.txt file. For the download step, only
2833     # the things specifically affecting the clone operation should be recorded.
2834     # If the repo changes, the clone script should be run again.
2835     # But if only the tag changes, avoid running the clone script again.
2836     # Let the 'always' running update step checkout the new tag.
2837     #
2838     set(extra_repo_info
2839 "repository=${git_repository}
2840 remote=${git_remote_name}
2841 init_submodules=${git_init_submodules}
2842 recurse_submodules=${git_submodules_recurse}
2843 submodules=${git_submodules}
2844 CMP0097=${_EP_CMP0097}
2845 ")
2846     get_filename_component(src_name "${source_dir}" NAME)
2847     get_filename_component(work_dir "${source_dir}" PATH)
2848
2849     # Since git clone doesn't succeed if the non-empty source_dir exists,
2850     # create a cmake script to invoke as download command.
2851     # The script will delete the source directory and then call git clone.
2852     #
2853     _ep_write_gitclone_script(
2854       ${tmp_dir}/${name}-gitclone.cmake
2855       ${source_dir}
2856       ${GIT_EXECUTABLE}
2857       ${git_repository}
2858       ${git_tag}
2859       ${git_remote_name}
2860       ${git_init_submodules}
2861       "${git_submodules_recurse}"
2862       "${git_submodules}"
2863       "${git_shallow}"
2864       "${git_progress}"
2865       "${git_config}"
2866       ${src_name}
2867       ${work_dir}
2868       ${stamp_dir}/${name}-gitinfo.txt
2869       ${stamp_dir}/${name}-gitclone-lastrun.txt
2870       "${tls_verify}"
2871     )
2872     set(comment "Performing download step (git clone) for '${name}'")
2873     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
2874
2875   elseif(hg_repository)
2876     set(method hg)
2877     find_package(Hg QUIET)
2878     if(NOT HG_EXECUTABLE)
2879       message(FATAL_ERROR "error: could not find hg for clone of ${name}")
2880     endif()
2881
2882     get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
2883     if(NOT hg_tag)
2884       set(hg_tag "tip")
2885     endif()
2886
2887     # The command doesn't expose any details, so we need to record additional
2888     # information in the RepositoryInfo.txt file. For the download step, only
2889     # the things specifically affecting the clone operation should be recorded.
2890     # If the repo changes, the clone script should be run again.
2891     # But if only the tag changes, avoid running the clone script again.
2892     # Let the 'always' running update step checkout the new tag.
2893     #
2894     set(extra_repo_info "repository=${hg_repository}")
2895     get_filename_component(src_name "${source_dir}" NAME)
2896     get_filename_component(work_dir "${source_dir}" PATH)
2897
2898     # Since hg clone doesn't succeed if the non-empty source_dir exists,
2899     # create a cmake script to invoke as download command.
2900     # The script will delete the source directory and then call hg clone.
2901     #
2902     _ep_write_hgclone_script(
2903       ${tmp_dir}/${name}-hgclone.cmake
2904       ${source_dir}
2905       ${HG_EXECUTABLE}
2906       ${hg_repository}
2907       ${hg_tag}
2908       ${src_name}
2909       ${work_dir}
2910       ${stamp_dir}/${name}-hginfo.txt
2911       ${stamp_dir}/${name}-hgclone-lastrun.txt
2912     )
2913     set(comment "Performing download step (hg clone) for '${name}'")
2914     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake)
2915
2916   elseif(url)
2917     set(method url)
2918     get_filename_component(work_dir "${source_dir}" PATH)
2919     get_property(hash TARGET ${name} PROPERTY _EP_URL_HASH)
2920     _ep_get_hash_regex(_ep_hash_regex)
2921     if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
2922       _ep_get_hash_algos(_ep_hash_algos)
2923       list(JOIN _ep_hash_algos "|" _ep_hash_algos)
2924       message(FATAL_ERROR
2925         "URL_HASH is set to\n"
2926         "  ${hash}\n"
2927         "but must be ALGO=value where ALGO is\n"
2928         "  ${_ep_hash_algos}\n"
2929         "and value is a hex string."
2930       )
2931     endif()
2932     get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
2933     if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}")
2934       message(FATAL_ERROR
2935         "URL_MD5 is set to\n"
2936         "  ${md5}\n"
2937         "but must be a hex string."
2938       )
2939     endif()
2940     if(md5 AND NOT hash)
2941       set(hash "MD5=${md5}")
2942     endif()
2943     set(extra_repo_info
2944 "url(s)=${url}
2945 hash=${hash}
2946 ")
2947
2948     list(LENGTH url url_list_length)
2949     if(NOT "${url_list_length}" STREQUAL "1")
2950       foreach(entry ${url})
2951         if(NOT "${entry}" MATCHES "^[a-z]+://")
2952           message(FATAL_ERROR
2953             "At least one entry of URL is a path (invalid in a list)"
2954           )
2955         endif()
2956       endforeach()
2957       if("x${fname}" STREQUAL "x")
2958         list(GET url 0 fname)
2959       endif()
2960     endif()
2961
2962     if(IS_DIRECTORY "${url}")
2963       get_filename_component(abs_dir "${url}" ABSOLUTE)
2964       set(comment "Performing download step (DIR copy) for '${name}'")
2965       set(cmd
2966         ${CMAKE_COMMAND} -E rm -rf ${source_dir}
2967         COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir}
2968       )
2969     else()
2970       get_property(no_extract
2971         TARGET "${name}"
2972         PROPERTY _EP_DOWNLOAD_NO_EXTRACT
2973       )
2974       string(APPEND extra_repo_info "no_extract=${no_extract}\n")
2975       if("${url}" MATCHES "^[a-z]+://")
2976         # TODO: Should download and extraction be different steps?
2977         if("x${fname}" STREQUAL "x")
2978           set(fname "${url}")
2979         endif()
2980         set(ext_regex [[7z|tar|tar\.bz2|tar\.gz|tar\.xz|tbz2|tgz|txz|zip]])
2981         if("${fname}" MATCHES "([^/\\?#]+(\\.|=)(${ext_regex}))([/?#].*)?$")
2982           set(fname "${CMAKE_MATCH_1}")
2983         elseif(no_extract)
2984           get_filename_component(fname "${fname}" NAME)
2985         else()
2986           # Fall back to a default file name.  The actual file name does not
2987           # matter because it is used only internally and our extraction tool
2988           # inspects the file content directly.  If it turns out the wrong URL
2989           # was given that will be revealed during the build which is an easier
2990           # place for users to diagnose than an error here anyway.
2991           set(fname "archive.tar")
2992         endif()
2993         string(REPLACE ";" "-" fname "${fname}")
2994         set(file ${download_dir}/${fname})
2995         get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
2996         get_property(inactivity_timeout
2997           TARGET ${name}
2998           PROPERTY _EP_INACTIVITY_TIMEOUT
2999         )
3000         get_property(no_progress
3001           TARGET ${name}
3002           PROPERTY _EP_DOWNLOAD_NO_PROGRESS
3003         )
3004         get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
3005         get_property(tls_cainfo TARGET ${name} PROPERTY _EP_TLS_CAINFO)
3006         get_property(netrc TARGET ${name} PROPERTY _EP_NETRC)
3007         get_property(netrc_file TARGET ${name} PROPERTY _EP_NETRC_FILE)
3008         get_property(http_username TARGET ${name} PROPERTY _EP_HTTP_USERNAME)
3009         get_property(http_password TARGET ${name} PROPERTY _EP_HTTP_PASSWORD)
3010         get_property(http_headers TARGET ${name} PROPERTY _EP_HTTP_HEADER)
3011         set(download_script "${stamp_dir}/download-${name}.cmake")
3012         _ep_write_downloadfile_script(
3013           "${download_script}"
3014           "${url}"
3015           "${file}"
3016           "${timeout}"
3017           "${inactivity_timeout}"
3018           "${no_progress}"
3019           "${hash}"
3020           "${tls_verify}"
3021           "${tls_cainfo}"
3022           "${http_username}:${http_password}"
3023           "${http_headers}"
3024           "${netrc}"
3025           "${netrc_file}"
3026         )
3027         set(cmd
3028           ${CMAKE_COMMAND} -P "${download_script}"
3029           COMMAND
3030         )
3031         if (no_extract)
3032           set(steps "download and verify")
3033         else ()
3034           set(steps "download, verify and extract")
3035         endif ()
3036         set(comment "Performing download step (${steps}) for '${name}'")
3037         # already verified by 'download_script'
3038         file(WRITE "${stamp_dir}/verify-${name}.cmake" "")
3039
3040         # Rather than adding everything to the RepositoryInfo.txt file, it is
3041         # more robust to just depend on the download script. That way, we will
3042         # re-download if any aspect of the download changes.
3043         list(APPEND depends "${download_script}")
3044       else()
3045         set(file "${url}")
3046         if (no_extract)
3047           set(steps "verify")
3048         else ()
3049           set(steps "verify and extract")
3050         endif ()
3051         set(comment "Performing download step (${steps}) for '${name}'")
3052         _ep_write_verifyfile_script(
3053           "${stamp_dir}/verify-${name}.cmake"
3054           "${file}"
3055           "${hash}"
3056         )
3057       endif()
3058       list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake)
3059       get_target_property(extract_timestamp ${name}
3060         _EP_DOWNLOAD_EXTRACT_TIMESTAMP
3061       )
3062       if(no_extract)
3063         if(NOT extract_timestamp STREQUAL "extract_timestamp-NOTFOUND")
3064           message(FATAL_ERROR
3065             "Cannot specify DOWNLOAD_EXTRACT_TIMESTAMP when using "
3066             "DOWNLOAD_NO_EXTRACT TRUE"
3067           )
3068         endif()
3069         set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file})
3070       else()
3071         if(extract_timestamp STREQUAL "extract_timestamp-NOTFOUND")
3072           # Default depends on policy CMP0135
3073           if(_EP_CMP0135 STREQUAL "")
3074             message(AUTHOR_WARNING
3075               "The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy "
3076               "CMP0135 is not set. The policy's OLD behavior will be used. "
3077               "When using a URL download, the timestamps of extracted files "
3078               "should preferably be that of the time of extraction, otherwise "
3079               "code that depends on the extracted contents might not be "
3080               "rebuilt if the URL changes. The OLD behavior preserves the "
3081               "timestamps from the archive instead, but this is usually not "
3082               "what you want. Update your project to the NEW behavior or "
3083               "specify the DOWNLOAD_EXTRACT_TIMESTAMP option with a value of "
3084               "true to avoid this robustness issue."
3085             )
3086             set(extract_timestamp TRUE)
3087           elseif(_EP_CMP0135 STREQUAL "NEW")
3088             set(extract_timestamp FALSE)
3089           else()
3090             set(extract_timestamp TRUE)
3091           endif()
3092         endif()
3093         if(extract_timestamp)
3094           set(options "")
3095         else()
3096           set(options "--touch")
3097         endif()
3098         _ep_write_extractfile_script(
3099           "${stamp_dir}/extract-${name}.cmake"
3100           "${name}"
3101           "${file}"
3102           "${source_dir}"
3103           "${options}"
3104         )
3105         list(APPEND cmd
3106           COMMAND ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake
3107         )
3108       endif ()
3109     endif()
3110   else()
3111     set(method source_dir)
3112     _ep_is_dir_empty("${source_dir}" empty)
3113     if(${empty})
3114       message(FATAL_ERROR
3115         "No download info given for '${name}' and its source directory:\n"
3116         " ${source_dir}\n"
3117         "is not an existing non-empty directory.  Please specify one of:\n"
3118         " * SOURCE_DIR with an existing non-empty directory\n"
3119         " * DOWNLOAD_COMMAND\n"
3120         " * URL\n"
3121         " * GIT_REPOSITORY\n"
3122         " * SVN_REPOSITORY\n"
3123         " * HG_REPOSITORY\n"
3124         " * CVS_REPOSITORY and CVS_MODULE"
3125       )
3126     endif()
3127   endif()
3128
3129   # We use configure_file() to write the repo_info_file so that the file's
3130   # timestamp is not updated if we don't change the contents
3131
3132   set(repo_info_file ${stamp_dir}/${name}-${method}info.txt)
3133   list(APPEND depends ${repo_info_file})
3134   configure_file(
3135     "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/RepositoryInfo.txt.in"
3136     "${repo_info_file}"
3137     @ONLY
3138   )
3139
3140   get_property(log
3141     TARGET ${name}
3142     PROPERTY _EP_LOG_DOWNLOAD
3143   )
3144   if(log)
3145     set(log LOG 1)
3146   else()
3147     set(log "")
3148   endif()
3149
3150   get_property(uses_terminal
3151     TARGET ${name}
3152     PROPERTY _EP_USES_TERMINAL_DOWNLOAD
3153   )
3154   if(uses_terminal)
3155     set(uses_terminal USES_TERMINAL 1)
3156   else()
3157     set(uses_terminal "")
3158   endif()
3159
3160   set(__cmdQuoted)
3161   foreach(__item IN LISTS cmd)
3162     string(APPEND __cmdQuoted " [==[${__item}]==]")
3163   endforeach()
3164   cmake_language(EVAL CODE "
3165     ExternalProject_Add_Step(\${name} download
3166       INDEPENDENT TRUE
3167       COMMENT \${comment}
3168       COMMAND ${__cmdQuoted}
3169       WORKING_DIRECTORY \${work_dir}
3170       DEPENDS \${depends}
3171       DEPENDEES mkdir
3172       ${log}
3173       ${uses_terminal}
3174     )"
3175   )
3176 endfunction()
3177
3178 function(_ep_get_update_disconnected var name)
3179   get_property(update_disconnected_set
3180     TARGET ${name}
3181     PROPERTY _EP_UPDATE_DISCONNECTED
3182     SET
3183   )
3184   if(update_disconnected_set)
3185     get_property(update_disconnected
3186       TARGET ${name}
3187       PROPERTY _EP_UPDATE_DISCONNECTED
3188     )
3189   else()
3190     get_property(update_disconnected
3191       DIRECTORY
3192       PROPERTY EP_UPDATE_DISCONNECTED
3193     )
3194   endif()
3195   set(${var} "${update_disconnected}" PARENT_SCOPE)
3196 endfunction()
3197
3198 function(_ep_add_update_command name)
3199   ExternalProject_Get_Property(${name} source_dir tmp_dir)
3200
3201   get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
3202   get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
3203   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
3204   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
3205   get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
3206   get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
3207
3208   _ep_get_update_disconnected(update_disconnected ${name})
3209
3210   set(work_dir)
3211   set(comment)
3212   set(always)
3213
3214   if(cmd_set)
3215     set(work_dir ${source_dir})
3216     if(NOT "x${cmd}" STREQUAL "x")
3217       set(always 1)
3218     endif()
3219   elseif(cvs_repository)
3220     if(NOT CVS_EXECUTABLE)
3221       message(FATAL_ERROR "error: could not find cvs for update of ${name}")
3222     endif()
3223     set(work_dir ${source_dir})
3224     set(comment "Performing update step (CVS update) for '${name}'")
3225     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
3226     set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
3227     set(always 1)
3228   elseif(svn_repository)
3229     if(NOT Subversion_SVN_EXECUTABLE)
3230       message(FATAL_ERROR "error: could not find svn for update of ${name}")
3231     endif()
3232     set(work_dir ${source_dir})
3233     set(comment "Performing update step (SVN update) for '${name}'")
3234     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
3235     get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
3236     get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
3237     get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
3238     get_property(uses_terminal TARGET ${name} PROPERTY _EP_USES_TERMINAL_UPDATE)
3239     if(uses_terminal)
3240       set(svn_interactive_args "")
3241     else()
3242       set(svn_interactive_args "--non-interactive")
3243     endif()
3244     set(svn_user_pw_args "")
3245     if(DEFINED svn_username)
3246       set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
3247     endif()
3248     if(DEFINED svn_password)
3249       set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
3250     endif()
3251     if(svn_trust_cert)
3252       set(svn_trust_cert_args --trust-server-cert)
3253     endif()
3254     set(cmd
3255       ${Subversion_SVN_EXECUTABLE}
3256       up
3257       ${svn_revision}
3258       ${svn_interactive_args}
3259       ${svn_trust_cert_args}
3260       ${svn_user_pw_args}
3261     )
3262     set(always 1)
3263   elseif(git_repository)
3264     # FetchContent gives us these directly, so don't try to recompute them
3265     if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
3266       unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
3267       find_package(Git QUIET)
3268       if(NOT GIT_EXECUTABLE)
3269         message(FATAL_ERROR "error: could not find git for fetch of ${name}")
3270       endif()
3271     endif()
3272     set(work_dir ${source_dir})
3273     set(comment "Performing update step for '${name}'")
3274
3275     get_property(git_tag
3276       TARGET ${name}
3277       PROPERTY _EP_GIT_TAG
3278     )
3279     if(NOT git_tag)
3280       set(git_tag "master")
3281     endif()
3282
3283     get_property(git_remote_name
3284       TARGET ${name}
3285       PROPERTY _EP_GIT_REMOTE_NAME
3286     )
3287     if(NOT git_remote_name)
3288       set(git_remote_name "origin")
3289     endif()
3290
3291     set(git_init_submodules TRUE)
3292     get_property(git_submodules_set
3293       TARGET ${name}
3294       PROPERTY _EP_GIT_SUBMODULES
3295       SET
3296     )
3297     if(git_submodules_set)
3298       get_property(git_submodules
3299         TARGET ${name}
3300         PROPERTY _EP_GIT_SUBMODULES
3301       )
3302       if(git_submodules  STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
3303         set(git_init_submodules FALSE)
3304       endif()
3305     endif()
3306
3307     get_property(git_update_strategy
3308       TARGET ${name}
3309       PROPERTY _EP_GIT_REMOTE_UPDATE_STRATEGY
3310     )
3311     if(NOT git_update_strategy)
3312       set(git_update_strategy "${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
3313     endif()
3314     if(NOT git_update_strategy)
3315       set(git_update_strategy REBASE)
3316     endif()
3317     set(strategies CHECKOUT REBASE REBASE_CHECKOUT)
3318     if(NOT git_update_strategy IN_LIST strategies)
3319       message(FATAL_ERROR
3320         "'${git_update_strategy}' is not one of the supported strategies: "
3321         "${strategies}"
3322       )
3323     endif()
3324
3325     _ep_get_git_submodules_recurse(git_submodules_recurse)
3326
3327     _ep_write_gitupdate_script(
3328       "${tmp_dir}/${name}-gitupdate.cmake"
3329       "${GIT_EXECUTABLE}"
3330       "${git_tag}"
3331       "${git_remote_name}"
3332       "${git_init_submodules}"
3333       "${git_submodules_recurse}"
3334       "${git_submodules}"
3335       "${git_repository}"
3336       "${work_dir}"
3337       "${git_update_strategy}"
3338     )
3339     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake)
3340     set(always 1)
3341   elseif(hg_repository)
3342     if(NOT HG_EXECUTABLE)
3343       message(FATAL_ERROR "error: could not find hg for pull of ${name}")
3344     endif()
3345     set(work_dir ${source_dir})
3346     set(comment "Performing update step (hg pull) for '${name}'")
3347
3348     get_property(hg_tag
3349       TARGET ${name}
3350       PROPERTY _EP_HG_TAG
3351     )
3352     if(NOT hg_tag)
3353       set(hg_tag "tip")
3354     endif()
3355
3356     if("${HG_VERSION_STRING}" STREQUAL "2.1")
3357       set(notesAnchor
3358         "#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X"
3359       )
3360       message(WARNING
3361 "Mercurial 2.1 does not distinguish an empty pull from a failed pull:
3362  http://mercurial.selenic.com/wiki/UpgradeNotes${notesAnchor}
3363  http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656
3364 Update to Mercurial >= 2.1.1.
3365 ")
3366     endif()
3367
3368     set(cmd
3369       ${HG_EXECUTABLE} pull
3370       COMMAND ${HG_EXECUTABLE} update ${hg_tag}
3371     )
3372     set(always 1)
3373   endif()
3374
3375   get_property(log
3376     TARGET ${name}
3377     PROPERTY _EP_LOG_UPDATE
3378   )
3379   if(log)
3380     set(log LOG 1)
3381   else()
3382     set(log "")
3383   endif()
3384
3385   get_property(uses_terminal
3386     TARGET ${name}
3387     PROPERTY _EP_USES_TERMINAL_UPDATE
3388   )
3389   if(uses_terminal)
3390     set(uses_terminal USES_TERMINAL 1)
3391   else()
3392     set(uses_terminal "")
3393   endif()
3394
3395   set(__cmdQuoted)
3396   foreach(__item IN LISTS cmd)
3397     string(APPEND __cmdQuoted " [==[${__item}]==]")
3398   endforeach()
3399   cmake_language(EVAL CODE "
3400     ExternalProject_Add_Step(${name} update
3401       INDEPENDENT TRUE
3402       COMMENT \${comment}
3403       COMMAND ${__cmdQuoted}
3404       ALWAYS \${always}
3405       EXCLUDE_FROM_MAIN \${update_disconnected}
3406       WORKING_DIRECTORY \${work_dir}
3407       DEPENDEES download
3408       ${log}
3409       ${uses_terminal}
3410     )"
3411   )
3412
3413 endfunction()
3414
3415
3416 function(_ep_add_patch_command name)
3417   ExternalProject_Get_Property(${name} source_dir)
3418
3419   get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
3420   get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
3421
3422   set(work_dir)
3423
3424   if(cmd_set)
3425     set(work_dir ${source_dir})
3426   endif()
3427
3428   get_property(log
3429     TARGET ${name}
3430     PROPERTY _EP_LOG_PATCH
3431   )
3432   if(log)
3433     set(log LOG 1)
3434   else()
3435     set(log "")
3436   endif()
3437
3438   get_property(uses_terminal
3439     TARGET ${name}
3440     PROPERTY _EP_USES_TERMINAL_PATCH
3441   )
3442   if(uses_terminal)
3443     set(uses_terminal USES_TERMINAL 1)
3444   else()
3445     set(uses_terminal "")
3446   endif()
3447
3448   _ep_get_update_disconnected(update_disconnected ${name})
3449   if(update_disconnected)
3450     set(patch_dep download)
3451   else()
3452     set(patch_dep update)
3453   endif()
3454
3455   set(__cmdQuoted)
3456   foreach(__item IN LISTS cmd)
3457     string(APPEND __cmdQuoted " [==[${__item}]==]")
3458   endforeach()
3459   cmake_language(EVAL CODE "
3460     ExternalProject_Add_Step(${name} patch
3461       INDEPENDENT TRUE
3462       COMMAND ${__cmdQuoted}
3463       WORKING_DIRECTORY \${work_dir}
3464       DEPENDEES \${patch_dep}
3465       ${log}
3466       ${uses_terminal}
3467     )"
3468   )
3469 endfunction()
3470
3471 function(_ep_get_file_deps var name)
3472   set(file_deps)
3473
3474   get_property(deps
3475     TARGET ${name}
3476     PROPERTY _EP_DEPENDS
3477   )
3478   foreach(dep IN LISTS deps)
3479     get_property(dep_type
3480       TARGET ${dep}
3481       PROPERTY TYPE
3482     )
3483     if(dep_type STREQUAL "UTILITY")
3484       get_property(is_ep
3485         TARGET ${dep}
3486         PROPERTY _EP_IS_EXTERNAL_PROJECT
3487       )
3488       if(is_ep)
3489         _ep_get_step_stampfile(${dep} "done" done_stamp_file)
3490         list(APPEND file_deps ${done_stamp_file})
3491       endif()
3492     endif()
3493   endforeach()
3494
3495   set("${var}" "${file_deps}" PARENT_SCOPE)
3496 endfunction()
3497
3498 function(_ep_extract_configure_command var name)
3499   get_property(cmd_set
3500     TARGET ${name}
3501     PROPERTY _EP_CONFIGURE_COMMAND
3502     SET
3503   )
3504   if(cmd_set)
3505     get_property(cmd
3506       TARGET ${name}
3507       PROPERTY _EP_CONFIGURE_COMMAND
3508     )
3509   else()
3510     get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
3511     if(cmake_command)
3512       set(cmd "${cmake_command}")
3513     else()
3514       set(cmd "${CMAKE_COMMAND}")
3515     endif()
3516
3517     get_property(cmake_args
3518       TARGET ${name}
3519       PROPERTY _EP_CMAKE_ARGS
3520     )
3521     list(APPEND cmd ${cmake_args})
3522
3523     # If there are any CMAKE_CACHE_ARGS or CMAKE_CACHE_DEFAULT_ARGS,
3524     # write an initial cache and use it
3525     get_property(cmake_cache_args
3526       TARGET ${name}
3527       PROPERTY _EP_CMAKE_CACHE_ARGS
3528     )
3529     get_property(cmake_cache_default_args
3530       TARGET ${name}
3531       PROPERTY _EP_CMAKE_CACHE_DEFAULT_ARGS
3532     )
3533
3534     set(has_cmake_cache_args 0)
3535     if(NOT "${cmake_cache_args}" STREQUAL "")
3536       set(has_cmake_cache_args 1)
3537     endif()
3538
3539     set(has_cmake_cache_default_args 0)
3540     if(NOT "${cmake_cache_default_args}" STREQUAL "")
3541       set(has_cmake_cache_default_args 1)
3542     endif()
3543
3544     get_target_property(cmake_generator ${name}
3545       _EP_CMAKE_GENERATOR
3546     )
3547     get_target_property(cmake_generator_instance ${name}
3548       _EP_CMAKE_GENERATOR_INSTANCE
3549     )
3550     get_target_property(cmake_generator_platform ${name}
3551       _EP_CMAKE_GENERATOR_PLATFORM
3552     )
3553     get_target_property(cmake_generator_toolset ${name}
3554       _EP_CMAKE_GENERATOR_TOOLSET
3555     )
3556     if(cmake_generator)
3557       list(APPEND cmd "-G${cmake_generator}")
3558       if(cmake_generator_platform)
3559         list(APPEND cmd "-A${cmake_generator_platform}")
3560       endif()
3561       if(cmake_generator_toolset)
3562         list(APPEND cmd "-T${cmake_generator_toolset}")
3563       endif()
3564       if(cmake_generator_instance)
3565         list(APPEND cmd
3566           "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${cmake_generator_instance}"
3567         )
3568       endif()
3569     else()
3570       if(CMAKE_EXTRA_GENERATOR)
3571         list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
3572       else()
3573         list(APPEND cmd "-G${CMAKE_GENERATOR}")
3574         if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
3575           set(has_cmake_cache_default_args 1)
3576           list(APPEND cmake_cache_default_args
3577             "-DGHS_TARGET_PLATFORM:STRING=${GHS_TARGET_PLATFORM}"
3578             "-DGHS_PRIMARY_TARGET:STRING=${GHS_PRIMARY_TARGET}"
3579             "-DGHS_TOOLSET_ROOT:STRING=${GHS_TOOLSET_ROOT}"
3580             "-DGHS_OS_ROOT:STRING=${GHS_OS_ROOT}"
3581             "-DGHS_OS_DIR:STRING=${GHS_OS_DIR}"
3582             "-DGHS_BSP_NAME:STRING=${GHS_BSP_NAME}"
3583           )
3584         endif()
3585       endif()
3586       if(cmake_generator_platform)
3587         message(FATAL_ERROR
3588           "Option CMAKE_GENERATOR_PLATFORM not allowed without "
3589           "CMAKE_GENERATOR."
3590         )
3591       endif()
3592       if(CMAKE_GENERATOR_PLATFORM)
3593         list(APPEND cmd "-A${CMAKE_GENERATOR_PLATFORM}")
3594       endif()
3595       if(cmake_generator_toolset)
3596         message(FATAL_ERROR
3597           "Option CMAKE_GENERATOR_TOOLSET not allowed without CMAKE_GENERATOR."
3598         )
3599       endif()
3600       if(CMAKE_GENERATOR_TOOLSET)
3601         list(APPEND cmd "-T${CMAKE_GENERATOR_TOOLSET}")
3602       endif()
3603       if(cmake_generator_instance)
3604         message(FATAL_ERROR
3605           "Option CMAKE_GENERATOR_INSTANCE not allowed without CMAKE_GENERATOR."
3606         )
3607       endif()
3608       if(CMAKE_GENERATOR_INSTANCE)
3609         list(APPEND cmd
3610           "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}"
3611         )
3612       endif()
3613     endif()
3614
3615     if(has_cmake_cache_args OR has_cmake_cache_default_args)
3616       set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
3617       if(has_cmake_cache_args)
3618         _ep_command_line_to_initial_cache(
3619           script_initial_cache_force
3620           "${cmake_cache_args}"
3621           1
3622         )
3623       endif()
3624       if(has_cmake_cache_default_args)
3625         _ep_command_line_to_initial_cache(
3626           script_initial_cache_default
3627           "${cmake_cache_default_args}"
3628           0
3629         )
3630       endif()
3631       _ep_write_initial_cache(
3632         ${name}
3633         "${_ep_cache_args_script}"
3634         "${script_initial_cache_force}${script_initial_cache_default}"
3635       )
3636       list(APPEND cmd "-C${_ep_cache_args_script}")
3637       _ep_replace_location_tags(${name} _ep_cache_args_script)
3638       set(_ep_cache_args_script
3639         "${_ep_cache_args_script}"
3640         PARENT_SCOPE
3641       )
3642     endif()
3643
3644     list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
3645   endif()
3646
3647   set("${var}" "${cmd}" PARENT_SCOPE)
3648 endfunction()
3649
3650 # TODO: Make sure external projects use the proper compiler
3651 function(_ep_add_configure_command name)
3652   ExternalProject_Get_Property(${name} binary_dir tmp_dir)
3653
3654   set(file_deps)
3655   get_property(configure_handled_by_build
3656     TARGET ${name}
3657     PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD
3658   )
3659   if(NOT configure_handled_by_build)
3660     # Depend on other external projects (file-level)
3661     _ep_get_file_deps(file_deps ${name})
3662   endif()
3663
3664   _ep_extract_configure_command(cmd ${name})
3665
3666   # If anything about the configure command changes, (command itself, cmake
3667   # used, cmake args or cmake generator) then re-run the configure step.
3668   # Fixes issue https://gitlab.kitware.com/cmake/cmake/-/issues/10258
3669   #
3670   configure_file(
3671     ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/cfgcmd.txt.in
3672     ${tmp_dir}/${name}-cfgcmd.txt
3673     @ONLY
3674   )
3675   list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt)
3676   list(APPEND file_deps ${_ep_cache_args_script})
3677
3678   get_property(log
3679     TARGET ${name}
3680     PROPERTY _EP_LOG_CONFIGURE
3681   )
3682   if(log)
3683     set(log LOG 1)
3684   else()
3685     set(log "")
3686   endif()
3687
3688   get_property(uses_terminal
3689     TARGET ${name}
3690     PROPERTY _EP_USES_TERMINAL_CONFIGURE
3691   )
3692   if(uses_terminal)
3693     set(uses_terminal USES_TERMINAL 1)
3694   else()
3695     set(uses_terminal "")
3696   endif()
3697
3698   set(__cmdQuoted)
3699   foreach(__item IN LISTS cmd)
3700     string(APPEND __cmdQuoted " [==[${__item}]==]")
3701   endforeach()
3702   cmake_language(EVAL CODE "
3703     ExternalProject_Add_Step(${name} configure
3704       INDEPENDENT FALSE
3705       COMMAND ${__cmdQuoted}
3706       WORKING_DIRECTORY \${binary_dir}
3707       DEPENDEES patch
3708       DEPENDS \${file_deps}
3709       ${log}
3710       ${uses_terminal}
3711     )"
3712   )
3713 endfunction()
3714
3715
3716 function(_ep_add_build_command name)
3717   ExternalProject_Get_Property(${name} binary_dir)
3718
3719   set(file_deps)
3720   get_property(configure_handled_by_build
3721     TARGET ${name}
3722     PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD
3723   )
3724   if(configure_handled_by_build)
3725     # Depend on other external projects (file-level)
3726     _ep_get_file_deps(file_deps ${name})
3727   endif()
3728
3729   get_property(cmd_set
3730     TARGET ${name}
3731     PROPERTY _EP_BUILD_COMMAND
3732     SET
3733   )
3734   if(cmd_set)
3735     get_property(cmd
3736       TARGET ${name}
3737       PROPERTY _EP_BUILD_COMMAND
3738     )
3739   else()
3740     _ep_get_build_command(${name} BUILD cmd)
3741   endif()
3742
3743   get_property(log
3744     TARGET ${name}
3745     PROPERTY _EP_LOG_BUILD
3746   )
3747   if(log)
3748     set(log LOG 1)
3749   else()
3750     set(log "")
3751   endif()
3752
3753   get_property(uses_terminal
3754     TARGET ${name}
3755     PROPERTY _EP_USES_TERMINAL_BUILD
3756   )
3757   if(uses_terminal)
3758     set(uses_terminal USES_TERMINAL 1)
3759   else()
3760     set(uses_terminal "")
3761   endif()
3762
3763   get_property(build_always
3764     TARGET ${name}
3765     PROPERTY _EP_BUILD_ALWAYS
3766   )
3767   if(build_always)
3768     set(always 1)
3769   else()
3770     set(always 0)
3771   endif()
3772
3773   get_property(build_byproducts
3774     TARGET ${name}
3775     PROPERTY _EP_BUILD_BYPRODUCTS
3776   )
3777
3778   set(__cmdQuoted)
3779   foreach(__item IN LISTS cmd)
3780     string(APPEND __cmdQuoted " [==[${__item}]==]")
3781   endforeach()
3782   cmake_language(EVAL CODE "
3783     ExternalProject_Add_Step(${name} build
3784       INDEPENDENT FALSE
3785       COMMAND ${__cmdQuoted}
3786       BYPRODUCTS \${build_byproducts}
3787       WORKING_DIRECTORY \${binary_dir}
3788       DEPENDEES configure
3789       DEPENDS \${file_deps}
3790       ALWAYS \${always}
3791       ${log}
3792       ${uses_terminal}
3793     )"
3794   )
3795 endfunction()
3796
3797
3798 function(_ep_add_install_command name)
3799   ExternalProject_Get_Property(${name} binary_dir)
3800
3801   get_property(cmd_set
3802     TARGET ${name}
3803     PROPERTY _EP_INSTALL_COMMAND
3804     SET
3805   )
3806   if(cmd_set)
3807     get_property(cmd
3808       TARGET ${name}
3809       PROPERTY _EP_INSTALL_COMMAND
3810     )
3811   else()
3812     _ep_get_build_command(${name} INSTALL cmd)
3813   endif()
3814
3815   get_property(log
3816     TARGET ${name}
3817     PROPERTY _EP_LOG_INSTALL
3818   )
3819   if(log)
3820     set(log LOG 1)
3821   else()
3822     set(log "")
3823   endif()
3824
3825   get_property(uses_terminal
3826     TARGET ${name}
3827     PROPERTY _EP_USES_TERMINAL_INSTALL
3828   )
3829   if(uses_terminal)
3830     set(uses_terminal USES_TERMINAL 1)
3831   else()
3832     set(uses_terminal "")
3833   endif()
3834
3835   set(__cmdQuoted)
3836   foreach(__item IN LISTS cmd)
3837     string(APPEND __cmdQuoted " [==[${__item}]==]")
3838   endforeach()
3839   cmake_language(EVAL CODE "
3840     ExternalProject_Add_Step(${name} install
3841       INDEPENDENT FALSE
3842       COMMAND ${__cmdQuoted}
3843       WORKING_DIRECTORY \${binary_dir}
3844       DEPENDEES build
3845       ${log}
3846       ${uses_terminal}
3847     )"
3848   )
3849 endfunction()
3850
3851
3852 function(_ep_add_test_command name)
3853   ExternalProject_Get_Property(${name} binary_dir)
3854
3855   get_property(before TARGET ${name} PROPERTY _EP_TEST_BEFORE_INSTALL)
3856   get_property(after TARGET ${name} PROPERTY _EP_TEST_AFTER_INSTALL)
3857   get_property(exclude TARGET ${name} PROPERTY _EP_TEST_EXCLUDE_FROM_MAIN)
3858   get_property(cmd_set TARGET ${name} PROPERTY _EP_TEST_COMMAND SET)
3859
3860   # Only actually add the test step if one of the test related properties is
3861   # explicitly set. (i.e. the test step is omitted unless requested...)
3862   #
3863   if(cmd_set OR before OR after OR exclude)
3864     if(cmd_set)
3865       get_property(cmd
3866         TARGET ${name}
3867         PROPERTY _EP_TEST_COMMAND
3868       )
3869     else()
3870       _ep_get_build_command(${name} TEST cmd)
3871     endif()
3872
3873     if(before)
3874       set(dependees_args DEPENDEES build)
3875     else()
3876       set(dependees_args DEPENDEES install)
3877     endif()
3878
3879     if(exclude)
3880       set(dependers_args "")
3881       set(exclude_args EXCLUDE_FROM_MAIN 1)
3882     else()
3883       if(before)
3884         set(dependers_args DEPENDERS install)
3885       else()
3886         set(dependers_args "")
3887       endif()
3888       set(exclude_args "")
3889     endif()
3890
3891     get_property(log
3892       TARGET ${name}
3893       PROPERTY _EP_LOG_TEST
3894     )
3895     if(log)
3896       set(log LOG 1)
3897     else()
3898       set(log "")
3899     endif()
3900
3901     get_property(uses_terminal
3902       TARGET ${name}
3903       PROPERTY _EP_USES_TERMINAL_TEST
3904     )
3905     if(uses_terminal)
3906       set(uses_terminal USES_TERMINAL 1)
3907     else()
3908       set(uses_terminal "")
3909     endif()
3910
3911     set(__cmdQuoted)
3912     foreach(__item IN LISTS cmd)
3913       string(APPEND __cmdQuoted " [==[${__item}]==]")
3914     endforeach()
3915     cmake_language(EVAL CODE "
3916       ExternalProject_Add_Step(${name} test
3917         INDEPENDENT FALSE
3918         COMMAND ${__cmdQuoted}
3919         WORKING_DIRECTORY \${binary_dir}
3920         ${dependees_args}
3921         ${dependers_args}
3922         ${exclude_args}
3923         ${log}
3924         ${uses_terminal}
3925       )"
3926     )
3927   endif()
3928 endfunction()
3929
3930
3931 function(ExternalProject_Add name)
3932   cmake_policy(GET CMP0097 _EP_CMP0097
3933     PARENT_SCOPE # undocumented, do not use outside of CMake
3934   )
3935   cmake_policy(GET CMP0114 cmp0114
3936     PARENT_SCOPE # undocumented, do not use outside of CMake
3937   )
3938   if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12 AND
3939      NOT cmp0114 STREQUAL "NEW")
3940     message(AUTHOR_WARNING
3941       "Policy CMP0114 is not set to NEW.  "
3942       "In order to support the Xcode \"new build system\", "
3943       "this project must be updated to set policy CMP0114 to NEW."
3944       "\n"
3945       "Since CMake is generating for the Xcode \"new build system\", "
3946       "ExternalProject_Add will use policy CMP0114's NEW behavior anyway, "
3947       "but the generated build system may not match what the project intends."
3948     )
3949     set(cmp0114 "NEW")
3950   endif()
3951   cmake_policy(GET CMP0135 _EP_CMP0135
3952     PARENT_SCOPE # undocumented, do not use outside of CMake
3953   )
3954
3955   _ep_get_configuration_subdir_genex(cfgdir)
3956
3957   # Add a custom target for the external project.
3958   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
3959   _ep_get_complete_stampfile(${name} complete_stamp_file)
3960
3961   cmake_policy(PUSH)
3962   if(cmp0114 STREQUAL "NEW")
3963     # To implement CMP0114 NEW behavior with Makefile generators,
3964     # we need CMP0113 NEW behavior.
3965     cmake_policy(SET CMP0113 NEW)
3966   endif()
3967   # The "ALL" option to add_custom_target just tells it to not set the
3968   # EXCLUDE_FROM_ALL target property. Later, if the EXCLUDE_FROM_ALL
3969   # argument was passed, we explicitly set it for the target.
3970   add_custom_target(${name} ALL DEPENDS ${complete_stamp_file})
3971   cmake_policy(POP)
3972   set_target_properties(${name} PROPERTIES
3973     _EP_IS_EXTERNAL_PROJECT 1
3974     LABELS ${name}
3975     FOLDER "ExternalProjectTargets/${name}"
3976     _EP_CMP0114 "${cmp0114}"
3977   )
3978
3979   set(keywords
3980     #
3981     # Directory options
3982     #
3983     PREFIX
3984     TMP_DIR
3985     STAMP_DIR
3986     LOG_DIR
3987     DOWNLOAD_DIR
3988     SOURCE_DIR
3989     BINARY_DIR
3990     INSTALL_DIR
3991     #
3992     # Download step options
3993     #
3994     DOWNLOAD_COMMAND
3995     #
3996     URL
3997     URL_HASH
3998     URL_MD5
3999     DOWNLOAD_NAME
4000     DOWNLOAD_EXTRACT_TIMESTAMP
4001     DOWNLOAD_NO_EXTRACT
4002     DOWNLOAD_NO_PROGRESS
4003     TIMEOUT
4004     INACTIVITY_TIMEOUT
4005     HTTP_USERNAME
4006     HTTP_PASSWORD
4007     HTTP_HEADER
4008     TLS_VERIFY     # Also used for git clone operations
4009     TLS_CAINFO
4010     NETRC
4011     NETRC_FILE
4012     #
4013     GIT_REPOSITORY
4014     GIT_TAG
4015     GIT_REMOTE_NAME
4016     GIT_SUBMODULES
4017     GIT_SUBMODULES_RECURSE
4018     GIT_SHALLOW
4019     GIT_PROGRESS
4020     GIT_CONFIG
4021     GIT_REMOTE_UPDATE_STRATEGY
4022     #
4023     SVN_REPOSITORY
4024     SVN_REVISION
4025     SVN_USERNAME
4026     SVN_PASSWORD
4027     SVN_TRUST_CERT
4028     #
4029     HG_REPOSITORY
4030     HG_TAG
4031     #
4032     CVS_REPOSITORY
4033     CVS_MODULE
4034     CVS_TAG
4035     #
4036     # Update step options
4037     #
4038     UPDATE_COMMAND
4039     UPDATE_DISCONNECTED
4040     #
4041     # Patch step options
4042     #
4043     PATCH_COMMAND
4044     #
4045     # Configure step options
4046     #
4047     CONFIGURE_COMMAND
4048     CMAKE_COMMAND
4049     CMAKE_GENERATOR
4050     CMAKE_GENERATOR_PLATFORM
4051     CMAKE_GENERATOR_TOOLSET
4052     CMAKE_GENERATOR_INSTANCE
4053     CMAKE_ARGS
4054     CMAKE_CACHE_ARGS
4055     CMAKE_CACHE_DEFAULT_ARGS
4056     SOURCE_SUBDIR
4057     CONFIGURE_HANDLED_BY_BUILD
4058     #
4059     # Build step options
4060     #
4061     BUILD_COMMAND
4062     BUILD_IN_SOURCE
4063     BUILD_ALWAYS
4064     BUILD_BYPRODUCTS
4065     #
4066     # Install step options
4067     #
4068     INSTALL_COMMAND
4069     #
4070     # Test step options
4071     #
4072     TEST_COMMAND
4073     TEST_BEFORE_INSTALL
4074     TEST_AFTER_INSTALL
4075     TEST_EXCLUDE_FROM_MAIN
4076     #
4077     # Logging options
4078     #
4079     LOG_DOWNLOAD
4080     LOG_UPDATE
4081     LOG_PATCH
4082     LOG_CONFIGURE
4083     LOG_BUILD
4084     LOG_INSTALL
4085     LOG_TEST
4086     LOG_MERGED_STDOUTERR
4087     LOG_OUTPUT_ON_FAILURE
4088     #
4089     # Terminal access options
4090     #
4091     USES_TERMINAL_DOWNLOAD
4092     USES_TERMINAL_UPDATE
4093     USES_TERMINAL_PATCH
4094     USES_TERMINAL_CONFIGURE
4095     USES_TERMINAL_BUILD
4096     USES_TERMINAL_INSTALL
4097     USES_TERMINAL_TEST
4098     #
4099     # Target options
4100     #
4101     DEPENDS
4102     EXCLUDE_FROM_ALL
4103     STEP_TARGETS
4104     INDEPENDENT_STEP_TARGETS
4105     #
4106     # Miscellaneous options
4107     #
4108     LIST_SEPARATOR
4109   )
4110   _ep_parse_arguments(
4111     ExternalProject_Add
4112     "${keywords}"
4113     ${name}
4114     _EP_
4115     "${ARGN}"
4116   )
4117   _ep_set_directories(${name})
4118   _ep_get_step_stampfile(${name} "done" done_stamp_file)
4119   _ep_get_step_stampfile(${name} "install" install_stamp_file)
4120
4121   # Set the EXCLUDE_FROM_ALL target property if required.
4122   get_property(exclude_from_all
4123     TARGET ${name}
4124     PROPERTY _EP_EXCLUDE_FROM_ALL
4125   )
4126   if(exclude_from_all)
4127     set_property(TARGET ${name} PROPERTY EXCLUDE_FROM_ALL TRUE)
4128   endif()
4129
4130   # The 'complete' step depends on all other steps and creates a
4131   # 'done' mark.  A dependent external project's 'configure' step
4132   # depends on the 'done' mark so that it rebuilds when this project
4133   # rebuilds.  It is important that 'done' is not the output of any
4134   # custom command so that CMake does not propagate build rules to
4135   # other external project targets, which may cause problems during
4136   # parallel builds.  However, the Ninja generator needs to see the entire
4137   # dependency graph, and can cope with custom commands belonging to
4138   # multiple targets, so we add the 'done' mark as an output for Ninja only.
4139   set(complete_outputs ${complete_stamp_file})
4140   if(${CMAKE_GENERATOR} MATCHES "Ninja")
4141     set(complete_outputs ${complete_outputs} ${done_stamp_file})
4142   endif()
4143
4144   add_custom_command(
4145     OUTPUT ${complete_outputs}
4146     COMMENT "Completed '${name}'"
4147     COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
4148     COMMAND ${CMAKE_COMMAND} -E touch ${complete_stamp_file}
4149     COMMAND ${CMAKE_COMMAND} -E touch ${done_stamp_file}
4150     DEPENDS ${install_stamp_file}
4151     VERBATIM
4152   )
4153
4154   # Depend on other external projects (target-level).
4155   get_property(deps
4156     TARGET ${name}
4157     PROPERTY _EP_DEPENDS
4158   )
4159   foreach(arg IN LISTS deps)
4160     add_dependencies(${name} ${arg})
4161   endforeach()
4162
4163   # Set up custom build steps based on the target properties.
4164   # Each step depends on the previous one.
4165   #
4166   # The target depends on the output of the final step.
4167   # (Already set up above in the DEPENDS of the add_custom_target command.)
4168   #
4169   _ep_add_mkdir_command(${name})
4170   _ep_add_download_command(${name})
4171   _ep_add_update_command(${name})
4172   _ep_add_patch_command(${name})
4173   _ep_add_configure_command(${name})
4174   _ep_add_build_command(${name})
4175   _ep_add_install_command(${name})
4176
4177   # Test is special in that it might depend on build, or it might depend
4178   # on install.
4179   #
4180   _ep_add_test_command(${name})
4181 endfunction()
4182
4183 cmake_policy(POP)