1 # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
4 #[=======================================================================[.rst:
12 External Project Definition
13 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
15 .. command:: ExternalProject_Add
17 The ``ExternalProject_Add()`` function creates a custom target to drive
18 download, update/patch, configure, build, install and test steps of an
23 ExternalProject_Add(<name> [<option>...])
25 The individual steps within the process can be driven independently if
26 required (e.g. for CDash submission) and extra custom steps can be defined,
27 along with the ability to control the step dependencies. The directory
28 structure used for the management of the external project can also be
29 customized. The function supports a large number of options which can be used
30 to tailor the external project behavior.
32 **Directory Options:**
33 Most of the time, the default directory layout is sufficient. It is largely
34 an implementation detail that the main project usually doesn't need to
35 change. In some circumstances, however, control over the directory layout
36 can be useful or necessary. The directory options are potentially more
37 useful from the point of view that the main build can use the
38 :command:`ExternalProject_Get_Property` command to retrieve their values,
39 thereby allowing the main project to refer to build artifacts of the
43 Root directory for the external project. Unless otherwise noted below,
44 all other directories associated with the external project will be
48 Directory in which to store temporary files.
51 Directory in which to store the timestamps of each step. Log files from
52 individual steps are also created in here unless overridden by LOG_DIR
53 (see *Logging Options* below).
56 Directory in which to store the logs of each step.
58 ``DOWNLOAD_DIR <dir>``
59 Directory in which to store downloaded files before unpacking them. This
60 directory is only used by the URL download method, all other download
61 methods use ``SOURCE_DIR`` directly instead.
64 Source directory into which downloaded contents will be unpacked, or for
65 non-URL download methods, the directory in which the repository should be
66 checked out, cloned, etc. If no download method is specified, this must
67 point to an existing directory where the external project has already
68 been unpacked or cloned/checked out.
71 If a download method is specified, any existing contents of the source
72 directory may be deleted. Only the URL download method checks whether
73 this directory is either missing or empty before initiating the
74 download, stopping with an error if it is not empty. All other
75 download methods silently discard any previous contents of the source
79 Specify the build directory location. This option is ignored if
80 ``BUILD_IN_SOURCE`` is enabled.
83 Installation prefix to be placed in the ``<INSTALL_DIR>`` placeholder.
84 This does not actually configure the external project to install to
85 the given prefix. That must be done by passing appropriate arguments
86 to the external project configuration step, e.g. using ``<INSTALL_DIR>``.
88 If any of the above ``..._DIR`` options are not specified, their defaults
89 are computed as follows. If the ``PREFIX`` option is given or the
90 ``EP_PREFIX`` directory property is set, then an external project is built
91 and installed under the specified prefix::
93 TMP_DIR = <prefix>/tmp
94 STAMP_DIR = <prefix>/src/<name>-stamp
95 DOWNLOAD_DIR = <prefix>/src
96 SOURCE_DIR = <prefix>/src/<name>
97 BINARY_DIR = <prefix>/src/<name>-build
98 INSTALL_DIR = <prefix>
101 Otherwise, if the ``EP_BASE`` directory property is set then components
102 of an external project are stored under the specified base::
104 TMP_DIR = <base>/tmp/<name>
105 STAMP_DIR = <base>/Stamp/<name>
106 DOWNLOAD_DIR = <base>/Download/<name>
107 SOURCE_DIR = <base>/Source/<name>
108 BINARY_DIR = <base>/Build/<name>
109 INSTALL_DIR = <base>/Install/<name>
110 LOG_DIR = <STAMP_DIR>
112 If no ``PREFIX``, ``EP_PREFIX``, or ``EP_BASE`` is specified, then the
113 default is to set ``PREFIX`` to ``<name>-prefix``. Relative paths are
114 interpreted with respect to :variable:`CMAKE_CURRENT_BINARY_DIR` at the
115 point where ``ExternalProject_Add()`` is called.
117 **Download Step Options:**
118 A download method can be omitted if the ``SOURCE_DIR`` option is used to
119 point to an existing non-empty directory. Otherwise, one of the download
120 methods below must be specified (multiple download methods should not be
121 given) or a custom ``DOWNLOAD_COMMAND`` provided.
123 ``DOWNLOAD_COMMAND <cmd>...``
124 Overrides the command used for the download step
125 (:manual:`generator expressions <cmake-generator-expressions(7)>` are
126 supported). If this option is specified, all other download options will
127 be ignored. Providing an empty string for ``<cmd>`` effectively disables
131 ``URL <url1> [<url2>...]``
132 List of paths and/or URL(s) of the external project's source. When more
133 than one URL is given, they are tried in turn until one succeeds. A URL
134 may be an ordinary path in the local file system (in which case it
135 must be the only URL provided) or any downloadable URL supported by the
136 :command:`file(DOWNLOAD)` command. A local filesystem path may refer to
137 either an existing directory or to an archive file, whereas a URL is
138 expected to point to a file which can be treated as an archive. When an
139 archive is used, it will be unpacked automatically unless the
140 ``DOWNLOAD_NO_EXTRACT`` option is set to prevent it. The archive type
141 is determined by inspecting the actual content rather than using logic
142 based on the file extension.
144 ``URL_HASH <algo>=<hashValue>``
145 Hash of the archive file to be downloaded. The argument should be of
146 the form ``<algo>=<hashValue>`` where ``algo`` can be any of the hashing
147 algorithms supported by the :command:`file()` command. Specifying this
148 option is strongly recommended for URL downloads, as it ensures the
149 integrity of the downloaded content. It is also used as a check for a
150 previously downloaded file, allowing connection to the remote location
151 to be avoided altogether if the local directory already has a file from
152 an earlier download that matches the specified hash.
155 Equivalent to ``URL_HASH MD5=<md5>``.
157 ``DOWNLOAD_NAME <fname>``
158 File name to use for the downloaded file. If not given, the end of the
159 URL is used to determine the file name. This option is rarely needed,
160 the default name is generally suitable and is not normally used outside
161 of code internal to the ``ExternalProject`` module.
163 ``DOWNLOAD_NO_EXTRACT <bool>``
164 Allows the extraction part of the download step to be disabled by
165 passing a boolean true value for this option. If this option is not
166 given, the downloaded contents will be unpacked automatically if
167 required. If extraction has been disabled, the full path to the
168 downloaded file is available as ``<DOWNLOADED_FILE>`` in subsequent
169 steps or as the property ``DOWNLOADED_FILE`` with the
170 :command:`ExternalProject_Get_Property` command.
172 ``DOWNLOAD_NO_PROGRESS <bool>``
173 Can be used to disable logging the download progress. If this option is
174 not given, download progress messages will be logged.
176 ``TIMEOUT <seconds>``
177 Maximum time allowed for file download operations.
179 ``HTTP_USERNAME <username>``
180 Username for the download operation if authentication is required.
182 ``HTTP_PASSWORD <password>``
183 Password for the download operation if authentication is required.
185 ``HTTP_HEADER <header1> [<header2>...]``
186 Provides an arbitrary list of HTTP headers for the download operation.
187 This can be useful for accessing content in systems like AWS, etc.
189 ``TLS_VERIFY <bool>``
190 Specifies whether certificate verification should be performed for
191 https URLs. If this option is not provided, the default behavior is
192 determined by the ``CMAKE_TLS_VERIFY`` variable (see
193 :command:`file(DOWNLOAD)`). If that is also not set, certificate
194 verification will not be performed. In situations where ``URL_HASH``
195 cannot be provided, this option can be an alternative verification
198 ``TLS_CAINFO <file>``
199 Specify a custom certificate authority file to use if ``TLS_VERIFY``
200 is enabled. If this option is not specified, the value of the
201 ``CMAKE_TLS_CAINFO`` variable will be used instead (see
202 :command:`file(DOWNLOAD)`)
205 Specify whether the ``.netrc`` file is to be used for operation.
206 If this option is not specified, the value of the ``CMAKE_NETRC``
207 variable will be used instead (see :command:`file(DOWNLOAD)`)
211 The ``.netrc`` file is ignored.
214 The ``.netrc`` file is optional, and information in the URL
215 is preferred. The file will be scanned to find which ever
216 information is not specified in the URL.
218 The ``.netrc`` file is required, and information in the URL
221 ``NETRC_FILE <file>``
222 Specify an alternative ``.netrc`` file to the one in your home directory
223 if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option
224 is not specified, the value of the ``CMAKE_NETRC_FILE`` variable will
225 be used instead (see :command:`file(DOWNLOAD)`)
228 NOTE: A git version of 1.6.5 or later is required if this download method
231 ``GIT_REPOSITORY <url>``
232 URL of the git repository. Any URL understood by the ``git`` command
236 Git branch name, tag or commit hash. Note that branch names and tags
237 should generally be specified as remote names (i.e. ``origin/myBranch``
238 rather than simply ``myBranch``). This ensures that if the remote end
239 has its tag moved or branch rebased or history rewritten, the local
240 clone will still be updated correctly. In general, however, specifying
241 a commit hash should be preferred for a number of reasons:
243 - If the local clone already has the commit corresponding to the hash,
244 no ``git fetch`` needs to be performed to check for changes each time
245 CMake is re-run. This can result in a significant speed up if many
246 external projects are being used.
247 - Using a specific git hash ensures that the main project's own history
248 is fully traceable to a specific point in the external project's
249 evolution. If a branch or tag name is used instead, then checking out
250 a specific commit of the main project doesn't necessarily pin the
251 whole build to a specific point in the life of the external project.
252 The lack of such deterministic behavior makes the main project lose
253 traceability and repeatability.
255 If ``GIT_SHALLOW`` is enabled then ``GIT_TAG`` works only with
256 branch names and tags. A commit hash is not allowed.
258 ``GIT_REMOTE_NAME <name>``
259 The optional name of the remote. If this option is not specified, it
260 defaults to ``origin``.
262 ``GIT_SUBMODULES <module>...``
263 Specific git submodules that should also be updated. If this option is
264 not provided, all git submodules will be updated. When :policy:`CMP0097`
265 is set to ``NEW`` if this value is set to an empty string then no submodules
266 are initialized or updated.
268 ``GIT_SUBMODULES_RECURSE <bool>``
269 Specify whether git submodules (if any) should update recursively by
270 passing the ``--recursive`` flag to ``git submodule update``.
271 If not specified, the default is on.
273 ``GIT_SHALLOW <bool>``
274 When this option is enabled, the ``git clone`` operation will be given
275 the ``--depth 1`` option. This performs a shallow clone, which avoids
276 downloading the whole history and instead retrieves just the commit
277 denoted by the ``GIT_TAG`` option.
279 ``GIT_PROGRESS <bool>``
280 When enabled, this option instructs the ``git clone`` operation to
281 report its progress by passing it the ``--progress`` option. Without
282 this option, the clone step for large projects may appear to make the
283 build stall, since nothing will be logged until the clone operation
284 finishes. While this option can be used to provide progress to prevent
285 the appearance of the build having stalled, it may also make the build
286 overly noisy if lots of external projects are used.
288 ``GIT_CONFIG <option1> [<option2>...]``
289 Specify a list of config options to pass to ``git clone``. Each option
290 listed will be transformed into its own ``--config <option>`` on the
291 ``git clone`` command line, with each option required to be in the
295 ``SVN_REPOSITORY <url>``
296 URL of the Subversion repository.
298 ``SVN_REVISION -r<rev>``
299 Revision to checkout from the Subversion repository.
301 ``SVN_USERNAME <username>``
302 Username for the Subversion checkout and update.
304 ``SVN_PASSWORD <password>``
305 Password for the Subversion checkout and update.
307 ``SVN_TRUST_CERT <bool>``
308 Specifies whether to trust the Subversion server site certificate. If
309 enabled, the ``--trust-server-cert`` option is passed to the ``svn``
310 checkout and update commands.
313 ``HG_REPOSITORY <url>``
314 URL of the mercurial repository.
317 Mercurial branch name, tag or commit id.
320 ``CVS_REPOSITORY <cvsroot>``
321 CVSROOT of the CVS repository.
324 Module to checkout from the CVS repository.
327 Tag to checkout from the CVS repository.
329 **Update/Patch Step Options:**
330 Whenever CMake is re-run, by default the external project's sources will be
331 updated if the download method supports updates (e.g. a git repository
332 would be checked if the ``GIT_TAG`` does not refer to a specific commit).
334 ``UPDATE_COMMAND <cmd>...``
335 Overrides the download method's update step with a custom command.
337 :manual:`generator expressions <cmake-generator-expressions(7)>`.
339 ``UPDATE_DISCONNECTED <bool>``
340 When enabled, this option causes the update step to be skipped. It does
341 not, however, prevent the download step. The update step can still be
342 added as a step target (see :command:`ExternalProject_Add_StepTargets`)
343 and called manually. This is useful if you want to allow developers to
344 build the project when disconnected from the network (the network may
345 still be needed for the download step though).
347 When this option is present, it is generally advisable to make the value
348 a cache variable under the developer's control rather than hard-coding
349 it. If this option is not present, the default value is taken from the
350 ``EP_UPDATE_DISCONNECTED`` directory property. If that is also not
351 defined, updates are performed as normal. The ``EP_UPDATE_DISCONNECTED``
352 directory property is intended as a convenience for controlling the
353 ``UPDATE_DISCONNECTED`` behavior for an entire section of a project's
354 directory hierarchy and may be a more convenient method of giving
355 developers control over whether or not to perform updates (assuming the
356 project also provides a cache variable or some other convenient method
357 for setting the directory property).
359 ``PATCH_COMMAND <cmd>...``
360 Specifies a custom command to patch the sources after an update. By
361 default, no patch command is defined. Note that it can be quite difficult
362 to define an appropriate patch command that performs robustly, especially
363 for download methods such as git where changing the ``GIT_TAG`` will not
364 discard changes from a previous patch, but the patch command will be
365 called again after updating to the new tag.
367 **Configure Step Options:**
368 The configure step is run after the download and update steps. By default,
369 the external project is assumed to be a CMake project, but this can be
370 overridden if required.
372 ``CONFIGURE_COMMAND <cmd>...``
373 The default configure command runs CMake with options based on the main
374 project. For non-CMake external projects, the ``CONFIGURE_COMMAND``
375 option must be used to override this behavior
376 (:manual:`generator expressions <cmake-generator-expressions(7)>` are
377 supported). For projects that require no configure step, specify this
378 option with an empty string as the command to execute.
380 ``CMAKE_COMMAND /.../cmake``
381 Specify an alternative cmake executable for the configure step (use an
382 absolute path). This is generally not recommended, since it is
383 usually desirable to use the same CMake version throughout the whole
384 build. This option is ignored if a custom configure command has been
385 specified with ``CONFIGURE_COMMAND``.
387 ``CMAKE_GENERATOR <gen>``
388 Override the CMake generator used for the configure step. Without this
389 option, the same generator as the main build will be used. This option is
390 ignored if a custom configure command has been specified with the
391 ``CONFIGURE_COMMAND`` option.
393 ``CMAKE_GENERATOR_PLATFORM <platform>``
394 Pass a generator-specific platform name to the CMake command (see
395 :variable:`CMAKE_GENERATOR_PLATFORM`). It is an error to provide this
396 option without the ``CMAKE_GENERATOR`` option.
398 ``CMAKE_GENERATOR_TOOLSET <toolset>``
399 Pass a generator-specific toolset name to the CMake command (see
400 :variable:`CMAKE_GENERATOR_TOOLSET`). It is an error to provide this
401 option without the ``CMAKE_GENERATOR`` option.
403 ``CMAKE_GENERATOR_INSTANCE <instance>``
404 Pass a generator-specific instance selection to the CMake command (see
405 :variable:`CMAKE_GENERATOR_INSTANCE`). It is an error to provide this
406 option without the ``CMAKE_GENERATOR`` option.
408 ``CMAKE_ARGS <arg>...``
409 The specified arguments are passed to the ``cmake`` command line. They
410 can be any argument the ``cmake`` command understands, not just cache
411 values defined by ``-D...`` arguments (see also
412 :manual:`CMake Options <cmake(1)>`). In addition, arguments may use
413 :manual:`generator expressions <cmake-generator-expressions(7)>`.
415 ``CMAKE_CACHE_ARGS <arg>...``
416 This is an alternate way of specifying cache variables where command line
417 length issues may become a problem. The arguments are expected to be in
418 the form ``-Dvar:STRING=value``, which are then transformed into
419 CMake :command:`set` commands with the ``FORCE`` option used. These
420 ``set()`` commands are written to a pre-load script which is then applied
421 using the :manual:`cmake -C <cmake(1)>` command line option. Arguments
422 may use :manual:`generator expressions <cmake-generator-expressions(7)>`.
424 ``CMAKE_CACHE_DEFAULT_ARGS <arg>...``
425 This is the same as the ``CMAKE_CACHE_ARGS`` option except the ``set()``
426 commands do not include the ``FORCE`` keyword. This means the values act
427 as initial defaults only and will not override any variables already set
428 from a previous run. Use this option with care, as it can lead to
429 different behavior depending on whether the build starts from a fresh
430 build directory or re-uses previous build contents.
432 If the CMake generator is the ``Green Hills MULTI`` and not overridden then
433 the original project's settings for the GHS toolset and target system
434 customization cache variables are propagated into the external project.
436 ``SOURCE_SUBDIR <dir>``
437 When no ``CONFIGURE_COMMAND`` option is specified, the configure step
438 assumes the external project has a ``CMakeLists.txt`` file at the top of
439 its source tree (i.e. in ``SOURCE_DIR``). The ``SOURCE_SUBDIR`` option
440 can be used to point to an alternative directory within the source tree
441 to use as the top of the CMake source tree instead. This must be a
442 relative path and it will be interpreted as being relative to
443 ``SOURCE_DIR``. When ``BUILD_IN_SOURCE 1`` is specified, the
444 ``BUILD_COMMAND`` is used to point to an alternative directory within the
447 **Build Step Options:**
448 If the configure step assumed the external project uses CMake as its build
449 system, the build step will also. Otherwise, the build step will assume a
450 Makefile-based build and simply run ``make`` with no arguments as the
451 default build step. This can be overridden with custom build commands if
454 ``BUILD_COMMAND <cmd>...``
455 Overrides the default build command
456 (:manual:`generator expressions <cmake-generator-expressions(7)>` are
457 supported). If this option is not given, the default build command will
458 be chosen to integrate with the main build in the most appropriate way
459 (e.g. using recursive ``make`` for Makefile generators or
460 ``cmake --build`` if the project uses a CMake build). This option can be
461 specified with an empty string as the command to make the build step do
464 ``BUILD_IN_SOURCE <bool>``
465 When this option is enabled, the build will be done directly within the
466 external project's source tree. This should generally be avoided, the use
467 of a separate build directory is usually preferred, but it can be useful
468 when the external project assumes an in-source build. The ``BINARY_DIR``
469 option should not be specified if building in-source.
471 ``BUILD_ALWAYS <bool>``
472 Enabling this option forces the build step to always be run. This can be
473 the easiest way to robustly ensure that the external project's own build
474 dependencies are evaluated rather than relying on the default
475 success timestamp-based method. This option is not normally needed unless
476 developers are expected to modify something the external project's build
477 depends on in a way that is not detectable via the step target
478 dependencies (e.g. ``SOURCE_DIR`` is used without a download method and
479 developers might modify the sources in ``SOURCE_DIR``).
481 ``BUILD_BYPRODUCTS <file>...``
482 Specifies files that will be generated by the build command but which
483 might or might not have their modification time updated by subsequent
484 builds. These ultimately get passed through as ``BYPRODUCTS`` to the
485 build step's own underlying call to :command:`add_custom_command`.
487 **Install Step Options:**
488 If the configure step assumed the external project uses CMake as its build
489 system, the install step will also. Otherwise, the install step will assume
490 a Makefile-based build and simply run ``make install`` as the default build
491 step. This can be overridden with custom install commands if required.
493 ``INSTALL_COMMAND <cmd>...``
494 The external project's own install step is invoked as part of the main
495 project's *build*. It is done after the external project's build step
496 and may be before or after the external project's test step (see the
497 ``TEST_BEFORE_INSTALL`` option below). The external project's install
498 rules are not part of the main project's install rules, so if anything
499 from the external project should be installed as part of the main build,
500 these need to be specified in the main build as additional
501 :command:`install` commands. The default install step builds the
502 ``install`` target of the external project, but this can be overridden
503 with a custom command using this option
504 (:manual:`generator expressions <cmake-generator-expressions(7)>` are
505 supported). Passing an empty string as the ``<cmd>`` makes the install
508 **Test Step Options:**
509 The test step is only defined if at least one of the following ``TEST_...``
510 options are provided.
512 ``TEST_COMMAND <cmd>...``
513 Overrides the default test command
514 (:manual:`generator expressions <cmake-generator-expressions(7)>` are
515 supported). If this option is not given, the default behavior of the test
516 step is to build the external project's own ``test`` target. This option
517 can be specified with ``<cmd>`` as an empty string, which allows the test
518 step to still be defined, but it will do nothing. Do not specify any of
519 the other ``TEST_...`` options if providing an empty string as the test
520 command, but prefer to omit all ``TEST_...`` options altogether if the
521 test step target is not needed.
523 ``TEST_BEFORE_INSTALL <bool>``
524 When this option is enabled, the test step will be executed before the
525 install step. The default behavior is for the test step to run after the
528 ``TEST_AFTER_INSTALL <bool>``
529 This option is mainly useful as a way to indicate that the test step is
530 desired but all default behavior is sufficient. Specifying this option
531 with a boolean true value ensures the test step is defined and that it
532 comes after the install step. If both ``TEST_BEFORE_INSTALL`` and
533 ``TEST_AFTER_INSTALL`` are enabled, the latter is silently ignored.
535 ``TEST_EXCLUDE_FROM_MAIN <bool>``
536 If enabled, the main build's default ALL target will not depend on the
537 test step. This can be a useful way of ensuring the test step is defined
538 but only gets invoked when manually requested.
540 **Output Logging Options:**
541 Each of the following ``LOG_...`` options can be used to wrap the relevant
542 step in a script to capture its output to files. The log files will be
543 created in ``LOG_DIR`` if supplied or otherwise the ``STAMP_DIR``
544 directory with step-specific file names.
546 ``LOG_DOWNLOAD <bool>``
547 When enabled, the output of the download step is logged to files.
549 ``LOG_UPDATE <bool>``
550 When enabled, the output of the update step is logged to files.
553 When enabled, the output of the patch step is logged to files.
555 ``LOG_CONFIGURE <bool>``
556 When enabled, the output of the configure step is logged to files.
559 When enabled, the output of the build step is logged to files.
561 ``LOG_INSTALL <bool>``
562 When enabled, the output of the install step is logged to files.
565 When enabled, the output of the test step is logged to files.
567 ``LOG_MERGED_STDOUTERR <bool>``
568 When enabled, stdout and stderr will be merged for any step whose
569 output is being logged to files.
571 ``LOG_OUTPUT_ON_FAILURE <bool>``
572 This option only has an effect if at least one of the other ``LOG_<step>``
573 options is enabled. If an error occurs for a step which has logging to
574 file enabled, that step's output will be printed to the console if
575 ``LOG_OUTPUT_ON_FAILURE`` is set to true. For cases where a large amount
576 of output is recorded, just the end of that output may be printed to the
579 **Terminal Access Options:**
580 Steps can be given direct access to the terminal in some cases. Giving a
581 step access to the terminal may allow it to receive terminal input if
582 required, such as for authentication details not provided by other options.
583 With the :generator:`Ninja` generator, these options place the steps in the
584 ``console`` :prop_gbl:`job pool <JOB_POOLS>`. Each step can be given access
585 to the terminal individually via the following options:
587 ``USES_TERMINAL_DOWNLOAD <bool>``
588 Give the download step access to the terminal.
590 ``USES_TERMINAL_UPDATE <bool>``
591 Give the update step access to the terminal.
593 ``USES_TERMINAL_CONFIGURE <bool>``
594 Give the configure step access to the terminal.
596 ``USES_TERMINAL_BUILD <bool>``
597 Give the build step access to the terminal.
599 ``USES_TERMINAL_INSTALL <bool>``
600 Give the install step access to the terminal.
602 ``USES_TERMINAL_TEST <bool>``
603 Give the test step access to the terminal.
606 ``DEPENDS <targets>...``
607 Specify other targets on which the external project depends. The other
608 targets will be brought up to date before any of the external project's
609 steps are executed. Because the external project uses additional custom
610 targets internally for each step, the ``DEPENDS`` option is the most
611 convenient way to ensure all of those steps depend on the other targets.
613 :command:`add_dependencies(\<name\> \<targets\>) <add_dependencies>` will
614 not make any of the steps dependent on ``<targets>``.
616 ``EXCLUDE_FROM_ALL <bool>``
617 When enabled, this option excludes the external project from the default
618 ALL target of the main build.
620 ``STEP_TARGETS <step-target>...``
621 Generate custom targets for the specified steps. This is required if the
622 steps need to be triggered manually or if they need to be used as
623 dependencies of other targets. If this option is not specified, the
624 default value is taken from the ``EP_STEP_TARGETS`` directory property.
625 See :command:`ExternalProject_Add_Step` below for further discussion of
626 the effects of this option.
628 ``INDEPENDENT_STEP_TARGETS <step-target>...``
629 Generate custom targets for the specified steps and prevent these targets
630 from having the usual dependencies applied to them. If this option is not
631 specified, the default value is taken from the
632 ``EP_INDEPENDENT_STEP_TARGETS`` directory property. This option is mostly
633 useful for allowing individual steps to be driven independently, such as
634 for a CDash setup where each step should be initiated and reported
635 individually rather than as one whole build. See
636 :command:`ExternalProject_Add_Step` below for further discussion of the
637 effects of this option.
639 **Miscellaneous Options:**
640 ``LIST_SEPARATOR <sep>``
641 For any of the various ``..._COMMAND`` options, replace ``;`` with
642 ``<sep>`` in the specified command lines. This can be useful where list
643 variables may be given in commands where they should end up as
644 space-separated arguments (``<sep>`` would be a single space character
645 string in this case).
648 Any of the other ``..._COMMAND`` options can have additional commands
649 appended to them by following them with as many ``COMMAND ...`` options
651 (:manual:`generator expressions <cmake-generator-expressions(7)>` are
652 supported). For example:
654 .. code-block:: cmake
656 ExternalProject_Add(example
657 ... # Download options, etc.
658 BUILD_COMMAND ${CMAKE_COMMAND} -E echo "Starting $<CONFIG> build"
659 COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config $<CONFIG>
660 COMMAND ${CMAKE_COMMAND} -E echo "$<CONFIG> build complete"
663 It should also be noted that each build step is created via a call to
664 :command:`ExternalProject_Add_Step`. See that command's documentation for the
665 automatic substitutions that are supported for some options.
667 Obtaining Project Properties
668 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
670 .. command:: ExternalProject_Get_Property
672 The ``ExternalProject_Get_Property()`` function retrieves external project
675 .. code-block:: cmake
677 ExternalProject_Get_Property(<name> <prop1> [<prop2>...])
679 The function stores property values in variables of the same name. Property
680 names correspond to the keyword argument names of ``ExternalProject_Add()``.
681 For example, the source directory might be retrieved like so:
683 .. code-block:: cmake
685 ExternalProject_Get_property(myExtProj SOURCE_DIR)
686 message("Source dir of myExtProj = ${SOURCE_DIR}")
688 Explicit Step Management
689 ^^^^^^^^^^^^^^^^^^^^^^^^
691 The ``ExternalProject_Add()`` function on its own is often sufficient for
692 incorporating an external project into the main build. Certain scenarios
693 require additional work to implement desired behavior, such as adding in a
694 custom step or making steps available as manually triggerable targets. The
695 ``ExternalProject_Add_Step()``, ``ExternalProject_Add_StepTargets()`` and
696 ``ExternalProject_Add_StepDependencies`` functions provide the lower level
697 control needed to implement such step-level capabilities.
699 .. command:: ExternalProject_Add_Step
701 The ``ExternalProject_Add_Step()`` function specifies an additional custom
702 step for an external project defined by an earlier call to
703 :command:`ExternalProject_Add`:
705 .. code-block:: cmake
707 ExternalProject_Add_Step(<name> <step> [<option>...])
709 ``<name>`` is the same as the name passed to the original call to
710 :command:`ExternalProject_Add`. The specified ``<step>`` must not be one of
711 the pre-defined steps (``mkdir``, ``download``, ``update``, ``skip-update``,
712 ``patch``, ``configure``, ``build``, ``install`` or ``test``). The supported
716 The command line to be executed by this custom step
717 (:manual:`generator expressions <cmake-generator-expressions(7)>` are
718 supported). This option can be repeated multiple times to specify multiple
719 commands to be executed in order.
721 ``COMMENT "<text>..."``
722 Text to be printed when the custom step executes.
724 ``DEPENDEES <step>...``
725 Other steps (custom or pre-defined) on which this step depends.
727 ``DEPENDERS <step>...``
728 Other steps (custom or pre-defined) that depend on this new custom step.
730 ``DEPENDS <file>...``
731 Files on which this custom step depends.
733 ``BYPRODUCTS <file>...``
734 Files that will be generated by this custom step but which might or might
735 not have their modification time updated by subsequent builds. This list of
736 files will ultimately be passed through as the ``BYPRODUCTS`` option to the
737 :command:`add_custom_command` used to implement the custom step internally.
740 When enabled, this option specifies that the custom step should always be
741 run (i.e. that it is always considered out of date).
743 ``EXCLUDE_FROM_MAIN <bool>``
744 When enabled, this option specifies that the external project's main target
745 does not depend on the custom step.
747 ``WORKING_DIRECTORY <dir>``
748 Specifies the working directory to set before running the custom step's
749 command. If this option is not specified, the directory will be the value
750 of the :variable:`CMAKE_CURRENT_BINARY_DIR` at the point where
751 ``ExternalProject_Add_Step()`` was called.
754 If set, this causes the output from the custom step to be captured to files
755 in the external project's ``LOG_DIR`` if supplied or ``STAMP_DIR``.
757 ``USES_TERMINAL <bool>``
758 If enabled, this gives the custom step direct access to the terminal if
761 The command line, comment, working directory and byproducts of every
762 standard and custom step are processed to replace the tokens
763 ``<SOURCE_DIR>``, ``<SOURCE_SUBDIR>``, ``<BINARY_DIR>``, ``<INSTALL_DIR>``
764 ``<TMP_DIR>``, ``<DOWNLOAD_DIR>`` and ``<DOWNLOADED_FILE>`` with their
765 corresponding property values defined in the original call to
766 :command:`ExternalProject_Add`.
768 .. command:: ExternalProject_Add_StepTargets
770 The ``ExternalProject_Add_StepTargets()`` function generates targets for the
771 steps listed. The name of each created target will be of the form
774 .. code-block:: cmake
776 ExternalProject_Add_StepTargets(<name> [NO_DEPENDS] <step1> [<step2>...])
778 Creating a target for a step allows it to be used as a dependency of another
779 target or to be triggered manually. Having targets for specific steps also
780 allows them to be driven independently of each other by specifying targets on
781 build command lines. For example, you may be submitting to a sub-project
782 based dashboard where you want to drive the configure portion of the build,
783 then submit to the dashboard, followed by the build portion, followed
784 by tests. If you invoke a custom target that depends on a step halfway
785 through the step dependency chain, then all the previous steps will also run
786 to ensure everything is up to date.
788 If the ``NO_DEPENDS`` option is specified, the step target will not depend on
789 the dependencies of the external project (i.e. on any dependencies of the
790 ``<name>`` custom target created by :command:`ExternalProject_Add`). This is
791 usually safe for the ``download``, ``update`` and ``patch`` steps, since they
792 do not typically require that the dependencies are updated and built. Using
793 ``NO_DEPENDS`` for any of the other pre-defined steps, however, may break
794 parallel builds. Only use ``NO_DEPENDS`` where it is certain that the named
795 steps genuinely do not have dependencies. For custom steps, consider whether
796 or not the custom commands require the dependencies to be configured, built
799 Internally, :command:`ExternalProject_Add` calls
800 :command:`ExternalProject_Add_Step` to create each step. If any
801 ``STEP_TARGETS`` or ``INDEPENDENT_STEP_TARGETS`` were specified, then
802 ``ExternalProject_Add_StepTargets()`` will also be called after
803 :command:`ExternalProject_Add_Step`. ``INDEPENDENT_STEP_TARGETS`` have the
804 ``NO_DEPENDS`` option set, whereas ``STEP_TARGETS`` do not. Other than that,
805 the two options result in ``ExternalProject_Add_StepTargets()`` being called
806 in the same way. Even if a step is not mentioned in either of those two
807 options, ``ExternalProject_Add_StepTargets()`` can still be called later to
808 manually define a target for the step.
810 The ``STEP_TARGETS`` and ``INDEPENDENT_STEP_TARGETS`` options for
811 :command:`ExternalProject_Add` are generally the easiest way to ensure
812 targets are created for specific steps of interest. For custom steps,
813 ``ExternalProject_Add_StepTargets()`` must be called explicitly if a target
814 should also be created for that custom step. An alternative to these two
815 options is to populate the ``EP_STEP_TARGETS`` and
816 ``EP_INDEPENDENT_STEP_TARGETS`` directory properties. These act as defaults
817 for the step target options and can save having to repeatedly specify the
818 same set of step targets when multiple external projects are being defined.
820 .. command:: ExternalProject_Add_StepDependencies
822 The ``ExternalProject_Add_StepDependencies()`` function can be used to add
823 dependencies to a step. The dependencies added must be targets CMake already
824 knows about (these can be ordinary executable or library targets, custom
825 targets or even step targets of another external project):
827 .. code-block:: cmake
829 ExternalProject_Add_StepDependencies(<name> <step> <target1> [<target2>...])
831 This function takes care to set both target and file level dependencies and
832 will ensure that parallel builds will not break. It should be used instead of
833 :command:`add_dependencies` whenever adding a dependency for some of the step
834 targets generated by the ``ExternalProject`` module.
839 The following example shows how to download and build a hypothetical project
840 called *FooBar* from github:
842 .. code-block:: cmake
844 include(ExternalProject)
845 ExternalProject_Add(foobar
846 GIT_REPOSITORY git@github.com:FooCo/FooBar.git
847 GIT_TAG origin/release/1.2.3
850 For the sake of the example, also define a second hypothetical external project
851 called *SecretSauce*, which is downloaded from a web server. Two URLs are given
852 to take advantage of a faster internal network if available, with a fallback to
853 a slower external server. The project is a typical ``Makefile`` project with no
854 configure step, so some of the default commands are overridden. The build is
855 only required to build the *sauce* target:
857 .. code-block:: cmake
859 find_program(MAKE_EXE NAMES gmake nmake make)
860 ExternalProject_Add(secretsauce
861 URL http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
862 https://www.somecompany.com/downloads/sauce-2.7.zip
863 URL_HASH MD5=d41d8cd98f00b204e9800998ecf8427e
865 BUILD_COMMAND ${MAKE_EXE} sauce
868 Suppose the build step of ``secretsauce`` requires that ``foobar`` must already
869 be built. This could be enforced like so:
871 .. code-block:: cmake
873 ExternalProject_Add_StepDependencies(secretsauce build foobar)
875 Another alternative would be to create a custom target for ``foobar``'s build
876 step and make ``secretsauce`` depend on that rather than the whole ``foobar``
877 project. This would mean ``foobar`` only needs to be built, it doesn't need to
878 run its install or test steps before ``secretsauce`` can be built. The
879 dependency can also be defined along with the ``secretsauce`` project:
881 .. code-block:: cmake
883 ExternalProject_Add_StepTargets(foobar build)
884 ExternalProject_Add(secretsauce
885 URL http://intranet.somecompany.com/artifacts/sauce-2.7.tgz
886 https://www.somecompany.com/downloads/sauce-2.7.zip
887 URL_HASH MD5=d41d8cd98f00b204e9800998ecf8427e
889 BUILD_COMMAND ${MAKE_EXE} sauce
893 Instead of calling :command:`ExternalProject_Add_StepTargets`, the target could
894 be defined along with the ``foobar`` project itself:
896 .. code-block:: cmake
898 ExternalProject_Add(foobar
899 GIT_REPOSITORY git@github.com:FooCo/FooBar.git
900 GIT_TAG origin/release/1.2.3
904 If many external projects should have the same set of step targets, setting a
905 directory property may be more convenient. The ``build`` step target could be
906 created automatically by setting the ``EP_STEP_TARGETS`` directory property
907 before creating the external projects with :command:`ExternalProject_Add`:
909 .. code-block:: cmake
911 set_property(DIRECTORY PROPERTY EP_STEP_TARGETS build)
913 Lastly, suppose that ``secretsauce`` provides a script called ``makedoc`` which
914 can be used to generate its own documentation. Further suppose that the script
915 expects the output directory to be provided as the only parameter and that it
916 should be run from the ``secretsauce`` source directory. A custom step and a
917 custom target to trigger the script can be defined like so:
919 .. code-block:: cmake
921 ExternalProject_Add_Step(secretsauce docs
922 COMMAND <SOURCE_DIR>/makedoc <BINARY_DIR>
923 WORKING_DIRECTORY <SOURCE_DIR>
924 COMMENT "Building secretsauce docs"
926 EXCLUDE_FROM_MAIN TRUE
928 ExternalProject_Add_StepTargets(secretsauce docs)
930 The custom step could then be triggered from the main build like so::
932 cmake --build . --target secretsauce-docs
934 #]=======================================================================]
937 cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced
939 # Pre-compute a regex to match documented keywords for each command.
940 math(EXPR _ep_documentation_line_count "${CMAKE_CURRENT_LIST_LINE} - 4")
941 file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines
942 LIMIT_COUNT ${_ep_documentation_line_count}
943 REGEX "^\\.\\. command:: [A-Za-z0-9_]+|^ +``[A-Z0-9_]+ [^`]*``$")
944 foreach(line IN LISTS lines)
945 if("${line}" MATCHES "^\\.\\. command:: ([A-Za-z0-9_]+)")
947 string(APPEND _ep_keywords_${_ep_func} ")$")
949 set(_ep_func "${CMAKE_MATCH_1}")
950 #message("function [${_ep_func}]")
951 set(_ep_keywords_${_ep_func} "^(")
953 elseif("${line}" MATCHES "^ +``([A-Z0-9_]+) [^`]*``$")
954 set(_ep_key "${CMAKE_MATCH_1}")
955 # COMMAND should never be included as a keyword,
956 # for ExternalProject_Add(), as it is treated as a
957 # special case by argument parsing as an extension
958 # of a previous ..._COMMAND
959 if("x${_ep_key}x" STREQUAL "xCOMMANDx" AND
960 "x${_ep_func}x" STREQUAL "xExternalProject_Addx")
963 #message(" keyword [${_ep_key}]")
964 string(APPEND _ep_keywords_${_ep_func}
965 "${_ep_keyword_sep}${_ep_key}")
966 set(_ep_keyword_sep "|")
970 string(APPEND _ep_keywords_${_ep_func} ")$")
973 # Save regex matching supported hash algorithm names.
974 set(_ep_hash_algos "MD5|SHA1|SHA224|SHA256|SHA384|SHA512|SHA3_224|SHA3_256|SHA3_384|SHA3_512")
975 set(_ep_hash_regex "^(${_ep_hash_algos})=([0-9A-Fa-f]+)$")
977 set(_ExternalProject_SELF "${CMAKE_CURRENT_LIST_FILE}")
978 get_filename_component(_ExternalProject_SELF_DIR "${_ExternalProject_SELF}" PATH)
980 function(_ep_parse_arguments f name ns args)
981 # Transfer the arguments to this function into target properties for the
982 # new custom target we just added so that we can set up all the build steps
983 # correctly based on target properties.
985 # We loop through ARGN and consider the namespace starting with an
986 # upper-case letter followed by at least two more upper-case letters,
987 # numbers or underscores to be keywords.
989 if(NOT DEFINED _ExternalProject_SELF)
990 message(FATAL_ERROR "error: ExternalProject module must be explicitly included before using ${f} function")
995 foreach(arg IN LISTS args)
998 if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND
999 NOT (("x${arg}x" STREQUAL "x${key}x") AND ("x${key}x" STREQUAL "xCOMMANDx")) AND
1000 NOT arg MATCHES "^(TRUE|FALSE)$")
1001 if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
1009 if(NOT arg STREQUAL "")
1010 set_property(TARGET ${name} APPEND PROPERTY ${ns}${key} "${arg}")
1012 get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
1014 get_property(value TARGET ${name} PROPERTY ${ns}${key})
1015 set_property(TARGET ${name} PROPERTY ${ns}${key} "${value};${arg}")
1017 set_property(TARGET ${name} PROPERTY ${ns}${key} "${arg}")
1022 message(AUTHOR_WARNING "value '${arg}' with no previous keyword in ${f}")
1027 get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
1034 define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED
1035 BRIEF_DOCS "Base directory for External Project storage."
1037 "See documentation of the ExternalProject_Add() function in the "
1038 "ExternalProject module."
1041 define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
1042 BRIEF_DOCS "Top prefix for External Project storage."
1044 "See documentation of the ExternalProject_Add() function in the "
1045 "ExternalProject module."
1048 define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
1050 "List of ExternalProject steps that automatically get corresponding targets"
1052 "These targets will be dependent on the main target dependencies. "
1053 "See documentation of the ExternalProject_Add_StepTargets() function in the "
1054 "ExternalProject module."
1057 define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED
1059 "List of ExternalProject steps that automatically get corresponding targets"
1061 "These targets will not be dependent on the main target dependencies. "
1062 "See documentation of the ExternalProject_Add_StepTargets() function in the "
1063 "ExternalProject module."
1066 define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED
1067 BRIEF_DOCS "Never update automatically from the remote repo."
1069 "See documentation of the ExternalProject_Add() function in the "
1070 "ExternalProject module."
1073 function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name init_submodules git_submodules_recurse git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
1074 if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
1075 # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
1076 set(git_checkout_explicit-- "--")
1078 # Use `git checkout <branch>` even though this risks ambiguity with a
1079 # local path. Unfortunately we cannot use `git checkout <tree-ish> --`
1080 # because that will not search for remote branch names, a common use case.
1081 set(git_checkout_explicit-- "")
1083 if("${git_tag}" STREQUAL "")
1084 message(FATAL_ERROR "Tag for git checkout should not be empty.")
1087 set(git_clone_options "--no-checkout")
1089 if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10)
1090 list(APPEND git_clone_options "--depth 1 --no-single-branch")
1092 list(APPEND git_clone_options "--depth 1")
1096 list(APPEND git_clone_options --progress)
1098 foreach(config IN LISTS git_config)
1099 list(APPEND git_clone_options --config \"${config}\")
1101 if(NOT ${git_remote_name} STREQUAL "origin")
1102 list(APPEND git_clone_options --origin \"${git_remote_name}\")
1105 string (REPLACE ";" " " git_clone_options "${git_clone_options}")
1108 # disable cert checking if explicitly told not to do it
1109 if(NOT "x${tls_verify}" STREQUAL "x" AND NOT tls_verify)
1111 -c http.sslVerify=false)
1113 string (REPLACE ";" " " git_options "${git_options}")
1115 file(WRITE ${script_filename}
1117 if(NOT \"${gitclone_infofile}\" IS_NEWER_THAN \"${gitclone_stampfile}\")
1118 message(STATUS \"Avoiding repeated git clone, stamp file is up to date: '${gitclone_stampfile}'\")
1123 COMMAND \${CMAKE_COMMAND} -E rm -rf \"${source_dir}\"
1124 RESULT_VARIABLE error_code
1127 message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
1130 # try the clone 3 times in case there is an odd git clone issue
1132 set(number_of_tries 0)
1133 while(error_code AND number_of_tries LESS 3)
1135 COMMAND \"${git_EXECUTABLE}\" ${git_options} clone ${git_clone_options} \"${git_repository}\" \"${src_name}\"
1136 WORKING_DIRECTORY \"${work_dir}\"
1137 RESULT_VARIABLE error_code
1139 math(EXPR number_of_tries \"\${number_of_tries} + 1\")
1141 if(number_of_tries GREATER 1)
1142 message(STATUS \"Had to git clone more than once:
1143 \${number_of_tries} times.\")
1146 message(FATAL_ERROR \"Failed to clone repository: '${git_repository}'\")
1150 COMMAND \"${git_EXECUTABLE}\" ${git_options} checkout ${git_tag} ${git_checkout_explicit--}
1151 WORKING_DIRECTORY \"${work_dir}/${src_name}\"
1152 RESULT_VARIABLE error_code
1155 message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
1158 set(init_submodules ${init_submodules})
1161 COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update ${git_submodules_recurse} --init ${git_submodules}
1162 WORKING_DIRECTORY \"${work_dir}/${src_name}\"
1163 RESULT_VARIABLE error_code
1167 message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
1170 # Complete success, update the script-last-run stamp file:
1173 COMMAND \${CMAKE_COMMAND} -E copy
1174 \"${gitclone_infofile}\"
1175 \"${gitclone_stampfile}\"
1176 RESULT_VARIABLE error_code
1179 message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${gitclone_stampfile}'\")
1187 function(_ep_write_hgclone_script script_filename source_dir hg_EXECUTABLE hg_repository hg_tag src_name work_dir hgclone_infofile hgclone_stampfile)
1188 if("${hg_tag}" STREQUAL "")
1189 message(FATAL_ERROR "Tag for hg checkout should not be empty.")
1191 file(WRITE ${script_filename}
1193 if(NOT \"${hgclone_infofile}\" IS_NEWER_THAN \"${hgclone_stampfile}\")
1194 message(STATUS \"Avoiding repeated hg clone, stamp file is up to date: '${hgclone_stampfile}'\")
1199 COMMAND \${CMAKE_COMMAND} -E rm -rf \"${source_dir}\"
1200 RESULT_VARIABLE error_code
1203 message(FATAL_ERROR \"Failed to remove directory: '${source_dir}'\")
1207 COMMAND \"${hg_EXECUTABLE}\" clone -U \"${hg_repository}\" \"${src_name}\"
1208 WORKING_DIRECTORY \"${work_dir}\"
1209 RESULT_VARIABLE error_code
1212 message(FATAL_ERROR \"Failed to clone repository: '${hg_repository}'\")
1216 COMMAND \"${hg_EXECUTABLE}\" update ${hg_tag}
1217 WORKING_DIRECTORY \"${work_dir}/${src_name}\"
1218 RESULT_VARIABLE error_code
1221 message(FATAL_ERROR \"Failed to checkout tag: '${hg_tag}'\")
1224 # Complete success, update the script-last-run stamp file:
1227 COMMAND \${CMAKE_COMMAND} -E copy
1228 \"${hgclone_infofile}\"
1229 \"${hgclone_stampfile}\"
1230 RESULT_VARIABLE error_code
1233 message(FATAL_ERROR \"Failed to copy script-last-run stamp file: '${hgclone_stampfile}'\")
1242 function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name init_submodules git_submodules_recurse git_submodules git_repository work_dir)
1243 if("${git_tag}" STREQUAL "")
1244 message(FATAL_ERROR "Tag for git checkout should not be empty.")
1246 if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.6)
1247 set(git_stash_save_options --all --quiet)
1249 set(git_stash_save_options --quiet)
1251 file(WRITE ${script_filename}
1254 COMMAND \"${git_EXECUTABLE}\" rev-list --max-count=1 HEAD
1255 WORKING_DIRECTORY \"${work_dir}\"
1256 RESULT_VARIABLE error_code
1257 OUTPUT_VARIABLE head_sha
1258 OUTPUT_STRIP_TRAILING_WHITESPACE
1261 message(FATAL_ERROR \"Failed to get the hash for HEAD\")
1265 COMMAND \"${git_EXECUTABLE}\" show-ref ${git_tag}
1266 WORKING_DIRECTORY \"${work_dir}\"
1267 OUTPUT_VARIABLE show_ref_output
1269 # If a remote ref is asked for, which can possibly move around,
1270 # we must always do a fetch and checkout.
1271 if(\"\${show_ref_output}\" MATCHES \"remotes\")
1272 set(is_remote_ref 1)
1274 set(is_remote_ref 0)
1277 # Tag is in the form <remote>/<tag> (i.e. origin/master) we must strip
1278 # the remote from the tag.
1279 if(\"\${show_ref_output}\" MATCHES \"refs/remotes/${git_tag}\")
1280 string(REGEX MATCH \"^([^/]+)/(.+)$\" _unused \"${git_tag}\")
1281 set(git_remote \"\${CMAKE_MATCH_1}\")
1282 set(git_tag \"\${CMAKE_MATCH_2}\")
1284 set(git_remote \"${git_remote_name}\")
1285 set(git_tag \"${git_tag}\")
1288 # This will fail if the tag does not exist (it probably has not been fetched
1291 COMMAND \"${git_EXECUTABLE}\" rev-list --max-count=1 ${git_tag}
1292 WORKING_DIRECTORY \"${work_dir}\"
1293 RESULT_VARIABLE error_code
1294 OUTPUT_VARIABLE tag_sha
1295 OUTPUT_STRIP_TRAILING_WHITESPACE
1298 # Is the hash checkout out that we want?
1299 if(error_code OR is_remote_ref OR NOT (\"\${tag_sha}\" STREQUAL \"\${head_sha}\"))
1301 COMMAND \"${git_EXECUTABLE}\" fetch
1302 WORKING_DIRECTORY \"${work_dir}\"
1303 RESULT_VARIABLE error_code
1306 message(FATAL_ERROR \"Failed to fetch repository '${git_repository}'\")
1310 # Check if stash is needed
1312 COMMAND \"${git_EXECUTABLE}\" status --porcelain
1313 WORKING_DIRECTORY \"${work_dir}\"
1314 RESULT_VARIABLE error_code
1315 OUTPUT_VARIABLE repo_status
1318 message(FATAL_ERROR \"Failed to get the status\")
1320 string(LENGTH \"\${repo_status}\" need_stash)
1322 # If not in clean state, stash changes in order to be able to be able to
1323 # perform git pull --rebase
1326 COMMAND \"${git_EXECUTABLE}\" stash save ${git_stash_save_options}
1327 WORKING_DIRECTORY \"${work_dir}\"
1328 RESULT_VARIABLE error_code
1331 message(FATAL_ERROR \"Failed to stash changes\")
1335 # Pull changes from the remote branch
1337 COMMAND \"${git_EXECUTABLE}\" rebase \${git_remote}/\${git_tag}
1338 WORKING_DIRECTORY \"${work_dir}\"
1339 RESULT_VARIABLE error_code
1342 # Rebase failed: Restore previous state.
1344 COMMAND \"${git_EXECUTABLE}\" rebase --abort
1345 WORKING_DIRECTORY \"${work_dir}\"
1349 COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet
1350 WORKING_DIRECTORY \"${work_dir}\"
1353 message(FATAL_ERROR \"\\nFailed to rebase in: '${work_dir}/${src_name}'.\\nYou will have to resolve the conflicts manually\")
1358 COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet
1359 WORKING_DIRECTORY \"${work_dir}\"
1360 RESULT_VARIABLE error_code
1363 # Stash pop --index failed: Try again dropping the index
1365 COMMAND \"${git_EXECUTABLE}\" reset --hard --quiet
1366 WORKING_DIRECTORY \"${work_dir}\"
1367 RESULT_VARIABLE error_code
1370 COMMAND \"${git_EXECUTABLE}\" stash pop --quiet
1371 WORKING_DIRECTORY \"${work_dir}\"
1372 RESULT_VARIABLE error_code
1375 # Stash pop failed: Restore previous state.
1377 COMMAND \"${git_EXECUTABLE}\" reset --hard --quiet \${head_sha}
1378 WORKING_DIRECTORY \"${work_dir}\"
1381 COMMAND \"${git_EXECUTABLE}\" stash pop --index --quiet
1382 WORKING_DIRECTORY \"${work_dir}\"
1384 message(FATAL_ERROR \"\\nFailed to unstash changes in: '${work_dir}/${src_name}'.\\nYou will have to resolve the conflicts manually\")
1390 COMMAND \"${git_EXECUTABLE}\" checkout ${git_tag}
1391 WORKING_DIRECTORY \"${work_dir}\"
1392 RESULT_VARIABLE error_code
1395 message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
1399 set(init_submodules ${init_submodules})
1402 COMMAND \"${git_EXECUTABLE}\" submodule update ${git_submodules_recurse} --init ${git_submodules}
1403 WORKING_DIRECTORY \"${work_dir}/${src_name}\"
1404 RESULT_VARIABLE error_code
1408 message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
1415 endfunction(_ep_write_gitupdate_script)
1417 function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout no_progress hash tls_verify tls_cainfo userpwd http_headers netrc netrc_file)
1419 set(TIMEOUT_ARGS TIMEOUT ${timeout})
1420 set(TIMEOUT_MSG "${timeout} seconds")
1422 set(TIMEOUT_ARGS "# no TIMEOUT")
1423 set(TIMEOUT_MSG "none")
1427 set(SHOW_PROGRESS "")
1429 set(SHOW_PROGRESS "SHOW_PROGRESS")
1432 if("${hash}" MATCHES "${_ep_hash_regex}")
1433 set(ALGO "${CMAKE_MATCH_1}")
1434 string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
1437 set(EXPECT_VALUE "")
1440 set(TLS_VERIFY_CODE "")
1441 set(TLS_CAINFO_CODE "")
1443 set(NETRC_FILE_CODE "")
1445 # check for curl globals in the project
1446 if(DEFINED CMAKE_TLS_VERIFY)
1447 set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY ${CMAKE_TLS_VERIFY})")
1449 if(DEFINED CMAKE_TLS_CAINFO)
1450 set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${CMAKE_TLS_CAINFO}\")")
1452 if(DEFINED CMAKE_NETRC)
1453 set(NETRC_CODE "set(CMAKE_NETRC \"${CMAKE_NETRC}\")")
1455 if(DEFINED CMAKE_NETRC_FILE)
1456 set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${CMAKE_NETRC_FILE}\")")
1459 # now check for curl locals so that the local values
1460 # will override the globals
1462 # check for tls_verify argument
1463 string(LENGTH "${tls_verify}" tls_verify_len)
1464 if(tls_verify_len GREATER 0)
1465 set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY ${tls_verify})")
1467 # check for tls_cainfo argument
1468 string(LENGTH "${tls_cainfo}" tls_cainfo_len)
1469 if(tls_cainfo_len GREATER 0)
1470 set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")")
1472 # check for netrc argument
1473 string(LENGTH "${netrc}" netrc_len)
1474 if(netrc_len GREATER 0)
1475 set(NETRC_CODE "set(CMAKE_NETRC \"${netrc}\")")
1477 # check for netrc_file argument
1478 string(LENGTH "${netrc_file}" netrc_file_len)
1479 if(netrc_file_len GREATER 0)
1480 set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${netrc_file}\")")
1483 if(userpwd STREQUAL ":")
1486 set(USERPWD_ARGS USERPWD "${userpwd}")
1489 set(HTTP_HEADERS_ARGS "")
1490 if(NOT http_headers STREQUAL "")
1491 foreach(header ${http_headers})
1494 "HTTPHEADER \"${header}\"\n ${HTTP_HEADERS_ARGS}"
1510 # * HTTP_HEADERS_ARGS
1512 "${_ExternalProject_SELF_DIR}/ExternalProject-download.cmake.in"
1513 "${script_filename}"
1518 function(_ep_write_verifyfile_script script_filename LOCAL hash)
1519 if("${hash}" MATCHES "${_ep_hash_regex}")
1520 set(ALGO "${CMAKE_MATCH_1}")
1521 string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE)
1524 set(EXPECT_VALUE "")
1532 "${_ExternalProject_SELF_DIR}/ExternalProject-verify.cmake.in"
1533 "${script_filename}"
1539 function(_ep_write_extractfile_script script_filename name filename directory)
1542 if(filename MATCHES "(\\.|=)(7z|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$")
1546 if(filename MATCHES "(\\.|=)tar$")
1550 if(args STREQUAL "")
1551 message(SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .7z, .tar, .tar.bz2, .tar.gz, .tar.xz, .tbz2, .tgz, .txz and .zip")
1555 file(WRITE ${script_filename}
1556 "# Make file names absolute:
1558 get_filename_component(filename \"${filename}\" ABSOLUTE)
1559 get_filename_component(directory \"${directory}\" ABSOLUTE)
1561 message(STATUS \"extracting...
1563 dst='\${directory}'\")
1565 if(NOT EXISTS \"\${filename}\")
1566 message(FATAL_ERROR \"error: file to extract does not exist: '\${filename}'\")
1569 # Prepare a space for extracting:
1572 while(EXISTS \"\${directory}/../ex-${name}\${i}\")
1573 math(EXPR i \"\${i} + 1\")
1575 set(ut_dir \"\${directory}/../ex-${name}\${i}\")
1576 file(MAKE_DIRECTORY \"\${ut_dir}\")
1580 message(STATUS \"extracting... [tar ${args}]\")
1581 execute_process(COMMAND \${CMAKE_COMMAND} -E tar ${args} \${filename}
1582 WORKING_DIRECTORY \${ut_dir}
1586 message(STATUS \"extracting... [error clean up]\")
1587 file(REMOVE_RECURSE \"\${ut_dir}\")
1588 message(FATAL_ERROR \"error: extract of '\${filename}' failed\")
1591 # Analyze what came out of the tar file:
1593 message(STATUS \"extracting... [analysis]\")
1594 file(GLOB contents \"\${ut_dir}/*\")
1595 list(REMOVE_ITEM contents \"\${ut_dir}/.DS_Store\")
1596 list(LENGTH contents n)
1597 if(NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\")
1598 set(contents \"\${ut_dir}\")
1601 # Move \"the one\" directory to the final directory:
1603 message(STATUS \"extracting... [rename]\")
1604 file(REMOVE_RECURSE \${directory})
1605 get_filename_component(contents \${contents} ABSOLUTE)
1606 file(RENAME \${contents} \${directory})
1610 message(STATUS \"extracting... [clean up]\")
1611 file(REMOVE_RECURSE \"\${ut_dir}\")
1613 message(STATUS \"extracting... done\")
1620 function(_ep_set_directories name)
1621 get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX)
1623 get_property(prefix DIRECTORY PROPERTY EP_PREFIX)
1625 get_property(base DIRECTORY PROPERTY EP_BASE)
1627 set(prefix "${name}-prefix")
1632 set(tmp_default "${prefix}/tmp")
1633 set(download_default "${prefix}/src")
1634 set(source_default "${prefix}/src/${name}")
1635 set(binary_default "${prefix}/src/${name}-build")
1636 set(stamp_default "${prefix}/src/${name}-stamp")
1637 set(install_default "${prefix}")
1639 set(tmp_default "${base}/tmp/${name}")
1640 set(download_default "${base}/Download/${name}")
1641 set(source_default "${base}/Source/${name}")
1642 set(binary_default "${base}/Build/${name}")
1643 set(stamp_default "${base}/Stamp/${name}")
1644 set(install_default "${base}/Install/${name}")
1646 get_property(build_in_source TARGET ${name} PROPERTY _EP_BUILD_IN_SOURCE)
1648 get_property(have_binary_dir TARGET ${name} PROPERTY _EP_BINARY_DIR SET)
1651 "External project ${name} has both BINARY_DIR and BUILD_IN_SOURCE!")
1654 set(top "${CMAKE_CURRENT_BINARY_DIR}")
1656 # Apply defaults and convert to absolute paths.
1657 set(places stamp download source binary install tmp)
1658 foreach(var ${places})
1659 string(TOUPPER "${var}" VAR)
1660 get_property(${var}_dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
1662 set(${var}_dir "${${var}_default}")
1664 if(NOT IS_ABSOLUTE "${${var}_dir}")
1665 get_filename_component(${var}_dir "${top}/${${var}_dir}" ABSOLUTE)
1667 set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
1670 # Special case for default log directory based on stamp directory.
1671 get_property(log_dir TARGET ${name} PROPERTY _EP_LOG_DIR)
1673 get_property(log_dir TARGET ${name} PROPERTY _EP_STAMP_DIR)
1675 if(NOT IS_ABSOLUTE "${log_dir}")
1676 get_filename_component(log_dir "${top}/${log_dir}" ABSOLUTE)
1678 set_property(TARGET ${name} PROPERTY _EP_LOG_DIR "${log_dir}")
1680 get_property(source_subdir TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR)
1681 if(NOT source_subdir)
1682 set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "")
1683 elseif(IS_ABSOLUTE "${source_subdir}")
1685 "External project ${name} has non-relative SOURCE_SUBDIR!")
1687 # Prefix with a slash so that when appended to the source directory, it
1688 # behaves as expected.
1689 set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "/${source_subdir}")
1692 get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR)
1694 set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}/${source_subdir}")
1696 set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}")
1700 # Make the directories at CMake configure time *and* add a custom command
1701 # to make them at build time. They need to exist at makefile generation
1702 # time for Borland make and wmake so that CMake may generate makefiles
1703 # with "cd C:\short\paths\with\no\spaces" commands in them.
1705 # Additionally, the add_custom_command is still used in case somebody
1706 # removes one of the necessary directories and tries to rebuild without
1708 foreach(var ${places})
1709 string(TOUPPER "${var}" VAR)
1710 get_property(dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
1711 file(MAKE_DIRECTORY "${dir}")
1712 if(NOT EXISTS "${dir}")
1713 message(FATAL_ERROR "dir '${dir}' does not exist after file(MAKE_DIRECTORY)")
1719 # IMPORTANT: this MUST be a macro and not a function because of the
1720 # in-place replacements that occur in each ${var}
1722 macro(_ep_replace_location_tags target_name)
1724 foreach(var ${vars})
1726 foreach(dir SOURCE_DIR SOURCE_SUBDIR BINARY_DIR INSTALL_DIR TMP_DIR DOWNLOAD_DIR DOWNLOADED_FILE LOG_DIR)
1727 get_property(val TARGET ${target_name} PROPERTY _EP_${dir})
1728 string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}")
1735 function(_ep_command_line_to_initial_cache var args force)
1736 set(script_initial_cache "")
1737 set(regex "^([^:]+):([^=]+)=(.*)$")
1741 set(forceArg "FORCE")
1743 foreach(line ${args})
1744 if("${line}" MATCHES "^-D(.*)")
1745 set(line "${CMAKE_MATCH_1}")
1746 if(NOT "${setArg}" STREQUAL "")
1747 # This is required to build up lists in variables, or complete an entry
1748 string(APPEND setArg "${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})")
1749 string(APPEND script_initial_cache "\n${setArg}")
1753 if("${line}" MATCHES "${regex}")
1754 set(name "${CMAKE_MATCH_1}")
1755 set(type "${CMAKE_MATCH_2}")
1756 set(value "${CMAKE_MATCH_3}")
1757 set(setArg "set(${name} \"${value}")
1759 message(WARNING "Line '${line}' does not match regex. Ignoring.")
1762 # Assume this is a list to append to the last var
1763 string(APPEND accumulator ";${line}")
1766 # Catch the final line of the args
1767 if(NOT "${setArg}" STREQUAL "")
1768 string(APPEND setArg "${accumulator}\" CACHE ${type} \"Initial cache\" ${forceArg})")
1769 string(APPEND script_initial_cache "\n${setArg}")
1771 set(${var} ${script_initial_cache} PARENT_SCOPE)
1775 function(_ep_write_initial_cache target_name script_filename script_initial_cache)
1776 # Write out values into an initial cache, that will be passed to CMake with -C
1777 # Replace location tags.
1778 _ep_replace_location_tags(${target_name} script_initial_cache)
1779 _ep_replace_location_tags(${target_name} script_filename)
1780 # Replace list separators.
1781 get_property(sep TARGET ${target_name} PROPERTY _EP_LIST_SEPARATOR)
1782 if(sep AND script_initial_cache)
1783 string(REPLACE "${sep}" ";" script_initial_cache "${script_initial_cache}")
1785 # Write out the initial cache file to the location specified.
1786 file(GENERATE OUTPUT "${script_filename}" CONTENT "${script_initial_cache}")
1790 function(ExternalProject_Get_Property name)
1791 foreach(var ${ARGN})
1792 string(TOUPPER "${var}" VAR)
1793 get_property(is_set TARGET ${name} PROPERTY _EP_${VAR} SET)
1795 message(FATAL_ERROR "External project \"${name}\" has no ${var}")
1797 get_property(${var} TARGET ${name} PROPERTY _EP_${VAR})
1798 set(${var} "${${var}}" PARENT_SCOPE)
1803 function(_ep_get_configure_command_id name cfg_cmd_id_var)
1804 get_target_property(cmd ${name} _EP_CONFIGURE_COMMAND)
1807 # Explicit empty string means no configure step for this project
1808 set(${cfg_cmd_id_var} "none" PARENT_SCOPE)
1811 # Default is "use cmake":
1812 set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
1814 # Otherwise we have to analyze the value:
1815 if(cmd MATCHES "^[^;]*/configure")
1816 set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
1817 elseif(cmd MATCHES "^[^;]*/cmake" AND NOT cmd MATCHES ";-[PE];")
1818 set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
1819 elseif(cmd MATCHES "config")
1820 set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
1822 set(${cfg_cmd_id_var} "unknown:${cmd}" PARENT_SCOPE)
1829 function(_ep_get_build_command name step cmd_var)
1832 _ep_get_configure_command_id(${name} cfg_cmd_id)
1833 if(cfg_cmd_id STREQUAL "cmake")
1834 # CMake project. Select build command based on generator.
1835 get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
1836 if("${CMAKE_GENERATOR}" MATCHES "Make" AND
1837 ("${cmake_generator}" MATCHES "Make" OR NOT cmake_generator))
1838 # The project uses the same Makefile generator. Use recursive make.
1840 if(step STREQUAL "INSTALL")
1843 if("x${step}x" STREQUAL "xTESTx")
1847 # Drive the project with "cmake --build".
1848 get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
1850 set(cmd "${cmake_command}")
1852 set(cmd "${CMAKE_COMMAND}")
1854 set(args --build ".")
1855 get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
1857 if (CMAKE_CFG_INTDIR AND
1858 NOT CMAKE_CFG_INTDIR STREQUAL "." AND
1859 NOT CMAKE_CFG_INTDIR MATCHES "\\$")
1860 # CMake 3.4 and below used the CMAKE_CFG_INTDIR placeholder value
1861 # provided by multi-configuration generators. Some projects were
1862 # taking advantage of that undocumented implementation detail to
1863 # specify a specific configuration here. They should use
1864 # BUILD_COMMAND to change the default command instead, but for
1865 # compatibility honor the value.
1866 set(config ${CMAKE_CFG_INTDIR})
1867 message(AUTHOR_WARNING "CMAKE_CFG_INTDIR should not be set by project code.\n"
1868 "To get a non-default build command, use the BUILD_COMMAND option.")
1870 set(config $<CONFIG>)
1872 list(APPEND args --config ${config})
1874 if(step STREQUAL "INSTALL")
1875 list(APPEND args --target install)
1877 # But for "TEST" drive the project with corresponding "ctest".
1878 if("x${step}x" STREQUAL "xTESTx")
1879 string(REGEX REPLACE "^(.*/)cmake([^/]*)$" "\\1ctest\\2" cmd "${cmd}")
1882 list(APPEND args -C ${config})
1887 # Non-CMake project. Guess "make" and "make install" and "make test".
1888 if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
1889 # Try to get the parallel arguments
1894 if(step STREQUAL "INSTALL")
1897 if("x${step}x" STREQUAL "xTESTx")
1902 # Use user-specified arguments instead of default arguments, if any.
1903 get_property(have_args TARGET ${name} PROPERTY _EP_${step}_ARGS SET)
1905 get_target_property(args ${name} _EP_${step}_ARGS)
1908 list(APPEND cmd ${args})
1909 set(${cmd_var} "${cmd}" PARENT_SCOPE)
1912 function(_ep_write_log_script name step cmd_var)
1913 ExternalProject_Get_Property(${name} log_dir)
1914 ExternalProject_Get_Property(${name} stamp_dir)
1915 set(command "${${cmd_var}}")
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)")
1925 if(WIN32 AND NOT CYGWIN)
1926 set(code_cygpath_make "
1927 if(\${make} MATCHES \"^/\")
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
1935 if(NOT cygpath_error)
1936 set(make \${cygpath_make})
1944 if("${CMAKE_CFG_INTDIR}" MATCHES "^\\$")
1945 string(REPLACE "${CMAKE_CFG_INTDIR}" "\${config}" command "${command}")
1946 set(config "-Dconfig=${CMAKE_CFG_INTDIR}")
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)
1956 set(msg \"Command failed (\${result}):\\n\")
1957 foreach(arg IN LISTS command)
1958 set(msg \"\${msg} '\${arg}'\")
1960 message(FATAL_ERROR \"\${msg}\")
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}")
1974 string(APPEND cmd "${sep}${arg}")
1978 string(APPEND code "set(command \"${cmd}\")${code_execute_process}")
1979 file(GENERATE OUTPUT "${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake" CONTENT "${code}")
1980 set(command ${CMAKE_COMMAND} "-Dmake=\${make}" "-Dconfig=\${config}" -P ${stamp_dir}/${name}-${step}-$<CONFIG>-impl.cmake)
1983 # Wrap the command in a script to log output to files.
1984 set(script ${stamp_dir}/${name}-${step}-$<CONFIG>.cmake)
1985 set(logbase ${log_dir}/${name}-${step})
1986 get_property(log_merged TARGET ${name} PROPERTY _EP_LOG_MERGED_STDOUTERR)
1987 get_property(log_output_on_failure TARGET ${name} PROPERTY _EP_LOG_OUTPUT_ON_FAILURE)
1989 set(stdout_log "${logbase}.log")
1990 set(stderr_log "${logbase}.log")
1992 set(stdout_log "${logbase}-out.log")
1993 set(stderr_log "${logbase}-err.log")
1996 cmake_minimum_required(VERSION 3.15)
1997 ${code_cygpath_make}
1998 set(command \"${command}\")
1999 set(log_merged \"${log_merged}\")
2000 set(log_output_on_failure \"${log_output_on_failure}\")
2001 set(stdout_log \"${stdout_log}\")
2002 set(stderr_log \"${stderr_log}\")
2005 RESULT_VARIABLE result
2006 OUTPUT_FILE \"\${stdout_log}\"
2007 ERROR_FILE \"\${stderr_log}\"
2009 macro(read_up_to_max_size log_file output_var)
2010 file(SIZE \${log_file} determined_size)
2012 if (determined_size GREATER max_size)
2013 math(EXPR seek_position \"\${determined_size} - \${max_size}\")
2014 file(READ \${log_file} \${output_var} OFFSET \${seek_position})
2015 set(\${output_var} \"...skipping to end...\\n\${\${output_var}}\")
2017 file(READ \${log_file} \${output_var})
2021 set(msg \"Command failed: \${result}\\n\")
2022 foreach(arg IN LISTS command)
2023 set(msg \"\${msg} '\${arg}'\")
2026 set(msg \"\${msg}\\nSee also\\n \${stderr_log}\")
2028 set(msg \"\${msg}\\nSee also\\n ${logbase}-*.log\")
2030 if (\${log_output_on_failure})
2031 message(SEND_ERROR \"\${msg}\")
2033 read_up_to_max_size(\"\${stderr_log}\" error_log_contents)
2034 message(STATUS \"Log output is:\\n\${error_log_contents}\")
2036 read_up_to_max_size(\"\${stdout_log}\" out_log_contents)
2037 read_up_to_max_size(\"\${stderr_log}\" err_log_contents)
2038 message(STATUS \"stdout output is:\\n\${out_log_contents}\")
2039 message(STATUS \"stderr output is:\\n\${err_log_contents}\")
2041 message(FATAL_ERROR \"Stopping after outputting logs.\")
2043 message(FATAL_ERROR \"\${msg}\")
2046 set(msg \"${name} ${step} command succeeded. See also ${logbase}-*.log\")
2047 message(STATUS \"\${msg}\")
2050 file(GENERATE OUTPUT "${script}" CONTENT "${code}")
2051 set(command ${CMAKE_COMMAND} ${make} ${config} -P ${script})
2052 set(${cmd_var} "${command}" PARENT_SCOPE)
2055 # This module used to use "/${CMAKE_CFG_INTDIR}" directly and produced
2056 # makefiles with "/./" in paths for custom command dependencies. Which
2057 # resulted in problems with parallel make -j invocations.
2059 # This function was added so that the suffix (search below for ${cfgdir}) is
2060 # only set to "/${CMAKE_CFG_INTDIR}" when ${CMAKE_CFG_INTDIR} is not going to
2061 # be "." (multi-configuration build systems like Visual Studio and Xcode...)
2063 function(_ep_get_configuration_subdir_suffix suffix_var)
2065 get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
2067 set(suffix "/${CMAKE_CFG_INTDIR}")
2069 set(${suffix_var} "${suffix}" PARENT_SCOPE)
2073 function(_ep_get_step_stampfile name step stampfile_var)
2074 ExternalProject_Get_Property(${name} stamp_dir)
2076 _ep_get_configuration_subdir_suffix(cfgdir)
2077 set(stampfile "${stamp_dir}${cfgdir}/${name}-${step}")
2079 set(${stampfile_var} "${stampfile}" PARENT_SCOPE)
2083 function(_ep_get_complete_stampfile name stampfile_var)
2084 set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
2085 _ep_get_configuration_subdir_suffix(cfgdir)
2086 set(stampfile "${cmf_dir}${cfgdir}/${name}-complete")
2088 set(${stampfile_var} ${stampfile} PARENT_SCOPE)
2092 function(ExternalProject_Add_StepTargets name)
2094 if(ARGC GREATER 1 AND "${ARGV1}" STREQUAL "NO_DEPENDS")
2096 list(REMOVE_AT steps 0)
2098 foreach(step ${steps})
2099 if(no_deps AND "${step}" MATCHES "^(configure|build|install|test)$")
2100 message(AUTHOR_WARNING "Using NO_DEPENDS for \"${step}\" step might break parallel builds")
2102 _ep_get_step_stampfile(${name} ${step} stamp_file)
2103 add_custom_target(${name}-${step}
2104 DEPENDS ${stamp_file})
2105 set_property(TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP 1)
2106 set_property(TARGET ${name}-${step} PROPERTY LABELS ${name})
2107 set_property(TARGET ${name}-${step} PROPERTY FOLDER "ExternalProjectTargets/${name}")
2109 # Depend on other external projects (target-level).
2111 get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
2112 foreach(arg IN LISTS deps)
2113 add_dependencies(${name}-${step} ${arg})
2120 function(ExternalProject_Add_Step name step)
2121 _ep_get_complete_stampfile(${name} complete_stamp_file)
2122 _ep_get_step_stampfile(${name} ${step} stamp_file)
2124 _ep_parse_arguments(ExternalProject_Add_Step
2125 ${name} _EP_${step}_ "${ARGN}")
2127 get_property(exclude_from_main TARGET ${name} PROPERTY _EP_${step}_EXCLUDE_FROM_MAIN)
2128 if(NOT exclude_from_main)
2129 add_custom_command(APPEND
2130 OUTPUT ${complete_stamp_file}
2131 DEPENDS ${stamp_file}
2135 # Steps depending on this step.
2136 get_property(dependers TARGET ${name} PROPERTY _EP_${step}_DEPENDERS)
2137 foreach(depender IN LISTS dependers)
2138 _ep_get_step_stampfile(${name} ${depender} depender_stamp_file)
2139 add_custom_command(APPEND
2140 OUTPUT ${depender_stamp_file}
2141 DEPENDS ${stamp_file}
2145 # Dependencies on files.
2146 get_property(depends TARGET ${name} PROPERTY _EP_${step}_DEPENDS)
2148 # Byproducts of the step.
2149 get_property(byproducts TARGET ${name} PROPERTY _EP_${step}_BYPRODUCTS)
2151 # Dependencies on steps.
2152 get_property(dependees TARGET ${name} PROPERTY _EP_${step}_DEPENDEES)
2153 foreach(dependee IN LISTS dependees)
2154 _ep_get_step_stampfile(${name} ${dependee} dependee_stamp_file)
2155 list(APPEND depends ${dependee_stamp_file})
2158 # The command to run.
2159 get_property(command TARGET ${name} PROPERTY _EP_${step}_COMMAND)
2161 set(comment "Performing ${step} step for '${name}'")
2163 set(comment "No ${step} step for '${name}'")
2165 get_property(work_dir TARGET ${name} PROPERTY _EP_${step}_WORKING_DIRECTORY)
2167 # Replace list separators.
2168 get_property(sep TARGET ${name} PROPERTY _EP_LIST_SEPARATOR)
2170 string(REPLACE "${sep}" "\\;" command "${command}")
2173 # Replace location tags.
2174 _ep_replace_location_tags(${name} comment command work_dir byproducts)
2177 get_property(comment_set TARGET ${name} PROPERTY _EP_${step}_COMMENT SET)
2179 get_property(comment TARGET ${name} PROPERTY _EP_${step}_COMMENT)
2183 get_property(uses_terminal TARGET ${name} PROPERTY _EP_${step}_USES_TERMINAL)
2185 set(uses_terminal USES_TERMINAL)
2187 set(uses_terminal "")
2191 get_property(always TARGET ${name} PROPERTY _EP_${step}_ALWAYS)
2193 set_property(SOURCE ${stamp_file} PROPERTY SYMBOLIC 1)
2195 # Remove any existing stamp in case the option changed in an existing tree.
2196 get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
2198 foreach(cfg ${CMAKE_CONFIGURATION_TYPES})
2199 string(REPLACE "/${CMAKE_CFG_INTDIR}" "/${cfg}" stamp_file_config "${stamp_file}")
2200 file(REMOVE ${stamp_file_config})
2203 file(REMOVE ${stamp_file})
2206 set(touch ${CMAKE_COMMAND} -E touch ${stamp_file})
2209 # Wrap with log script?
2210 get_property(log TARGET ${name} PROPERTY _EP_${step}_LOG)
2212 _ep_write_log_script(${name} ${step} command)
2215 if("${command}" STREQUAL "")
2216 # Some generators (i.e. Xcode) will not generate a file level target
2217 # if no command is set, and therefore the dependencies on this
2218 # target will be broken.
2219 # The empty command is replaced by an echo command here in order to
2221 set(command ${CMAKE_COMMAND} -E echo_append)
2225 OUTPUT ${stamp_file}
2226 BYPRODUCTS ${byproducts}
2231 WORKING_DIRECTORY ${work_dir}
2235 set_property(TARGET ${name} APPEND PROPERTY _EP_STEPS ${step})
2237 # Add custom "step target"?
2238 get_property(step_targets TARGET ${name} PROPERTY _EP_STEP_TARGETS)
2239 if(NOT step_targets)
2240 get_property(step_targets DIRECTORY PROPERTY EP_STEP_TARGETS)
2242 foreach(st ${step_targets})
2243 if("${st}" STREQUAL "${step}")
2244 ExternalProject_Add_StepTargets(${name} ${step})
2249 get_property(independent_step_targets TARGET ${name} PROPERTY _EP_INDEPENDENT_STEP_TARGETS)
2250 if(NOT independent_step_targets)
2251 get_property(independent_step_targets DIRECTORY PROPERTY EP_INDEPENDENT_STEP_TARGETS)
2253 foreach(st ${independent_step_targets})
2254 if("${st}" STREQUAL "${step}")
2255 ExternalProject_Add_StepTargets(${name} NO_DEPENDS ${step})
2262 function(ExternalProject_Add_StepDependencies name step)
2263 set(dependencies ${ARGN})
2265 # Sanity checks on "name" and "step".
2266 if(NOT TARGET ${name})
2267 message(FATAL_ERROR "Cannot find target \"${name}\". Perhaps it has not yet been created using ExternalProject_Add.")
2270 get_property(type TARGET ${name} PROPERTY TYPE)
2271 if(NOT type STREQUAL "UTILITY")
2272 message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add.")
2275 get_property(is_ep TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT)
2277 message(FATAL_ERROR "Target \"${name}\" was not generated by ExternalProject_Add.")
2280 get_property(steps TARGET ${name} PROPERTY _EP_STEPS)
2281 list(FIND steps ${step} is_step)
2283 message(FATAL_ERROR "External project \"${name}\" does not have a step \"${step}\".")
2286 if(TARGET ${name}-${step})
2287 get_property(type TARGET ${name}-${step} PROPERTY TYPE)
2288 if(NOT type STREQUAL "UTILITY")
2289 message(FATAL_ERROR "Target \"${name}-${step}\" was not generated by ExternalProject_Add_StepTargets.")
2291 get_property(is_ep_step TARGET ${name}-${step} PROPERTY _EP_IS_EXTERNAL_PROJECT_STEP)
2293 message(FATAL_ERROR "Target \"${name}-${step}\" was not generated by ExternalProject_Add_StepTargets.")
2297 # Always add file-level dependency, but add target-level dependency
2298 # only if the target exists for that step.
2299 _ep_get_step_stampfile(${name} ${step} stamp_file)
2300 foreach(dep ${dependencies})
2301 add_custom_command(APPEND
2302 OUTPUT ${stamp_file}
2304 if(TARGET ${name}-${step})
2305 foreach(dep ${dependencies})
2306 add_dependencies(${name}-${step} ${dep})
2314 function(_ep_add_mkdir_command name)
2315 ExternalProject_Get_Property(${name}
2316 source_dir binary_dir install_dir stamp_dir download_dir tmp_dir log_dir)
2318 _ep_get_configuration_subdir_suffix(cfgdir)
2320 ExternalProject_Add_Step(${name} mkdir
2321 COMMENT "Creating directories for '${name}'"
2322 COMMAND ${CMAKE_COMMAND} -E make_directory ${source_dir}
2323 COMMAND ${CMAKE_COMMAND} -E make_directory ${binary_dir}
2324 COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}
2325 COMMAND ${CMAKE_COMMAND} -E make_directory ${tmp_dir}
2326 COMMAND ${CMAKE_COMMAND} -E make_directory ${stamp_dir}${cfgdir}
2327 COMMAND ${CMAKE_COMMAND} -E make_directory ${download_dir}
2328 COMMAND ${CMAKE_COMMAND} -E make_directory ${log_dir}
2333 function(_ep_is_dir_empty dir empty_var)
2334 file(GLOB gr "${dir}/*")
2335 if("${gr}" STREQUAL "")
2336 set(${empty_var} 1 PARENT_SCOPE)
2338 set(${empty_var} 0 PARENT_SCOPE)
2342 function(_ep_get_git_submodules_recurse git_submodules_recurse)
2343 # Checks for GIT_SUBMODULES_RECURSE property
2344 # Default is ON, which sets git_submodules_recurse output variable to "--recursive"
2345 # Otherwise, the output variable is set to an empty value ""
2346 get_property(git_submodules_recurse_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES_RECURSE SET)
2347 if(NOT git_submodules_recurse_set)
2348 set(recurseFlag "--recursive")
2350 get_property(git_submodules_recurse_value TARGET ${name} PROPERTY _EP_GIT_SUBMODULES_RECURSE)
2351 if(git_submodules_recurse_value)
2352 set(recurseFlag "--recursive")
2357 set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE)
2359 # The git submodule update '--recursive' flag requires git >= v1.6.5
2360 if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5)
2361 message(FATAL_ERROR "error: git version 1.6.5 or later required for --recursive flag with 'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'")
2366 function(_ep_add_download_command name)
2367 ExternalProject_Get_Property(${name} source_dir stamp_dir download_dir tmp_dir)
2369 get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
2370 get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
2371 get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
2372 get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
2373 get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
2374 get_property(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
2375 get_property(url TARGET ${name} PROPERTY _EP_URL)
2376 get_property(fname TARGET ${name} PROPERTY _EP_DOWNLOAD_NAME)
2378 # TODO: Perhaps file:// should be copied to download dir before extraction.
2379 string(REGEX REPLACE "file://" "" url "${url}")
2386 set(work_dir ${download_dir})
2387 elseif(cvs_repository)
2388 find_package(CVS QUIET)
2389 if(NOT CVS_EXECUTABLE)
2390 message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
2393 get_target_property(cvs_module ${name} _EP_CVS_MODULE)
2395 message(FATAL_ERROR "error: no CVS_MODULE")
2398 get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
2400 set(repository ${cvs_repository})
2401 set(module ${cvs_module})
2404 "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
2405 "${stamp_dir}/${name}-cvsinfo.txt"
2409 get_filename_component(src_name "${source_dir}" NAME)
2410 get_filename_component(work_dir "${source_dir}" PATH)
2411 set(comment "Performing download step (CVS checkout) for '${name}'")
2412 set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q co ${cvs_tag} -d ${src_name} ${cvs_module})
2413 list(APPEND depends ${stamp_dir}/${name}-cvsinfo.txt)
2414 elseif(svn_repository)
2415 find_package(Subversion QUIET)
2416 if(NOT Subversion_SVN_EXECUTABLE)
2417 message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
2420 get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
2421 get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
2422 get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
2423 get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
2425 set(repository "${svn_repository} user=${svn_username} password=${svn_password}")
2427 set(tag ${svn_revision})
2429 "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
2430 "${stamp_dir}/${name}-svninfo.txt"
2434 get_filename_component(src_name "${source_dir}" NAME)
2435 get_filename_component(work_dir "${source_dir}" PATH)
2436 set(comment "Performing download step (SVN checkout) for '${name}'")
2437 set(svn_user_pw_args "")
2438 if(DEFINED svn_username)
2439 set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
2441 if(DEFINED svn_password)
2442 set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
2445 set(svn_trust_cert_args --trust-server-cert)
2447 set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_revision}
2448 --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args} ${src_name})
2449 list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
2450 elseif(git_repository)
2451 unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
2452 find_package(Git QUIET)
2453 if(NOT GIT_EXECUTABLE)
2454 message(FATAL_ERROR "error: could not find git for clone of ${name}")
2457 _ep_get_git_submodules_recurse(git_submodules_recurse)
2459 get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
2461 set(git_tag "master")
2464 set(git_init_submodules TRUE)
2465 get_property(git_submodules_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES SET)
2466 if(git_submodules_set)
2467 get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
2468 if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
2469 set(git_init_submodules FALSE)
2473 get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
2474 if(NOT git_remote_name)
2475 set(git_remote_name "origin")
2478 get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
2479 if("x${tls_verify}" STREQUAL "x" AND DEFINED CMAKE_TLS_VERIFY)
2480 set(tls_verify "${CMAKE_TLS_VERIFY}")
2482 get_property(git_shallow TARGET ${name} PROPERTY _EP_GIT_SHALLOW)
2483 get_property(git_progress TARGET ${name} PROPERTY _EP_GIT_PROGRESS)
2484 get_property(git_config TARGET ${name} PROPERTY _EP_GIT_CONFIG)
2486 # For the download step, and the git clone operation, only the repository
2487 # should be recorded in a configured RepositoryInfo file. If the repo
2488 # changes, the clone script should be run again. But if only the tag
2489 # changes, avoid running the clone script again. Let the 'always' running
2490 # update step checkout the new tag.
2492 set(repository ${git_repository})
2494 set(tag ${git_remote_name})
2496 "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
2497 "${stamp_dir}/${name}-gitinfo.txt"
2501 get_filename_component(src_name "${source_dir}" NAME)
2502 get_filename_component(work_dir "${source_dir}" PATH)
2504 # Since git clone doesn't succeed if the non-empty source_dir exists,
2505 # create a cmake script to invoke as download command.
2506 # The script will delete the source directory and then call git clone.
2508 _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
2509 ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules_recurse}" "${git_submodules}" "${git_shallow}" "${git_progress}" "${git_config}" ${src_name} ${work_dir}
2510 ${stamp_dir}/${name}-gitinfo.txt ${stamp_dir}/${name}-gitclone-lastrun.txt "${tls_verify}"
2512 set(comment "Performing download step (git clone) for '${name}'")
2513 set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake)
2514 list(APPEND depends ${stamp_dir}/${name}-gitinfo.txt)
2515 elseif(hg_repository)
2516 find_package(Hg QUIET)
2517 if(NOT HG_EXECUTABLE)
2518 message(FATAL_ERROR "error: could not find hg for clone of ${name}")
2521 get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
2526 # For the download step, and the hg clone operation, only the repository
2527 # should be recorded in a configured RepositoryInfo file. If the repo
2528 # changes, the clone script should be run again. But if only the tag
2529 # changes, avoid running the clone script again. Let the 'always' running
2530 # update step checkout the new tag.
2532 set(repository ${hg_repository})
2536 "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
2537 "${stamp_dir}/${name}-hginfo.txt"
2541 get_filename_component(src_name "${source_dir}" NAME)
2542 get_filename_component(work_dir "${source_dir}" PATH)
2544 # Since hg clone doesn't succeed if the non-empty source_dir exists,
2545 # create a cmake script to invoke as download command.
2546 # The script will delete the source directory and then call hg clone.
2548 _ep_write_hgclone_script(${tmp_dir}/${name}-hgclone.cmake ${source_dir}
2549 ${HG_EXECUTABLE} ${hg_repository} ${hg_tag} ${src_name} ${work_dir}
2550 ${stamp_dir}/${name}-hginfo.txt ${stamp_dir}/${name}-hgclone-lastrun.txt
2552 set(comment "Performing download step (hg clone) for '${name}'")
2553 set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake)
2554 list(APPEND depends ${stamp_dir}/${name}-hginfo.txt)
2556 get_filename_component(work_dir "${source_dir}" PATH)
2557 get_property(hash TARGET ${name} PROPERTY _EP_URL_HASH)
2558 if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}")
2559 message(FATAL_ERROR "URL_HASH is set to\n ${hash}\n"
2560 "but must be ALGO=value where ALGO is\n ${_ep_hash_algos}\n"
2561 "and value is a hex string.")
2563 get_property(md5 TARGET ${name} PROPERTY _EP_URL_MD5)
2564 if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}")
2565 message(FATAL_ERROR "URL_MD5 is set to\n ${md5}\nbut must be a hex string.")
2567 if(md5 AND NOT hash)
2568 set(hash "MD5=${md5}")
2570 set(repository "external project URL")
2571 set(module "${url}")
2574 "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
2575 "${stamp_dir}/${name}-urlinfo.txt"
2578 list(APPEND depends ${stamp_dir}/${name}-urlinfo.txt)
2580 list(LENGTH url url_list_length)
2581 if(NOT "${url_list_length}" STREQUAL "1")
2582 foreach(entry ${url})
2583 if(NOT "${entry}" MATCHES "^[a-z]+://")
2584 message(FATAL_ERROR "At least one entry of URL is a path (invalid in a list)")
2587 if("x${fname}" STREQUAL "x")
2588 list(GET url 0 fname)
2592 if(IS_DIRECTORY "${url}")
2593 get_filename_component(abs_dir "${url}" ABSOLUTE)
2594 set(comment "Performing download step (DIR copy) for '${name}'")
2595 set(cmd ${CMAKE_COMMAND} -E rm -rf ${source_dir}
2596 COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir})
2598 get_property(no_extract TARGET "${name}" PROPERTY _EP_DOWNLOAD_NO_EXTRACT)
2599 if("${url}" MATCHES "^[a-z]+://")
2600 # TODO: Should download and extraction be different steps?
2601 if("x${fname}" STREQUAL "x")
2604 if("${fname}" MATCHES [[([^/\?#]+(\.|=)(7z|tar|tar\.bz2|tar\.gz|tar\.xz|tbz2|tgz|txz|zip))([/?#].*)?$]])
2605 set(fname "${CMAKE_MATCH_1}")
2607 get_filename_component(fname "${fname}" NAME)
2609 # Fall back to a default file name. The actual file name does not
2610 # matter because it is used only internally and our extraction tool
2611 # inspects the file content directly. If it turns out the wrong URL
2612 # was given that will be revealed during the build which is an easier
2613 # place for users to diagnose than an error here anyway.
2614 set(fname "archive.tar")
2616 string(REPLACE ";" "-" fname "${fname}")
2617 set(file ${download_dir}/${fname})
2618 get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
2619 get_property(no_progress TARGET ${name} PROPERTY _EP_DOWNLOAD_NO_PROGRESS)
2620 get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY)
2621 get_property(tls_cainfo TARGET ${name} PROPERTY _EP_TLS_CAINFO)
2622 get_property(netrc TARGET ${name} PROPERTY _EP_NETRC)
2623 get_property(netrc_file TARGET ${name} PROPERTY _EP_NETRC_FILE)
2624 get_property(http_username TARGET ${name} PROPERTY _EP_HTTP_USERNAME)
2625 get_property(http_password TARGET ${name} PROPERTY _EP_HTTP_PASSWORD)
2626 get_property(http_headers TARGET ${name} PROPERTY _EP_HTTP_HEADER)
2627 set(download_script "${stamp_dir}/download-${name}.cmake")
2628 _ep_write_downloadfile_script("${download_script}" "${url}" "${file}" "${timeout}" "${no_progress}" "${hash}" "${tls_verify}" "${tls_cainfo}" "${http_username}:${http_password}" "${http_headers}" "${netrc}" "${netrc_file}")
2629 set(cmd ${CMAKE_COMMAND} -P "${download_script}"
2632 set(steps "download and verify")
2634 set(steps "download, verify and extract")
2636 set(comment "Performing download step (${steps}) for '${name}'")
2637 file(WRITE "${stamp_dir}/verify-${name}.cmake" "") # already verified by 'download_script'
2643 set(steps "verify and extract")
2645 set(comment "Performing download step (${steps}) for '${name}'")
2646 _ep_write_verifyfile_script("${stamp_dir}/verify-${name}.cmake" "${file}" "${hash}")
2648 list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake)
2650 _ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${name}" "${file}" "${source_dir}")
2651 list(APPEND cmd COMMAND ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
2653 set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file})
2657 _ep_is_dir_empty("${source_dir}" empty)
2660 "No download info given for '${name}' and its source directory:\n"
2662 "is not an existing non-empty directory. Please specify one of:\n"
2663 " * SOURCE_DIR with an existing non-empty directory\n"
2664 " * DOWNLOAD_COMMAND\n"
2666 " * GIT_REPOSITORY\n"
2667 " * SVN_REPOSITORY\n"
2668 " * HG_REPOSITORY\n"
2669 " * CVS_REPOSITORY and CVS_MODULE"
2674 get_property(log TARGET ${name} PROPERTY _EP_LOG_DOWNLOAD)
2681 get_property(uses_terminal TARGET ${name} PROPERTY
2682 _EP_USES_TERMINAL_DOWNLOAD)
2684 set(uses_terminal USES_TERMINAL 1)
2686 set(uses_terminal "")
2689 ExternalProject_Add_Step(${name} download
2692 WORKING_DIRECTORY ${work_dir}
2701 function(_ep_add_update_command name)
2702 ExternalProject_Get_Property(${name} source_dir tmp_dir)
2704 get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
2705 get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
2706 get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
2707 get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
2708 get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
2709 get_property(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
2710 get_property(update_disconnected_set TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED SET)
2711 if(update_disconnected_set)
2712 get_property(update_disconnected TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED)
2714 get_property(update_disconnected DIRECTORY PROPERTY EP_UPDATE_DISCONNECTED)
2722 set(work_dir ${source_dir})
2723 if(NOT "x${cmd}" STREQUAL "x")
2726 elseif(cvs_repository)
2727 if(NOT CVS_EXECUTABLE)
2728 message(FATAL_ERROR "error: could not find cvs for update of ${name}")
2730 set(work_dir ${source_dir})
2731 set(comment "Performing update step (CVS update) for '${name}'")
2732 get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
2733 set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
2735 elseif(svn_repository)
2736 if(NOT Subversion_SVN_EXECUTABLE)
2737 message(FATAL_ERROR "error: could not find svn for update of ${name}")
2739 set(work_dir ${source_dir})
2740 set(comment "Performing update step (SVN update) for '${name}'")
2741 get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
2742 get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
2743 get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
2744 get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
2745 set(svn_user_pw_args "")
2746 if(DEFINED svn_username)
2747 set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}")
2749 if(DEFINED svn_password)
2750 set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}")
2753 set(svn_trust_cert_args --trust-server-cert)
2755 set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_revision}
2756 --non-interactive ${svn_trust_cert_args} ${svn_user_pw_args})
2758 elseif(git_repository)
2759 unset(CMAKE_MODULE_PATH) # Use CMake builtin find module
2760 find_package(Git QUIET)
2761 if(NOT GIT_EXECUTABLE)
2762 message(FATAL_ERROR "error: could not find git for fetch of ${name}")
2764 set(work_dir ${source_dir})
2765 set(comment "Performing update step for '${name}'")
2766 get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
2768 set(git_tag "master")
2770 get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
2771 if(NOT git_remote_name)
2772 set(git_remote_name "origin")
2775 set(git_init_submodules TRUE)
2776 get_property(git_submodules_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES SET)
2777 if(git_submodules_set)
2778 get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
2779 if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
2780 set(git_init_submodules FALSE)
2784 _ep_get_git_submodules_recurse(git_submodules_recurse)
2786 _ep_write_gitupdate_script(${tmp_dir}/${name}-gitupdate.cmake
2787 ${GIT_EXECUTABLE} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules_recurse}" "${git_submodules}" ${git_repository} ${work_dir}
2789 set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake)
2791 elseif(hg_repository)
2792 if(NOT HG_EXECUTABLE)
2793 message(FATAL_ERROR "error: could not find hg for pull of ${name}")
2795 set(work_dir ${source_dir})
2796 set(comment "Performing update step (hg pull) for '${name}'")
2797 get_property(hg_tag TARGET ${name} PROPERTY _EP_HG_TAG)
2801 if("${HG_VERSION_STRING}" STREQUAL "2.1")
2802 message(WARNING "Mercurial 2.1 does not distinguish an empty pull from a failed pull:
2803 http://mercurial.selenic.com/wiki/UpgradeNotes#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X
2804 http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656
2805 Update to Mercurial >= 2.1.1.
2808 set(cmd ${HG_EXECUTABLE} pull
2809 COMMAND ${HG_EXECUTABLE} update ${hg_tag}
2814 get_property(log TARGET ${name} PROPERTY _EP_LOG_UPDATE)
2821 get_property(uses_terminal TARGET ${name} PROPERTY
2822 _EP_USES_TERMINAL_UPDATE)
2824 set(uses_terminal USES_TERMINAL 1)
2826 set(uses_terminal "")
2829 ExternalProject_Add_Step(${name} update
2833 EXCLUDE_FROM_MAIN ${update_disconnected}
2834 WORKING_DIRECTORY ${work_dir}
2840 if(update_disconnected)
2841 _ep_get_step_stampfile(${name} skip-update skip-update_stamp_file)
2842 string(REPLACE "Performing" "Skipping" comment "${comment}")
2843 ExternalProject_Add_Step(${name} skip-update
2847 WORKING_DIRECTORY ${work_dir}
2852 set_property(SOURCE ${skip-update_stamp_file} PROPERTY SYMBOLIC 1)
2858 function(_ep_add_patch_command name)
2859 ExternalProject_Get_Property(${name} source_dir)
2861 get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
2862 get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
2867 set(work_dir ${source_dir})
2870 get_property(log TARGET ${name} PROPERTY _EP_LOG_PATCH)
2877 ExternalProject_Add_Step(${name} patch
2879 WORKING_DIRECTORY ${work_dir}
2886 function(_ep_extract_configure_command var name)
2887 get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
2889 get_property(cmd TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND)
2891 get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
2893 set(cmd "${cmake_command}")
2895 set(cmd "${CMAKE_COMMAND}")
2898 get_property(cmake_args TARGET ${name} PROPERTY _EP_CMAKE_ARGS)
2899 list(APPEND cmd ${cmake_args})
2901 # If there are any CMAKE_CACHE_ARGS or CMAKE_CACHE_DEFAULT_ARGS,
2902 # write an initial cache and use it
2903 get_property(cmake_cache_args TARGET ${name} PROPERTY _EP_CMAKE_CACHE_ARGS)
2904 get_property(cmake_cache_default_args TARGET ${name} PROPERTY _EP_CMAKE_CACHE_DEFAULT_ARGS)
2906 set(has_cmake_cache_args 0)
2907 if(NOT "${cmake_cache_args}" STREQUAL "")
2908 set(has_cmake_cache_args 1)
2911 set(has_cmake_cache_default_args 0)
2912 if(NOT "${cmake_cache_default_args}" STREQUAL "")
2913 set(has_cmake_cache_default_args 1)
2916 get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
2917 get_target_property(cmake_generator_instance ${name} _EP_CMAKE_GENERATOR_INSTANCE)
2918 get_target_property(cmake_generator_platform ${name} _EP_CMAKE_GENERATOR_PLATFORM)
2919 get_target_property(cmake_generator_toolset ${name} _EP_CMAKE_GENERATOR_TOOLSET)
2921 list(APPEND cmd "-G${cmake_generator}")
2922 if(cmake_generator_platform)
2923 list(APPEND cmd "-A${cmake_generator_platform}")
2925 if(cmake_generator_toolset)
2926 list(APPEND cmd "-T${cmake_generator_toolset}")
2928 if(cmake_generator_instance)
2929 list(APPEND cmd "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${cmake_generator_instance}")
2932 if(CMAKE_EXTRA_GENERATOR)
2933 list(APPEND cmd "-G${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}")
2935 list(APPEND cmd "-G${CMAKE_GENERATOR}")
2936 if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
2937 set(has_cmake_cache_default_args 1)
2938 set(cmake_cache_default_args ${cmake_cache_default_args}
2939 "-DGHS_TARGET_PLATFORM:STRING=${GHS_TARGET_PLATFORM}"
2940 "-DGHS_PRIMARY_TARGET:STRING=${GHS_PRIMARY_TARGET}"
2941 "-DGHS_TOOLSET_ROOT:STRING=${GHS_TOOLSET_ROOT}"
2942 "-DGHS_OS_ROOT:STRING=${GHS_OS_ROOT}"
2943 "-DGHS_OS_DIR:STRING=${GHS_OS_DIR}"
2944 "-DGHS_BSP_NAME:STRING=${GHS_BSP_NAME}")
2947 if(cmake_generator_platform)
2948 message(FATAL_ERROR "Option CMAKE_GENERATOR_PLATFORM not allowed without CMAKE_GENERATOR.")
2950 if(CMAKE_GENERATOR_PLATFORM)
2951 list(APPEND cmd "-A${CMAKE_GENERATOR_PLATFORM}")
2953 if(cmake_generator_toolset)
2954 message(FATAL_ERROR "Option CMAKE_GENERATOR_TOOLSET not allowed without CMAKE_GENERATOR.")
2956 if(CMAKE_GENERATOR_TOOLSET)
2957 list(APPEND cmd "-T${CMAKE_GENERATOR_TOOLSET}")
2959 if(cmake_generator_instance)
2960 message(FATAL_ERROR "Option CMAKE_GENERATOR_INSTANCE not allowed without CMAKE_GENERATOR.")
2962 if(CMAKE_GENERATOR_INSTANCE)
2963 list(APPEND cmd "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}")
2967 if(has_cmake_cache_args OR has_cmake_cache_default_args)
2968 set(_ep_cache_args_script "<TMP_DIR>/${name}-cache-$<CONFIG>.cmake")
2969 if(has_cmake_cache_args)
2970 _ep_command_line_to_initial_cache(script_initial_cache_force "${cmake_cache_args}" 1)
2972 if(has_cmake_cache_default_args)
2973 _ep_command_line_to_initial_cache(script_initial_cache_default "${cmake_cache_default_args}" 0)
2975 _ep_write_initial_cache(${name} "${_ep_cache_args_script}" "${script_initial_cache_force}${script_initial_cache_default}")
2976 list(APPEND cmd "-C${_ep_cache_args_script}")
2979 list(APPEND cmd "<SOURCE_DIR><SOURCE_SUBDIR>")
2982 set("${var}" "${cmd}" PARENT_SCOPE)
2985 # TODO: Make sure external projects use the proper compiler
2986 function(_ep_add_configure_command name)
2987 ExternalProject_Get_Property(${name} binary_dir tmp_dir)
2989 # Depend on other external projects (file-level).
2991 get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
2992 foreach(dep IN LISTS deps)
2993 get_property(dep_type TARGET ${dep} PROPERTY TYPE)
2994 if(dep_type STREQUAL "UTILITY")
2995 get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
2997 _ep_get_step_stampfile(${dep} "done" done_stamp_file)
2998 list(APPEND file_deps ${done_stamp_file})
3003 _ep_extract_configure_command(cmd ${name})
3005 # If anything about the configure command changes, (command itself, cmake
3006 # used, cmake args or cmake generator) then re-run the configure step.
3007 # Fixes issue https://gitlab.kitware.com/cmake/cmake/issues/10258
3009 if(NOT EXISTS ${tmp_dir}/${name}-cfgcmd.txt.in)
3010 file(WRITE ${tmp_dir}/${name}-cfgcmd.txt.in "cmd='\@cmd\@'\n")
3012 configure_file(${tmp_dir}/${name}-cfgcmd.txt.in ${tmp_dir}/${name}-cfgcmd.txt)
3013 list(APPEND file_deps ${tmp_dir}/${name}-cfgcmd.txt)
3014 list(APPEND file_deps ${_ep_cache_args_script})
3016 get_property(log TARGET ${name} PROPERTY _EP_LOG_CONFIGURE)
3023 get_property(uses_terminal TARGET ${name} PROPERTY
3024 _EP_USES_TERMINAL_CONFIGURE)
3026 set(uses_terminal USES_TERMINAL 1)
3028 set(uses_terminal "")
3031 get_property(update_disconnected_set TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED SET)
3032 if(update_disconnected_set)
3033 get_property(update_disconnected TARGET ${name} PROPERTY _EP_UPDATE_DISCONNECTED)
3035 get_property(update_disconnected DIRECTORY PROPERTY EP_UPDATE_DISCONNECTED)
3037 if(update_disconnected)
3038 set(update_dep skip-update)
3040 set(update_dep update)
3043 ExternalProject_Add_Step(${name} configure
3045 WORKING_DIRECTORY ${binary_dir}
3046 DEPENDEES ${update_dep} patch
3047 DEPENDS ${file_deps}
3054 function(_ep_add_build_command name)
3055 ExternalProject_Get_Property(${name} binary_dir)
3057 get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
3059 get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
3061 _ep_get_build_command(${name} BUILD cmd)
3064 get_property(log TARGET ${name} PROPERTY _EP_LOG_BUILD)
3071 get_property(uses_terminal TARGET ${name} PROPERTY
3072 _EP_USES_TERMINAL_BUILD)
3074 set(uses_terminal USES_TERMINAL 1)
3076 set(uses_terminal "")
3079 get_property(build_always TARGET ${name} PROPERTY _EP_BUILD_ALWAYS)
3086 get_property(build_byproducts TARGET ${name} PROPERTY _EP_BUILD_BYPRODUCTS)
3088 ExternalProject_Add_Step(${name} build
3090 BYPRODUCTS ${build_byproducts}
3091 WORKING_DIRECTORY ${binary_dir}
3100 function(_ep_add_install_command name)
3101 ExternalProject_Get_Property(${name} binary_dir)
3103 get_property(cmd_set TARGET ${name} PROPERTY _EP_INSTALL_COMMAND SET)
3105 get_property(cmd TARGET ${name} PROPERTY _EP_INSTALL_COMMAND)
3107 _ep_get_build_command(${name} INSTALL cmd)
3110 get_property(log TARGET ${name} PROPERTY _EP_LOG_INSTALL)
3117 get_property(uses_terminal TARGET ${name} PROPERTY
3118 _EP_USES_TERMINAL_INSTALL)
3120 set(uses_terminal USES_TERMINAL 1)
3122 set(uses_terminal "")
3125 ExternalProject_Add_Step(${name} install
3127 WORKING_DIRECTORY ${binary_dir}
3135 function(_ep_add_test_command name)
3136 ExternalProject_Get_Property(${name} binary_dir)
3138 get_property(before TARGET ${name} PROPERTY _EP_TEST_BEFORE_INSTALL)
3139 get_property(after TARGET ${name} PROPERTY _EP_TEST_AFTER_INSTALL)
3140 get_property(exclude TARGET ${name} PROPERTY _EP_TEST_EXCLUDE_FROM_MAIN)
3141 get_property(cmd_set TARGET ${name} PROPERTY _EP_TEST_COMMAND SET)
3143 # Only actually add the test step if one of the test related properties is
3144 # explicitly set. (i.e. the test step is omitted unless requested...)
3146 if(cmd_set OR before OR after OR exclude)
3148 get_property(cmd TARGET ${name} PROPERTY _EP_TEST_COMMAND)
3150 _ep_get_build_command(${name} TEST cmd)
3154 set(dependees_args DEPENDEES build)
3156 set(dependees_args DEPENDEES install)
3160 set(dependers_args "")
3161 set(exclude_args EXCLUDE_FROM_MAIN 1)
3164 set(dependers_args DEPENDERS install)
3166 set(dependers_args "")
3168 set(exclude_args "")
3171 get_property(log TARGET ${name} PROPERTY _EP_LOG_TEST)
3178 get_property(uses_terminal TARGET ${name} PROPERTY
3179 _EP_USES_TERMINAL_TEST)
3181 set(uses_terminal USES_TERMINAL 1)
3183 set(uses_terminal "")
3186 ExternalProject_Add_Step(${name} test
3188 WORKING_DIRECTORY ${binary_dir}
3199 function(ExternalProject_Add name)
3200 cmake_policy(GET CMP0097 _EP_CMP0097
3201 PARENT_SCOPE # undocumented, do not use outside of CMake
3204 _ep_get_configuration_subdir_suffix(cfgdir)
3206 # Add a custom target for the external project.
3207 set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
3208 _ep_get_complete_stampfile(${name} complete_stamp_file)
3210 # The "ALL" option to add_custom_target just tells it to not set the
3211 # EXCLUDE_FROM_ALL target property. Later, if the EXCLUDE_FROM_ALL
3212 # argument was passed, we explicitly set it for the target.
3213 add_custom_target(${name} ALL DEPENDS ${complete_stamp_file})
3214 set_property(TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT 1)
3215 set_property(TARGET ${name} PROPERTY LABELS ${name})
3216 set_property(TARGET ${name} PROPERTY FOLDER "ExternalProjectTargets/${name}")
3218 _ep_parse_arguments(ExternalProject_Add ${name} _EP_ "${ARGN}")
3219 _ep_set_directories(${name})
3220 _ep_get_step_stampfile(${name} "done" done_stamp_file)
3221 _ep_get_step_stampfile(${name} "install" install_stamp_file)
3223 # Set the EXCLUDE_FROM_ALL target property if required.
3224 get_property(exclude_from_all TARGET ${name} PROPERTY _EP_EXCLUDE_FROM_ALL)
3225 if(exclude_from_all)
3226 set_property(TARGET ${name} PROPERTY EXCLUDE_FROM_ALL TRUE)
3229 # The 'complete' step depends on all other steps and creates a
3230 # 'done' mark. A dependent external project's 'configure' step
3231 # depends on the 'done' mark so that it rebuilds when this project
3232 # rebuilds. It is important that 'done' is not the output of any
3233 # custom command so that CMake does not propagate build rules to
3234 # other external project targets, which may cause problems during
3235 # parallel builds. However, the Ninja generator needs to see the entire
3236 # dependency graph, and can cope with custom commands belonging to
3237 # multiple targets, so we add the 'done' mark as an output for Ninja only.
3238 set(complete_outputs ${complete_stamp_file})
3239 if(${CMAKE_GENERATOR} MATCHES "Ninja")
3240 set(complete_outputs ${complete_outputs} ${done_stamp_file})
3244 OUTPUT ${complete_outputs}
3245 COMMENT "Completed '${name}'"
3246 COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
3247 COMMAND ${CMAKE_COMMAND} -E touch ${complete_stamp_file}
3248 COMMAND ${CMAKE_COMMAND} -E touch ${done_stamp_file}
3249 DEPENDS ${install_stamp_file}
3254 # Depend on other external projects (target-level).
3255 get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
3256 foreach(arg IN LISTS deps)
3257 add_dependencies(${name} ${arg})
3260 # Set up custom build steps based on the target properties.
3261 # Each step depends on the previous one.
3263 # The target depends on the output of the final step.
3264 # (Already set up above in the DEPENDS of the add_custom_target command.)
3266 _ep_add_mkdir_command(${name})
3267 _ep_add_download_command(${name})
3268 _ep_add_update_command(${name})
3269 _ep_add_patch_command(${name})
3270 _ep_add_configure_command(${name})
3271 _ep_add_build_command(${name})
3272 _ep_add_install_command(${name})
3274 # Test is special in that it might depend on build, or it might depend
3277 _ep_add_test_command(${name})