Imported Upstream version 3.25.0
[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       if(step STREQUAL "INSTALL")
1844         set(args --install ".")
1845       else()
1846         set(args --build ".")
1847       endif()
1848       get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
1849       if(_isMultiConfig)
1850         if (CMAKE_CFG_INTDIR AND
1851             NOT CMAKE_CFG_INTDIR STREQUAL "." AND
1852             NOT CMAKE_CFG_INTDIR MATCHES "\\$")
1853           # CMake 3.4 and below used the CMAKE_CFG_INTDIR placeholder value
1854           # provided by multi-configuration generators.  Some projects were
1855           # taking advantage of that undocumented implementation detail to
1856           # specify a specific configuration here.  They should use
1857           # BUILD_COMMAND to change the default command instead, but for
1858           # compatibility honor the value.
1859           set(config ${CMAKE_CFG_INTDIR})
1860           message(AUTHOR_WARNING
1861             "CMAKE_CFG_INTDIR should not be set by project code.\n"
1862             "To get a non-default build command, use the BUILD_COMMAND option."
1863           )
1864         else()
1865           set(config $<CONFIG>)
1866         endif()
1867         list(APPEND args --config ${config})
1868       endif()
1869       # But for "TEST" drive the project with corresponding "ctest".
1870       if("x${step}x" STREQUAL "xTESTx")
1871         string(REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}")
1872         set(args "")
1873         if(_isMultiConfig)
1874           list(APPEND args -C ${config})
1875         endif()
1876       endif()
1877     endif()
1878   else()
1879     # Non-CMake project.  Guess "make" and "make install" and "make test".
1880     if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
1881       # Try to get the parallel arguments
1882       set(cmd "$(MAKE)")
1883     else()
1884       set(cmd "make")
1885     endif()
1886     if(step STREQUAL "INSTALL")
1887       set(args install)
1888     endif()
1889     if("x${step}x" STREQUAL "xTESTx")
1890       set(args test)
1891     endif()
1892   endif()
1893
1894   # Use user-specified arguments instead of default arguments, if any.
1895   get_property(have_args TARGET ${name} PROPERTY _EP_${step}_ARGS SET)
1896   if(have_args)
1897     get_target_property(args ${name} _EP_${step}_ARGS)
1898   endif()
1899
1900   if(NOT "${args}" STREQUAL "")
1901     # args could have empty items, so we must quote it to prevent them
1902     # from being silently removed
1903     list(APPEND cmd "${args}")
1904   endif()
1905   set(${cmd_var} "${cmd}" PARENT_SCOPE)
1906 endfunction()
1907
1908 function(_ep_write_log_script
1909   name
1910   step
1911   cmd_var
1912 )
1913   ExternalProject_Get_Property(${name} log_dir)
1914   ExternalProject_Get_Property(${name} stamp_dir)
1915   set(command "${${cmd_var}}")
1916
1917   set(make "")
1918   set(code_cygpath_make "")
1919   if(command MATCHES "^\\$\\(MAKE\\)")
1920     # GNU make recognizes the string "$(MAKE)" as recursive make, so
1921     # ensure that it appears directly in the makefile.
1922     string(REGEX REPLACE "^\\$\\(MAKE\\)" "\${make}" command "${command}")
1923     set(make "-Dmake=$(MAKE)")
1924
1925     if(WIN32 AND NOT CYGWIN)
1926       set(code_cygpath_make "
1927 if(\${make} MATCHES \"^/\")
1928   execute_process(
1929     COMMAND cygpath -w \${make}
1930     OUTPUT_VARIABLE cygpath_make
1931     ERROR_VARIABLE cygpath_make
1932     RESULT_VARIABLE cygpath_error
1933     OUTPUT_STRIP_TRAILING_WHITESPACE
1934   )
1935   if(NOT cygpath_error)
1936     set(make \${cygpath_make})
1937   endif()
1938 endif()
1939 ")
1940     endif()
1941   endif()
1942
1943   set(config "")
1944   if("${CMAKE_CFG_INTDIR}" MATCHES "^\\$")
1945     string(REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}")
1946     set(config "-Dconfig=${CMAKE_CFG_INTDIR}")
1947   endif()
1948
1949   # Wrap multiple 'COMMAND' lines up into a second-level wrapper
1950   # script so all output can be sent to one log file.
1951   if(command MATCHES "(^|;)COMMAND;")
1952     set(code_execute_process "
1953 ${code_cygpath_make}
1954 execute_process(COMMAND \${command} RESULT_VARIABLE result)
1955 if(result)
1956   set(msg \"Command failed (\${result}):\\n\")
1957   foreach(arg IN LISTS command)
1958     set(msg \"\${msg} '\${arg}'\")
1959   endforeach()
1960   message(FATAL_ERROR \"\${msg}\")
1961 endif()
1962 ")
1963     set(code "")
1964     set(cmd "")
1965     set(sep "")
1966     foreach(arg IN LISTS command)
1967       if("x${arg}" STREQUAL "xCOMMAND")
1968         if(NOT "x${cmd}" STREQUAL "x")
1969           string(APPEND code "set(command \"${cmd}\")${code_execute_process}")
1970         endif()
1971         set(cmd "")
1972         set(sep "")
1973       else()
1974         string(APPEND cmd "${sep}${arg}")
1975         set(sep ";")
1976       endif()
1977     endforeach()
1978     string(APPEND code "set(command \"${cmd}\")${code_execute_process}")
1979     file(GENERATE
1980       OUTPUT "${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake"
1981       CONTENT "${code}"
1982     )
1983     set(command
1984       ${CMAKE_COMMAND}
1985       "-Dmake=\${make}"
1986       "-Dconfig=\${config}"
1987       -P ${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake
1988     )
1989   endif()
1990
1991   # Wrap the command in a script to log output to files.
1992   set(script ${stamp_dir}/${name}-${step}-$<CONFIG>.cmake)
1993   set(logbase ${log_dir}/${name}-${step})
1994   get_property(log_merged
1995     TARGET ${name}
1996     PROPERTY _EP_LOG_MERGED_STDOUTERR
1997   )
1998   get_property(log_output_on_failure
1999     TARGET ${name}
2000     PROPERTY _EP_LOG_OUTPUT_ON_FAILURE
2001   )
2002   if (log_merged)
2003     set(stdout_log "${logbase}.log")
2004     set(stderr_log "${logbase}.log")
2005   else()
2006     set(stdout_log "${logbase}-out.log")
2007     set(stderr_log "${logbase}-err.log")
2008   endif()
2009   set(code "
2010 cmake_minimum_required(VERSION 3.15)
2011 ${code_cygpath_make}
2012 set(command \"${command}\")
2013 set(log_merged \"${log_merged}\")
2014 set(log_output_on_failure \"${log_output_on_failure}\")
2015 set(stdout_log \"${stdout_log}\")
2016 set(stderr_log \"${stderr_log}\")
2017 execute_process(
2018   COMMAND \${command}
2019   RESULT_VARIABLE result
2020   OUTPUT_FILE \"\${stdout_log}\"
2021   ERROR_FILE \"\${stderr_log}\"
2022 )
2023 macro(read_up_to_max_size log_file output_var)
2024   file(SIZE \${log_file} determined_size)
2025   set(max_size 10240)
2026   if (determined_size GREATER max_size)
2027     math(EXPR seek_position \"\${determined_size} - \${max_size}\")
2028     file(READ \${log_file} \${output_var} OFFSET \${seek_position})
2029     set(\${output_var} \"...skipping to end...\\n\${\${output_var}}\")
2030   else()
2031     file(READ \${log_file} \${output_var})
2032   endif()
2033 endmacro()
2034 if(result)
2035   set(msg \"Command failed: \${result}\\n\")
2036   foreach(arg IN LISTS command)
2037     set(msg \"\${msg} '\${arg}'\")
2038   endforeach()
2039   if (\${log_merged})
2040     set(msg \"\${msg}\\nSee also\\n  \${stderr_log}\")
2041   else()
2042     set(msg \"\${msg}\\nSee also\\n  ${logbase}-*.log\")
2043   endif()
2044   if (\${log_output_on_failure})
2045     message(SEND_ERROR \"\${msg}\")
2046     if (\${log_merged})
2047       read_up_to_max_size(\"\${stderr_log}\" error_log_contents)
2048       message(STATUS \"Log output is:\\n\${error_log_contents}\")
2049     else()
2050       read_up_to_max_size(\"\${stdout_log}\" out_log_contents)
2051       read_up_to_max_size(\"\${stderr_log}\" err_log_contents)
2052       message(STATUS \"stdout output is:\\n\${out_log_contents}\")
2053       message(STATUS \"stderr output is:\\n\${err_log_contents}\")
2054     endif()
2055     message(FATAL_ERROR \"Stopping after outputting logs.\")
2056   else()
2057     message(FATAL_ERROR \"\${msg}\")
2058   endif()
2059 else()
2060   if(NOT \"${CMAKE_GENERATOR}\" MATCHES \"Ninja\")
2061     set(msg \"${name} ${step} command succeeded.  See also ${logbase}-*.log\")
2062     message(STATUS \"\${msg}\")
2063   endif()
2064 endif()
2065 ")
2066   file(GENERATE OUTPUT "${script}" CONTENT "${code}")
2067   set(command ${CMAKE_COMMAND} ${make} ${config} -P ${script})
2068   set(${cmd_var} "${command}" PARENT_SCOPE)
2069 endfunction()
2070
2071 # On multi-config generators, provide a placeholder for a per-config subdir.
2072 # On single-config generators, this is empty.
2073 function(_ep_get_configuration_subdir_genex suffix_var)
2074   set(suffix "")
2075   get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
2076   if(_isMultiConfig)
2077     if(CMAKE_GENERATOR STREQUAL "Xcode")
2078       # The Xcode generator does not support per-config sources,
2079       # so use the underlying build system's placeholder instead.
2080       set(suffix "/${CMAKE_CFG_INTDIR}")
2081     else()
2082       set(suffix "/$<CONFIG>")
2083     endif()
2084   endif()
2085   set(${suffix_var} "${suffix}" PARENT_SCOPE)
2086 endfunction()
2087
2088
2089 function(_ep_get_step_stampfile
2090   name
2091   step
2092   stampfile_var
2093 )
2094   ExternalProject_Get_Property(${name} stamp_dir)
2095
2096   _ep_get_configuration_subdir_genex(cfgdir)
2097   set(stampfile "${stamp_dir}${cfgdir}/${name}-${step}")
2098
2099   set(${stampfile_var} "${stampfile}" PARENT_SCOPE)
2100 endfunction()
2101
2102
2103 function(_ep_get_complete_stampfile
2104   name
2105   stampfile_var
2106 )
2107   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
2108   _ep_get_configuration_subdir_genex(cfgdir)
2109   set(stampfile "${cmf_dir}${cfgdir}/${name}-complete")
2110
2111   set(${stampfile_var} ${stampfile} PARENT_SCOPE)
2112 endfunction()
2113
2114
2115 function(_ep_step_add_target
2116   name
2117   step
2118   no_deps
2119 )
2120   if(TARGET ${name}-${step})
2121     return()
2122   endif()
2123   get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
2124   _ep_get_step_stampfile(${name} ${step} stamp_file)
2125   cmake_policy(PUSH)
2126   if(cmp0114 STREQUAL "NEW")
2127     # To implement CMP0114 NEW behavior with Makefile generators,
2128     # we need CMP0113 NEW behavior.
2129     cmake_policy(SET CMP0113 NEW)
2130   endif()
2131   add_custom_target(${name}-${step} DEPENDS ${stamp_file})
2132   cmake_policy(POP)
2133   set_target_properties(${name}-${step} PROPERTIES
2134     _EP_IS_EXTERNAL_PROJECT_STEP 1
2135     LABELS "${name}"
2136     FOLDER "ExternalProjectTargets/${name}"
2137   )
2138
2139   if(cmp0114 STREQUAL "NEW")
2140     # Add target-level dependencies for the step.
2141     get_property(exclude_from_main
2142       TARGET ${name}
2143       PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN
2144     )
2145     if(NOT exclude_from_main)
2146       add_dependencies(${name} ${name}-${step})
2147     endif()
2148     _ep_step_add_target_dependencies(${name} ${step} ${step})
2149     _ep_step_add_target_dependents(${name} ${step} ${step})
2150
2151     get_property(independent TARGET ${name} PROPERTY _EP_${step}_INDEPENDENT)
2152   else()
2153     if(no_deps AND "${step}" MATCHES "^(configure|build|install|test)$")
2154       message(AUTHOR_WARNING
2155         "Using NO_DEPENDS for \"${step}\" step  might break parallel builds"
2156       )
2157     endif()
2158     set(independent ${no_deps})
2159   endif()
2160
2161   # Depend on other external projects (target-level).
2162   if(NOT independent)
2163     get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
2164     foreach(arg IN LISTS deps)
2165       add_dependencies(${name}-${step} ${arg})
2166     endforeach()
2167   endif()
2168 endfunction()
2169
2170
2171 function(_ep_step_add_target_dependencies
2172   name
2173   step
2174   node
2175 )
2176   get_property(dependees
2177     TARGET ${name}
2178     PROPERTY _EP_${node}_INTERNAL_DEPENDEES
2179   )
2180   list(REMOVE_DUPLICATES dependees)
2181   foreach(dependee IN LISTS dependees)
2182     get_property(exclude_from_main
2183       TARGET ${name}
2184       PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN
2185     )
2186     get_property(dependee_dependers
2187       TARGET ${name}
2188       PROPERTY _EP_${dependee}_INTERNAL_DEPENDERS
2189     )
2190     if(exclude_from_main OR dependee_dependers MATCHES ";")
2191       # The step on which our step target depends itself has
2192       # dependents in multiple targes.  It needs a step target too
2193       # so that there is a unique place for its custom command.
2194       _ep_step_add_target("${name}" "${dependee}" "FALSE")
2195     endif()
2196
2197     if(TARGET ${name}-${dependee})
2198       add_dependencies(${name}-${step} ${name}-${dependee})
2199     else()
2200       _ep_step_add_target_dependencies(${name} ${step} ${dependee})
2201     endif()
2202   endforeach()
2203 endfunction()
2204
2205
2206 function(_ep_step_add_target_dependents
2207   name
2208   step
2209   node
2210 )
2211   get_property(dependers
2212     TARGET ${name}
2213     PROPERTY _EP_${node}_INTERNAL_DEPENDERS
2214   )
2215   list(REMOVE_DUPLICATES dependers)
2216   foreach(depender IN LISTS dependers)
2217     if(TARGET ${name}-${depender})
2218       add_dependencies(${name}-${depender} ${name}-${step})
2219     else()
2220       _ep_step_add_target_dependents(${name} ${step} ${depender})
2221     endif()
2222   endforeach()
2223 endfunction()
2224
2225
2226 function(ExternalProject_Add_StepTargets name)
2227   get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
2228   set(steps ${ARGN})
2229   if(ARGC GREATER 1 AND "${ARGV1}" STREQUAL "NO_DEPENDS")
2230     set(no_deps 1)
2231     list(REMOVE_AT steps 0)
2232   else()
2233     set(no_deps 0)
2234   endif()
2235   if(cmp0114 STREQUAL "NEW")
2236     if(no_deps)
2237       message(FATAL_ERROR
2238         "The 'NO_DEPENDS' option is no longer allowed.  "
2239         "It has been superseded by the per-step 'INDEPENDENT' option.  "
2240         "See policy CMP0114."
2241       )
2242     endif()
2243   elseif(cmp0114 STREQUAL "")
2244     cmake_policy(GET_WARNING CMP0114 _cmp0114_warning)
2245     string(APPEND _cmp0114_warning "\n"
2246       "ExternalProject target '${name}' would depend on the targets for "
2247       "step(s) '${steps}' under policy CMP0114, but this is being left out "
2248       "for compatibility since the policy is not set."
2249     )
2250     if(no_deps)
2251       string(APPEND _cmp0114_warning "  "
2252         "Also, the NO_DEPENDS option is deprecated in favor of policy CMP0114."
2253       )
2254     endif()
2255     message(AUTHOR_WARNING "${_cmp0114_warning}")
2256   endif()
2257   foreach(step ${steps})
2258     _ep_step_add_target("${name}" "${step}" "${no_deps}")
2259   endforeach()
2260 endfunction()
2261
2262
2263 function(ExternalProject_Add_Step name step)
2264   get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114)
2265   _ep_get_complete_stampfile(${name} complete_stamp_file)
2266   _ep_get_step_stampfile(${name} ${step} stamp_file)
2267
2268   set(keywords
2269     COMMAND
2270     COMMENT
2271     DEPENDEES
2272     DEPENDERS
2273     DEPENDS
2274     INDEPENDENT
2275     BYPRODUCTS
2276     ALWAYS
2277     EXCLUDE_FROM_MAIN
2278     WORKING_DIRECTORY
2279     LOG
2280     USES_TERMINAL
2281   )
2282   _ep_parse_arguments(
2283     ExternalProject_Add_Step
2284     "${keywords}"
2285     ${name}
2286     _EP_${step}_
2287     "${ARGN}"
2288   )
2289
2290   get_property(independent
2291     TARGET ${name}
2292     PROPERTY _EP_${step}_INDEPENDENT
2293   )
2294   if(independent STREQUAL "")
2295     set(independent FALSE)
2296     set_property(TARGET ${name} PROPERTY
2297       _EP_${step}_INDEPENDENT "${independent}"
2298     )
2299   endif()
2300
2301   get_property(exclude_from_main
2302     TARGET ${name}
2303     PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN
2304   )
2305   if(NOT exclude_from_main)
2306     add_custom_command(APPEND
2307       OUTPUT ${complete_stamp_file}
2308       DEPENDS ${stamp_file}
2309     )
2310   endif()
2311
2312   # Steps depending on this step.
2313   get_property(dependers TARGET ${name} PROPERTY _EP_${step}_DEPENDERS)
2314   set_property(TARGET ${name} APPEND PROPERTY
2315     _EP_${step}_INTERNAL_DEPENDERS ${dependers}
2316   )
2317   foreach(depender IN LISTS dependers)
2318     set_property(TARGET ${name} APPEND PROPERTY
2319       _EP_${depender}_INTERNAL_DEPENDEES ${step}
2320     )
2321     _ep_get_step_stampfile(${name} ${depender} depender_stamp_file)
2322     add_custom_command(APPEND
2323       OUTPUT ${depender_stamp_file}
2324       DEPENDS ${stamp_file}
2325     )
2326     if(cmp0114 STREQUAL "NEW" AND NOT independent)
2327       get_property(dep_independent
2328         TARGET ${name}
2329         PROPERTY _EP_${depender}_INDEPENDENT
2330       )
2331       if(dep_independent)
2332         message(FATAL_ERROR
2333           "ExternalProject '${name}' step '${depender}' is marked INDEPENDENT "
2334           "but depends on step '${step}' that is not marked INDEPENDENT."
2335         )
2336       endif()
2337     endif()
2338   endforeach()
2339
2340   # Dependencies on files.
2341   get_property(depends TARGET ${name} PROPERTY _EP_${step}_DEPENDS)
2342
2343   # Byproducts of the step.
2344   get_property(byproducts TARGET ${name} PROPERTY _EP_${step}_BYPRODUCTS)
2345
2346   # Dependencies on steps.
2347   get_property(dependees TARGET ${name} PROPERTY _EP_${step}_DEPENDEES)
2348   set_property(TARGET ${name} APPEND PROPERTY
2349     _EP_${step}_INTERNAL_DEPENDEES ${dependees}
2350   )
2351   foreach(dependee IN LISTS dependees)
2352     set_property(TARGET ${name} APPEND PROPERTY
2353       _EP_${dependee}_INTERNAL_DEPENDERS ${step}
2354     )
2355     _ep_get_step_stampfile(${name} ${dependee} dependee_stamp_file)
2356     list(APPEND depends ${dependee_stamp_file})
2357     if(cmp0114 STREQUAL "NEW" AND independent)
2358       get_property(dep_independent
2359         TARGET ${name}
2360         PROPERTY _EP_${dependee}_INDEPENDENT
2361       )
2362       if(NOT dep_independent)
2363         message(FATAL_ERROR
2364           "ExternalProject '${name}' step '${step}' is marked INDEPENDENT "
2365           "but depends on step '${dependee}' that is not marked INDEPENDENT."
2366         )
2367       endif()
2368     endif()
2369   endforeach()
2370
2371   # The command to run.
2372   get_property(command TARGET ${name} PROPERTY _EP_${step}_COMMAND)
2373   if(command)
2374     set(comment "Performing ${step} step for '${name}'")
2375   else()
2376     set(comment "No ${step} step for '${name}'")
2377   endif()
2378   get_property(work_dir
2379     TARGET ${name}
2380     PROPERTY _EP_${step}_WORKING_DIRECTORY
2381   )
2382
2383   # Replace list separators.
2384   get_property(sep
2385     TARGET ${name}
2386     PROPERTY _EP_LIST_SEPARATOR
2387   )
2388   if(sep AND command)
2389     string(REPLACE "${sep}" "\\;" command "${command}")
2390   endif()
2391
2392   # Replace location tags.
2393   _ep_replace_location_tags(
2394     ${name}
2395     comment
2396     command
2397     work_dir
2398     byproducts
2399   )
2400
2401   # Custom comment?
2402   get_property(comment_set
2403     TARGET ${name}
2404     PROPERTY _EP_${step}_COMMENT
2405     SET
2406   )
2407   if(comment_set)
2408     get_property(comment
2409       TARGET ${name}
2410       PROPERTY _EP_${step}_COMMENT
2411     )
2412   endif()
2413
2414   # Uses terminal?
2415   get_property(uses_terminal
2416     TARGET ${name}
2417     PROPERTY _EP_${step}_USES_TERMINAL
2418   )
2419   if(uses_terminal)
2420     set(uses_terminal USES_TERMINAL)
2421   else()
2422     set(uses_terminal "")
2423   endif()
2424
2425   # Run every time?
2426   get_property(always
2427     TARGET ${name}
2428     PROPERTY _EP_${step}_ALWAYS
2429   )
2430   if(always)
2431     set(touch)
2432     # Mark stamp files for all configs as SYMBOLIC since we do not create them.
2433     # Remove any existing stamp in case the option changed in an existing tree.
2434     get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
2435     if(_isMultiConfig)
2436       _ep_get_configuration_subdir_genex(cfgdir)
2437       foreach(cfg ${CMAKE_CONFIGURATION_TYPES})
2438         string(REPLACE "${cfgdir}" "/${cfg}"
2439           stamp_file_config "${stamp_file}"
2440         )
2441         set_property(SOURCE ${stamp_file_config} PROPERTY SYMBOLIC 1)
2442         file(REMOVE ${stamp_file_config})
2443       endforeach()
2444       if(CMAKE_GENERATOR STREQUAL "Xcode")
2445         # See Xcode case in _ep_get_configuration_subdir_genex.
2446         set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
2447       endif()
2448     else()
2449       set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
2450       file(REMOVE ${stamp_file})
2451     endif()
2452   else()
2453     set(touch ${CMAKE_COMMAND} -E touch ${stamp_file})
2454   endif()
2455
2456   # Wrap with log script?
2457   get_property(log TARGET ${name} PROPERTY _EP_${step}_LOG)
2458   if(command AND log)
2459     _ep_write_log_script(${name} ${step} command)
2460   endif()
2461
2462   if("${command}" STREQUAL "")
2463     # Some generators (i.e. Xcode) will not generate a file level target
2464     # if no command is set, and therefore the dependencies on this
2465     # target will be broken.
2466     # The empty command is replaced by an echo command here in order to
2467     # avoid this issue.
2468     set(command ${CMAKE_COMMAND} -E echo_append)
2469   endif()
2470
2471   set(__cmdQuoted)
2472   foreach(__item IN LISTS command)
2473     string(APPEND __cmdQuoted " [==[${__item}]==]")
2474   endforeach()
2475   cmake_language(EVAL CODE "
2476     add_custom_command(
2477       OUTPUT \${stamp_file}
2478       BYPRODUCTS \${byproducts}
2479       COMMENT \${comment}
2480       COMMAND ${__cmdQuoted}
2481       COMMAND \${touch}
2482       DEPENDS \${depends}
2483       WORKING_DIRECTORY \${work_dir}
2484       VERBATIM
2485       ${uses_terminal}
2486     )"
2487   )
2488   set_property(TARGET ${name} APPEND PROPERTY _EP_STEPS ${step})
2489
2490   # Add custom "step target"?
2491   get_property(step_targets
2492     TARGET ${name}
2493     PROPERTY _EP_STEP_TARGETS
2494   )
2495   if(NOT step_targets)
2496     get_property(step_targets
2497       DIRECTORY
2498       PROPERTY EP_STEP_TARGETS
2499     )
2500   endif()
2501   foreach(st ${step_targets})
2502     if("${st}" STREQUAL "${step}")
2503       _ep_step_add_target("${name}" "${step}" "FALSE")
2504       break()
2505     endif()
2506   endforeach()
2507
2508   get_property(independent_step_targets
2509     TARGET ${name} PROPERTY
2510     _EP_INDEPENDENT_STEP_TARGETS
2511   )
2512   if(NOT independent_step_targets)
2513     get_property(independent_step_targets
2514       DIRECTORY
2515       PROPERTY EP_INDEPENDENT_STEP_TARGETS
2516     )
2517   endif()
2518   if(cmp0114 STREQUAL "NEW")
2519     if(independent_step_targets)
2520       message(FATAL_ERROR
2521         "ExternalProject '${name}' option 'INDEPENDENT_STEP_TARGETS' is set to"
2522         "\n  ${independent_step_targets}\n"
2523         "but the option is no longer allowed.  "
2524         "It has been superseded by the per-step 'INDEPENDENT' option.  "
2525         "See policy CMP0114."
2526       )
2527     endif()
2528   else()
2529     if(independent_step_targets AND cmp0114 STREQUAL "")
2530       get_property(warned
2531         TARGET ${name}
2532         PROPERTY _EP_CMP0114_WARNED_INDEPENDENT_STEP_TARGETS
2533       )
2534       if(NOT warned)
2535         set_property(TARGET ${name} PROPERTY
2536           _EP_CMP0114_WARNED_INDEPENDENT_STEP_TARGETS 1
2537         )
2538         cmake_policy(GET_WARNING CMP0114 _cmp0114_warning)
2539         string(APPEND _cmp0114_warning
2540           "\n"
2541           "ExternalProject '${name}' option INDEPENDENT_STEP_TARGETS is set to"
2542           "\n  ${independent_step_targets}\n"
2543           "but the option is deprecated in favor of policy CMP0114."
2544         )
2545         message(AUTHOR_WARNING "${_cmp0114_warning}")
2546       endif()
2547     endif()
2548     foreach(st ${independent_step_targets})
2549       if("${st}" STREQUAL "${step}")
2550         _ep_step_add_target("${name}" "${step}" "TRUE")
2551         break()
2552       endif()
2553     endforeach()
2554   endif()
2555 endfunction()
2556
2557
2558 function(ExternalProject_Add_StepDependencies name step)
2559   set(dependencies ${ARGN})
2560
2561   # Sanity checks on "name" and "step".
2562   if(NOT TARGET ${name})
2563     message(FATAL_ERROR
2564       "Cannot find target \"${name}\". Perhaps it has not yet been created "
2565       "using ExternalProject_Add."
2566     )
2567   endif()
2568
2569   get_property(type TARGET ${name} PROPERTY TYPE)
2570   if(NOT type STREQUAL "UTILITY")
2571     message(FATAL_ERROR
2572       "Target \"${name}\" was not generated by ExternalProject_Add."
2573     )
2574   endif()
2575
2576   get_property(is_ep TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT)
2577   if(NOT is_ep)
2578     message(FATAL_ERROR
2579       "Target \"${name}\" was not generated by ExternalProject_Add."
2580     )
2581   endif()
2582
2583   get_property(steps TARGET ${name} PROPERTY _EP_STEPS)
2584   list(FIND steps ${step} is_step)
2585   if(is_step LESS 0)
2586     message(FATAL_ERROR
2587       "External project \"${name}\" does not have a step \"${step}\"."
2588     )
2589   endif()
2590
2591   if(TARGET ${name}-${step})
2592     get_property(type TARGET ${name}-${step} PROPERTY TYPE)
2593     if(NOT type STREQUAL "UTILITY")
2594       message(FATAL_ERROR
2595         "Target \"${name}-${step}\" was not generated by "
2596         "ExternalProject_Add_StepTargets."
2597       )
2598     endif()
2599     get_property(is_ep_step
2600       TARGET ${name}-${step}
2601       PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP
2602     )
2603     if(NOT is_ep_step)
2604       message(FATAL_ERROR
2605         "Target \"${name}-${step}\" was not generated by "
2606         "ExternalProject_Add_StepTargets."
2607       )
2608     endif()
2609   endif()
2610
2611   # Always add file-level dependency, but add target-level dependency
2612   # only if the target exists for that step.
2613   _ep_get_step_stampfile(${name} ${step} stamp_file)
2614   foreach(dep ${dependencies})
2615     add_custom_command(APPEND
2616       OUTPUT ${stamp_file}
2617       DEPENDS ${dep}
2618     )
2619     if(TARGET ${name}-${step})
2620       foreach(dep ${dependencies})
2621         add_dependencies(${name}-${step} ${dep})
2622       endforeach()
2623     endif()
2624   endforeach()
2625
2626 endfunction()
2627
2628
2629 function(_ep_add_mkdir_command name)
2630   ExternalProject_Get_Property(${name} tmp_dir)
2631   set(script_filename "${tmp_dir}/${name}-mkdirs.cmake")
2632   _ep_get_configuration_subdir_genex(cfgdir)
2633
2634   ExternalProject_Add_Step(${name} mkdir
2635     INDEPENDENT TRUE
2636     COMMENT "Creating directories for '${name}'"
2637     COMMAND ${CMAKE_COMMAND} -Dcfgdir=${cfgdir} -P ${script_filename}
2638   )
2639 endfunction()
2640
2641
2642 function(_ep_is_dir_empty dir empty_var)
2643   file(GLOB gr "${dir}/*")
2644   if("${gr}" STREQUAL "")
2645     set(${empty_var} 1 PARENT_SCOPE)
2646   else()
2647     set(${empty_var} 0 PARENT_SCOPE)
2648   endif()
2649 endfunction()
2650
2651 function(_ep_get_git_submodules_recurse git_submodules_recurse)
2652   # Checks for GIT_SUBMODULES_RECURSE property. Default is ON, which sets
2653   # git_submodules_recurse output variable to "--recursive". Otherwise, the
2654   # output variable is set to an empty value "".
2655   get_property(git_submodules_recurse_set
2656     TARGET ${name}
2657     PROPERTY _EP_GIT_SUBMODULES_RECURSE
2658     SET
2659   )
2660   if(NOT git_submodules_recurse_set)
2661     set(recurseFlag "--recursive")
2662   else()
2663     get_property(git_submodules_recurse_value
2664       TARGET ${name}
2665       PROPERTY _EP_GIT_SUBMODULES_RECURSE
2666     )
2667     if(git_submodules_recurse_value)
2668       set(recurseFlag "--recursive")
2669     else()
2670       set(recurseFlag "")
2671     endif()
2672   endif()
2673   set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE)
2674
2675   # The git submodule update '--recursive' flag requires git >= v1.6.5
2676   if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5)
2677     message(FATAL_ERROR
2678       "git version 1.6.5 or later required for --recursive flag with "
2679       "'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'"
2680     )
2681   endif()
2682 endfunction()
2683
2684
2685 function(_ep_add_download_command name)
2686   ExternalProject_Get_Property(${name}
2687     source_dir
2688     stamp_dir
2689     download_dir
2690     tmp_dir
2691   )
2692
2693   get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
2694   get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
2695   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
2696   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
2697   get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
2698   get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
2699   get_property(url TARGET ${name} PROPERTY _EP_URL)
2700   get_property(fname TARGET ${name} PROPERTY _EP_DOWNLOAD_NAME)
2701
2702   # TODO: Perhaps file:// should be copied to download dir before extraction.
2703   string(REGEX REPLACE "file://" "" url "${url}")
2704
2705   set(depends)
2706   set(comment)
2707   set(work_dir)
2708   set(extra_repo_info)
2709
2710   if(cmd_set)
2711     set(work_dir ${download_dir})
2712     set(method custom)
2713   elseif(cvs_repository)
2714     set(method cvs)
2715     find_package(CVS QUIET)
2716     if(NOT CVS_EXECUTABLE)
2717       message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
2718     endif()
2719
2720     get_target_property(cvs_module ${name} _EP_CVS_MODULE)
2721     if(NOT cvs_module)
2722       message(FATAL_ERROR "error: no CVS_MODULE")
2723     endif()
2724
2725     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
2726     get_filename_component(src_name "${source_dir}" NAME)
2727     get_filename_component(work_dir "${source_dir}" PATH)
2728     set(comment "Performing download step (CVS checkout) for '${name}'")
2729     set(cmd
2730       ${CVS_EXECUTABLE}
2731       -d ${cvs_repository}
2732       -q
2733       co ${cvs_tag}
2734       -d ${src_name}
2735       ${cvs_module}
2736     )
2737
2738   elseif(svn_repository)
2739     set(method svn)
2740     find_package(Subversion QUIET)
2741     if(NOT Subversion_SVN_EXECUTABLE)
2742       message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
2743     endif()
2744
2745     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
2746     get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
2747     get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
2748     get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
2749     get_property(uses_terminal
2750       TARGET ${name}
2751       PROPERTY _EP_USES_TERMINAL_DOWNLOAD
2752     )
2753     if(uses_terminal)
2754       set(svn_interactive_args "")
2755     else()
2756       set(svn_interactive_args "--non-interactive")
2757     endif()
2758
2759     get_filename_component(src_name "${source_dir}" NAME)
2760     get_filename_component(work_dir "${source_dir}" PATH)
2761     set(comment "Performing download step (SVN checkout) for '${name}'")
2762     set(svn_user_pw_args "")
2763     if(DEFINED svn_username)
2764       set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
2765     endif()
2766     if(DEFINED svn_password)
2767       set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
2768     endif()
2769     if(svn_trust_cert)
2770       set(svn_trust_cert_args --trust-server-cert)
2771     endif()
2772     set(cmd
2773       ${Subversion_SVN_EXECUTABLE}
2774       co
2775       ${svn_repository}
2776       ${svn_revision}
2777       ${svn_interactive_args}
2778       ${svn_trust_cert_args}
2779       ${svn_user_pw_args}
2780       ${src_name}
2781     )
2782
2783   elseif(git_repository)
2784     set(method git)
2785     # FetchContent gives us these directly, so don't try to recompute them
2786     if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
2787       unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
2788       find_package(Git QUIET)
2789       if(NOT GIT_EXECUTABLE)
2790         message(FATAL_ERROR "error: could not find git for clone of ${name}")
2791       endif()
2792     endif()
2793
2794     _ep_get_git_submodules_recurse(git_submodules_recurse)
2795
2796     get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
2797     if(NOT git_tag)
2798       set(git_tag "master")
2799     endif()
2800
2801     set(git_init_submodules TRUE)
2802     get_property(git_submodules_set
2803       TARGET ${name}
2804       PROPERTY _EP_GIT_SUBMODULES SET
2805     )
2806     if(git_submodules_set)
2807       get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
2808       if(git_submodules  STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
2809         set(git_init_submodules FALSE)
2810       endif()
2811     endif()
2812
2813     get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
2814     if(NOT git_remote_name)
2815       set(git_remote_name "origin")
2816     endif()
2817
2818     get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
2819     if("x${tls_verify}" STREQUAL "x" AND DEFINED CMAKE_TLS_VERIFY)
2820       set(tls_verify "${CMAKE_TLS_VERIFY}")
2821     endif()
2822     get_property(git_shallow TARGET ${name} PROPERTY _EP_GIT_SHALLOW)
2823     get_property(git_progress TARGET ${name} PROPERTY _EP_GIT_PROGRESS)
2824     get_property(git_config TARGET ${name} PROPERTY _EP_GIT_CONFIG)
2825
2826     # If git supports it, make checkouts quiet when checking out a git hash.
2827     # This avoids the very noisy detached head message.
2828     if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7)
2829       list(PREPEND git_config advice.detachedHead=false)
2830     endif()
2831
2832     # The command doesn't expose any details, so we need to record additional
2833     # information in the RepositoryInfo.txt file. For the download step, only
2834     # the things specifically affecting the clone operation should be recorded.
2835     # If the repo changes, the clone script should be run again.
2836     # But if only the tag changes, avoid running the clone script again.
2837     # Let the 'always' running update step checkout the new tag.
2838     #
2839     set(extra_repo_info
2840 "repository=${git_repository}
2841 remote=${git_remote_name}
2842 init_submodules=${git_init_submodules}
2843 recurse_submodules=${git_submodules_recurse}
2844 submodules=${git_submodules}
2845 CMP0097=${_EP_CMP0097}
2846 ")
2847     get_filename_component(src_name "${source_dir}" NAME)
2848     get_filename_component(work_dir "${source_dir}" PATH)
2849
2850     # Since git clone doesn't succeed if the non-empty source_dir exists,
2851     # create a cmake script to invoke as download command.
2852     # The script will delete the source directory and then call git clone.
2853     #
2854     _ep_write_gitclone_script(
2855       ${tmp_dir}/${name}-gitclone.cmake
2856       ${source_dir}
2857       ${GIT_EXECUTABLE}
2858       ${git_repository}
2859       ${git_tag}
2860       ${git_remote_name}
2861       ${git_init_submodules}
2862       "${git_submodules_recurse}"
2863       "${git_submodules}"
2864       "${git_shallow}"
2865       "${git_progress}"
2866       "${git_config}"
2867       ${src_name}
2868       ${work_dir}
2869       ${stamp_dir}/${name}-gitinfo.txt
2870       ${stamp_dir}/${name}-gitclone-lastrun.txt
2871       "${tls_verify}"
2872     )
2873     set(comment "Performing download step (git clone) for '${name}'")
2874     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
2875
2876   elseif(hg_repository)
2877     set(method hg)
2878     find_package(Hg QUIET)
2879     if(NOT HG_EXECUTABLE)
2880       message(FATAL_ERROR "error: could not find hg for clone of ${name}")
2881     endif()
2882
2883     get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
2884     if(NOT hg_tag)
2885       set(hg_tag "tip")
2886     endif()
2887
2888     # The command doesn't expose any details, so we need to record additional
2889     # information in the RepositoryInfo.txt file. For the download step, only
2890     # the things specifically affecting the clone operation should be recorded.
2891     # If the repo changes, the clone script should be run again.
2892     # But if only the tag changes, avoid running the clone script again.
2893     # Let the 'always' running update step checkout the new tag.
2894     #
2895     set(extra_repo_info "repository=${hg_repository}")
2896     get_filename_component(src_name "${source_dir}" NAME)
2897     get_filename_component(work_dir "${source_dir}" PATH)
2898
2899     # Since hg clone doesn't succeed if the non-empty source_dir exists,
2900     # create a cmake script to invoke as download command.
2901     # The script will delete the source directory and then call hg clone.
2902     #
2903     _ep_write_hgclone_script(
2904       ${tmp_dir}/${name}-hgclone.cmake
2905       ${source_dir}
2906       ${HG_EXECUTABLE}
2907       ${hg_repository}
2908       ${hg_tag}
2909       ${src_name}
2910       ${work_dir}
2911       ${stamp_dir}/${name}-hginfo.txt
2912       ${stamp_dir}/${name}-hgclone-lastrun.txt
2913     )
2914     set(comment "Performing download step (hg clone) for '${name}'")
2915     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake)
2916
2917   elseif(url)
2918     set(method url)
2919     get_filename_component(work_dir "${source_dir}" PATH)
2920     get_property(hash TARGET ${name} PROPERTY _EP_URL_HASH)
2921     _ep_get_hash_regex(_ep_hash_regex)
2922     if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
2923       _ep_get_hash_algos(_ep_hash_algos)
2924       list(JOIN _ep_hash_algos "|" _ep_hash_algos)
2925       message(FATAL_ERROR
2926         "URL_HASH is set to\n"
2927         "  ${hash}\n"
2928         "but must be ALGO=value where ALGO is\n"
2929         "  ${_ep_hash_algos}\n"
2930         "and value is a hex string."
2931       )
2932     endif()
2933     get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
2934     if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}")
2935       message(FATAL_ERROR
2936         "URL_MD5 is set to\n"
2937         "  ${md5}\n"
2938         "but must be a hex string."
2939       )
2940     endif()
2941     if(md5 AND NOT hash)
2942       set(hash "MD5=${md5}")
2943     endif()
2944     set(extra_repo_info
2945 "url(s)=${url}
2946 hash=${hash}
2947 ")
2948
2949     list(LENGTH url url_list_length)
2950     if(NOT "${url_list_length}" STREQUAL "1")
2951       foreach(entry ${url})
2952         if(NOT "${entry}" MATCHES "^[a-z]+://")
2953           message(FATAL_ERROR
2954             "At least one entry of URL is a path (invalid in a list)"
2955           )
2956         endif()
2957       endforeach()
2958       if("x${fname}" STREQUAL "x")
2959         list(GET url 0 fname)
2960       endif()
2961     endif()
2962
2963     if(IS_DIRECTORY "${url}")
2964       get_filename_component(abs_dir "${url}" ABSOLUTE)
2965       set(comment "Performing download step (DIR copy) for '${name}'")
2966       set(cmd
2967         ${CMAKE_COMMAND} -E rm -rf ${source_dir}
2968         COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir}
2969       )
2970     else()
2971       get_property(no_extract
2972         TARGET "${name}"
2973         PROPERTY _EP_DOWNLOAD_NO_EXTRACT
2974       )
2975       string(APPEND extra_repo_info "no_extract=${no_extract}\n")
2976       if("${url}" MATCHES "^[a-z]+://")
2977         # TODO: Should download and extraction be different steps?
2978         if("x${fname}" STREQUAL "x")
2979           set(fname "${url}")
2980         endif()
2981         set(ext_regex [[7z|tar|tar\.bz2|tar\.gz|tar\.xz|tbz2|tgz|txz|zip]])
2982         if("${fname}" MATCHES "([^/\\?#]+(\\.|=)(${ext_regex}))([/?#].*)?$")
2983           set(fname "${CMAKE_MATCH_1}")
2984         elseif(no_extract)
2985           get_filename_component(fname "${fname}" NAME)
2986         else()
2987           # Fall back to a default file name.  The actual file name does not
2988           # matter because it is used only internally and our extraction tool
2989           # inspects the file content directly.  If it turns out the wrong URL
2990           # was given that will be revealed during the build which is an easier
2991           # place for users to diagnose than an error here anyway.
2992           set(fname "archive.tar")
2993         endif()
2994         string(REPLACE ";" "-" fname "${fname}")
2995         set(file ${download_dir}/${fname})
2996         get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
2997         get_property(inactivity_timeout
2998           TARGET ${name}
2999           PROPERTY _EP_INACTIVITY_TIMEOUT
3000         )
3001         get_property(no_progress
3002           TARGET ${name}
3003           PROPERTY _EP_DOWNLOAD_NO_PROGRESS
3004         )
3005         get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
3006         get_property(tls_cainfo TARGET ${name} PROPERTY _EP_TLS_CAINFO)
3007         get_property(netrc TARGET ${name} PROPERTY _EP_NETRC)
3008         get_property(netrc_file TARGET ${name} PROPERTY _EP_NETRC_FILE)
3009         get_property(http_username TARGET ${name} PROPERTY _EP_HTTP_USERNAME)
3010         get_property(http_password TARGET ${name} PROPERTY _EP_HTTP_PASSWORD)
3011         get_property(http_headers TARGET ${name} PROPERTY _EP_HTTP_HEADER)
3012         set(download_script "${stamp_dir}/download-${name}.cmake")
3013         _ep_write_downloadfile_script(
3014           "${download_script}"
3015           "${url}"
3016           "${file}"
3017           "${timeout}"
3018           "${inactivity_timeout}"
3019           "${no_progress}"
3020           "${hash}"
3021           "${tls_verify}"
3022           "${tls_cainfo}"
3023           "${http_username}:${http_password}"
3024           "${http_headers}"
3025           "${netrc}"
3026           "${netrc_file}"
3027         )
3028         set(cmd
3029           ${CMAKE_COMMAND} -P "${download_script}"
3030           COMMAND
3031         )
3032         if (no_extract)
3033           set(steps "download and verify")
3034         else ()
3035           set(steps "download, verify and extract")
3036         endif ()
3037         set(comment "Performing download step (${steps}) for '${name}'")
3038         # already verified by 'download_script'
3039         file(WRITE "${stamp_dir}/verify-${name}.cmake" "")
3040
3041         # Rather than adding everything to the RepositoryInfo.txt file, it is
3042         # more robust to just depend on the download script. That way, we will
3043         # re-download if any aspect of the download changes.
3044         list(APPEND depends "${download_script}")
3045       else()
3046         set(file "${url}")
3047         if (no_extract)
3048           set(steps "verify")
3049         else ()
3050           set(steps "verify and extract")
3051         endif ()
3052         set(comment "Performing download step (${steps}) for '${name}'")
3053         _ep_write_verifyfile_script(
3054           "${stamp_dir}/verify-${name}.cmake"
3055           "${file}"
3056           "${hash}"
3057         )
3058       endif()
3059       list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake)
3060       get_target_property(extract_timestamp ${name}
3061         _EP_DOWNLOAD_EXTRACT_TIMESTAMP
3062       )
3063       if(no_extract)
3064         if(NOT extract_timestamp STREQUAL "extract_timestamp-NOTFOUND")
3065           message(FATAL_ERROR
3066             "Cannot specify DOWNLOAD_EXTRACT_TIMESTAMP when using "
3067             "DOWNLOAD_NO_EXTRACT TRUE"
3068           )
3069         endif()
3070         set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file})
3071       else()
3072         if(extract_timestamp STREQUAL "extract_timestamp-NOTFOUND")
3073           # Default depends on policy CMP0135
3074           if(_EP_CMP0135 STREQUAL "")
3075             message(AUTHOR_WARNING
3076               "The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy "
3077               "CMP0135 is not set. The policy's OLD behavior will be used. "
3078               "When using a URL download, the timestamps of extracted files "
3079               "should preferably be that of the time of extraction, otherwise "
3080               "code that depends on the extracted contents might not be "
3081               "rebuilt if the URL changes. The OLD behavior preserves the "
3082               "timestamps from the archive instead, but this is usually not "
3083               "what you want. Update your project to the NEW behavior or "
3084               "specify the DOWNLOAD_EXTRACT_TIMESTAMP option with a value of "
3085               "true to avoid this robustness issue."
3086             )
3087             set(extract_timestamp TRUE)
3088           elseif(_EP_CMP0135 STREQUAL "NEW")
3089             set(extract_timestamp FALSE)
3090           else()
3091             set(extract_timestamp TRUE)
3092           endif()
3093         endif()
3094         if(extract_timestamp)
3095           set(options "")
3096         else()
3097           set(options "--touch")
3098         endif()
3099         _ep_write_extractfile_script(
3100           "${stamp_dir}/extract-${name}.cmake"
3101           "${name}"
3102           "${file}"
3103           "${source_dir}"
3104           "${options}"
3105         )
3106         list(APPEND cmd
3107           COMMAND ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake
3108         )
3109       endif ()
3110     endif()
3111   else()
3112     set(method source_dir)
3113     _ep_is_dir_empty("${source_dir}" empty)
3114     if(${empty})
3115       message(FATAL_ERROR
3116         "No download info given for '${name}' and its source directory:\n"
3117         " ${source_dir}\n"
3118         "is not an existing non-empty directory.  Please specify one of:\n"
3119         " * SOURCE_DIR with an existing non-empty directory\n"
3120         " * DOWNLOAD_COMMAND\n"
3121         " * URL\n"
3122         " * GIT_REPOSITORY\n"
3123         " * SVN_REPOSITORY\n"
3124         " * HG_REPOSITORY\n"
3125         " * CVS_REPOSITORY and CVS_MODULE"
3126       )
3127     endif()
3128   endif()
3129
3130   # We use configure_file() to write the repo_info_file so that the file's
3131   # timestamp is not updated if we don't change the contents
3132
3133   set(repo_info_file ${stamp_dir}/${name}-${method}info.txt)
3134   list(APPEND depends ${repo_info_file})
3135   configure_file(
3136     "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/RepositoryInfo.txt.in"
3137     "${repo_info_file}"
3138     @ONLY
3139   )
3140
3141   get_property(log
3142     TARGET ${name}
3143     PROPERTY _EP_LOG_DOWNLOAD
3144   )
3145   if(log)
3146     set(log LOG 1)
3147   else()
3148     set(log "")
3149   endif()
3150
3151   get_property(uses_terminal
3152     TARGET ${name}
3153     PROPERTY _EP_USES_TERMINAL_DOWNLOAD
3154   )
3155   if(uses_terminal)
3156     set(uses_terminal USES_TERMINAL 1)
3157   else()
3158     set(uses_terminal "")
3159   endif()
3160
3161   set(__cmdQuoted)
3162   foreach(__item IN LISTS cmd)
3163     string(APPEND __cmdQuoted " [==[${__item}]==]")
3164   endforeach()
3165   cmake_language(EVAL CODE "
3166     ExternalProject_Add_Step(\${name} download
3167       INDEPENDENT TRUE
3168       COMMENT \${comment}
3169       COMMAND ${__cmdQuoted}
3170       WORKING_DIRECTORY \${work_dir}
3171       DEPENDS \${depends}
3172       DEPENDEES mkdir
3173       ${log}
3174       ${uses_terminal}
3175     )"
3176   )
3177 endfunction()
3178
3179 function(_ep_get_update_disconnected var name)
3180   get_property(update_disconnected_set
3181     TARGET ${name}
3182     PROPERTY _EP_UPDATE_DISCONNECTED
3183     SET
3184   )
3185   if(update_disconnected_set)
3186     get_property(update_disconnected
3187       TARGET ${name}
3188       PROPERTY _EP_UPDATE_DISCONNECTED
3189     )
3190   else()
3191     get_property(update_disconnected
3192       DIRECTORY
3193       PROPERTY EP_UPDATE_DISCONNECTED
3194     )
3195   endif()
3196   set(${var} "${update_disconnected}" PARENT_SCOPE)
3197 endfunction()
3198
3199 function(_ep_add_update_command name)
3200   ExternalProject_Get_Property(${name} source_dir tmp_dir)
3201
3202   get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
3203   get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
3204   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
3205   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
3206   get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
3207   get_property(hg_repository  TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
3208
3209   _ep_get_update_disconnected(update_disconnected ${name})
3210
3211   set(work_dir)
3212   set(comment)
3213   set(always)
3214
3215   if(cmd_set)
3216     set(work_dir ${source_dir})
3217     if(NOT "x${cmd}" STREQUAL "x")
3218       set(always 1)
3219     endif()
3220   elseif(cvs_repository)
3221     if(NOT CVS_EXECUTABLE)
3222       message(FATAL_ERROR "error: could not find cvs for update of ${name}")
3223     endif()
3224     set(work_dir ${source_dir})
3225     set(comment "Performing update step (CVS update) for '${name}'")
3226     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
3227     set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
3228     set(always 1)
3229   elseif(svn_repository)
3230     if(NOT Subversion_SVN_EXECUTABLE)
3231       message(FATAL_ERROR "error: could not find svn for update of ${name}")
3232     endif()
3233     set(work_dir ${source_dir})
3234     set(comment "Performing update step (SVN update) for '${name}'")
3235     get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
3236     get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
3237     get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
3238     get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
3239     get_property(uses_terminal TARGET ${name} PROPERTY _EP_USES_TERMINAL_UPDATE)
3240     if(uses_terminal)
3241       set(svn_interactive_args "")
3242     else()
3243       set(svn_interactive_args "--non-interactive")
3244     endif()
3245     set(svn_user_pw_args "")
3246     if(DEFINED svn_username)
3247       set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
3248     endif()
3249     if(DEFINED svn_password)
3250       set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
3251     endif()
3252     if(svn_trust_cert)
3253       set(svn_trust_cert_args --trust-server-cert)
3254     endif()
3255     set(cmd
3256       ${Subversion_SVN_EXECUTABLE}
3257       up
3258       ${svn_revision}
3259       ${svn_interactive_args}
3260       ${svn_trust_cert_args}
3261       ${svn_user_pw_args}
3262     )
3263     set(always 1)
3264   elseif(git_repository)
3265     # FetchContent gives us these directly, so don't try to recompute them
3266     if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING)
3267       unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
3268       find_package(Git QUIET)
3269       if(NOT GIT_EXECUTABLE)
3270         message(FATAL_ERROR "error: could not find git for fetch of ${name}")
3271       endif()
3272     endif()
3273     set(work_dir ${source_dir})
3274     set(comment "Performing update step for '${name}'")
3275
3276     get_property(git_tag
3277       TARGET ${name}
3278       PROPERTY _EP_GIT_TAG
3279     )
3280     if(NOT git_tag)
3281       set(git_tag "master")
3282     endif()
3283
3284     get_property(git_remote_name
3285       TARGET ${name}
3286       PROPERTY _EP_GIT_REMOTE_NAME
3287     )
3288     if(NOT git_remote_name)
3289       set(git_remote_name "origin")
3290     endif()
3291
3292     set(git_init_submodules TRUE)
3293     get_property(git_submodules_set
3294       TARGET ${name}
3295       PROPERTY _EP_GIT_SUBMODULES
3296       SET
3297     )
3298     if(git_submodules_set)
3299       get_property(git_submodules
3300         TARGET ${name}
3301         PROPERTY _EP_GIT_SUBMODULES
3302       )
3303       if(git_submodules  STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
3304         set(git_init_submodules FALSE)
3305       endif()
3306     endif()
3307
3308     get_property(git_update_strategy
3309       TARGET ${name}
3310       PROPERTY _EP_GIT_REMOTE_UPDATE_STRATEGY
3311     )
3312     if(NOT git_update_strategy)
3313       set(git_update_strategy "${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
3314     endif()
3315     if(NOT git_update_strategy)
3316       set(git_update_strategy REBASE)
3317     endif()
3318     set(strategies CHECKOUT REBASE REBASE_CHECKOUT)
3319     if(NOT git_update_strategy IN_LIST strategies)
3320       message(FATAL_ERROR
3321         "'${git_update_strategy}' is not one of the supported strategies: "
3322         "${strategies}"
3323       )
3324     endif()
3325
3326     _ep_get_git_submodules_recurse(git_submodules_recurse)
3327
3328     _ep_write_gitupdate_script(
3329       "${tmp_dir}/${name}-gitupdate.cmake"
3330       "${GIT_EXECUTABLE}"
3331       "${git_tag}"
3332       "${git_remote_name}"
3333       "${git_init_submodules}"
3334       "${git_submodules_recurse}"
3335       "${git_submodules}"
3336       "${git_repository}"
3337       "${work_dir}"
3338       "${git_update_strategy}"
3339     )
3340     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake)
3341     set(always 1)
3342   elseif(hg_repository)
3343     if(NOT HG_EXECUTABLE)
3344       message(FATAL_ERROR "error: could not find hg for pull of ${name}")
3345     endif()
3346     set(work_dir ${source_dir})
3347     set(comment "Performing update step (hg pull) for '${name}'")
3348
3349     get_property(hg_tag
3350       TARGET ${name}
3351       PROPERTY _EP_HG_TAG
3352     )
3353     if(NOT hg_tag)
3354       set(hg_tag "tip")
3355     endif()
3356
3357     if("${HG_VERSION_STRING}" STREQUAL "2.1")
3358       set(notesAnchor
3359         "#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X"
3360       )
3361       message(WARNING
3362 "Mercurial 2.1 does not distinguish an empty pull from a failed pull:
3363  http://mercurial.selenic.com/wiki/UpgradeNotes${notesAnchor}
3364  http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656
3365 Update to Mercurial >= 2.1.1.
3366 ")
3367     endif()
3368
3369     set(cmd
3370       ${HG_EXECUTABLE} pull
3371       COMMAND ${HG_EXECUTABLE} update ${hg_tag}
3372     )
3373     set(always 1)
3374   endif()
3375
3376   get_property(log
3377     TARGET ${name}
3378     PROPERTY _EP_LOG_UPDATE
3379   )
3380   if(log)
3381     set(log LOG 1)
3382   else()
3383     set(log "")
3384   endif()
3385
3386   get_property(uses_terminal
3387     TARGET ${name}
3388     PROPERTY _EP_USES_TERMINAL_UPDATE
3389   )
3390   if(uses_terminal)
3391     set(uses_terminal USES_TERMINAL 1)
3392   else()
3393     set(uses_terminal "")
3394   endif()
3395
3396   set(__cmdQuoted)
3397   foreach(__item IN LISTS cmd)
3398     string(APPEND __cmdQuoted " [==[${__item}]==]")
3399   endforeach()
3400   cmake_language(EVAL CODE "
3401     ExternalProject_Add_Step(${name} update
3402       INDEPENDENT TRUE
3403       COMMENT \${comment}
3404       COMMAND ${__cmdQuoted}
3405       ALWAYS \${always}
3406       EXCLUDE_FROM_MAIN \${update_disconnected}
3407       WORKING_DIRECTORY \${work_dir}
3408       DEPENDEES download
3409       ${log}
3410       ${uses_terminal}
3411     )"
3412   )
3413
3414 endfunction()
3415
3416
3417 function(_ep_add_patch_command name)
3418   ExternalProject_Get_Property(${name} source_dir)
3419
3420   get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
3421   get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
3422
3423   set(work_dir)
3424
3425   if(cmd_set)
3426     set(work_dir ${source_dir})
3427   endif()
3428
3429   get_property(log
3430     TARGET ${name}
3431     PROPERTY _EP_LOG_PATCH
3432   )
3433   if(log)
3434     set(log LOG 1)
3435   else()
3436     set(log "")
3437   endif()
3438
3439   get_property(uses_terminal
3440     TARGET ${name}
3441     PROPERTY _EP_USES_TERMINAL_PATCH
3442   )
3443   if(uses_terminal)
3444     set(uses_terminal USES_TERMINAL 1)
3445   else()
3446     set(uses_terminal "")
3447   endif()
3448
3449   _ep_get_update_disconnected(update_disconnected ${name})
3450   if(update_disconnected)
3451     set(patch_dep download)
3452   else()
3453     set(patch_dep update)
3454   endif()
3455
3456   set(__cmdQuoted)
3457   foreach(__item IN LISTS cmd)
3458     string(APPEND __cmdQuoted " [==[${__item}]==]")
3459   endforeach()
3460   cmake_language(EVAL CODE "
3461     ExternalProject_Add_Step(${name} patch
3462       INDEPENDENT TRUE
3463       COMMAND ${__cmdQuoted}
3464       WORKING_DIRECTORY \${work_dir}
3465       DEPENDEES \${patch_dep}
3466       ${log}
3467       ${uses_terminal}
3468     )"
3469   )
3470 endfunction()
3471
3472 function(_ep_get_file_deps var name)
3473   set(file_deps)
3474
3475   get_property(deps
3476     TARGET ${name}
3477     PROPERTY _EP_DEPENDS
3478   )
3479   foreach(dep IN LISTS deps)
3480     get_property(dep_type
3481       TARGET ${dep}
3482       PROPERTY TYPE
3483     )
3484     if(dep_type STREQUAL "UTILITY")
3485       get_property(is_ep
3486         TARGET ${dep}
3487         PROPERTY _EP_IS_EXTERNAL_PROJECT
3488       )
3489       if(is_ep)
3490         _ep_get_step_stampfile(${dep} "done" done_stamp_file)
3491         list(APPEND file_deps ${done_stamp_file})
3492       endif()
3493     endif()
3494   endforeach()
3495
3496   set("${var}" "${file_deps}" PARENT_SCOPE)
3497 endfunction()
3498
3499 function(_ep_extract_configure_command var name)
3500   get_property(cmd_set
3501     TARGET ${name}
3502     PROPERTY _EP_CONFIGURE_COMMAND
3503     SET
3504   )
3505   if(cmd_set)
3506     get_property(cmd
3507       TARGET ${name}
3508       PROPERTY _EP_CONFIGURE_COMMAND
3509     )
3510   else()
3511     get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
3512     if(cmake_command)
3513       set(cmd "${cmake_command}")
3514     else()
3515       set(cmd "${CMAKE_COMMAND}")
3516     endif()
3517
3518     get_property(cmake_args
3519       TARGET ${name}
3520       PROPERTY _EP_CMAKE_ARGS
3521     )
3522     list(APPEND cmd ${cmake_args})
3523
3524     # If there are any CMAKE_CACHE_ARGS or CMAKE_CACHE_DEFAULT_ARGS,
3525     # write an initial cache and use it
3526     get_property(cmake_cache_args
3527       TARGET ${name}
3528       PROPERTY _EP_CMAKE_CACHE_ARGS
3529     )
3530     get_property(cmake_cache_default_args
3531       TARGET ${name}
3532       PROPERTY _EP_CMAKE_CACHE_DEFAULT_ARGS
3533     )
3534
3535     set(has_cmake_cache_args 0)
3536     if(NOT "${cmake_cache_args}" STREQUAL "")
3537       set(has_cmake_cache_args 1)
3538     endif()
3539
3540     set(has_cmake_cache_default_args 0)
3541     if(NOT "${cmake_cache_default_args}" STREQUAL "")
3542       set(has_cmake_cache_default_args 1)
3543     endif()
3544
3545     get_target_property(cmake_generator ${name}
3546       _EP_CMAKE_GENERATOR
3547     )
3548     get_target_property(cmake_generator_instance ${name}
3549       _EP_CMAKE_GENERATOR_INSTANCE
3550     )
3551     get_target_property(cmake_generator_platform ${name}
3552       _EP_CMAKE_GENERATOR_PLATFORM
3553     )
3554     get_target_property(cmake_generator_toolset ${name}
3555       _EP_CMAKE_GENERATOR_TOOLSET
3556     )
3557     if(cmake_generator)
3558       list(APPEND cmd "-G${cmake_generator}")
3559       if(cmake_generator_platform)
3560         list(APPEND cmd "-A${cmake_generator_platform}")
3561       endif()
3562       if(cmake_generator_toolset)
3563         list(APPEND cmd "-T${cmake_generator_toolset}")
3564       endif()
3565       if(cmake_generator_instance)
3566         list(APPEND cmd
3567           "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${cmake_generator_instance}"
3568         )
3569       endif()
3570     else()
3571       if(CMAKE_EXTRA_GENERATOR)
3572         list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
3573       else()
3574         list(APPEND cmd "-G${CMAKE_GENERATOR}")
3575         if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
3576           set(has_cmake_cache_default_args 1)
3577           list(APPEND cmake_cache_default_args
3578             "-DGHS_TARGET_PLATFORM:STRING=${GHS_TARGET_PLATFORM}"
3579             "-DGHS_PRIMARY_TARGET:STRING=${GHS_PRIMARY_TARGET}"
3580             "-DGHS_TOOLSET_ROOT:STRING=${GHS_TOOLSET_ROOT}"
3581             "-DGHS_OS_ROOT:STRING=${GHS_OS_ROOT}"
3582             "-DGHS_OS_DIR:STRING=${GHS_OS_DIR}"
3583             "-DGHS_BSP_NAME:STRING=${GHS_BSP_NAME}"
3584           )
3585         endif()
3586       endif()
3587       if(cmake_generator_platform)
3588         message(FATAL_ERROR
3589           "Option CMAKE_GENERATOR_PLATFORM not allowed without "
3590           "CMAKE_GENERATOR."
3591         )
3592       endif()
3593       if(CMAKE_GENERATOR_PLATFORM)
3594         list(APPEND cmd "-A${CMAKE_GENERATOR_PLATFORM}")
3595       endif()
3596       if(cmake_generator_toolset)
3597         message(FATAL_ERROR
3598           "Option CMAKE_GENERATOR_TOOLSET not allowed without CMAKE_GENERATOR."
3599         )
3600       endif()
3601       if(CMAKE_GENERATOR_TOOLSET)
3602         list(APPEND cmd "-T${CMAKE_GENERATOR_TOOLSET}")
3603       endif()
3604       if(cmake_generator_instance)
3605         message(FATAL_ERROR
3606           "Option CMAKE_GENERATOR_INSTANCE not allowed without CMAKE_GENERATOR."
3607         )
3608       endif()
3609       if(CMAKE_GENERATOR_INSTANCE)
3610         list(APPEND cmd
3611           "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}"
3612         )
3613       endif()
3614     endif()
3615
3616     if(has_cmake_cache_args OR has_cmake_cache_default_args)
3617       set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
3618       if(has_cmake_cache_args)
3619         _ep_command_line_to_initial_cache(
3620           script_initial_cache_force
3621           "${cmake_cache_args}"
3622           1
3623         )
3624       endif()
3625       if(has_cmake_cache_default_args)
3626         _ep_command_line_to_initial_cache(
3627           script_initial_cache_default
3628           "${cmake_cache_default_args}"
3629           0
3630         )
3631       endif()
3632       _ep_write_initial_cache(
3633         ${name}
3634         "${_ep_cache_args_script}"
3635         "${script_initial_cache_force}${script_initial_cache_default}"
3636       )
3637       list(APPEND cmd "-C${_ep_cache_args_script}")
3638       _ep_replace_location_tags(${name} _ep_cache_args_script)
3639       set(_ep_cache_args_script
3640         "${_ep_cache_args_script}"
3641         PARENT_SCOPE
3642       )
3643     endif()
3644
3645     list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
3646   endif()
3647
3648   set("${var}" "${cmd}" PARENT_SCOPE)
3649 endfunction()
3650
3651 # TODO: Make sure external projects use the proper compiler
3652 function(_ep_add_configure_command name)
3653   ExternalProject_Get_Property(${name} binary_dir tmp_dir)
3654
3655   set(file_deps)
3656   get_property(configure_handled_by_build
3657     TARGET ${name}
3658     PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD
3659   )
3660   if(NOT configure_handled_by_build)
3661     # Depend on other external projects (file-level)
3662     _ep_get_file_deps(file_deps ${name})
3663   endif()
3664
3665   _ep_extract_configure_command(cmd ${name})
3666
3667   # If anything about the configure command changes, (command itself, cmake
3668   # used, cmake args or cmake generator) then re-run the configure step.
3669   # Fixes issue https://gitlab.kitware.com/cmake/cmake/-/issues/10258
3670   #
3671   configure_file(
3672     ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/cfgcmd.txt.in
3673     ${tmp_dir}/${name}-cfgcmd.txt
3674     @ONLY
3675   )
3676   list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt)
3677   list(APPEND file_deps ${_ep_cache_args_script})
3678
3679   get_property(log
3680     TARGET ${name}
3681     PROPERTY _EP_LOG_CONFIGURE
3682   )
3683   if(log)
3684     set(log LOG 1)
3685   else()
3686     set(log "")
3687   endif()
3688
3689   get_property(uses_terminal
3690     TARGET ${name}
3691     PROPERTY _EP_USES_TERMINAL_CONFIGURE
3692   )
3693   if(uses_terminal)
3694     set(uses_terminal USES_TERMINAL 1)
3695   else()
3696     set(uses_terminal "")
3697   endif()
3698
3699   set(__cmdQuoted)
3700   foreach(__item IN LISTS cmd)
3701     string(APPEND __cmdQuoted " [==[${__item}]==]")
3702   endforeach()
3703   cmake_language(EVAL CODE "
3704     ExternalProject_Add_Step(${name} configure
3705       INDEPENDENT FALSE
3706       COMMAND ${__cmdQuoted}
3707       WORKING_DIRECTORY \${binary_dir}
3708       DEPENDEES patch
3709       DEPENDS \${file_deps}
3710       ${log}
3711       ${uses_terminal}
3712     )"
3713   )
3714 endfunction()
3715
3716
3717 function(_ep_add_build_command name)
3718   ExternalProject_Get_Property(${name} binary_dir)
3719
3720   set(file_deps)
3721   get_property(configure_handled_by_build
3722     TARGET ${name}
3723     PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD
3724   )
3725   if(configure_handled_by_build)
3726     # Depend on other external projects (file-level)
3727     _ep_get_file_deps(file_deps ${name})
3728   endif()
3729
3730   get_property(cmd_set
3731     TARGET ${name}
3732     PROPERTY _EP_BUILD_COMMAND
3733     SET
3734   )
3735   if(cmd_set)
3736     get_property(cmd
3737       TARGET ${name}
3738       PROPERTY _EP_BUILD_COMMAND
3739     )
3740   else()
3741     _ep_get_build_command(${name} BUILD cmd)
3742   endif()
3743
3744   get_property(log
3745     TARGET ${name}
3746     PROPERTY _EP_LOG_BUILD
3747   )
3748   if(log)
3749     set(log LOG 1)
3750   else()
3751     set(log "")
3752   endif()
3753
3754   get_property(uses_terminal
3755     TARGET ${name}
3756     PROPERTY _EP_USES_TERMINAL_BUILD
3757   )
3758   if(uses_terminal)
3759     set(uses_terminal USES_TERMINAL 1)
3760   else()
3761     set(uses_terminal "")
3762   endif()
3763
3764   get_property(build_always
3765     TARGET ${name}
3766     PROPERTY _EP_BUILD_ALWAYS
3767   )
3768   if(build_always)
3769     set(always 1)
3770   else()
3771     set(always 0)
3772   endif()
3773
3774   get_property(build_byproducts
3775     TARGET ${name}
3776     PROPERTY _EP_BUILD_BYPRODUCTS
3777   )
3778
3779   set(__cmdQuoted)
3780   foreach(__item IN LISTS cmd)
3781     string(APPEND __cmdQuoted " [==[${__item}]==]")
3782   endforeach()
3783   cmake_language(EVAL CODE "
3784     ExternalProject_Add_Step(${name} build
3785       INDEPENDENT FALSE
3786       COMMAND ${__cmdQuoted}
3787       BYPRODUCTS \${build_byproducts}
3788       WORKING_DIRECTORY \${binary_dir}
3789       DEPENDEES configure
3790       DEPENDS \${file_deps}
3791       ALWAYS \${always}
3792       ${log}
3793       ${uses_terminal}
3794     )"
3795   )
3796 endfunction()
3797
3798
3799 function(_ep_add_install_command name)
3800   ExternalProject_Get_Property(${name} binary_dir)
3801
3802   get_property(cmd_set
3803     TARGET ${name}
3804     PROPERTY _EP_INSTALL_COMMAND
3805     SET
3806   )
3807   if(cmd_set)
3808     get_property(cmd
3809       TARGET ${name}
3810       PROPERTY _EP_INSTALL_COMMAND
3811     )
3812   else()
3813     _ep_get_build_command(${name} INSTALL cmd)
3814   endif()
3815
3816   get_property(log
3817     TARGET ${name}
3818     PROPERTY _EP_LOG_INSTALL
3819   )
3820   if(log)
3821     set(log LOG 1)
3822   else()
3823     set(log "")
3824   endif()
3825
3826   get_property(uses_terminal
3827     TARGET ${name}
3828     PROPERTY _EP_USES_TERMINAL_INSTALL
3829   )
3830   if(uses_terminal)
3831     set(uses_terminal USES_TERMINAL 1)
3832   else()
3833     set(uses_terminal "")
3834   endif()
3835
3836   # With BUILD_ALWAYS+BUILD_BYPRODUCTS, Ninja restats the
3837   # build step outputs and may not consider this step to
3838   # be out-of-date.  Explicitly mark it out-of-date too.
3839   get_property(build_always
3840     TARGET ${name}
3841     PROPERTY _EP_BUILD_ALWAYS
3842   )
3843   if(build_always)
3844     set(always 1)
3845   else()
3846     set(always 0)
3847   endif()
3848
3849   set(__cmdQuoted)
3850   foreach(__item IN LISTS cmd)
3851     string(APPEND __cmdQuoted " [==[${__item}]==]")
3852   endforeach()
3853   cmake_language(EVAL CODE "
3854     ExternalProject_Add_Step(${name} install
3855       INDEPENDENT FALSE
3856       COMMAND ${__cmdQuoted}
3857       WORKING_DIRECTORY \${binary_dir}
3858       DEPENDEES build
3859       ALWAYS \${always}
3860       ${log}
3861       ${uses_terminal}
3862     )"
3863   )
3864 endfunction()
3865
3866
3867 function(_ep_add_test_command name)
3868   ExternalProject_Get_Property(${name} binary_dir)
3869
3870   get_property(before TARGET ${name} PROPERTY _EP_TEST_BEFORE_INSTALL)
3871   get_property(after TARGET ${name} PROPERTY _EP_TEST_AFTER_INSTALL)
3872   get_property(exclude TARGET ${name} PROPERTY _EP_TEST_EXCLUDE_FROM_MAIN)
3873   get_property(cmd_set TARGET ${name} PROPERTY _EP_TEST_COMMAND SET)
3874
3875   # Only actually add the test step if one of the test related properties is
3876   # explicitly set. (i.e. the test step is omitted unless requested...)
3877   #
3878   if(cmd_set OR before OR after OR exclude)
3879     if(cmd_set)
3880       get_property(cmd
3881         TARGET ${name}
3882         PROPERTY _EP_TEST_COMMAND
3883       )
3884     else()
3885       _ep_get_build_command(${name} TEST cmd)
3886     endif()
3887
3888     if(before)
3889       set(dependees_args DEPENDEES build)
3890     else()
3891       set(dependees_args DEPENDEES install)
3892     endif()
3893
3894     if(exclude)
3895       set(dependers_args "")
3896       set(exclude_args EXCLUDE_FROM_MAIN 1)
3897     else()
3898       if(before)
3899         set(dependers_args DEPENDERS install)
3900       else()
3901         set(dependers_args "")
3902       endif()
3903       set(exclude_args "")
3904     endif()
3905
3906     get_property(log
3907       TARGET ${name}
3908       PROPERTY _EP_LOG_TEST
3909     )
3910     if(log)
3911       set(log LOG 1)
3912     else()
3913       set(log "")
3914     endif()
3915
3916     get_property(uses_terminal
3917       TARGET ${name}
3918       PROPERTY _EP_USES_TERMINAL_TEST
3919     )
3920     if(uses_terminal)
3921       set(uses_terminal USES_TERMINAL 1)
3922     else()
3923       set(uses_terminal "")
3924     endif()
3925
3926     set(__cmdQuoted)
3927     foreach(__item IN LISTS cmd)
3928       string(APPEND __cmdQuoted " [==[${__item}]==]")
3929     endforeach()
3930     cmake_language(EVAL CODE "
3931       ExternalProject_Add_Step(${name} test
3932         INDEPENDENT FALSE
3933         COMMAND ${__cmdQuoted}
3934         WORKING_DIRECTORY \${binary_dir}
3935         ${dependees_args}
3936         ${dependers_args}
3937         ${exclude_args}
3938         ${log}
3939         ${uses_terminal}
3940       )"
3941     )
3942   endif()
3943 endfunction()
3944
3945
3946 function(ExternalProject_Add name)
3947   cmake_policy(GET CMP0097 _EP_CMP0097
3948     PARENT_SCOPE # undocumented, do not use outside of CMake
3949   )
3950   cmake_policy(GET CMP0114 cmp0114
3951     PARENT_SCOPE # undocumented, do not use outside of CMake
3952   )
3953   if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12 AND
3954      NOT cmp0114 STREQUAL "NEW")
3955     message(AUTHOR_WARNING
3956       "Policy CMP0114 is not set to NEW.  "
3957       "In order to support the Xcode \"new build system\", "
3958       "this project must be updated to set policy CMP0114 to NEW."
3959       "\n"
3960       "Since CMake is generating for the Xcode \"new build system\", "
3961       "ExternalProject_Add will use policy CMP0114's NEW behavior anyway, "
3962       "but the generated build system may not match what the project intends."
3963     )
3964     set(cmp0114 "NEW")
3965   endif()
3966   cmake_policy(GET CMP0135 _EP_CMP0135
3967     PARENT_SCOPE # undocumented, do not use outside of CMake
3968   )
3969
3970   _ep_get_configuration_subdir_genex(cfgdir)
3971
3972   # Add a custom target for the external project.
3973   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
3974   _ep_get_complete_stampfile(${name} complete_stamp_file)
3975
3976   cmake_policy(PUSH)
3977   if(cmp0114 STREQUAL "NEW")
3978     # To implement CMP0114 NEW behavior with Makefile generators,
3979     # we need CMP0113 NEW behavior.
3980     cmake_policy(SET CMP0113 NEW)
3981   endif()
3982   # The "ALL" option to add_custom_target just tells it to not set the
3983   # EXCLUDE_FROM_ALL target property. Later, if the EXCLUDE_FROM_ALL
3984   # argument was passed, we explicitly set it for the target.
3985   add_custom_target(${name} ALL DEPENDS ${complete_stamp_file})
3986   cmake_policy(POP)
3987   set_target_properties(${name} PROPERTIES
3988     _EP_IS_EXTERNAL_PROJECT 1
3989     LABELS ${name}
3990     FOLDER "ExternalProjectTargets/${name}"
3991     _EP_CMP0114 "${cmp0114}"
3992   )
3993
3994   set(keywords
3995     #
3996     # Directory options
3997     #
3998     PREFIX
3999     TMP_DIR
4000     STAMP_DIR
4001     LOG_DIR
4002     DOWNLOAD_DIR
4003     SOURCE_DIR
4004     BINARY_DIR
4005     INSTALL_DIR
4006     #
4007     # Download step options
4008     #
4009     DOWNLOAD_COMMAND
4010     #
4011     URL
4012     URL_HASH
4013     URL_MD5
4014     DOWNLOAD_NAME
4015     DOWNLOAD_EXTRACT_TIMESTAMP
4016     DOWNLOAD_NO_EXTRACT
4017     DOWNLOAD_NO_PROGRESS
4018     TIMEOUT
4019     INACTIVITY_TIMEOUT
4020     HTTP_USERNAME
4021     HTTP_PASSWORD
4022     HTTP_HEADER
4023     TLS_VERIFY     # Also used for git clone operations
4024     TLS_CAINFO
4025     NETRC
4026     NETRC_FILE
4027     #
4028     GIT_REPOSITORY
4029     GIT_TAG
4030     GIT_REMOTE_NAME
4031     GIT_SUBMODULES
4032     GIT_SUBMODULES_RECURSE
4033     GIT_SHALLOW
4034     GIT_PROGRESS
4035     GIT_CONFIG
4036     GIT_REMOTE_UPDATE_STRATEGY
4037     #
4038     SVN_REPOSITORY
4039     SVN_REVISION
4040     SVN_USERNAME
4041     SVN_PASSWORD
4042     SVN_TRUST_CERT
4043     #
4044     HG_REPOSITORY
4045     HG_TAG
4046     #
4047     CVS_REPOSITORY
4048     CVS_MODULE
4049     CVS_TAG
4050     #
4051     # Update step options
4052     #
4053     UPDATE_COMMAND
4054     UPDATE_DISCONNECTED
4055     #
4056     # Patch step options
4057     #
4058     PATCH_COMMAND
4059     #
4060     # Configure step options
4061     #
4062     CONFIGURE_COMMAND
4063     CMAKE_COMMAND
4064     CMAKE_GENERATOR
4065     CMAKE_GENERATOR_PLATFORM
4066     CMAKE_GENERATOR_TOOLSET
4067     CMAKE_GENERATOR_INSTANCE
4068     CMAKE_ARGS
4069     CMAKE_CACHE_ARGS
4070     CMAKE_CACHE_DEFAULT_ARGS
4071     SOURCE_SUBDIR
4072     CONFIGURE_HANDLED_BY_BUILD
4073     #
4074     # Build step options
4075     #
4076     BUILD_COMMAND
4077     BUILD_IN_SOURCE
4078     BUILD_ALWAYS
4079     BUILD_BYPRODUCTS
4080     #
4081     # Install step options
4082     #
4083     INSTALL_COMMAND
4084     #
4085     # Test step options
4086     #
4087     TEST_COMMAND
4088     TEST_BEFORE_INSTALL
4089     TEST_AFTER_INSTALL
4090     TEST_EXCLUDE_FROM_MAIN
4091     #
4092     # Logging options
4093     #
4094     LOG_DOWNLOAD
4095     LOG_UPDATE
4096     LOG_PATCH
4097     LOG_CONFIGURE
4098     LOG_BUILD
4099     LOG_INSTALL
4100     LOG_TEST
4101     LOG_MERGED_STDOUTERR
4102     LOG_OUTPUT_ON_FAILURE
4103     #
4104     # Terminal access options
4105     #
4106     USES_TERMINAL_DOWNLOAD
4107     USES_TERMINAL_UPDATE
4108     USES_TERMINAL_PATCH
4109     USES_TERMINAL_CONFIGURE
4110     USES_TERMINAL_BUILD
4111     USES_TERMINAL_INSTALL
4112     USES_TERMINAL_TEST
4113     #
4114     # Target options
4115     #
4116     DEPENDS
4117     EXCLUDE_FROM_ALL
4118     STEP_TARGETS
4119     INDEPENDENT_STEP_TARGETS
4120     #
4121     # Miscellaneous options
4122     #
4123     LIST_SEPARATOR
4124   )
4125   _ep_parse_arguments(
4126     ExternalProject_Add
4127     "${keywords}"
4128     ${name}
4129     _EP_
4130     "${ARGN}"
4131   )
4132   _ep_set_directories(${name})
4133   _ep_get_step_stampfile(${name} "done" done_stamp_file)
4134   _ep_get_step_stampfile(${name} "install" install_stamp_file)
4135
4136   # Set the EXCLUDE_FROM_ALL target property if required.
4137   get_property(exclude_from_all
4138     TARGET ${name}
4139     PROPERTY _EP_EXCLUDE_FROM_ALL
4140   )
4141   if(exclude_from_all)
4142     set_property(TARGET ${name} PROPERTY EXCLUDE_FROM_ALL TRUE)
4143   endif()
4144
4145   # The 'complete' step depends on all other steps and creates a
4146   # 'done' mark.  A dependent external project's 'configure' step
4147   # depends on the 'done' mark so that it rebuilds when this project
4148   # rebuilds.  It is important that 'done' is not the output of any
4149   # custom command so that CMake does not propagate build rules to
4150   # other external project targets, which may cause problems during
4151   # parallel builds.  However, the Ninja generator needs to see the entire
4152   # dependency graph, and can cope with custom commands belonging to
4153   # multiple targets, so we add the 'done' mark as an output for Ninja only.
4154   set(complete_outputs ${complete_stamp_file})
4155   if(${CMAKE_GENERATOR} MATCHES "Ninja")
4156     set(complete_outputs ${complete_outputs} ${done_stamp_file})
4157   endif()
4158
4159   add_custom_command(
4160     OUTPUT ${complete_outputs}
4161     COMMENT "Completed '${name}'"
4162     COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
4163     COMMAND ${CMAKE_COMMAND} -E touch ${complete_stamp_file}
4164     COMMAND ${CMAKE_COMMAND} -E touch ${done_stamp_file}
4165     DEPENDS ${install_stamp_file}
4166     VERBATIM
4167   )
4168
4169   # Depend on other external projects (target-level).
4170   get_property(deps
4171     TARGET ${name}
4172     PROPERTY _EP_DEPENDS
4173   )
4174   foreach(arg IN LISTS deps)
4175     add_dependencies(${name} ${arg})
4176   endforeach()
4177
4178   # Set up custom build steps based on the target properties.
4179   # Each step depends on the previous one.
4180   #
4181   # The target depends on the output of the final step.
4182   # (Already set up above in the DEPENDS of the add_custom_target command.)
4183   #
4184   _ep_add_mkdir_command(${name})
4185   _ep_add_download_command(${name})
4186   _ep_add_update_command(${name})
4187   _ep_add_patch_command(${name})
4188   _ep_add_configure_command(${name})
4189   _ep_add_build_command(${name})
4190   _ep_add_install_command(${name})
4191
4192   # Test is special in that it might depend on build, or it might depend
4193   # on install.
4194   #
4195   _ep_add_test_command(${name})
4196 endfunction()
4197
4198 cmake_policy(POP)