diff options
author | Craig Scott <craig.scott@crascit.com> | 2024-05-13 10:24:03 (GMT) |
---|---|---|
committer | Craig Scott <craig.scott@crascit.com> | 2024-05-13 10:24:47 (GMT) |
commit | 173daad58de172ad5edbbf72117b5597c7339007 (patch) | |
tree | 55af3f1352d1eef00574cf2552bb2caf1037800a | |
parent | 462e58326730d1ee06bb19006e1887e104d8f5e9 (diff) | |
download | CMake-173daad58de172ad5edbbf72117b5597c7339007.zip CMake-173daad58de172ad5edbbf72117b5597c7339007.tar.gz CMake-173daad58de172ad5edbbf72117b5597c7339007.tar.bz2 |
ExternalProject: Move more internal commands out of main file
The commands moved to shared_internal_commands.cmake
will soon be used directly by FetchContent, which cannot
always include the full ExternalProject.cmake file (e.g. it may
be used in CMake script mode).
Issue: #21703
9 files changed, 1551 insertions, 1528 deletions
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 9b5d59a..423de3b 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -1296,543 +1296,12 @@ cmake_policy(PUSH) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST -macro(_ep_get_hash_algos out_var) - set(${out_var} - MD5 - SHA1 - SHA224 - SHA256 - SHA384 - SHA512 - SHA3_224 - SHA3_256 - SHA3_384 - SHA3_512 - ) -endmacro() - -macro(_ep_get_hash_regex out_var) - _ep_get_hash_algos(${out_var}) - list(JOIN ${out_var} "|" ${out_var}) - set(${out_var} "^(${${out_var}})=([0-9A-Fa-f]+)$") -endmacro() - -function(_ep_parse_arguments_to_vars - f - keywords - name - ns - args -) - # Transfer the arguments into variables in the calling scope. - # Because some keywords can be repeated, we can't use cmake_parse_arguments(). - # Instead, we loop through the args and consider the namespace starting with - # an upper-case letter followed by at least two more upper-case letters, - # numbers or underscores to be keywords. - - foreach(key IN LISTS keywords) - unset(${ns}${key}) - endforeach() - - set(key) - - foreach(arg IN LISTS args) - set(is_value 1) - - if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND - NOT (("x${arg}x" STREQUAL "x${key}x") AND - ("x${key}x" STREQUAL "xCOMMANDx")) AND - NOT arg MATCHES "^(TRUE|FALSE|YES)$") - if(arg IN_LIST keywords) - set(is_value 0) - endif() - endif() - - if(is_value) - if(key) - # Value - list(APPEND ${ns}${key} "${arg}") - else() - # Missing Keyword - message(AUTHOR_WARNING - "value '${arg}' with no previous keyword in ${f}" - ) - endif() - else() - set(key "${arg}") - endif() - endforeach() - - foreach(key IN LISTS keywords) - if(DEFINED ${ns}${key}) - set(${ns}${key} "${${ns}${key}}" PARENT_SCOPE) - else() - unset(${ns}${key} PARENT_SCOPE) - endif() - endforeach() - -endfunction() - -# NOTE: This cannot be a macro because that will evaluate anything that looks -# like a CMake variable in any of the args. -function(_ep_parse_arguments - f - keywords - name - ns - args -) - _ep_parse_arguments_to_vars( - "${f}" - "${keywords}" - ${name} - ${ns} - "${args}" - ) - - foreach(key IN LISTS keywords) - if(DEFINED ${ns}${key}) - set(${ns}${key} "${${ns}${key}}" PARENT_SCOPE) - else() - unset(${ns}${key} PARENT_SCOPE) - endif() - endforeach() - - # Transfer the arguments to the target as target properties. These are - # read by the various steps, potentially from different scopes. - foreach(key IN LISTS keywords) - if(DEFINED ${ns}${key}) - set_property(TARGET ${name} PROPERTY ${ns}${key} "${${ns}${key}}") - endif() - endforeach() - -endfunction() - - define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED) define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED) define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED) define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED) define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED) -function(_ep_get_tls_version name tls_version_var) - # Note that the arguments are assumed to have already been parsed and have - # been translated into variables with the prefix _EP_... by a call to - # ep_parse_arguments() or ep_parse_arguments_to_vars(). - set(tls_version_regex "^1\\.[0-3]$") - set(tls_version "${_EP_TLS_VERSION}") - if(NOT "x${tls_version}" STREQUAL "x") - if(NOT tls_version MATCHES "${tls_version_regex}") - message(FATAL_ERROR "TLS_VERSION '${tls_version}' not known") - endif() - elseif(NOT "x${CMAKE_TLS_VERSION}" STREQUAL "x") - set(tls_version "${CMAKE_TLS_VERSION}") - if(NOT tls_version MATCHES "${tls_version_regex}") - message(FATAL_ERROR "CMAKE_TLS_VERSION '${tls_version}' not known") - endif() - elseif(NOT "x$ENV{CMAKE_TLS_VERSION}" STREQUAL "x") - set(tls_version "$ENV{CMAKE_TLS_VERSION}") - if(NOT tls_version MATCHES "${tls_version_regex}") - message(FATAL_ERROR "ENV{CMAKE_TLS_VERSION} '${tls_version}' not known") - endif() - endif() - set("${tls_version_var}" "${tls_version}" PARENT_SCOPE) -endfunction() - -function(_ep_get_tls_verify name tls_verify_var) - # Note that the arguments are assumed to have already been parsed and have - # been translated into variables with the prefix _EP_... by a call to - # ep_parse_arguments() or ep_parse_arguments_to_vars(). - set(tls_verify "${_EP_TLS_VERIFY}") - if("x${tls_verify}" STREQUAL "x") - if(NOT "x${CMAKE_TLS_VERIFY}" STREQUAL "x") - set(tls_verify "${CMAKE_TLS_VERIFY}") - elseif(NOT "x$ENV{CMAKE_TLS_VERIFY}" STREQUAL "x") - set(tls_verify "$ENV{CMAKE_TLS_VERIFY}") - endif() - endif() - set("${tls_verify_var}" "${tls_verify}" PARENT_SCOPE) -endfunction() - -function(_ep_get_tls_cainfo name tls_cainfo_var) - # Note that the arguments are assumed to have already been parsed and have - # been translated into variables with the prefix _EP_... by a call to - # ep_parse_arguments() or ep_parse_arguments_to_vars(). - set(tls_cainfo "${_EP_TLS_CAINFO}") - if("x${tls_cainfo}" STREQUAL "x" AND DEFINED CMAKE_TLS_CAINFO) - set(tls_cainfo "${CMAKE_TLS_CAINFO}") - endif() - set("${tls_cainfo_var}" "${tls_cainfo}" PARENT_SCOPE) -endfunction() - -function(_ep_get_netrc name netrc_var) - # Note that the arguments are assumed to have already been parsed and have - # been translated into variables with the prefix _EP_... by a call to - # ep_parse_arguments() or ep_parse_arguments_to_vars(). - set(netrc "${_EP_NETRC}") - if("x${netrc}" STREQUAL "x" AND DEFINED CMAKE_NETRC) - set(netrc "${CMAKE_NETRC}") - endif() - set("${netrc_var}" "${netrc}" PARENT_SCOPE) -endfunction() - -function(_ep_get_netrc_file name netrc_file_var) - # Note that the arguments are assumed to have already been parsed and have - # been translated into variables with the prefix _EP_... by a call to - # ep_parse_arguments() or ep_parse_arguments_to_vars(). - set(netrc_file "${_EP_NETRC_FILE}") - if("x${netrc_file}" STREQUAL "x" AND DEFINED CMAKE_NETRC_FILE) - set(netrc_file "${CMAKE_NETRC_FILE}") - endif() - set("${netrc_file_var}" "${netrc_file}" PARENT_SCOPE) -endfunction() - -function(_ep_write_gitclone_script - script_filename - source_dir - git_EXECUTABLE - git_repository - git_tag - git_remote_name - init_submodules - git_submodules_recurse - git_submodules - git_shallow - git_progress - git_config - src_name - work_dir - gitclone_infofile - gitclone_stampfile - tls_version - tls_verify -) - - if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5) - # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path. - set(git_checkout_explicit-- "--") - else() - # Use `git checkout <branch>` even though this risks ambiguity with a - # local path. Unfortunately we cannot use `git checkout <tree-ish> --` - # because that will not search for remote branch names, a common use case. - set(git_checkout_explicit-- "") - endif() - if("${git_tag}" STREQUAL "") - message(FATAL_ERROR "Tag for git checkout should not be empty.") - endif() - - if(GIT_VERSION_STRING VERSION_LESS 2.20 OR - 2.21 VERSION_LESS_EQUAL GIT_VERSION_STRING) - set(git_clone_options "--no-checkout") - else() - set(git_clone_options) - endif() - if(git_shallow) - if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10) - list(APPEND git_clone_options "--depth 1 --no-single-branch") - else() - list(APPEND git_clone_options "--depth 1") - endif() - endif() - if(git_progress) - list(APPEND git_clone_options --progress) - endif() - foreach(config IN LISTS git_config) - list(APPEND git_clone_options --config \"${config}\") - endforeach() - if(NOT ${git_remote_name} STREQUAL "origin") - list(APPEND git_clone_options --origin \"${git_remote_name}\") - endif() - - # The clone config option is sticky, it will apply to all subsequent git - # update operations. The submodules config option is not sticky, because - # git doesn't provide any way to do that. Thus, we will have to pass the - # same config option in the update step too for submodules, but not for - # the main git repo. - set(git_submodules_config_options "") - if(NOT "x${tls_version}" STREQUAL "x") - list(APPEND git_clone_options -c http.sslVersion=tlsv${tls_version}) - list(APPEND git_submodules_config_options -c http.sslVersion=tlsv${tls_version}) - endif() - if(NOT "x${tls_verify}" STREQUAL "x") - if(tls_verify) - # Default git behavior is "true", but the user might have changed the - # global default to "false". Since TLS_VERIFY was given, ensure we honor - # the specified setting regardless of what the global default might be. - list(APPEND git_clone_options -c http.sslVerify=true) - list(APPEND git_submodules_config_options -c http.sslVerify=true) - else() - list(APPEND git_clone_options -c http.sslVerify=false) - list(APPEND git_submodules_config_options -c http.sslVerify=false) - endif() - endif() - - string (REPLACE ";" " " git_clone_options "${git_clone_options}") - - configure_file( - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/gitclone.cmake.in - ${script_filename} - @ONLY - ) -endfunction() - -function(_ep_write_hgclone_script - script_filename - source_dir - hg_EXECUTABLE - hg_repository - hg_tag - src_name - work_dir - hgclone_infofile - hgclone_stampfile -) - - if("${hg_tag}" STREQUAL "") - message(FATAL_ERROR "Tag for hg checkout should not be empty.") - endif() - - configure_file( - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/hgclone.cmake.in - ${script_filename} - @ONLY - ) -endfunction() - - -function(_ep_write_gitupdate_script - script_filename - git_EXECUTABLE - git_tag - git_remote_name - init_submodules - git_submodules_recurse - git_submodules - git_repository - work_dir - git_update_strategy - tls_version - tls_verify -) - - if("${git_tag}" STREQUAL "") - message(FATAL_ERROR "Tag for git checkout should not be empty.") - endif() - set(git_stash_save_options --quiet) - if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7) - # This avoids stashing files covered by .gitignore - list(APPEND git_stash_save_options --include-untracked) - elseif(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.6) - # Untracked files, but also ignored files, so potentially slower - list(APPEND git_stash_save_options --all) - endif() - - # The submodules config option is not sticky, git doesn't provide any way - # to do that. We have to pass this config option for the update step too. - # We don't need to set it for the non-submodule update because it gets - # recorded as part of the clone operation in a sticky manner. - set(git_submodules_config_options "") - if(NOT "x${tls_version}" STREQUAL "x") - list(APPEND git_submodules_config_options -c http.sslVersion=tlsv${tls_version}) - endif() - if(NOT "x${tls_verify}" STREQUAL "x") - if(tls_verify) - # Default git behavior is "true", but the user might have changed the - # global default to "false". Since TLS_VERIFY was given, ensure we honor - # the specified setting regardless of what the global default might be. - list(APPEND git_submodules_config_options -c http.sslVerify=true) - else() - list(APPEND git_submodules_config_options -c http.sslVerify=false) - endif() - endif() - - configure_file( - "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/gitupdate.cmake.in" - "${script_filename}" - @ONLY - ) -endfunction() - -function(_ep_write_downloadfile_script - script_filename - REMOTE - LOCAL - timeout - inactivity_timeout - no_progress - hash - tls_version - tls_verify - tls_cainfo - userpwd - http_headers - netrc - netrc_file -) - if("x${REMOTE}" STREQUAL "x") - message(FATAL_ERROR "REMOTE can't be empty") - endif() - if("x${LOCAL}" STREQUAL "x") - message(FATAL_ERROR "LOCAL can't be empty") - endif() - - # REMOTE could contain special characters that parse as separate arguments. - # Things like parentheses are legitimate characters in a URL, but would be - # seen as the start of a new unquoted argument by the cmake language parser. - # Avoid those special cases by preparing quoted strings for direct inclusion - # in the foreach() call that iterates over the set of URLs in REMOTE. - set(REMOTE "[====[${REMOTE}]====]") - string(REPLACE ";" "]====] [====[" REMOTE "${REMOTE}") - - if(timeout) - set(TIMEOUT_ARGS TIMEOUT ${timeout}) - set(TIMEOUT_MSG "${timeout} seconds") - else() - set(TIMEOUT_ARGS "# no TIMEOUT") - set(TIMEOUT_MSG "none") - endif() - if(inactivity_timeout) - set(INACTIVITY_TIMEOUT_ARGS INACTIVITY_TIMEOUT ${inactivity_timeout}) - set(INACTIVITY_TIMEOUT_MSG "${inactivity_timeout} seconds") - else() - set(INACTIVITY_TIMEOUT_ARGS "# no INACTIVITY_TIMEOUT") - set(INACTIVITY_TIMEOUT_MSG "none") - endif() - - if(no_progress) - set(SHOW_PROGRESS "") - else() - set(SHOW_PROGRESS "SHOW_PROGRESS") - endif() - - _ep_get_hash_regex(_ep_hash_regex) - if("${hash}" MATCHES "${_ep_hash_regex}") - set(ALGO "${CMAKE_MATCH_1}") - string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE) - else() - set(ALGO "") - set(EXPECT_VALUE "") - endif() - - set(TLS_VERSION_CODE "") - if(NOT "x${tls_version}" STREQUAL "x") - set(TLS_VERSION_CODE "set(CMAKE_TLS_VERSION \"${tls_version}\")") - endif() - - set(TLS_VERIFY_CODE "") - if(NOT "x${tls_verify}" STREQUAL "x") - set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY \"${tls_verify}\")") - endif() - - set(TLS_CAINFO_CODE "") - if(NOT "x${tls_cainfo}" STREQUAL "x") - set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")") - endif() - - set(NETRC_CODE "") - if(NOT "x${netrc}" STREQUAL "x") - set(NETRC_CODE "set(CMAKE_NETRC \"${netrc}\")") - endif() - - set(NETRC_FILE_CODE "") - if(NOT "x${netrc_file}" STREQUAL "x") - set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${netrc_file}\")") - endif() - - if(userpwd STREQUAL ":") - set(USERPWD_ARGS) - else() - set(USERPWD_ARGS USERPWD "${userpwd}") - endif() - - set(HTTP_HEADERS_ARGS "") - if(NOT http_headers STREQUAL "") - foreach(header IN LISTS http_headers) - string(PREPEND HTTP_HEADERS_ARGS - "HTTPHEADER \"${header}\"\n " - ) - endforeach() - endif() - - # Used variables: - # * TLS_VERSION_CODE - # * TLS_VERIFY_CODE - # * TLS_CAINFO_CODE - # * ALGO - # * EXPECT_VALUE - # * REMOTE - # * LOCAL - # * SHOW_PROGRESS - # * TIMEOUT_ARGS - # * TIMEOUT_MSG - # * USERPWD_ARGS - # * HTTP_HEADERS_ARGS - configure_file( - "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/download.cmake.in" - "${script_filename}" - @ONLY - ) -endfunction() - -function(_ep_write_verifyfile_script - script_filename - LOCAL - hash -) - _ep_get_hash_regex(_ep_hash_regex) - if("${hash}" MATCHES "${_ep_hash_regex}") - set(ALGO "${CMAKE_MATCH_1}") - string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE) - else() - set(ALGO "") - set(EXPECT_VALUE "") - endif() - - # Used variables: - # * ALGO - # * EXPECT_VALUE - # * LOCAL - configure_file( - "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/verify.cmake.in" - "${script_filename}" - @ONLY - ) -endfunction() - - -function(_ep_write_extractfile_script - script_filename - name - filename - directory - options -) - set(args "") - - if(filename MATCHES - "(\\.|=)(7z|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$") - set(args xfz) - endif() - - if(filename MATCHES "(\\.|=)tar$") - set(args xf) - endif() - - if(args STREQUAL "") - message(FATAL_ERROR - "Do not know how to extract '${filename}' -- known types are: " - ".7z, .tar, .tar.bz2, .tar.gz, .tar.xz, .tbz2, .tgz, .txz and .zip" - ) - endif() - - configure_file( - "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/extractfile.cmake.in" - "${script_filename}" - @ONLY - ) -endfunction() - - function(_ep_set_directories name) get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX) if(NOT prefix) @@ -2185,6 +1654,7 @@ function(_ep_get_build_command set(${cmd_var} "${cmd}" PARENT_SCOPE) endfunction() + function(_ep_write_log_script name step @@ -2348,6 +1818,7 @@ endif() set(${cmd_var} "${command}" PARENT_SCOPE) endfunction() + # On multi-config generators, provide a placeholder for a per-config subdir. # On single-config generators, this is empty. function(_ep_get_configuration_subdir_genex suffix_var) @@ -2534,6 +2005,10 @@ function(ExternalProject_Add_StepTargets name) endfunction() +# While this function is referenced in shared_internal_commands.cmake in a few +# places, all of those code paths will only be reached by calling one of the +# functions defined in this file. Keep it here, since it is part of the public +# interface of ExternalProject. function(ExternalProject_Add_Step name step) get_property(cmp0114 TARGET ${name} PROPERTY _EP_CMP0114) _ep_get_complete_stampfile(${name} complete_stamp_file) @@ -2923,850 +2398,6 @@ function(_ep_add_mkdir_command name) endfunction() -function(_ep_is_dir_empty dir empty_var) - file(GLOB gr "${dir}/*") - if("${gr}" STREQUAL "") - set(${empty_var} 1 PARENT_SCOPE) - else() - set(${empty_var} 0 PARENT_SCOPE) - endif() -endfunction() - -function(_ep_get_git_submodules_recurse git_submodules_recurse) - # Checks for GIT_SUBMODULES_RECURSE argument. Default is ON, which sets - # git_submodules_recurse output variable to "--recursive". Otherwise, the - # output variable is set to an empty value "". - # Note that the arguments are assumed to have already been parsed and have - # been translated into variables with the prefix _EP_... by a call to - # ep_parse_arguments() or ep_parse_arguments_to_vars(). - if(NOT DEFINED _EP_GIT_SUBMODULES_RECURSE) - set(recurseFlag "--recursive") - else() - if(_EP_GIT_SUBMODULES_RECURSE) - set(recurseFlag "--recursive") - else() - set(recurseFlag "") - endif() - endif() - set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE) - - # The git submodule update '--recursive' flag requires git >= v1.6.5 - if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5) - message(FATAL_ERROR - "git version 1.6.5 or later required for --recursive flag with " - "'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'" - ) - endif() -endfunction() - - -function(_ep_add_download_command name) - # The various _EP_... variables mentioned here and throughout this function - # are expected to already have been set by the caller via a call to - # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables - # with different names are assigned to for historical reasons only to keep - # the code more readable and minimize change. - - set(source_dir "${_EP_SOURCE_DIR}") - set(stamp_dir "${_EP_STAMP_DIR}") - set(download_dir "${_EP_DOWNLOAD_DIR}") - set(tmp_dir "${_EP_TMP_DIR}") - - set(cmd "${_EP_DOWNLOAD_COMMAND}") - set(cvs_repository "${_EP_CVS_REPOSITORY}") - set(svn_repository "${_EP_SVN_REPOSITORY}") - set(git_repository "${_EP_GIT_REPOSITORY}") - set(hg_repository "${_EP_HG_REPOSITORY}") - set(url "${_EP_URL}") - set(fname "${_EP_DOWNLOAD_NAME}") - - # TODO: Perhaps file:// should be copied to download dir before extraction. - string(REGEX REPLACE "file://" "" url "${url}") - - set(depends) - set(comment) - set(work_dir) - set(extra_repo_info) - - if(DEFINED _EP_DOWNLOAD_COMMAND) - set(work_dir ${download_dir}) - set(method custom) - elseif(cvs_repository) - set(method cvs) - find_package(CVS QUIET) - if(NOT CVS_EXECUTABLE) - message(FATAL_ERROR "error: could not find cvs for checkout of ${name}") - endif() - - set(cvs_module "${_EP_CVS_MODULE}") - if(NOT cvs_module) - message(FATAL_ERROR "error: no CVS_MODULE") - endif() - - set(cvs_tag "${_EP_CVS_TAG}") - get_filename_component(src_name "${source_dir}" NAME) - get_filename_component(work_dir "${source_dir}" PATH) - set(comment "Performing download step (CVS checkout) for '${name}'") - set(cmd - ${CVS_EXECUTABLE} - -d ${cvs_repository} - -q - co ${cvs_tag} - -d ${src_name} - ${cvs_module} - ) - - elseif(svn_repository) - set(method svn) - find_package(Subversion QUIET) - if(NOT Subversion_SVN_EXECUTABLE) - message(FATAL_ERROR "error: could not find svn for checkout of ${name}") - endif() - - set(svn_revision "${_EP_SVN_REVISION}") - set(svn_username "${_EP_SVN_USERNAME}") - set(svn_password "${_EP_SVN_PASSWORD}") - set(svn_trust_cert "${_EP_SVN_TRUST_CERT}") - set(uses_terminal "${_EP_USES_TERMINAL_DOWNLOAD}") - # The --trust-server-cert option requires --non-interactive - if(uses_terminal AND NOT svn_trust_cert) - set(svn_interactive_args "") - else() - set(svn_interactive_args "--non-interactive") - endif() - - get_filename_component(src_name "${source_dir}" NAME) - get_filename_component(work_dir "${source_dir}" PATH) - set(comment "Performing download step (SVN checkout) for '${name}'") - set(svn_user_pw_args "") - if(DEFINED _EP_SVN_USERNAME) - set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}") - endif() - if(DEFINED _EP_SVN_PASSWORD) - set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}") - endif() - if(svn_trust_cert) - set(svn_trust_cert_args --trust-server-cert) - endif() - set(cmd - ${Subversion_SVN_EXECUTABLE} - co - ${svn_repository} - ${svn_revision} - ${svn_interactive_args} - ${svn_trust_cert_args} - ${svn_user_pw_args} - ${src_name} - ) - - elseif(git_repository) - set(method git) - # FetchContent gives us these directly, so don't try to recompute them - if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING) - unset(CMAKE_MODULE_PATH) # Use CMake builtin find module - find_package(Git QUIET) - if(NOT GIT_EXECUTABLE) - message(FATAL_ERROR "error: could not find git for clone of ${name}") - endif() - endif() - - _ep_get_git_submodules_recurse(git_submodules_recurse) - - set(git_tag "${_EP_GIT_TAG}") - if(NOT git_tag) - set(git_tag "master") - endif() - - set(git_init_submodules TRUE) - if(DEFINED _EP_GIT_SUBMODULES) - set(git_submodules "${_EP_GIT_SUBMODULES}") - if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW") - set(git_init_submodules FALSE) - endif() - endif() - - set(git_remote_name "${_EP_GIT_REMOTE_NAME}") - if(NOT git_remote_name) - set(git_remote_name "origin") - endif() - - _ep_get_tls_version(${name} tls_version) - _ep_get_tls_verify(${name} tls_verify) - set(git_shallow "${_EP_GIT_SHALLOW}") - set(git_progress "${_EP_GIT_PROGRESS}") - set(git_config "${_EP_GIT_CONFIG}") - - # If git supports it, make checkouts quiet when checking out a git hash. - # This avoids the very noisy detached head message. - if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7) - list(PREPEND git_config advice.detachedHead=false) - endif() - - # The command doesn't expose any details, so we need to record additional - # information in the RepositoryInfo.txt file. For the download step, only - # the things specifically affecting the clone operation should be recorded. - # If the repo changes, the clone script should be run again. - # But if only the tag changes, avoid running the clone script again. - # Let the 'always' running update step checkout the new tag. - # - set(extra_repo_info -"repository=${git_repository} -remote=${git_remote_name} -init_submodules=${git_init_submodules} -recurse_submodules=${git_submodules_recurse} -submodules=${git_submodules} -CMP0097=${_EP_CMP0097} -") - get_filename_component(src_name "${source_dir}" NAME) - get_filename_component(work_dir "${source_dir}" PATH) - - # Since git clone doesn't succeed if the non-empty source_dir exists, - # create a cmake script to invoke as download command. - # The script will delete the source directory and then call git clone. - # - _ep_write_gitclone_script( - ${tmp_dir}/${name}-gitclone.cmake - ${source_dir} - ${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} - ${stamp_dir}/${name}-gitinfo.txt - ${stamp_dir}/${name}-gitclone-lastrun.txt - "${tls_version}" - "${tls_verify}" - ) - set(comment "Performing download step (git clone) for '${name}'") - set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake) - - elseif(hg_repository) - set(method hg) - find_package(Hg QUIET) - if(NOT HG_EXECUTABLE) - message(FATAL_ERROR "error: could not find hg for clone of ${name}") - endif() - - set(hg_tag "${_EP_HG_TAG}") - if(NOT hg_tag) - set(hg_tag "tip") - endif() - - # The command doesn't expose any details, so we need to record additional - # information in the RepositoryInfo.txt file. For the download step, only - # the things specifically affecting the clone operation should be recorded. - # If the repo changes, the clone script should be run again. - # But if only the tag changes, avoid running the clone script again. - # Let the 'always' running update step checkout the new tag. - # - set(extra_repo_info "repository=${hg_repository}") - get_filename_component(src_name "${source_dir}" NAME) - get_filename_component(work_dir "${source_dir}" PATH) - - # Since hg clone doesn't succeed if the non-empty source_dir exists, - # create a cmake script to invoke as download command. - # The script will delete the source directory and then call hg clone. - # - _ep_write_hgclone_script( - ${tmp_dir}/${name}-hgclone.cmake - ${source_dir} - ${HG_EXECUTABLE} - ${hg_repository} - ${hg_tag} - ${src_name} - ${work_dir} - ${stamp_dir}/${name}-hginfo.txt - ${stamp_dir}/${name}-hgclone-lastrun.txt - ) - set(comment "Performing download step (hg clone) for '${name}'") - set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake) - - elseif(url) - set(method url) - get_filename_component(work_dir "${source_dir}" PATH) - set(hash "${_EP_URL_HASH}") - _ep_get_hash_regex(_ep_hash_regex) - if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}") - _ep_get_hash_algos(_ep_hash_algos) - list(JOIN _ep_hash_algos "|" _ep_hash_algos) - message(FATAL_ERROR - "URL_HASH is set to\n" - " ${hash}\n" - "but must be ALGO=value where ALGO is\n" - " ${_ep_hash_algos}\n" - "and value is a hex string." - ) - endif() - set(md5 "${_EP_URL_MD5}") - if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}") - message(FATAL_ERROR - "URL_MD5 is set to\n" - " ${md5}\n" - "but must be a hex string." - ) - endif() - if(md5 AND NOT hash) - set(hash "MD5=${md5}") - endif() - set(extra_repo_info -"url(s)=${url} -hash=${hash} -") - - list(LENGTH url url_list_length) - if(NOT "${url_list_length}" STREQUAL "1") - foreach(entry IN LISTS url) - if(NOT "${entry}" MATCHES "^[a-z]+://") - message(FATAL_ERROR - "At least one entry of URL is a path (invalid in a list)" - ) - endif() - endforeach() - if("x${fname}" STREQUAL "x") - list(GET url 0 fname) - endif() - endif() - - if(IS_DIRECTORY "${url}") - get_filename_component(abs_dir "${url}" ABSOLUTE) - set(comment "Performing download step (DIR copy) for '${name}'") - set(cmd - ${CMAKE_COMMAND} -E rm -rf ${source_dir} - COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir} - ) - else() - set(no_extract "${_EP_DOWNLOAD_NO_EXTRACT}") - string(APPEND extra_repo_info "no_extract=${no_extract}\n") - if("${url}" MATCHES "^[a-z]+://") - # TODO: Should download and extraction be different steps? - if("x${fname}" STREQUAL "x") - set(fname "${url}") - endif() - set(ext_regex [[7z|tar|tar\.bz2|tar\.gz|tar\.xz|tbz2|tgz|txz|zip]]) - if("${fname}" MATCHES "([^/\\?#]+(\\.|=)(${ext_regex}))([/?#].*)?$") - set(fname "${CMAKE_MATCH_1}") - elseif(no_extract) - get_filename_component(fname "${fname}" NAME) - else() - # Fall back to a default file name. The actual file name does not - # matter because it is used only internally and our extraction tool - # inspects the file content directly. If it turns out the wrong URL - # was given that will be revealed during the build which is an easier - # place for users to diagnose than an error here anyway. - set(fname "archive.tar") - endif() - string(REPLACE ";" "-" fname "${fname}") - set(file ${download_dir}/${fname}) - set(timeout "${_EP_TIMEOUT}") - set(inactivity_timeout "${_EP_INACTIVITY_TIMEOUT}") - set(no_progress "${_EP_DOWNLOAD_NO_PROGRESS}") - _ep_get_tls_version(${name} tls_version) - _ep_get_tls_verify(${name} tls_verify) - _ep_get_tls_cainfo(${name} tls_cainfo) - _ep_get_netrc(${name} netrc) - _ep_get_netrc_file(${name} netrc_file) - set(http_username "${_EP_HTTP_USERNAME}") - set(http_password "${_EP_HTTP_PASSWORD}") - set(http_headers "${_EP_HTTP_HEADER}") - set(download_script "${stamp_dir}/download-${name}.cmake") - _ep_write_downloadfile_script( - "${download_script}" - "${url}" - "${file}" - "${timeout}" - "${inactivity_timeout}" - "${no_progress}" - "${hash}" - "${tls_version}" - "${tls_verify}" - "${tls_cainfo}" - "${http_username}:${http_password}" - "${http_headers}" - "${netrc}" - "${netrc_file}" - ) - set(cmd - ${CMAKE_COMMAND} -P "${download_script}" - COMMAND - ) - if (no_extract) - set(steps "download and verify") - else () - set(steps "download, verify and extract") - endif () - set(comment "Performing download step (${steps}) for '${name}'") - # already verified by 'download_script' - file(WRITE "${stamp_dir}/verify-${name}.cmake" "") - - # Rather than adding everything to the RepositoryInfo.txt file, it is - # more robust to just depend on the download script. That way, we will - # re-download if any aspect of the download changes. - list(APPEND depends "${download_script}") - else() - set(file "${url}") - if (no_extract) - set(steps "verify") - else () - set(steps "verify and extract") - endif () - set(comment "Performing download step (${steps}) for '${name}'") - _ep_write_verifyfile_script( - "${stamp_dir}/verify-${name}.cmake" - "${file}" - "${hash}" - ) - endif() - list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake) - set(extract_timestamp "${_EP_DOWNLOAD_EXTRACT_TIMESTAMP}") - if(no_extract) - if(DEFINED _EP_DOWNLOAD_EXTRACT_TIMESTAMP) - message(FATAL_ERROR - "Cannot specify DOWNLOAD_EXTRACT_TIMESTAMP when using " - "DOWNLOAD_NO_EXTRACT TRUE" - ) - endif() - set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file}) - else() - if(NOT DEFINED _EP_DOWNLOAD_EXTRACT_TIMESTAMP) - # Default depends on policy CMP0135 - if(_EP_CMP0135 STREQUAL "") - message(AUTHOR_WARNING - "The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy " - "CMP0135 is not set. The policy's OLD behavior will be used. " - "When using a URL download, the timestamps of extracted files " - "should preferably be that of the time of extraction, otherwise " - "code that depends on the extracted contents might not be " - "rebuilt if the URL changes. The OLD behavior preserves the " - "timestamps from the archive instead, but this is usually not " - "what you want. Update your project to the NEW behavior or " - "specify the DOWNLOAD_EXTRACT_TIMESTAMP option with a value of " - "true to avoid this robustness issue." - ) - set(extract_timestamp TRUE) - elseif(_EP_CMP0135 STREQUAL "NEW") - set(extract_timestamp FALSE) - else() - set(extract_timestamp TRUE) - endif() - endif() - if(extract_timestamp) - set(options "") - else() - set(options "--touch") - endif() - _ep_write_extractfile_script( - "${stamp_dir}/extract-${name}.cmake" - "${name}" - "${file}" - "${source_dir}" - "${options}" - ) - list(APPEND cmd - COMMAND ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake - ) - endif () - endif() - else() - set(method source_dir) - _ep_is_dir_empty("${source_dir}" empty) - if(${empty}) - message(FATAL_ERROR - "No download info given for '${name}' and its source directory:\n" - " ${source_dir}\n" - "is not an existing non-empty directory. Please specify one of:\n" - " * SOURCE_DIR with an existing non-empty directory\n" - " * DOWNLOAD_COMMAND\n" - " * URL\n" - " * GIT_REPOSITORY\n" - " * SVN_REPOSITORY\n" - " * HG_REPOSITORY\n" - " * CVS_REPOSITORY and CVS_MODULE" - ) - endif() - endif() - - # We use configure_file() to write the repo_info_file so that the file's - # timestamp is not updated if we don't change the contents - - set(repo_info_file ${stamp_dir}/${name}-${method}info.txt) - list(APPEND depends ${repo_info_file}) - configure_file( - "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/RepositoryInfo.txt.in" - "${repo_info_file}" - @ONLY - ) - - if(_EP_LOG_DOWNLOAD) - set(log LOG 1) - else() - set(log "") - endif() - - if(_EP_USES_TERMINAL_DOWNLOAD) - set(uses_terminal USES_TERMINAL 1) - else() - set(uses_terminal "") - endif() - - set(__cmdQuoted) - foreach(__item IN LISTS cmd) - string(APPEND __cmdQuoted " [==[${__item}]==]") - endforeach() - cmake_language(EVAL CODE " - ExternalProject_Add_Step(\${name} download - INDEPENDENT TRUE - COMMENT \${comment} - COMMAND ${__cmdQuoted} - WORKING_DIRECTORY \${work_dir} - DEPENDS \${depends} - DEPENDEES mkdir - ${log} - ${uses_terminal} - )" - ) -endfunction() - -function(_ep_get_update_disconnected var name) - # Note that the arguments are assumed to have already been parsed and have - # been translated into variables with the prefix _EP_... by a call to - # ep_parse_arguments() or ep_parse_arguments_to_vars(). - if(DEFINED _EP_UPDATE_DISCONNECTED) - set(update_disconnected "${_EP_UPDATE_DISCONNECTED}") - else() - get_property(update_disconnected - DIRECTORY - PROPERTY EP_UPDATE_DISCONNECTED - ) - endif() - set(${var} "${update_disconnected}" PARENT_SCOPE) -endfunction() - -function(_ep_add_update_command name) - # The various _EP_... variables mentioned here and throughout this function - # are expected to already have been set by the caller via a call to - # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables - # with different names are assigned to for historical reasons only to keep - # the code more readable and minimize change. - - set(source_dir "${_EP_SOURCE_DIR}") - set(stamp_dir "${_EP_STAMP_DIR}") - set(tmp_dir "${_EP_TMP_DIR}") - - set(cmd "${_EP_UPDATE_COMMAND}") - set(cvs_repository "${_EP_CVS_REPOSITORY}") - set(svn_repository "${_EP_SVN_REPOSITORY}") - set(git_repository "${_EP_GIT_REPOSITORY}") - set(hg_repository "${_EP_HG_REPOSITORY}") - - _ep_get_update_disconnected(update_disconnected ${name}) - - set(work_dir) - set(comment) - set(always) - set(file_deps) - - if(DEFINED _EP_UPDATE_COMMAND) - set(work_dir ${source_dir}) - if(NOT "x${cmd}" STREQUAL "x") - set(always 1) - endif() - elseif(cvs_repository) - if(NOT CVS_EXECUTABLE) - message(FATAL_ERROR "error: could not find cvs for update of ${name}") - endif() - set(work_dir ${source_dir}) - set(comment "Performing update step (CVS update) for '${name}'") - set(cvs_tag "${_EP_CVS_TAG}") - set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag}) - set(always 1) - elseif(svn_repository) - if(NOT Subversion_SVN_EXECUTABLE) - message(FATAL_ERROR "error: could not find svn for update of ${name}") - endif() - set(work_dir ${source_dir}) - set(comment "Performing update step (SVN update) for '${name}'") - set(svn_revision "${_EP_SVN_REVISION}") - set(svn_username "${_EP_SVN_USERNAME}") - set(svn_password "${_EP_SVN_PASSWORD}") - set(svn_trust_cert "${_EP_SVN_TRUST_CERT}") - set(uses_terminal "${_EP_USES_TERMINAL_UPDATE}") - # The --trust-server-cert option requires --non-interactive - if(uses_terminal AND NOT svn_trust_cert) - set(svn_interactive_args "") - else() - set(svn_interactive_args "--non-interactive") - endif() - set(svn_user_pw_args "") - if(DEFINED svn_username) - set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}") - endif() - if(DEFINED svn_password) - set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}") - endif() - if(svn_trust_cert) - set(svn_trust_cert_args --trust-server-cert) - endif() - set(cmd - ${Subversion_SVN_EXECUTABLE} - up - ${svn_revision} - ${svn_interactive_args} - ${svn_trust_cert_args} - ${svn_user_pw_args} - ) - set(always 1) - elseif(git_repository) - # FetchContent gives us these directly, so don't try to recompute them - if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING) - unset(CMAKE_MODULE_PATH) # Use CMake builtin find module - find_package(Git QUIET) - if(NOT GIT_EXECUTABLE) - message(FATAL_ERROR "error: could not find git for fetch of ${name}") - endif() - endif() - set(work_dir ${source_dir}) - set(comment "Performing update step for '${name}'") - set(comment_disconnected "Performing disconnected update step for '${name}'") - - set(git_tag "${_EP_GIT_TAG}") - if(NOT git_tag) - set(git_tag "master") - endif() - - set(git_remote_name "${_EP_GIT_REMOTE_NAME}") - if(NOT git_remote_name) - set(git_remote_name "origin") - endif() - - set(git_init_submodules TRUE) - if(DEFINED _EP_GIT_SUBMODULES) - set(git_submodules "${_EP_GIT_SUBMODULES}") - if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW") - set(git_init_submodules FALSE) - endif() - endif() - - set(git_update_strategy "${_EP_GIT_REMOTE_UPDATE_STRATEGY}") - if(NOT git_update_strategy) - set(git_update_strategy "${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}") - endif() - if(NOT git_update_strategy) - set(git_update_strategy REBASE) - endif() - set(strategies CHECKOUT REBASE REBASE_CHECKOUT) - if(NOT git_update_strategy IN_LIST strategies) - message(FATAL_ERROR - "'${git_update_strategy}' is not one of the supported strategies: " - "${strategies}" - ) - endif() - - _ep_get_git_submodules_recurse(git_submodules_recurse) - - _ep_get_tls_version(${name} tls_version) - _ep_get_tls_verify(${name} tls_verify) - - set(update_script "${tmp_dir}/${name}-gitupdate.cmake") - list(APPEND file_deps ${update_script}) - _ep_write_gitupdate_script( - "${update_script}" - "${GIT_EXECUTABLE}" - "${git_tag}" - "${git_remote_name}" - "${git_init_submodules}" - "${git_submodules_recurse}" - "${git_submodules}" - "${git_repository}" - "${work_dir}" - "${git_update_strategy}" - "${tls_version}" - "${tls_verify}" - ) - set(cmd ${CMAKE_COMMAND} -Dcan_fetch=YES -P ${update_script}) - set(cmd_disconnected ${CMAKE_COMMAND} -Dcan_fetch=NO -P ${update_script}) - set(always 1) - elseif(hg_repository) - if(NOT HG_EXECUTABLE) - message(FATAL_ERROR "error: could not find hg for pull of ${name}") - endif() - set(work_dir ${source_dir}) - set(comment "Performing update step (hg pull) for '${name}'") - set(comment_disconnected "Performing disconnected update step for '${name}'") - - set(hg_tag "${_EP_HG_TAG}") - if(NOT hg_tag) - set(hg_tag "tip") - endif() - - if("${HG_VERSION_STRING}" STREQUAL "2.1") - set(notesAnchor - "#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X" - ) - message(WARNING -"Mercurial 2.1 does not distinguish an empty pull from a failed pull: - http://mercurial.selenic.com/wiki/UpgradeNotes${notesAnchor} - http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656 -Update to Mercurial >= 2.1.1. -") - endif() - - set(cmd - ${HG_EXECUTABLE} pull - COMMAND ${HG_EXECUTABLE} update ${hg_tag} - ) - set(cmd_disconnected ${HG_EXECUTABLE} update ${hg_tag}) - set(always 1) - endif() - - # We use configure_file() to write the update_info_file so that the file's - # timestamp is not updated if we don't change the contents - if(NOT DEFINED cmd_disconnected) - set(cmd_disconnected "${cmd}") - endif() - set(update_info_file ${stamp_dir}/${name}-update-info.txt) - list(APPEND file_deps ${update_info_file}) - configure_file( - "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/UpdateInfo.txt.in" - "${update_info_file}" - @ONLY - ) - - if(_EP_LOG_UPDATE) - set(log LOG 1) - else() - set(log "") - endif() - - if(_EP_USES_TERMINAL_UPDATE) - set(uses_terminal USES_TERMINAL 1) - else() - set(uses_terminal "") - endif() - - set(__cmdQuoted) - foreach(__item IN LISTS cmd) - string(APPEND __cmdQuoted " [==[${__item}]==]") - endforeach() - cmake_language(EVAL CODE " - ExternalProject_Add_Step(${name} update - INDEPENDENT TRUE - COMMENT \${comment} - COMMAND ${__cmdQuoted} - ALWAYS \${always} - EXCLUDE_FROM_MAIN \${update_disconnected} - WORKING_DIRECTORY \${work_dir} - DEPENDEES download - DEPENDS \${file_deps} - ${log} - ${uses_terminal} - )" - ) - if(update_disconnected) - if(NOT DEFINED comment_disconnected) - set(comment_disconnected "${comment}") - endif() - set(__cmdQuoted) - foreach(__item IN LISTS cmd_disconnected) - string(APPEND __cmdQuoted " [==[${__item}]==]") - endforeach() - - cmake_language(EVAL CODE " - ExternalProject_Add_Step(${name} update_disconnected - INDEPENDENT TRUE - COMMENT \${comment_disconnected} - COMMAND ${__cmdQuoted} - WORKING_DIRECTORY \${work_dir} - DEPENDEES download - DEPENDS \${file_deps} - ${log} - ${uses_terminal} - )" - ) - endif() - -endfunction() - - -function(_ep_add_patch_command name) - # The various _EP_... variables mentioned here and throughout this function - # are expected to already have been set by the caller via a call to - # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables - # with different names are assigned to for historical reasons only to keep - # the code more readable and minimize change. - - set(source_dir "${_EP_SOURCE_DIR}") - set(stamp_dir "${_EP_STAMP_DIR}") - - set(cmd "${_EP_PATCH_COMMAND}") - - set(work_dir) - if(DEFINED _EP_PATCH_COMMAND) - set(work_dir ${source_dir}) - endif() - - # We use configure_file() to write the patch_info_file so that the file's - # timestamp is not updated if we don't change the contents - set(patch_info_file ${stamp_dir}/${name}-patch-info.txt) - configure_file( - "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/PatchInfo.txt.in" - "${patch_info_file}" - @ONLY - ) - - if(_EP_LOG_PATCH) - set(log LOG 1) - else() - set(log "") - endif() - - if(_EP_USES_TERMINAL_PATCH) - set(uses_terminal USES_TERMINAL 1) - else() - set(uses_terminal "") - endif() - - _ep_get_update_disconnected(update_disconnected ${name}) - - set(__cmdQuoted) - foreach(__item IN LISTS cmd) - string(APPEND __cmdQuoted " [==[${__item}]==]") - endforeach() - cmake_language(EVAL CODE " - ExternalProject_Add_Step(${name} patch - INDEPENDENT TRUE - COMMAND ${__cmdQuoted} - WORKING_DIRECTORY \${work_dir} - EXCLUDE_FROM_MAIN \${update_disconnected} - DEPENDEES update - DEPENDS \${patch_info_file} - ${log} - ${uses_terminal} - )" - ) - - if(update_disconnected) - cmake_language(EVAL CODE " - ExternalProject_Add_Step(${name} patch_disconnected - INDEPENDENT TRUE - COMMAND ${__cmdQuoted} - WORKING_DIRECTORY \${work_dir} - DEPENDEES update_disconnected - DEPENDS \${patch_info_file} - ${log} - ${uses_terminal} - )" - ) - endif() - -endfunction() - function(_ep_get_file_deps var name) set(file_deps) @@ -3794,6 +2425,7 @@ function(_ep_get_file_deps var name) set("${var}" "${file_deps}" PARENT_SCOPE) endfunction() + function(_ep_extract_configure_command var name) get_property(cmd_set TARGET ${name} @@ -3949,6 +2581,7 @@ function(_ep_extract_configure_command var name) set("${var}" "${cmd}" PARENT_SCOPE) endfunction() + # TODO: Make sure external projects use the proper compiler function(_ep_add_configure_command name) ExternalProject_Get_Property(${name} binary_dir tmp_dir) @@ -4269,148 +2902,6 @@ function(_ep_add_test_command name) endfunction() -macro(_ep_get_add_keywords out_var) - set(${out_var} - # - # Directory options - # - PREFIX - TMP_DIR - STAMP_DIR - LOG_DIR - DOWNLOAD_DIR - SOURCE_DIR - BINARY_DIR - INSTALL_DIR - # - # Download step options - # - DOWNLOAD_COMMAND - # - URL - URL_HASH - URL_MD5 - DOWNLOAD_NAME - DOWNLOAD_EXTRACT_TIMESTAMP - DOWNLOAD_NO_EXTRACT - DOWNLOAD_NO_PROGRESS - TIMEOUT - INACTIVITY_TIMEOUT - HTTP_USERNAME - HTTP_PASSWORD - HTTP_HEADER - TLS_VERSION # Also used for git clone operations - TLS_VERIFY # Also used for git clone operations - TLS_CAINFO - NETRC - NETRC_FILE - # - GIT_REPOSITORY - GIT_TAG - GIT_REMOTE_NAME - GIT_SUBMODULES - GIT_SUBMODULES_RECURSE - GIT_SHALLOW - GIT_PROGRESS - GIT_CONFIG - GIT_REMOTE_UPDATE_STRATEGY - # - SVN_REPOSITORY - SVN_REVISION - SVN_USERNAME - SVN_PASSWORD - SVN_TRUST_CERT - # - HG_REPOSITORY - HG_TAG - # - CVS_REPOSITORY - CVS_MODULE - CVS_TAG - # - # Update step options - # - UPDATE_COMMAND - UPDATE_DISCONNECTED - # - # Patch step options - # - PATCH_COMMAND - # - # Configure step options - # - CONFIGURE_COMMAND - CMAKE_COMMAND - CMAKE_GENERATOR - CMAKE_GENERATOR_PLATFORM - CMAKE_GENERATOR_TOOLSET - CMAKE_GENERATOR_INSTANCE - CMAKE_ARGS - CMAKE_CACHE_ARGS - CMAKE_CACHE_DEFAULT_ARGS - SOURCE_SUBDIR - CONFIGURE_HANDLED_BY_BUILD - # - # Build step options - # - BUILD_COMMAND - BUILD_IN_SOURCE - BUILD_ALWAYS - BUILD_BYPRODUCTS - BUILD_JOB_SERVER_AWARE - # - # Install step options - # - INSTALL_COMMAND - INSTALL_BYPRODUCTS - # - # Test step options - # - TEST_COMMAND - TEST_BEFORE_INSTALL - TEST_AFTER_INSTALL - TEST_EXCLUDE_FROM_MAIN - # - # Logging options - # - LOG_DOWNLOAD - LOG_UPDATE - LOG_PATCH - LOG_CONFIGURE - LOG_BUILD - LOG_INSTALL - LOG_TEST - LOG_MERGED_STDOUTERR - LOG_OUTPUT_ON_FAILURE - # - # Terminal access options - # - USES_TERMINAL_DOWNLOAD - USES_TERMINAL_UPDATE - USES_TERMINAL_PATCH - USES_TERMINAL_CONFIGURE - USES_TERMINAL_BUILD - USES_TERMINAL_INSTALL - USES_TERMINAL_TEST - # - # Target options - # - DEPENDS - EXCLUDE_FROM_ALL - STEP_TARGETS - INDEPENDENT_STEP_TARGETS - # - # Miscellaneous options - # - LIST_SEPARATOR - # - # Internal options (undocumented) - # - EXTERNALPROJECT_INTERNAL_ARGUMENT_SEPARATOR - ) -endmacro() - - function(ExternalProject_Add name) cmake_policy(GET CMP0097 _EP_CMP0097 PARENT_SCOPE # undocumented, do not use outside of CMake diff --git a/Modules/ExternalProject/shared_internal_commands.cmake b/Modules/ExternalProject/shared_internal_commands.cmake index ca3cd9f..c6ab99b 100644 --- a/Modules/ExternalProject/shared_internal_commands.cmake +++ b/Modules/ExternalProject/shared_internal_commands.cmake @@ -75,6 +75,7 @@ function(_ep_get_git_remote_url output_variable working_directory) set("${output_variable}" "${git_remote_url}" PARENT_SCOPE) endfunction() + function(_ep_is_relative_git_remote output_variable remote_url) if(remote_url MATCHES "^\\.\\./") set("${output_variable}" TRUE PARENT_SCOPE) @@ -83,6 +84,7 @@ function(_ep_is_relative_git_remote output_variable remote_url) endif() endfunction() + # Return an absolute remote URL given an existing remote URL and relative path. # The output_variable will be set to an empty string if an absolute URL # could not be computed (no error message is output). @@ -133,6 +135,7 @@ function(_ep_resolve_relative_git_remote set("${output_variable}" "${protocol}${auth}${host}${separator}${path}" PARENT_SCOPE) endfunction() + # The output_variable will be set to the original git_repository if it # could not be resolved (no error message is output). The original value is # also returned if it doesn't need to be resolved. @@ -180,3 +183,1532 @@ function(_ep_resolve_git_remote set("${output_variable}" "${cmp0150_old_base_dir}/${git_repository}" PARENT_SCOPE) endfunction() + + +macro(_ep_get_hash_algos out_var) + set(${out_var} + MD5 + SHA1 + SHA224 + SHA256 + SHA384 + SHA512 + SHA3_224 + SHA3_256 + SHA3_384 + SHA3_512 + ) +endmacro() + + +macro(_ep_get_hash_regex out_var) + _ep_get_hash_algos(${out_var}) + list(JOIN ${out_var} "|" ${out_var}) + set(${out_var} "^(${${out_var}})=([0-9A-Fa-f]+)$") +endmacro() + + +function(_ep_parse_arguments_to_vars + f + keywords + name + ns + args +) + # Transfer the arguments into variables in the calling scope. + # Because some keywords can be repeated, we can't use cmake_parse_arguments(). + # Instead, we loop through the args and consider the namespace starting with + # an upper-case letter followed by at least two more upper-case letters, + # numbers or underscores to be keywords. + + foreach(key IN LISTS keywords) + unset(${ns}${key}) + endforeach() + + set(key) + + foreach(arg IN LISTS args) + set(is_value 1) + + if(arg MATCHES "^[A-Z][A-Z0-9_][A-Z0-9_]+$" AND + NOT (("x${arg}x" STREQUAL "x${key}x") AND + ("x${key}x" STREQUAL "xCOMMANDx")) AND + NOT arg MATCHES "^(TRUE|FALSE|YES)$") + if(arg IN_LIST keywords) + set(is_value 0) + endif() + endif() + + if(is_value) + if(key) + # Value + list(APPEND ${ns}${key} "${arg}") + else() + # Missing Keyword + message(AUTHOR_WARNING + "value '${arg}' with no previous keyword in ${f}" + ) + endif() + else() + set(key "${arg}") + endif() + endforeach() + + foreach(key IN LISTS keywords) + if(DEFINED ${ns}${key}) + set(${ns}${key} "${${ns}${key}}" PARENT_SCOPE) + else() + unset(${ns}${key} PARENT_SCOPE) + endif() + endforeach() + +endfunction() + + +# NOTE: This cannot be a macro because that will evaluate anything that looks +# like a CMake variable in any of the args. +function(_ep_parse_arguments + f + keywords + name + ns + args +) + _ep_parse_arguments_to_vars( + "${f}" + "${keywords}" + ${name} + ${ns} + "${args}" + ) + + foreach(key IN LISTS keywords) + if(DEFINED ${ns}${key}) + set(${ns}${key} "${${ns}${key}}" PARENT_SCOPE) + else() + unset(${ns}${key} PARENT_SCOPE) + endif() + endforeach() + + # Transfer the arguments to the target as target properties. These are + # read by the various steps, potentially from different scopes. + foreach(key IN LISTS keywords) + if(DEFINED ${ns}${key}) + set_property(TARGET ${name} PROPERTY ${ns}${key} "${${ns}${key}}") + endif() + endforeach() + +endfunction() + + +function(_ep_get_tls_version name tls_version_var) + # Note that the arguments are assumed to have already been parsed and have + # been translated into variables with the prefix _EP_... by a call to + # ep_parse_arguments() or ep_parse_arguments_to_vars(). + set(tls_version_regex "^1\\.[0-3]$") + set(tls_version "${_EP_TLS_VERSION}") + if(NOT "x${tls_version}" STREQUAL "x") + if(NOT tls_version MATCHES "${tls_version_regex}") + message(FATAL_ERROR "TLS_VERSION '${tls_version}' not known") + endif() + elseif(NOT "x${CMAKE_TLS_VERSION}" STREQUAL "x") + set(tls_version "${CMAKE_TLS_VERSION}") + if(NOT tls_version MATCHES "${tls_version_regex}") + message(FATAL_ERROR "CMAKE_TLS_VERSION '${tls_version}' not known") + endif() + elseif(NOT "x$ENV{CMAKE_TLS_VERSION}" STREQUAL "x") + set(tls_version "$ENV{CMAKE_TLS_VERSION}") + if(NOT tls_version MATCHES "${tls_version_regex}") + message(FATAL_ERROR "ENV{CMAKE_TLS_VERSION} '${tls_version}' not known") + endif() + endif() + set("${tls_version_var}" "${tls_version}" PARENT_SCOPE) +endfunction() + + +function(_ep_get_tls_verify name tls_verify_var) + # Note that the arguments are assumed to have already been parsed and have + # been translated into variables with the prefix _EP_... by a call to + # ep_parse_arguments() or ep_parse_arguments_to_vars(). + set(tls_verify "${_EP_TLS_VERIFY}") + if("x${tls_verify}" STREQUAL "x") + if(NOT "x${CMAKE_TLS_VERIFY}" STREQUAL "x") + set(tls_verify "${CMAKE_TLS_VERIFY}") + elseif(NOT "x$ENV{CMAKE_TLS_VERIFY}" STREQUAL "x") + set(tls_verify "$ENV{CMAKE_TLS_VERIFY}") + endif() + endif() + set("${tls_verify_var}" "${tls_verify}" PARENT_SCOPE) +endfunction() + + +function(_ep_get_tls_cainfo name tls_cainfo_var) + # Note that the arguments are assumed to have already been parsed and have + # been translated into variables with the prefix _EP_... by a call to + # ep_parse_arguments() or ep_parse_arguments_to_vars(). + set(tls_cainfo "${_EP_TLS_CAINFO}") + if("x${tls_cainfo}" STREQUAL "x" AND DEFINED CMAKE_TLS_CAINFO) + set(tls_cainfo "${CMAKE_TLS_CAINFO}") + endif() + set("${tls_cainfo_var}" "${tls_cainfo}" PARENT_SCOPE) +endfunction() + + +function(_ep_get_netrc name netrc_var) + # Note that the arguments are assumed to have already been parsed and have + # been translated into variables with the prefix _EP_... by a call to + # ep_parse_arguments() or ep_parse_arguments_to_vars(). + set(netrc "${_EP_NETRC}") + if("x${netrc}" STREQUAL "x" AND DEFINED CMAKE_NETRC) + set(netrc "${CMAKE_NETRC}") + endif() + set("${netrc_var}" "${netrc}" PARENT_SCOPE) +endfunction() + + +function(_ep_get_netrc_file name netrc_file_var) + # Note that the arguments are assumed to have already been parsed and have + # been translated into variables with the prefix _EP_... by a call to + # ep_parse_arguments() or ep_parse_arguments_to_vars(). + set(netrc_file "${_EP_NETRC_FILE}") + if("x${netrc_file}" STREQUAL "x" AND DEFINED CMAKE_NETRC_FILE) + set(netrc_file "${CMAKE_NETRC_FILE}") + endif() + set("${netrc_file_var}" "${netrc_file}" PARENT_SCOPE) +endfunction() + + +function(_ep_write_gitclone_script + script_filename + source_dir + git_EXECUTABLE + git_repository + git_tag + git_remote_name + init_submodules + git_submodules_recurse + git_submodules + git_shallow + git_progress + git_config + src_name + work_dir + gitclone_infofile + gitclone_stampfile + tls_version + tls_verify +) + + if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5) + # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path. + set(git_checkout_explicit-- "--") + else() + # Use `git checkout <branch>` even though this risks ambiguity with a + # local path. Unfortunately we cannot use `git checkout <tree-ish> --` + # because that will not search for remote branch names, a common use case. + set(git_checkout_explicit-- "") + endif() + if("${git_tag}" STREQUAL "") + message(FATAL_ERROR "Tag for git checkout should not be empty.") + endif() + + if(GIT_VERSION_STRING VERSION_LESS 2.20 OR + 2.21 VERSION_LESS_EQUAL GIT_VERSION_STRING) + set(git_clone_options "--no-checkout") + else() + set(git_clone_options) + endif() + if(git_shallow) + if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10) + list(APPEND git_clone_options "--depth 1 --no-single-branch") + else() + list(APPEND git_clone_options "--depth 1") + endif() + endif() + if(git_progress) + list(APPEND git_clone_options --progress) + endif() + foreach(config IN LISTS git_config) + list(APPEND git_clone_options --config \"${config}\") + endforeach() + if(NOT ${git_remote_name} STREQUAL "origin") + list(APPEND git_clone_options --origin \"${git_remote_name}\") + endif() + + # The clone config option is sticky, it will apply to all subsequent git + # update operations. The submodules config option is not sticky, because + # git doesn't provide any way to do that. Thus, we will have to pass the + # same config option in the update step too for submodules, but not for + # the main git repo. + set(git_submodules_config_options "") + if(NOT "x${tls_version}" STREQUAL "x") + list(APPEND git_clone_options -c http.sslVersion=tlsv${tls_version}) + list(APPEND git_submodules_config_options -c http.sslVersion=tlsv${tls_version}) + endif() + if(NOT "x${tls_verify}" STREQUAL "x") + if(tls_verify) + # Default git behavior is "true", but the user might have changed the + # global default to "false". Since TLS_VERIFY was given, ensure we honor + # the specified setting regardless of what the global default might be. + list(APPEND git_clone_options -c http.sslVerify=true) + list(APPEND git_submodules_config_options -c http.sslVerify=true) + else() + list(APPEND git_clone_options -c http.sslVerify=false) + list(APPEND git_submodules_config_options -c http.sslVerify=false) + endif() + endif() + + string (REPLACE ";" " " git_clone_options "${git_clone_options}") + + configure_file( + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/gitclone.cmake.in + ${script_filename} + @ONLY + ) +endfunction() + + +function(_ep_write_hgclone_script + script_filename + source_dir + hg_EXECUTABLE + hg_repository + hg_tag + src_name + work_dir + hgclone_infofile + hgclone_stampfile +) + + if("${hg_tag}" STREQUAL "") + message(FATAL_ERROR "Tag for hg checkout should not be empty.") + endif() + + configure_file( + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/hgclone.cmake.in + ${script_filename} + @ONLY + ) +endfunction() + + +function(_ep_write_gitupdate_script + script_filename + git_EXECUTABLE + git_tag + git_remote_name + init_submodules + git_submodules_recurse + git_submodules + git_repository + work_dir + git_update_strategy + tls_version + tls_verify +) + + if("${git_tag}" STREQUAL "") + message(FATAL_ERROR "Tag for git checkout should not be empty.") + endif() + set(git_stash_save_options --quiet) + if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7) + # This avoids stashing files covered by .gitignore + list(APPEND git_stash_save_options --include-untracked) + elseif(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.6) + # Untracked files, but also ignored files, so potentially slower + list(APPEND git_stash_save_options --all) + endif() + + # The submodules config option is not sticky, git doesn't provide any way + # to do that. We have to pass this config option for the update step too. + # We don't need to set it for the non-submodule update because it gets + # recorded as part of the clone operation in a sticky manner. + set(git_submodules_config_options "") + if(NOT "x${tls_version}" STREQUAL "x") + list(APPEND git_submodules_config_options -c http.sslVersion=tlsv${tls_version}) + endif() + if(NOT "x${tls_verify}" STREQUAL "x") + if(tls_verify) + # Default git behavior is "true", but the user might have changed the + # global default to "false". Since TLS_VERIFY was given, ensure we honor + # the specified setting regardless of what the global default might be. + list(APPEND git_submodules_config_options -c http.sslVerify=true) + else() + list(APPEND git_submodules_config_options -c http.sslVerify=false) + endif() + endif() + + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/gitupdate.cmake.in" + "${script_filename}" + @ONLY + ) +endfunction() + + +function(_ep_write_downloadfile_script + script_filename + REMOTE + LOCAL + timeout + inactivity_timeout + no_progress + hash + tls_version + tls_verify + tls_cainfo + userpwd + http_headers + netrc + netrc_file +) + if("x${REMOTE}" STREQUAL "x") + message(FATAL_ERROR "REMOTE can't be empty") + endif() + if("x${LOCAL}" STREQUAL "x") + message(FATAL_ERROR "LOCAL can't be empty") + endif() + + # REMOTE could contain special characters that parse as separate arguments. + # Things like parentheses are legitimate characters in a URL, but would be + # seen as the start of a new unquoted argument by the cmake language parser. + # Avoid those special cases by preparing quoted strings for direct inclusion + # in the foreach() call that iterates over the set of URLs in REMOTE. + set(REMOTE "[====[${REMOTE}]====]") + string(REPLACE ";" "]====] [====[" REMOTE "${REMOTE}") + + if(timeout) + set(TIMEOUT_ARGS TIMEOUT ${timeout}) + set(TIMEOUT_MSG "${timeout} seconds") + else() + set(TIMEOUT_ARGS "# no TIMEOUT") + set(TIMEOUT_MSG "none") + endif() + if(inactivity_timeout) + set(INACTIVITY_TIMEOUT_ARGS INACTIVITY_TIMEOUT ${inactivity_timeout}) + set(INACTIVITY_TIMEOUT_MSG "${inactivity_timeout} seconds") + else() + set(INACTIVITY_TIMEOUT_ARGS "# no INACTIVITY_TIMEOUT") + set(INACTIVITY_TIMEOUT_MSG "none") + endif() + + if(no_progress) + set(SHOW_PROGRESS "") + else() + set(SHOW_PROGRESS "SHOW_PROGRESS") + endif() + + _ep_get_hash_regex(_ep_hash_regex) + if("${hash}" MATCHES "${_ep_hash_regex}") + set(ALGO "${CMAKE_MATCH_1}") + string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE) + else() + set(ALGO "") + set(EXPECT_VALUE "") + endif() + + set(TLS_VERSION_CODE "") + if(NOT "x${tls_version}" STREQUAL "x") + set(TLS_VERSION_CODE "set(CMAKE_TLS_VERSION \"${tls_version}\")") + endif() + + set(TLS_VERIFY_CODE "") + if(NOT "x${tls_verify}" STREQUAL "x") + set(TLS_VERIFY_CODE "set(CMAKE_TLS_VERIFY \"${tls_verify}\")") + endif() + + set(TLS_CAINFO_CODE "") + if(NOT "x${tls_cainfo}" STREQUAL "x") + set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")") + endif() + + set(NETRC_CODE "") + if(NOT "x${netrc}" STREQUAL "x") + set(NETRC_CODE "set(CMAKE_NETRC \"${netrc}\")") + endif() + + set(NETRC_FILE_CODE "") + if(NOT "x${netrc_file}" STREQUAL "x") + set(NETRC_FILE_CODE "set(CMAKE_NETRC_FILE \"${netrc_file}\")") + endif() + + if(userpwd STREQUAL ":") + set(USERPWD_ARGS) + else() + set(USERPWD_ARGS USERPWD "${userpwd}") + endif() + + set(HTTP_HEADERS_ARGS "") + if(NOT http_headers STREQUAL "") + foreach(header IN LISTS http_headers) + string(PREPEND HTTP_HEADERS_ARGS + "HTTPHEADER \"${header}\"\n " + ) + endforeach() + endif() + + # Used variables: + # * TLS_VERSION_CODE + # * TLS_VERIFY_CODE + # * TLS_CAINFO_CODE + # * ALGO + # * EXPECT_VALUE + # * REMOTE + # * LOCAL + # * SHOW_PROGRESS + # * TIMEOUT_ARGS + # * TIMEOUT_MSG + # * USERPWD_ARGS + # * HTTP_HEADERS_ARGS + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/download.cmake.in" + "${script_filename}" + @ONLY + ) +endfunction() + + +function(_ep_write_verifyfile_script + script_filename + LOCAL + hash +) + _ep_get_hash_regex(_ep_hash_regex) + if("${hash}" MATCHES "${_ep_hash_regex}") + set(ALGO "${CMAKE_MATCH_1}") + string(TOLOWER "${CMAKE_MATCH_2}" EXPECT_VALUE) + else() + set(ALGO "") + set(EXPECT_VALUE "") + endif() + + # Used variables: + # * ALGO + # * EXPECT_VALUE + # * LOCAL + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/verify.cmake.in" + "${script_filename}" + @ONLY + ) +endfunction() + + +function(_ep_write_extractfile_script + script_filename + name + filename + directory + options +) + set(args "") + + if(filename MATCHES + "(\\.|=)(7z|tar\\.bz2|tar\\.gz|tar\\.xz|tbz2|tgz|txz|zip)$") + set(args xfz) + endif() + + if(filename MATCHES "(\\.|=)tar$") + set(args xf) + endif() + + if(args STREQUAL "") + message(FATAL_ERROR + "Do not know how to extract '${filename}' -- known types are: " + ".7z, .tar, .tar.bz2, .tar.gz, .tar.xz, .tbz2, .tgz, .txz and .zip" + ) + endif() + + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/extractfile.cmake.in" + "${script_filename}" + @ONLY + ) +endfunction() + + +function(_ep_is_dir_empty dir empty_var) + file(GLOB gr "${dir}/*") + if("${gr}" STREQUAL "") + set(${empty_var} 1 PARENT_SCOPE) + else() + set(${empty_var} 0 PARENT_SCOPE) + endif() +endfunction() + +function(_ep_get_git_submodules_recurse git_submodules_recurse) + # Checks for GIT_SUBMODULES_RECURSE argument. Default is ON, which sets + # git_submodules_recurse output variable to "--recursive". Otherwise, the + # output variable is set to an empty value "". + # Note that the arguments are assumed to have already been parsed and have + # been translated into variables with the prefix _EP_... by a call to + # ep_parse_arguments() or ep_parse_arguments_to_vars(). + if(NOT DEFINED _EP_GIT_SUBMODULES_RECURSE) + set(recurseFlag "--recursive") + else() + if(_EP_GIT_SUBMODULES_RECURSE) + set(recurseFlag "--recursive") + else() + set(recurseFlag "") + endif() + endif() + set(${git_submodules_recurse} "${recurseFlag}" PARENT_SCOPE) + + # The git submodule update '--recursive' flag requires git >= v1.6.5 + if(recurseFlag AND GIT_VERSION_STRING VERSION_LESS 1.6.5) + message(FATAL_ERROR + "git version 1.6.5 or later required for --recursive flag with " + "'git submodule ...': GIT_VERSION_STRING='${GIT_VERSION_STRING}'" + ) + endif() +endfunction() + + +function(_ep_add_download_command name) + # The various _EP_... variables mentioned here and throughout this function + # are expected to already have been set by the caller via a call to + # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables + # with different names are assigned to for historical reasons only to keep + # the code more readable and minimize change. + + set(source_dir "${_EP_SOURCE_DIR}") + set(stamp_dir "${_EP_STAMP_DIR}") + set(download_dir "${_EP_DOWNLOAD_DIR}") + set(tmp_dir "${_EP_TMP_DIR}") + + set(cmd "${_EP_DOWNLOAD_COMMAND}") + set(cvs_repository "${_EP_CVS_REPOSITORY}") + set(svn_repository "${_EP_SVN_REPOSITORY}") + set(git_repository "${_EP_GIT_REPOSITORY}") + set(hg_repository "${_EP_HG_REPOSITORY}") + set(url "${_EP_URL}") + set(fname "${_EP_DOWNLOAD_NAME}") + + # TODO: Perhaps file:// should be copied to download dir before extraction. + string(REGEX REPLACE "file://" "" url "${url}") + + set(depends) + set(comment) + set(work_dir) + set(extra_repo_info) + + if(DEFINED _EP_DOWNLOAD_COMMAND) + set(work_dir ${download_dir}) + set(method custom) + elseif(cvs_repository) + set(method cvs) + find_package(CVS QUIET) + if(NOT CVS_EXECUTABLE) + message(FATAL_ERROR "error: could not find cvs for checkout of ${name}") + endif() + + set(cvs_module "${_EP_CVS_MODULE}") + if(NOT cvs_module) + message(FATAL_ERROR "error: no CVS_MODULE") + endif() + + set(cvs_tag "${_EP_CVS_TAG}") + get_filename_component(src_name "${source_dir}" NAME) + get_filename_component(work_dir "${source_dir}" PATH) + set(comment "Performing download step (CVS checkout) for '${name}'") + set(cmd + ${CVS_EXECUTABLE} + -d ${cvs_repository} + -q + co ${cvs_tag} + -d ${src_name} + ${cvs_module} + ) + + elseif(svn_repository) + set(method svn) + find_package(Subversion QUIET) + if(NOT Subversion_SVN_EXECUTABLE) + message(FATAL_ERROR "error: could not find svn for checkout of ${name}") + endif() + + set(svn_revision "${_EP_SVN_REVISION}") + set(svn_username "${_EP_SVN_USERNAME}") + set(svn_password "${_EP_SVN_PASSWORD}") + set(svn_trust_cert "${_EP_SVN_TRUST_CERT}") + set(uses_terminal "${_EP_USES_TERMINAL_DOWNLOAD}") + # The --trust-server-cert option requires --non-interactive + if(uses_terminal AND NOT svn_trust_cert) + set(svn_interactive_args "") + else() + set(svn_interactive_args "--non-interactive") + endif() + + get_filename_component(src_name "${source_dir}" NAME) + get_filename_component(work_dir "${source_dir}" PATH) + set(comment "Performing download step (SVN checkout) for '${name}'") + set(svn_user_pw_args "") + if(DEFINED _EP_SVN_USERNAME) + set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}") + endif() + if(DEFINED _EP_SVN_PASSWORD) + set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}") + endif() + if(svn_trust_cert) + set(svn_trust_cert_args --trust-server-cert) + endif() + set(cmd + ${Subversion_SVN_EXECUTABLE} + co + ${svn_repository} + ${svn_revision} + ${svn_interactive_args} + ${svn_trust_cert_args} + ${svn_user_pw_args} + ${src_name} + ) + + elseif(git_repository) + set(method git) + # FetchContent gives us these directly, so don't try to recompute them + if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING) + unset(CMAKE_MODULE_PATH) # Use CMake builtin find module + find_package(Git QUIET) + if(NOT GIT_EXECUTABLE) + message(FATAL_ERROR "error: could not find git for clone of ${name}") + endif() + endif() + + _ep_get_git_submodules_recurse(git_submodules_recurse) + + set(git_tag "${_EP_GIT_TAG}") + if(NOT git_tag) + set(git_tag "master") + endif() + + set(git_init_submodules TRUE) + if(DEFINED _EP_GIT_SUBMODULES) + set(git_submodules "${_EP_GIT_SUBMODULES}") + if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW") + set(git_init_submodules FALSE) + endif() + endif() + + set(git_remote_name "${_EP_GIT_REMOTE_NAME}") + if(NOT git_remote_name) + set(git_remote_name "origin") + endif() + + _ep_get_tls_version(${name} tls_version) + _ep_get_tls_verify(${name} tls_verify) + set(git_shallow "${_EP_GIT_SHALLOW}") + set(git_progress "${_EP_GIT_PROGRESS}") + set(git_config "${_EP_GIT_CONFIG}") + + # If git supports it, make checkouts quiet when checking out a git hash. + # This avoids the very noisy detached head message. + if(GIT_VERSION_STRING VERSION_GREATER_EQUAL 1.7.7) + list(PREPEND git_config advice.detachedHead=false) + endif() + + # The command doesn't expose any details, so we need to record additional + # information in the RepositoryInfo.txt file. For the download step, only + # the things specifically affecting the clone operation should be recorded. + # If the repo changes, the clone script should be run again. + # But if only the tag changes, avoid running the clone script again. + # Let the 'always' running update step checkout the new tag. + # + set(extra_repo_info + "repository=${git_repository} +remote=${git_remote_name} +init_submodules=${git_init_submodules} +recurse_submodules=${git_submodules_recurse} +submodules=${git_submodules} +CMP0097=${_EP_CMP0097} + ") + get_filename_component(src_name "${source_dir}" NAME) + get_filename_component(work_dir "${source_dir}" PATH) + + # Since git clone doesn't succeed if the non-empty source_dir exists, + # create a cmake script to invoke as download command. + # The script will delete the source directory and then call git clone. + # + _ep_write_gitclone_script( + ${tmp_dir}/${name}-gitclone.cmake + ${source_dir} + ${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} + ${stamp_dir}/${name}-gitinfo.txt + ${stamp_dir}/${name}-gitclone-lastrun.txt + "${tls_version}" + "${tls_verify}" + ) + set(comment "Performing download step (git clone) for '${name}'") + set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitclone.cmake) + + elseif(hg_repository) + set(method hg) + find_package(Hg QUIET) + if(NOT HG_EXECUTABLE) + message(FATAL_ERROR "error: could not find hg for clone of ${name}") + endif() + + set(hg_tag "${_EP_HG_TAG}") + if(NOT hg_tag) + set(hg_tag "tip") + endif() + + # The command doesn't expose any details, so we need to record additional + # information in the RepositoryInfo.txt file. For the download step, only + # the things specifically affecting the clone operation should be recorded. + # If the repo changes, the clone script should be run again. + # But if only the tag changes, avoid running the clone script again. + # Let the 'always' running update step checkout the new tag. + # + set(extra_repo_info "repository=${hg_repository}") + get_filename_component(src_name "${source_dir}" NAME) + get_filename_component(work_dir "${source_dir}" PATH) + + # Since hg clone doesn't succeed if the non-empty source_dir exists, + # create a cmake script to invoke as download command. + # The script will delete the source directory and then call hg clone. + # + _ep_write_hgclone_script( + ${tmp_dir}/${name}-hgclone.cmake + ${source_dir} + ${HG_EXECUTABLE} + ${hg_repository} + ${hg_tag} + ${src_name} + ${work_dir} + ${stamp_dir}/${name}-hginfo.txt + ${stamp_dir}/${name}-hgclone-lastrun.txt + ) + set(comment "Performing download step (hg clone) for '${name}'") + set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-hgclone.cmake) + + elseif(url) + set(method url) + get_filename_component(work_dir "${source_dir}" PATH) + set(hash "${_EP_URL_HASH}") + _ep_get_hash_regex(_ep_hash_regex) + if(hash AND NOT "${hash}" MATCHES "${_ep_hash_regex}") + _ep_get_hash_algos(_ep_hash_algos) + list(JOIN _ep_hash_algos "|" _ep_hash_algos) + message(FATAL_ERROR + "URL_HASH is set to\n" + " ${hash}\n" + "but must be ALGO=value where ALGO is\n" + " ${_ep_hash_algos}\n" + "and value is a hex string." + ) + endif() + set(md5 "${_EP_URL_MD5}") + if(md5 AND NOT "MD5=${md5}" MATCHES "${_ep_hash_regex}") + message(FATAL_ERROR + "URL_MD5 is set to\n" + " ${md5}\n" + "but must be a hex string." + ) + endif() + if(md5 AND NOT hash) + set(hash "MD5=${md5}") + endif() + set(extra_repo_info + "url(s)=${url} +hash=${hash} + ") + + list(LENGTH url url_list_length) + if(NOT "${url_list_length}" STREQUAL "1") + foreach(entry IN LISTS url) + if(NOT "${entry}" MATCHES "^[a-z]+://") + message(FATAL_ERROR + "At least one entry of URL is a path (invalid in a list)" + ) + endif() + endforeach() + if("x${fname}" STREQUAL "x") + list(GET url 0 fname) + endif() + endif() + + if(IS_DIRECTORY "${url}") + get_filename_component(abs_dir "${url}" ABSOLUTE) + set(comment "Performing download step (DIR copy) for '${name}'") + set(cmd + ${CMAKE_COMMAND} -E rm -rf ${source_dir} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir} + ) + else() + set(no_extract "${_EP_DOWNLOAD_NO_EXTRACT}") + string(APPEND extra_repo_info "no_extract=${no_extract}\n") + if("${url}" MATCHES "^[a-z]+://") + # TODO: Should download and extraction be different steps? + if("x${fname}" STREQUAL "x") + set(fname "${url}") + endif() + set(ext_regex [[7z|tar|tar\.bz2|tar\.gz|tar\.xz|tbz2|tgz|txz|zip]]) + if("${fname}" MATCHES "([^/\\?#]+(\\.|=)(${ext_regex}))([/?#].*)?$") + set(fname "${CMAKE_MATCH_1}") + elseif(no_extract) + get_filename_component(fname "${fname}" NAME) + else() + # Fall back to a default file name. The actual file name does not + # matter because it is used only internally and our extraction tool + # inspects the file content directly. If it turns out the wrong URL + # was given that will be revealed during the build which is an easier + # place for users to diagnose than an error here anyway. + set(fname "archive.tar") + endif() + string(REPLACE ";" "-" fname "${fname}") + set(file ${download_dir}/${fname}) + set(timeout "${_EP_TIMEOUT}") + set(inactivity_timeout "${_EP_INACTIVITY_TIMEOUT}") + set(no_progress "${_EP_DOWNLOAD_NO_PROGRESS}") + _ep_get_tls_version(${name} tls_version) + _ep_get_tls_verify(${name} tls_verify) + _ep_get_tls_cainfo(${name} tls_cainfo) + _ep_get_netrc(${name} netrc) + _ep_get_netrc_file(${name} netrc_file) + set(http_username "${_EP_HTTP_USERNAME}") + set(http_password "${_EP_HTTP_PASSWORD}") + set(http_headers "${_EP_HTTP_HEADER}") + set(download_script "${stamp_dir}/download-${name}.cmake") + _ep_write_downloadfile_script( + "${download_script}" + "${url}" + "${file}" + "${timeout}" + "${inactivity_timeout}" + "${no_progress}" + "${hash}" + "${tls_version}" + "${tls_verify}" + "${tls_cainfo}" + "${http_username}:${http_password}" + "${http_headers}" + "${netrc}" + "${netrc_file}" + ) + set(cmd + ${CMAKE_COMMAND} -P "${download_script}" + COMMAND + ) + if (no_extract) + set(steps "download and verify") + else () + set(steps "download, verify and extract") + endif () + set(comment "Performing download step (${steps}) for '${name}'") + # already verified by 'download_script' + file(WRITE "${stamp_dir}/verify-${name}.cmake" "") + + # Rather than adding everything to the RepositoryInfo.txt file, it is + # more robust to just depend on the download script. That way, we will + # re-download if any aspect of the download changes. + list(APPEND depends "${download_script}") + else() + set(file "${url}") + if (no_extract) + set(steps "verify") + else () + set(steps "verify and extract") + endif () + set(comment "Performing download step (${steps}) for '${name}'") + _ep_write_verifyfile_script( + "${stamp_dir}/verify-${name}.cmake" + "${file}" + "${hash}" + ) + endif() + list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake) + set(extract_timestamp "${_EP_DOWNLOAD_EXTRACT_TIMESTAMP}") + if(no_extract) + if(DEFINED _EP_DOWNLOAD_EXTRACT_TIMESTAMP) + message(FATAL_ERROR + "Cannot specify DOWNLOAD_EXTRACT_TIMESTAMP when using " + "DOWNLOAD_NO_EXTRACT TRUE" + ) + endif() + set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file}) + else() + if(NOT DEFINED _EP_DOWNLOAD_EXTRACT_TIMESTAMP) + # Default depends on policy CMP0135 + if(_EP_CMP0135 STREQUAL "") + message(AUTHOR_WARNING + "The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy " + "CMP0135 is not set. The policy's OLD behavior will be used. " + "When using a URL download, the timestamps of extracted files " + "should preferably be that of the time of extraction, otherwise " + "code that depends on the extracted contents might not be " + "rebuilt if the URL changes. The OLD behavior preserves the " + "timestamps from the archive instead, but this is usually not " + "what you want. Update your project to the NEW behavior or " + "specify the DOWNLOAD_EXTRACT_TIMESTAMP option with a value of " + "true to avoid this robustness issue." + ) + set(extract_timestamp TRUE) + elseif(_EP_CMP0135 STREQUAL "NEW") + set(extract_timestamp FALSE) + else() + set(extract_timestamp TRUE) + endif() + endif() + if(extract_timestamp) + set(options "") + else() + set(options "--touch") + endif() + _ep_write_extractfile_script( + "${stamp_dir}/extract-${name}.cmake" + "${name}" + "${file}" + "${source_dir}" + "${options}" + ) + list(APPEND cmd + COMMAND ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake + ) + endif () + endif() + else() + set(method source_dir) + _ep_is_dir_empty("${source_dir}" empty) + if(${empty}) + message(FATAL_ERROR + "No download info given for '${name}' and its source directory:\n" + " ${source_dir}\n" + "is not an existing non-empty directory. Please specify one of:\n" + " * SOURCE_DIR with an existing non-empty directory\n" + " * DOWNLOAD_COMMAND\n" + " * URL\n" + " * GIT_REPOSITORY\n" + " * SVN_REPOSITORY\n" + " * HG_REPOSITORY\n" + " * CVS_REPOSITORY and CVS_MODULE" + ) + endif() + endif() + + # We use configure_file() to write the repo_info_file so that the file's + # timestamp is not updated if we don't change the contents + + set(repo_info_file ${stamp_dir}/${name}-${method}info.txt) + list(APPEND depends ${repo_info_file}) + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RepositoryInfo.txt.in" + "${repo_info_file}" + @ONLY + ) + + if(_EP_LOG_DOWNLOAD) + set(log LOG 1) + else() + set(log "") + endif() + + if(_EP_USES_TERMINAL_DOWNLOAD) + set(uses_terminal USES_TERMINAL 1) + else() + set(uses_terminal "") + endif() + + set(__cmdQuoted) + foreach(__item IN LISTS cmd) + string(APPEND __cmdQuoted " [==[${__item}]==]") + endforeach() + cmake_language(EVAL CODE " + ExternalProject_Add_Step(\${name} download + INDEPENDENT TRUE + COMMENT \${comment} + COMMAND ${__cmdQuoted} + WORKING_DIRECTORY \${work_dir} + DEPENDS \${depends} + DEPENDEES mkdir + ${log} + ${uses_terminal} + )" + ) +endfunction() + +function(_ep_get_update_disconnected var name) + # Note that the arguments are assumed to have already been parsed and have + # been translated into variables with the prefix _EP_... by a call to + # ep_parse_arguments() or ep_parse_arguments_to_vars(). + if(DEFINED _EP_UPDATE_DISCONNECTED) + set(update_disconnected "${_EP_UPDATE_DISCONNECTED}") + else() + get_property(update_disconnected + DIRECTORY + PROPERTY EP_UPDATE_DISCONNECTED + ) + endif() + set(${var} "${update_disconnected}" PARENT_SCOPE) +endfunction() + +function(_ep_add_update_command name) + # The various _EP_... variables mentioned here and throughout this function + # are expected to already have been set by the caller via a call to + # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables + # with different names are assigned to for historical reasons only to keep + # the code more readable and minimize change. + + set(source_dir "${_EP_SOURCE_DIR}") + set(stamp_dir "${_EP_STAMP_DIR}") + set(tmp_dir "${_EP_TMP_DIR}") + + set(cmd "${_EP_UPDATE_COMMAND}") + set(cvs_repository "${_EP_CVS_REPOSITORY}") + set(svn_repository "${_EP_SVN_REPOSITORY}") + set(git_repository "${_EP_GIT_REPOSITORY}") + set(hg_repository "${_EP_HG_REPOSITORY}") + + _ep_get_update_disconnected(update_disconnected ${name}) + + set(work_dir) + set(comment) + set(always) + set(file_deps) + + if(DEFINED _EP_UPDATE_COMMAND) + set(work_dir ${source_dir}) + if(NOT "x${cmd}" STREQUAL "x") + set(always 1) + endif() + elseif(cvs_repository) + if(NOT CVS_EXECUTABLE) + message(FATAL_ERROR "error: could not find cvs for update of ${name}") + endif() + set(work_dir ${source_dir}) + set(comment "Performing update step (CVS update) for '${name}'") + set(cvs_tag "${_EP_CVS_TAG}") + set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag}) + set(always 1) + elseif(svn_repository) + if(NOT Subversion_SVN_EXECUTABLE) + message(FATAL_ERROR "error: could not find svn for update of ${name}") + endif() + set(work_dir ${source_dir}) + set(comment "Performing update step (SVN update) for '${name}'") + set(svn_revision "${_EP_SVN_REVISION}") + set(svn_username "${_EP_SVN_USERNAME}") + set(svn_password "${_EP_SVN_PASSWORD}") + set(svn_trust_cert "${_EP_SVN_TRUST_CERT}") + set(uses_terminal "${_EP_USES_TERMINAL_UPDATE}") + # The --trust-server-cert option requires --non-interactive + if(uses_terminal AND NOT svn_trust_cert) + set(svn_interactive_args "") + else() + set(svn_interactive_args "--non-interactive") + endif() + set(svn_user_pw_args "") + if(DEFINED svn_username) + set(svn_user_pw_args ${svn_user_pw_args} "--username=${svn_username}") + endif() + if(DEFINED svn_password) + set(svn_user_pw_args ${svn_user_pw_args} "--password=${svn_password}") + endif() + if(svn_trust_cert) + set(svn_trust_cert_args --trust-server-cert) + endif() + set(cmd + ${Subversion_SVN_EXECUTABLE} + up + ${svn_revision} + ${svn_interactive_args} + ${svn_trust_cert_args} + ${svn_user_pw_args} + ) + set(always 1) + elseif(git_repository) + # FetchContent gives us these directly, so don't try to recompute them + if(NOT GIT_EXECUTABLE OR NOT GIT_VERSION_STRING) + unset(CMAKE_MODULE_PATH) # Use CMake builtin find module + find_package(Git QUIET) + if(NOT GIT_EXECUTABLE) + message(FATAL_ERROR "error: could not find git for fetch of ${name}") + endif() + endif() + set(work_dir ${source_dir}) + set(comment "Performing update step for '${name}'") + set(comment_disconnected "Performing disconnected update step for '${name}'") + + set(git_tag "${_EP_GIT_TAG}") + if(NOT git_tag) + set(git_tag "master") + endif() + + set(git_remote_name "${_EP_GIT_REMOTE_NAME}") + if(NOT git_remote_name) + set(git_remote_name "origin") + endif() + + set(git_init_submodules TRUE) + if(DEFINED _EP_GIT_SUBMODULES) + set(git_submodules "${_EP_GIT_SUBMODULES}") + if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW") + set(git_init_submodules FALSE) + endif() + endif() + + set(git_update_strategy "${_EP_GIT_REMOTE_UPDATE_STRATEGY}") + if(NOT git_update_strategy) + set(git_update_strategy "${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}") + endif() + if(NOT git_update_strategy) + set(git_update_strategy REBASE) + endif() + set(strategies CHECKOUT REBASE REBASE_CHECKOUT) + if(NOT git_update_strategy IN_LIST strategies) + message(FATAL_ERROR + "'${git_update_strategy}' is not one of the supported strategies: " + "${strategies}" + ) + endif() + + _ep_get_git_submodules_recurse(git_submodules_recurse) + + _ep_get_tls_version(${name} tls_version) + _ep_get_tls_verify(${name} tls_verify) + + set(update_script "${tmp_dir}/${name}-gitupdate.cmake") + list(APPEND file_deps ${update_script}) + _ep_write_gitupdate_script( + "${update_script}" + "${GIT_EXECUTABLE}" + "${git_tag}" + "${git_remote_name}" + "${git_init_submodules}" + "${git_submodules_recurse}" + "${git_submodules}" + "${git_repository}" + "${work_dir}" + "${git_update_strategy}" + "${tls_version}" + "${tls_verify}" + ) + set(cmd ${CMAKE_COMMAND} -Dcan_fetch=YES -P ${update_script}) + set(cmd_disconnected ${CMAKE_COMMAND} -Dcan_fetch=NO -P ${update_script}) + set(always 1) + elseif(hg_repository) + if(NOT HG_EXECUTABLE) + message(FATAL_ERROR "error: could not find hg for pull of ${name}") + endif() + set(work_dir ${source_dir}) + set(comment "Performing update step (hg pull) for '${name}'") + set(comment_disconnected "Performing disconnected update step for '${name}'") + + set(hg_tag "${_EP_HG_TAG}") + if(NOT hg_tag) + set(hg_tag "tip") + endif() + + if("${HG_VERSION_STRING}" STREQUAL "2.1") + set(notesAnchor + "#A2.1.1:_revert_pull_return_code_change.2C_compile_issue_on_OS_X" + ) + message(WARNING + "Mercurial 2.1 does not distinguish an empty pull from a failed pull: + http://mercurial.selenic.com/wiki/UpgradeNotes${notesAnchor} + http://thread.gmane.org/gmane.comp.version-control.mercurial.devel/47656 +Update to Mercurial >= 2.1.1. +") + endif() + + set(cmd + ${HG_EXECUTABLE} pull + COMMAND ${HG_EXECUTABLE} update ${hg_tag} + ) + set(cmd_disconnected ${HG_EXECUTABLE} update ${hg_tag}) + set(always 1) + endif() + + # We use configure_file() to write the update_info_file so that the file's + # timestamp is not updated if we don't change the contents + if(NOT DEFINED cmd_disconnected) + set(cmd_disconnected "${cmd}") + endif() + set(update_info_file ${stamp_dir}/${name}-update-info.txt) + list(APPEND file_deps ${update_info_file}) + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UpdateInfo.txt.in" + "${update_info_file}" + @ONLY + ) + + if(_EP_LOG_UPDATE) + set(log LOG 1) + else() + set(log "") + endif() + + if(_EP_USES_TERMINAL_UPDATE) + set(uses_terminal USES_TERMINAL 1) + else() + set(uses_terminal "") + endif() + + set(__cmdQuoted) + foreach(__item IN LISTS cmd) + string(APPEND __cmdQuoted " [==[${__item}]==]") + endforeach() + cmake_language(EVAL CODE " + ExternalProject_Add_Step(${name} update + INDEPENDENT TRUE + COMMENT \${comment} + COMMAND ${__cmdQuoted} + ALWAYS \${always} + EXCLUDE_FROM_MAIN \${update_disconnected} + WORKING_DIRECTORY \${work_dir} + DEPENDEES download + DEPENDS \${file_deps} + ${log} + ${uses_terminal} + )" + ) + if(update_disconnected) + if(NOT DEFINED comment_disconnected) + set(comment_disconnected "${comment}") + endif() + set(__cmdQuoted) + foreach(__item IN LISTS cmd_disconnected) + string(APPEND __cmdQuoted " [==[${__item}]==]") + endforeach() + + cmake_language(EVAL CODE " + ExternalProject_Add_Step(${name} update_disconnected + INDEPENDENT TRUE + COMMENT \${comment_disconnected} + COMMAND ${__cmdQuoted} + WORKING_DIRECTORY \${work_dir} + DEPENDEES download + DEPENDS \${file_deps} + ${log} + ${uses_terminal} + )" + ) + endif() + +endfunction() + + +function(_ep_add_patch_command name) + # The various _EP_... variables mentioned here and throughout this function + # are expected to already have been set by the caller via a call to + # _ep_parse_arguments() or ep_parse_arguments_to_vars(). Other variables + # with different names are assigned to for historical reasons only to keep + # the code more readable and minimize change. + + set(source_dir "${_EP_SOURCE_DIR}") + set(stamp_dir "${_EP_STAMP_DIR}") + + set(cmd "${_EP_PATCH_COMMAND}") + + set(work_dir) + if(DEFINED _EP_PATCH_COMMAND) + set(work_dir ${source_dir}) + endif() + + # We use configure_file() to write the patch_info_file so that the file's + # timestamp is not updated if we don't change the contents + set(patch_info_file ${stamp_dir}/${name}-patch-info.txt) + configure_file( + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/PatchInfo.txt.in" + "${patch_info_file}" + @ONLY + ) + + if(_EP_LOG_PATCH) + set(log LOG 1) + else() + set(log "") + endif() + + if(_EP_USES_TERMINAL_PATCH) + set(uses_terminal USES_TERMINAL 1) + else() + set(uses_terminal "") + endif() + + _ep_get_update_disconnected(update_disconnected ${name}) + + set(__cmdQuoted) + foreach(__item IN LISTS cmd) + string(APPEND __cmdQuoted " [==[${__item}]==]") + endforeach() + cmake_language(EVAL CODE " + ExternalProject_Add_Step(${name} patch + INDEPENDENT TRUE + COMMAND ${__cmdQuoted} + WORKING_DIRECTORY \${work_dir} + EXCLUDE_FROM_MAIN \${update_disconnected} + DEPENDEES update + DEPENDS \${patch_info_file} + ${log} + ${uses_terminal} + )" + ) + + if(update_disconnected) + cmake_language(EVAL CODE " + ExternalProject_Add_Step(${name} patch_disconnected + INDEPENDENT TRUE + COMMAND ${__cmdQuoted} + WORKING_DIRECTORY \${work_dir} + DEPENDEES update_disconnected + DEPENDS \${patch_info_file} + ${log} + ${uses_terminal} + )" + ) + endif() + +endfunction() + + +macro(_ep_get_add_keywords out_var) + set(${out_var} + # + # Directory options + # + PREFIX + TMP_DIR + STAMP_DIR + LOG_DIR + DOWNLOAD_DIR + SOURCE_DIR + BINARY_DIR + INSTALL_DIR + # + # Download step options + # + DOWNLOAD_COMMAND + # + URL + URL_HASH + URL_MD5 + DOWNLOAD_NAME + DOWNLOAD_EXTRACT_TIMESTAMP + DOWNLOAD_NO_EXTRACT + DOWNLOAD_NO_PROGRESS + TIMEOUT + INACTIVITY_TIMEOUT + HTTP_USERNAME + HTTP_PASSWORD + HTTP_HEADER + TLS_VERSION # Also used for git clone operations + TLS_VERIFY # Also used for git clone operations + TLS_CAINFO + NETRC + NETRC_FILE + # + GIT_REPOSITORY + GIT_TAG + GIT_REMOTE_NAME + GIT_SUBMODULES + GIT_SUBMODULES_RECURSE + GIT_SHALLOW + GIT_PROGRESS + GIT_CONFIG + GIT_REMOTE_UPDATE_STRATEGY + # + SVN_REPOSITORY + SVN_REVISION + SVN_USERNAME + SVN_PASSWORD + SVN_TRUST_CERT + # + HG_REPOSITORY + HG_TAG + # + CVS_REPOSITORY + CVS_MODULE + CVS_TAG + # + # Update step options + # + UPDATE_COMMAND + UPDATE_DISCONNECTED + # + # Patch step options + # + PATCH_COMMAND + # + # Configure step options + # + CONFIGURE_COMMAND + CMAKE_COMMAND + CMAKE_GENERATOR + CMAKE_GENERATOR_PLATFORM + CMAKE_GENERATOR_TOOLSET + CMAKE_GENERATOR_INSTANCE + CMAKE_ARGS + CMAKE_CACHE_ARGS + CMAKE_CACHE_DEFAULT_ARGS + SOURCE_SUBDIR + CONFIGURE_HANDLED_BY_BUILD + # + # Build step options + # + BUILD_COMMAND + BUILD_IN_SOURCE + BUILD_ALWAYS + BUILD_BYPRODUCTS + BUILD_JOB_SERVER_AWARE + # + # Install step options + # + INSTALL_COMMAND + INSTALL_BYPRODUCTS + # + # Test step options + # + TEST_COMMAND + TEST_BEFORE_INSTALL + TEST_AFTER_INSTALL + TEST_EXCLUDE_FROM_MAIN + # + # Logging options + # + LOG_DOWNLOAD + LOG_UPDATE + LOG_PATCH + LOG_CONFIGURE + LOG_BUILD + LOG_INSTALL + LOG_TEST + LOG_MERGED_STDOUTERR + LOG_OUTPUT_ON_FAILURE + # + # Terminal access options + # + USES_TERMINAL_DOWNLOAD + USES_TERMINAL_UPDATE + USES_TERMINAL_PATCH + USES_TERMINAL_CONFIGURE + USES_TERMINAL_BUILD + USES_TERMINAL_INSTALL + USES_TERMINAL_TEST + # + # Target options + # + DEPENDS + EXCLUDE_FROM_ALL + STEP_TARGETS + INDEPENDENT_STEP_TARGETS + # + # Miscellaneous options + # + LIST_SEPARATOR + # + # Internal options (undocumented) + # + EXTERNALPROJECT_INTERNAL_ARGUMENT_SEPARATOR + ) +endmacro() diff --git a/Tests/RunCMake/CMP0135/CMP0135-WARN-stderr.txt b/Tests/RunCMake/CMP0135/CMP0135-WARN-stderr.txt index 6bf944e..1632d63 100644 --- a/Tests/RunCMake/CMP0135/CMP0135-WARN-stderr.txt +++ b/Tests/RunCMake/CMP0135/CMP0135-WARN-stderr.txt @@ -1,4 +1,4 @@ -CMake Warning \(dev\) at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\): +CMake Warning \(dev\) at .*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy CMP0135 is not set\. The policy's OLD behavior will be used\. When using a URL download, the timestamps of extracted files should preferably be that of @@ -9,7 +9,7 @@ CMake Warning \(dev\) at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\): DOWNLOAD_EXTRACT_TIMESTAMP option with a value of true to avoid this robustness issue\. .* -CMake Warning \(dev\) at .*/Modules/FetchContent.cmake:[0-9]+ \(message\): +CMake Warning \(dev\) at .*/Modules/FetchContent\.cmake:[0-9]+ \(message\): The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy CMP0135 is not set\. The policy's OLD behavior will be used\. When using a URL download, the timestamps of extracted files should preferably be that of diff --git a/Tests/RunCMake/ExternalProject/NoOptions-stderr.txt b/Tests/RunCMake/ExternalProject/NoOptions-stderr.txt index 2fc7d29..72c4b81 100644 --- a/Tests/RunCMake/ExternalProject/NoOptions-stderr.txt +++ b/Tests/RunCMake/ExternalProject/NoOptions-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\): +^CMake Error at .*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): No download info given for 'MyProj' and its source directory: .*/Tests/RunCMake/ExternalProject/NoOptions-build/MyProj-prefix/src/MyProj diff --git a/Tests/RunCMake/ExternalProject/SourceEmpty-stderr.txt b/Tests/RunCMake/ExternalProject/SourceEmpty-stderr.txt index 07c6e87..8789dde 100644 --- a/Tests/RunCMake/ExternalProject/SourceEmpty-stderr.txt +++ b/Tests/RunCMake/ExternalProject/SourceEmpty-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\): +^CMake Error at .*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): No download info given for 'MyProj' and its source directory: .*/Tests/RunCMake/ExternalProject/SourceEmpty-build/SourceEmpty diff --git a/Tests/RunCMake/ExternalProject/SourceMissing-stderr.txt b/Tests/RunCMake/ExternalProject/SourceMissing-stderr.txt index 373f6e3..9ff2681 100644 --- a/Tests/RunCMake/ExternalProject/SourceMissing-stderr.txt +++ b/Tests/RunCMake/ExternalProject/SourceMissing-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\): +^CMake Error at .*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): No download info given for 'MyProj' and its source directory: .*/Tests/RunCMake/ExternalProject/SourceMissing-build/SourceMissing diff --git a/Tests/RunCMake/ExternalProject/TLSVersionBadArg-stderr.txt b/Tests/RunCMake/ExternalProject/TLSVersionBadArg-stderr.txt index 1231797..f0973ba 100644 --- a/Tests/RunCMake/ExternalProject/TLSVersionBadArg-stderr.txt +++ b/Tests/RunCMake/ExternalProject/TLSVersionBadArg-stderr.txt @@ -1,9 +1,9 @@ ^CMake Error at [^ -]*/Modules/ExternalProject\.cmake:[0-9]+ \(message\): +]*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): TLS_VERSION 'bad-arg' not known Call Stack \(most recent call first\): [^ -]*/Modules/ExternalProject\.cmake:[0-9]+ \(_ep_get_tls_version\) +]*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(_ep_get_tls_version\) [^ ]*/Modules/ExternalProject\.cmake:[0-9]+ \(_ep_add_download_command\) TLSVersionBadArg\.cmake:[0-9]+ \(ExternalProject_Add\) diff --git a/Tests/RunCMake/ExternalProject/TLSVersionBadEnv-stderr.txt b/Tests/RunCMake/ExternalProject/TLSVersionBadEnv-stderr.txt index 38b0fb8..4069159 100644 --- a/Tests/RunCMake/ExternalProject/TLSVersionBadEnv-stderr.txt +++ b/Tests/RunCMake/ExternalProject/TLSVersionBadEnv-stderr.txt @@ -1,9 +1,9 @@ ^CMake Error at [^ -]*/Modules/ExternalProject\.cmake:[0-9]+ \(message\): +]*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): ENV{CMAKE_TLS_VERSION} 'bad-env' not known Call Stack \(most recent call first\): [^ -]*/Modules/ExternalProject\.cmake:[0-9]+ \(_ep_get_tls_version\) +]*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(_ep_get_tls_version\) [^ ]*/Modules/ExternalProject\.cmake:[0-9]+ \(_ep_add_download_command\) TLSVersionBadEnv\.cmake:[0-9]+ \(ExternalProject_Add\) diff --git a/Tests/RunCMake/ExternalProject/TLSVersionBadVar-stderr.txt b/Tests/RunCMake/ExternalProject/TLSVersionBadVar-stderr.txt index aaec60b..a5f7d64 100644 --- a/Tests/RunCMake/ExternalProject/TLSVersionBadVar-stderr.txt +++ b/Tests/RunCMake/ExternalProject/TLSVersionBadVar-stderr.txt @@ -1,9 +1,9 @@ ^CMake Error at [^ -]*/Modules/ExternalProject\.cmake:[0-9]+ \(message\): +]*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(message\): CMAKE_TLS_VERSION 'bad-var' not known Call Stack \(most recent call first\): [^ -]*/Modules/ExternalProject\.cmake:[0-9]+ \(_ep_get_tls_version\) +]*/Modules/ExternalProject/shared_internal_commands\.cmake:[0-9]+ \(_ep_get_tls_version\) [^ ]*/Modules/ExternalProject\.cmake:[0-9]+ \(_ep_add_download_command\) TLSVersionBadVar\.cmake:[0-9]+ \(ExternalProject_Add\) |