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