From 173daad58de172ad5edbbf72117b5597c7339007 Mon Sep 17 00:00:00 2001
From: Craig Scott <craig.scott@crascit.com>
Date: Mon, 13 May 2024 20:24:03 +1000
Subject: 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
---
 Modules/ExternalProject.cmake                      | 1525 +------------------
 .../ExternalProject/shared_internal_commands.cmake | 1532 ++++++++++++++++++++
 Tests/RunCMake/CMP0135/CMP0135-WARN-stderr.txt     |    4 +-
 .../RunCMake/ExternalProject/NoOptions-stderr.txt  |    2 +-
 .../ExternalProject/SourceEmpty-stderr.txt         |    2 +-
 .../ExternalProject/SourceMissing-stderr.txt       |    2 +-
 .../ExternalProject/TLSVersionBadArg-stderr.txt    |    4 +-
 .../ExternalProject/TLSVersionBadEnv-stderr.txt    |    4 +-
 .../ExternalProject/TLSVersionBadVar-stderr.txt    |    4 +-
 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\)
-- 
cgit v0.12