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