summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorCraig Scott <craig.scott@crascit.com>2024-05-18 09:04:39 (GMT)
committerKitware Robot <kwrobot@kitware.com>2024-05-18 09:05:03 (GMT)
commit2d653179dcf55d98c10be1eba10f1cd075c9105c (patch)
tree525a364b3506b45b7017a4a44fd0bd24e6ecf827 /Modules
parentff12b19786557560ec24bc5ad6a084dd6e96616c (diff)
parent7bf15e49a848b2ff0afe2697027935e7bc9e4992 (diff)
downloadCMake-2d653179dcf55d98c10be1eba10f1cd075c9105c.zip
CMake-2d653179dcf55d98c10be1eba10f1cd075c9105c.tar.gz
CMake-2d653179dcf55d98c10be1eba10f1cd075c9105c.tar.bz2
Merge topic 'fetchcontent-direct'
7bf15e49a8 ExternalProject: Fix misleading git update output b2496bf14c FetchContent: Populate directly without a sub-build 173daad58d ExternalProject: Move more internal commands out of main file 462e583267 ExternalProject: Switch download, update and patch to use _EP_ vars 0ccc8e340d ExternalProject: Provide ExternalProject_Add keywords through a macro 91e1015722 ExternalProject: Don't treat YES as a keyword a1743ce1ef ExternalProject: Fix minor formatting error Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: scivision <michael@scivision.dev> Merge-request: !9513
Diffstat (limited to 'Modules')
-rw-r--r--Modules/ExternalProject.cmake1536
-rw-r--r--Modules/ExternalProject/download.cmake.in22
-rw-r--r--Modules/ExternalProject/extractfile.cmake.in14
-rw-r--r--Modules/ExternalProject/gitclone.cmake.in18
-rw-r--r--Modules/ExternalProject/gitupdate.cmake.in29
-rw-r--r--Modules/ExternalProject/hgclone.cmake.in15
-rw-r--r--Modules/ExternalProject/shared_internal_commands.cmake1812
-rw-r--r--Modules/ExternalProject/stepscript.cmake.in9
-rw-r--r--Modules/ExternalProject/verify.cmake.in6
-rw-r--r--Modules/FetchContent.cmake223
10 files changed, 2124 insertions, 1560 deletions
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index e3fc59c..86d83f5 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -1296,492 +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
- f
- keywords
- name
- ns
- args
-)
- # Transfer the arguments to this function into target properties for the
- # new custom target we just added so that we can set up all the build steps
- # correctly based on target properties.
- #
- # Because some keywords can be repeated, we can't use cmake_parse_arguments().
- # Instead, we loop through ARGN 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.
-
- 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)$")
- if(arg IN_LIST keywords)
- set(is_value 0)
- endif()
- endif()
-
- if(is_value)
- if(key)
- # Value
- if(NOT arg STREQUAL "")
- set_property(TARGET ${name} APPEND PROPERTY ${ns}${key} "${arg}")
- else()
- get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
- if(have_key)
- get_property(value TARGET ${name} PROPERTY ${ns}${key})
- set_property(TARGET ${name} PROPERTY ${ns}${key} "${value};${arg}")
- else()
- set_property(TARGET ${name} PROPERTY ${ns}${key} "${arg}")
- endif()
- endif()
- else()
- # Missing Keyword
- message(AUTHOR_WARNING
- "value '${arg}' with no previous keyword in ${f}"
- )
- endif()
- else()
- set(key "${arg}")
- 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)
- set(tls_version_regex "^1\\.[0-3]$")
- get_property(tls_version TARGET ${name} PROPERTY _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)
- get_property(tls_verify TARGET ${name} PROPERTY _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)
- get_property(tls_cainfo TARGET ${name} PROPERTY _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)
- get_property(netrc TARGET ${name} PROPERTY _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)
- get_property(netrc_file TARGET ${name} PROPERTY _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)
@@ -1834,6 +1354,7 @@ function(_ep_set_directories name)
endif()
file(TO_CMAKE_PATH "${${var}_dir}" ${var}_dir)
set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
+ set(_EP_${VAR}_DIR "${${var}_dir}" PARENT_SCOPE)
endforeach()
# Special case for default log directory based on stamp directory.
@@ -1846,10 +1367,12 @@ function(_ep_set_directories name)
endif()
file(TO_CMAKE_PATH "${log_dir}" log_dir)
set_property(TARGET ${name} PROPERTY _EP_LOG_DIR "${log_dir}")
+ set(_EP_LOG_DIR "${log_dir}" PARENT_SCOPE)
get_property(source_subdir TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR)
if(NOT source_subdir)
set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "")
+ set(_EP_SOURCE_SUBDIR "" PARENT_SCOPE)
elseif(IS_ABSOLUTE "${source_subdir}")
message(FATAL_ERROR
"External project ${name} has non-relative SOURCE_SUBDIR!"
@@ -1859,6 +1382,7 @@ function(_ep_set_directories name)
# behaves as expected.
file(TO_CMAKE_PATH "${source_subdir}" source_subdir)
set_property(TARGET ${name} PROPERTY _EP_SOURCE_SUBDIR "/${source_subdir}")
+ set(_EP_SOURCE_SUBDIR "/${source_subdir}" PARENT_SCOPE)
endif()
if(build_in_source)
get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR)
@@ -1866,10 +1390,12 @@ function(_ep_set_directories name)
set_property(TARGET ${name} PROPERTY
_EP_BINARY_DIR "${source_dir}/${source_subdir}"
)
+ set(_EP_BINARY_DIR "${source_dir}/${source_subdir}" PARENT_SCOPE)
else()
set_property(TARGET ${name} PROPERTY
_EP_BINARY_DIR "${source_dir}"
)
+ set(_EP_BINARY_DIR "${source_dir}" PARENT_SCOPE)
endif()
endif()
@@ -2128,6 +1654,7 @@ function(_ep_get_build_command
set(${cmd_var} "${cmd}" PARENT_SCOPE)
endfunction()
+
function(_ep_write_log_script
name
step
@@ -2291,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)
@@ -2486,6 +2014,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)
@@ -2875,908 +2407,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 property. Default is ON, which sets
- # git_submodules_recurse output variable to "--recursive". Otherwise, the
- # output variable is set to an empty value "".
- get_property(git_submodules_recurse_set
- TARGET ${name}
- PROPERTY _EP_GIT_SUBMODULES_RECURSE
- SET
- )
- if(NOT git_submodules_recurse_set)
- set(recurseFlag "--recursive")
- else()
- get_property(git_submodules_recurse_value
- TARGET ${name}
- PROPERTY _EP_GIT_SUBMODULES_RECURSE
- )
- if(git_submodules_recurse_value)
- 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)
- ExternalProject_Get_Property(${name}
- source_dir
- stamp_dir
- download_dir
- tmp_dir
- )
-
- get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
- get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
- get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
- get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
- get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
- get_property(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
- get_property(url TARGET ${name} PROPERTY _EP_URL)
- get_property(fname TARGET ${name} PROPERTY _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(cmd_set)
- 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()
-
- get_target_property(cvs_module ${name} _EP_CVS_MODULE)
- if(NOT cvs_module)
- message(FATAL_ERROR "error: no CVS_MODULE")
- endif()
-
- get_property(cvs_tag TARGET ${name} PROPERTY _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()
-
- get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
- get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
- get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
- get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
- get_property(uses_terminal
- TARGET ${name}
- PROPERTY _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 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}
- 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)
-
- get_property(git_tag TARGET ${name} PROPERTY _EP_GIT_TAG)
- if(NOT git_tag)
- set(git_tag "master")
- endif()
-
- set(git_init_submodules TRUE)
- get_property(git_submodules_set
- TARGET ${name}
- PROPERTY _EP_GIT_SUBMODULES SET
- )
- if(git_submodules_set)
- get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
- if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
- set(git_init_submodules FALSE)
- endif()
- endif()
-
- get_property(git_remote_name TARGET ${name} PROPERTY _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)
- get_property(git_shallow TARGET ${name} PROPERTY _EP_GIT_SHALLOW)
- get_property(git_progress TARGET ${name} PROPERTY _EP_GIT_PROGRESS)
- get_property(git_config TARGET ${name} PROPERTY _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()
-
- get_property(hg_tag TARGET ${name} PROPERTY _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)
- get_property(hash TARGET ${name} PROPERTY _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()
- get_property(md5 TARGET ${name} PROPERTY _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()
- get_property(no_extract
- TARGET "${name}"
- PROPERTY _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})
- get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
- get_property(inactivity_timeout
- TARGET ${name}
- PROPERTY _EP_INACTIVITY_TIMEOUT
- )
- get_property(no_progress
- TARGET ${name}
- PROPERTY _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)
- get_property(http_username TARGET ${name} PROPERTY _EP_HTTP_USERNAME)
- get_property(http_password TARGET ${name} PROPERTY _EP_HTTP_PASSWORD)
- get_property(http_headers TARGET ${name} PROPERTY _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)
- get_target_property(extract_timestamp ${name}
- _EP_DOWNLOAD_EXTRACT_TIMESTAMP
- )
- if(no_extract)
- if(NOT extract_timestamp STREQUAL "extract_timestamp-NOTFOUND")
- 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(extract_timestamp STREQUAL "extract_timestamp-NOTFOUND")
- # 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
- )
-
- get_property(log
- TARGET ${name}
- PROPERTY _EP_LOG_DOWNLOAD
- )
- if(log)
- set(log LOG 1)
- else()
- set(log "")
- endif()
-
- get_property(uses_terminal
- TARGET ${name}
- PROPERTY _EP_USES_TERMINAL_DOWNLOAD
- )
- if(uses_terminal)
- 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)
- get_property(update_disconnected_set
- TARGET ${name}
- PROPERTY _EP_UPDATE_DISCONNECTED
- SET
- )
- if(update_disconnected_set)
- get_property(update_disconnected
- TARGET ${name}
- PROPERTY _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)
- ExternalProject_Get_Property(${name} source_dir stamp_dir tmp_dir)
-
- get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
- get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
- get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
- get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
- get_property(git_repository TARGET ${name} PROPERTY _EP_GIT_REPOSITORY)
- get_property(hg_repository TARGET ${name} PROPERTY _EP_HG_REPOSITORY )
-
- _ep_get_update_disconnected(update_disconnected ${name})
-
- set(work_dir)
- set(comment)
- set(always)
- set(file_deps)
-
- if(cmd_set)
- 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}'")
- get_property(cvs_tag TARGET ${name} PROPERTY _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}'")
- get_property(svn_revision TARGET ${name} PROPERTY _EP_SVN_REVISION)
- get_property(svn_username TARGET ${name} PROPERTY _EP_SVN_USERNAME)
- get_property(svn_password TARGET ${name} PROPERTY _EP_SVN_PASSWORD)
- get_property(svn_trust_cert TARGET ${name} PROPERTY _EP_SVN_TRUST_CERT)
- get_property(uses_terminal TARGET ${name} PROPERTY _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}'")
-
- get_property(git_tag
- TARGET ${name}
- PROPERTY _EP_GIT_TAG
- )
- if(NOT git_tag)
- set(git_tag "master")
- endif()
-
- get_property(git_remote_name
- TARGET ${name}
- PROPERTY _EP_GIT_REMOTE_NAME
- )
- if(NOT git_remote_name)
- set(git_remote_name "origin")
- endif()
-
- set(git_init_submodules TRUE)
- get_property(git_submodules_set
- TARGET ${name}
- PROPERTY _EP_GIT_SUBMODULES
- SET
- )
- if(git_submodules_set)
- get_property(git_submodules
- TARGET ${name}
- PROPERTY _EP_GIT_SUBMODULES
- )
- if(git_submodules STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
- set(git_init_submodules FALSE)
- endif()
- endif()
-
- get_property(git_update_strategy
- TARGET ${name}
- PROPERTY _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}'")
-
- get_property(hg_tag
- TARGET ${name}
- PROPERTY _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
- )
-
- get_property(log
- TARGET ${name}
- PROPERTY _EP_LOG_UPDATE
- )
- if(log)
- set(log LOG 1)
- else()
- set(log "")
- endif()
-
- get_property(uses_terminal
- TARGET ${name}
- PROPERTY _EP_USES_TERMINAL_UPDATE
- )
- if(uses_terminal)
- 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)
- ExternalProject_Get_Property(${name} source_dir stamp_dir)
-
- get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
- get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
-
- set(work_dir)
-
- if(cmd_set)
- 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
- )
-
- get_property(log
- TARGET ${name}
- PROPERTY _EP_LOG_PATCH
- )
- if(log)
- set(log LOG 1)
- else()
- set(log "")
- endif()
-
- get_property(uses_terminal
- TARGET ${name}
- PROPERTY _EP_USES_TERMINAL_PATCH
- )
- if(uses_terminal)
- 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)
@@ -3804,6 +2434,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}
@@ -3959,6 +2590,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)
@@ -4327,144 +2959,7 @@ function(ExternalProject_Add name)
_EP_CMP0114 "${cmp0114}"
)
- set(keywords
- #
- # 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
- )
+ _ep_get_add_keywords(keywords)
_ep_parse_arguments(
ExternalProject_Add
"${keywords}"
@@ -4494,6 +2989,7 @@ function(ExternalProject_Add name)
get_filename_component(work_dir "${source_dir}" PATH)
_ep_resolve_git_remote(resolved_git_repository "${repo}" "${cmp0150}" "${work_dir}")
set_property(TARGET ${name} PROPERTY _EP_GIT_REPOSITORY ${resolved_git_repository})
+ set(_EP_GIT_REPOSITORY "${resolved_git_repository}")
endif()
# The 'complete' step depends on all other steps and creates a
diff --git a/Modules/ExternalProject/download.cmake.in b/Modules/ExternalProject/download.cmake.in
index f21a91a..77d43d7 100644
--- a/Modules/ExternalProject/download.cmake.in
+++ b/Modules/ExternalProject/download.cmake.in
@@ -21,14 +21,14 @@ function(check_file_hash has_hash hash_is_good)
set("${has_hash}" TRUE PARENT_SCOPE)
- message(STATUS "verifying file...
+ message(VERBOSE "verifying file...
file='@LOCAL@'")
file("@ALGO@" "@LOCAL@" actual_value)
if(NOT "${actual_value}" STREQUAL "@EXPECT_VALUE@")
set("${hash_is_good}" FALSE PARENT_SCOPE)
- message(STATUS "@ALGO@ hash of
+ message(VERBOSE "@ALGO@ hash of
@LOCAL@
does not match expected value
expected: '@EXPECT_VALUE@'
@@ -44,7 +44,7 @@ function(sleep_before_download attempt)
endif()
if(attempt EQUAL 1)
- message(STATUS "Retrying...")
+ message(VERBOSE "Retrying...")
return()
endif()
@@ -66,7 +66,7 @@ function(sleep_before_download attempt)
set(sleep_seconds 1200)
endif()
- message(STATUS "Retry after ${sleep_seconds} seconds (attempt #${attempt}) ...")
+ message(VERBOSE "Retry after ${sleep_seconds} seconds (attempt #${attempt}) ...")
execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep "${sleep_seconds}")
endfunction()
@@ -75,17 +75,17 @@ if(EXISTS "@LOCAL@")
check_file_hash(has_hash hash_is_good)
if(has_hash)
if(hash_is_good)
- message(STATUS "File already exists and hash match (skip download):
+ message(VERBOSE "File already exists and hash match (skip download):
file='@LOCAL@'
@ALGO@='@EXPECT_VALUE@'"
)
return()
else()
- message(STATUS "File already exists but hash mismatch. Removing...")
+ message(VERBOSE "File already exists but hash mismatch. Removing...")
file(REMOVE "@LOCAL@")
endif()
else()
- message(STATUS "File already exists but no hash specified (use URL_HASH):
+ message(VERBOSE "File already exists but no hash specified (use URL_HASH):
file='@LOCAL@'
Old file will be removed and new file downloaded from URL."
)
@@ -95,7 +95,7 @@ endif()
set(retry_number 5)
-message(STATUS "Downloading...
+message(VERBOSE "Downloading...
dst='@LOCAL@'
timeout='@TIMEOUT_MSG@'
inactivity timeout='@INACTIVITY_TIMEOUT_MSG@'"
@@ -109,7 +109,7 @@ foreach(i RANGE ${retry_number})
endif()
foreach(url IN ITEMS @REMOTE@)
if(NOT url IN_LIST skip_url_list)
- message(STATUS "Using src='${url}'")
+ message(VERBOSE "Using src='${url}'")
@TLS_VERSION_CODE@
@TLS_VERIFY_CODE@
@@ -135,10 +135,10 @@ foreach(i RANGE ${retry_number})
if(status_code EQUAL 0)
check_file_hash(has_hash hash_is_good)
if(has_hash AND NOT hash_is_good)
- message(STATUS "Hash mismatch, removing...")
+ message(VERBOSE "Hash mismatch, removing...")
file(REMOVE "@LOCAL@")
else()
- message(STATUS "Downloading... done")
+ message(VERBOSE "Downloading... done")
return()
endif()
else()
diff --git a/Modules/ExternalProject/extractfile.cmake.in b/Modules/ExternalProject/extractfile.cmake.in
index 984565b..39daaff 100644
--- a/Modules/ExternalProject/extractfile.cmake.in
+++ b/Modules/ExternalProject/extractfile.cmake.in
@@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.5)
get_filename_component(filename "@filename@" ABSOLUTE)
get_filename_component(directory "@directory@" ABSOLUTE)
-message(STATUS "extracting...
+message(VERBOSE "extracting...
src='${filename}'
dst='${directory}'"
)
@@ -28,21 +28,21 @@ file(MAKE_DIRECTORY "${ut_dir}")
# Extract it:
#
-message(STATUS "extracting... [tar @args@]")
+message(VERBOSE "extracting... [tar @args@]")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar @args@ ${filename} @options@
WORKING_DIRECTORY ${ut_dir}
RESULT_VARIABLE rv
)
if(NOT rv EQUAL 0)
- message(STATUS "extracting... [error clean up]")
+ message(VERBOSE "extracting... [error clean up]")
file(REMOVE_RECURSE "${ut_dir}")
message(FATAL_ERROR "Extract of '${filename}' failed")
endif()
# Analyze what came out of the tar file:
#
-message(STATUS "extracting... [analysis]")
+message(VERBOSE "extracting... [analysis]")
file(GLOB contents "${ut_dir}/*")
list(REMOVE_ITEM contents "${ut_dir}/.DS_Store")
list(LENGTH contents n)
@@ -52,14 +52,14 @@ endif()
# Move "the one" directory to the final directory:
#
-message(STATUS "extracting... [rename]")
+message(VERBOSE "extracting... [rename]")
file(REMOVE_RECURSE ${directory})
get_filename_component(contents ${contents} ABSOLUTE)
file(RENAME ${contents} ${directory})
# Clean up:
#
-message(STATUS "extracting... [clean up]")
+message(VERBOSE "extracting... [clean up]")
file(REMOVE_RECURSE "${ut_dir}")
-message(STATUS "extracting... done")
+message(VERBOSE "extracting... done")
diff --git a/Modules/ExternalProject/gitclone.cmake.in b/Modules/ExternalProject/gitclone.cmake.in
index 94b329a..93424ed 100644
--- a/Modules/ExternalProject/gitclone.cmake.in
+++ b/Modules/ExternalProject/gitclone.cmake.in
@@ -5,16 +5,26 @@ cmake_minimum_required(VERSION 3.5)
if(EXISTS "@gitclone_stampfile@" AND EXISTS "@gitclone_infofile@" AND
"@gitclone_stampfile@" IS_NEWER_THAN "@gitclone_infofile@")
- message(STATUS
+ message(VERBOSE
"Avoiding repeated git clone, stamp file is up to date: "
"'@gitclone_stampfile@'"
)
return()
endif()
+# Even at VERBOSE level, we don't want to see the commands executed, but
+# enabling them to be shown for DEBUG may be useful to help diagnose problems.
+cmake_language(GET_MESSAGE_LOG_LEVEL active_log_level)
+if(active_log_level MATCHES "DEBUG|TRACE")
+ set(maybe_show_command "COMMAND_ECHO STDOUT")
+else()
+ set(maybe_show_command "")
+endif()
+
execute_process(
COMMAND ${CMAKE_COMMAND} -E rm -rf "@source_dir@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
message(FATAL_ERROR "Failed to remove directory: '@source_dir@'")
@@ -29,11 +39,12 @@ while(error_code AND number_of_tries LESS 3)
clone @git_clone_options@ "@git_repository@" "@src_name@"
WORKING_DIRECTORY "@work_dir@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
math(EXPR number_of_tries "${number_of_tries} + 1")
endwhile()
if(number_of_tries GREATER 1)
- message(STATUS "Had to git clone more than once: ${number_of_tries} times.")
+ message(NOTICE "Had to git clone more than once: ${number_of_tries} times.")
endif()
if(error_code)
message(FATAL_ERROR "Failed to clone repository: '@git_repository@'")
@@ -44,6 +55,7 @@ execute_process(
checkout "@git_tag@" @git_checkout_explicit--@
WORKING_DIRECTORY "@work_dir@/@src_name@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
message(FATAL_ERROR "Failed to checkout tag: '@git_tag@'")
@@ -56,6 +68,7 @@ if(init_submodules)
submodule update @git_submodules_recurse@ --init @git_submodules@
WORKING_DIRECTORY "@work_dir@/@src_name@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
endif()
if(error_code)
@@ -67,6 +80,7 @@ endif()
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy "@gitclone_infofile@" "@gitclone_stampfile@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
message(FATAL_ERROR "Failed to copy script-last-run stamp file: '@gitclone_stampfile@'")
diff --git a/Modules/ExternalProject/gitupdate.cmake.in b/Modules/ExternalProject/gitupdate.cmake.in
index 171aa7b..4e3fba6 100644
--- a/Modules/ExternalProject/gitupdate.cmake.in
+++ b/Modules/ExternalProject/gitupdate.cmake.in
@@ -3,12 +3,22 @@
cmake_minimum_required(VERSION 3.5)
+# Even at VERBOSE level, we don't want to see the commands executed, but
+# enabling them to be shown for DEBUG may be useful to help diagnose problems.
+cmake_language(GET_MESSAGE_LOG_LEVEL active_log_level)
+if(active_log_level MATCHES "DEBUG|TRACE")
+ set(maybe_show_command "COMMAND_ECHO STDOUT")
+else()
+ set(maybe_show_command "")
+endif()
+
function(do_fetch)
message(VERBOSE "Fetching latest from the remote @git_remote_name@")
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git fetch --tags --force "@git_remote_name@"
WORKING_DIRECTORY "@work_dir@"
COMMAND_ERROR_IS_FATAL LAST
+ ${maybe_show_command}
)
endfunction()
@@ -34,6 +44,9 @@ if(head_sha STREQUAL "")
message(FATAL_ERROR "Failed to get the hash for HEAD:\n${error_msg}")
endif()
+if("${can_fetch}" STREQUAL "")
+ set(can_fetch "@can_fetch_default@")
+endif()
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git show-ref "@git_tag@"
@@ -57,7 +70,7 @@ elseif(show_ref_output MATCHES "^[a-z0-9]+[ \\t]+refs/tags/")
# FIXME: We should provide an option to always fetch for this case
get_hash_for_ref("@git_tag@" tag_sha error_msg)
if(tag_sha STREQUAL head_sha)
- message(VERBOSE "Already at requested tag: ${tag_sha}")
+ message(VERBOSE "Already at requested tag: @git_tag@")
return()
endif()
@@ -97,7 +110,7 @@ else()
# because it can be confusing for users to see a failed git command.
# That failure is being handled here, so it isn't an error.
if(NOT error_msg STREQUAL "")
- message(VERBOSE "${error_msg}")
+ message(DEBUG "${error_msg}")
endif()
do_fetch()
set(checkout_name "@git_tag@")
@@ -181,6 +194,7 @@ if(need_stash)
COMMAND "@git_EXECUTABLE@" --git-dir=.git stash save @git_stash_save_options@
WORKING_DIRECTORY "@work_dir@"
COMMAND_ERROR_IS_FATAL ANY
+ ${maybe_show_command}
)
endif()
@@ -189,6 +203,7 @@ if(git_update_strategy STREQUAL "CHECKOUT")
COMMAND "@git_EXECUTABLE@" --git-dir=.git checkout "${checkout_name}"
WORKING_DIRECTORY "@work_dir@"
COMMAND_ERROR_IS_FATAL ANY
+ ${maybe_show_command}
)
else()
execute_process(
@@ -203,6 +218,7 @@ else()
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git rebase --abort
WORKING_DIRECTORY "@work_dir@"
+ ${maybe_show_command}
)
if(NOT git_update_strategy STREQUAL "REBASE_CHECKOUT")
@@ -211,6 +227,7 @@ else()
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git stash pop --index --quiet
WORKING_DIRECTORY "@work_dir@"
+ ${maybe_show_command}
)
endif()
message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'."
@@ -236,12 +253,14 @@ else()
${tag_name}
WORKING_DIRECTORY "@work_dir@"
COMMAND_ERROR_IS_FATAL ANY
+ ${maybe_show_command}
)
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git checkout "${checkout_name}"
WORKING_DIRECTORY "@work_dir@"
COMMAND_ERROR_IS_FATAL ANY
+ ${maybe_show_command}
)
endif()
endif()
@@ -252,27 +271,32 @@ if(need_stash)
COMMAND "@git_EXECUTABLE@" --git-dir=.git stash pop --index --quiet
WORKING_DIRECTORY "@work_dir@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
# Stash pop --index failed: Try again dropping the index
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git reset --hard --quiet
WORKING_DIRECTORY "@work_dir@"
+ ${maybe_show_command}
)
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git stash pop --quiet
WORKING_DIRECTORY "@work_dir@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
# Stash pop failed: Restore previous state.
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git reset --hard --quiet ${head_sha}
WORKING_DIRECTORY "@work_dir@"
+ ${maybe_show_command}
)
execute_process(
COMMAND "@git_EXECUTABLE@" --git-dir=.git stash pop --index --quiet
WORKING_DIRECTORY "@work_dir@"
+ ${maybe_show_command}
)
message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'."
"\nYou will have to resolve the conflicts manually")
@@ -288,5 +312,6 @@ if(init_submodules)
submodule update @git_submodules_recurse@ --init @git_submodules@
WORKING_DIRECTORY "@work_dir@"
COMMAND_ERROR_IS_FATAL ANY
+ ${maybe_show_command}
)
endif()
diff --git a/Modules/ExternalProject/hgclone.cmake.in b/Modules/ExternalProject/hgclone.cmake.in
index e2b55ba..993ab7f 100644
--- a/Modules/ExternalProject/hgclone.cmake.in
+++ b/Modules/ExternalProject/hgclone.cmake.in
@@ -5,16 +5,26 @@ cmake_minimum_required(VERSION 3.5)
if(EXISTS "@hgclone_stampfile@" AND EXISTS "@hgclone_infofile@" AND
"@hgclone_stampfile@" IS_NEWER_THAN "@hgclone_infofile@")
- message(STATUS
+ message(VERBOSE
"Avoiding repeated hg clone, stamp file is up to date: "
"'@hgclone_stampfile@'"
)
return()
endif()
+# Even at VERBOSE level, we don't want to see the commands executed, but
+# enabling them to be shown for DEBUG may be useful to help diagnose problems.
+cmake_language(GET_MESSAGE_LOG_LEVEL active_log_level)
+if(active_log_level MATCHES "DEBUG|TRACE")
+ set(maybe_show_command "COMMAND_ECHO STDOUT")
+else()
+ set(maybe_show_command "")
+endif()
+
execute_process(
COMMAND ${CMAKE_COMMAND} -E rm -rf "@source_dir@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
message(FATAL_ERROR "Failed to remove directory: '@source_dir@'")
@@ -24,6 +34,7 @@ execute_process(
COMMAND "@hg_EXECUTABLE@" clone -U "@hg_repository@" "@src_name@"
WORKING_DIRECTORY "@work_dir@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
message(FATAL_ERROR "Failed to clone repository: '@hg_repository@'")
@@ -33,6 +44,7 @@ execute_process(
COMMAND "@hg_EXECUTABLE@" update @hg_tag@
WORKING_DIRECTORY "@work_dir@/@src_name@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
message(FATAL_ERROR "Failed to checkout tag: '@hg_tag@'")
@@ -43,6 +55,7 @@ endif()
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy "@hgclone_infofile@" "@hgclone_stampfile@"
RESULT_VARIABLE error_code
+ ${maybe_show_command}
)
if(error_code)
message(FATAL_ERROR "Failed to copy script-last-run stamp file: '@hgclone_stampfile@'")
diff --git a/Modules/ExternalProject/shared_internal_commands.cmake b/Modules/ExternalProject/shared_internal_commands.cmake
index ca3cd9f..6c4f61a 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,1812 @@ 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_script_commands script_var work_dir cmd)
+ # We only support a subset of what ep_replace_location_tags() handles
+ set(location_tags
+ SOURCE_DIR
+ SOURCE_SUBDIR
+ BINARY_DIR
+ TMP_DIR
+ DOWNLOAD_DIR
+ DOWNLOADED_FILE
+ )
+
+ # There can be multiple COMMANDs, but we have to split those up to
+ # one command per call to execute_process()
+ set(execute_process_cmd
+ "execute_process(\n"
+ " WORKING_DIRECTORY \"${work_dir}\"\n"
+ " COMMAND_ERROR_IS_FATAL LAST\n"
+ )
+ cmake_language(GET_MESSAGE_LOG_LEVEL active_log_level)
+ if(active_log_level MATCHES "VERBOSE|DEBUG|TRACE")
+ string(APPEND execute_process_cmd " COMMAND_ECHO STDOUT\n")
+ endif()
+ string(APPEND execute_process_cmd " COMMAND ")
+
+ string(APPEND ${script_var} "${execute_process_cmd}")
+
+ foreach(cmd_arg IN LISTS cmd)
+ if(cmd_arg STREQUAL "COMMAND")
+ string(APPEND ${script_var} "\n)\n${execute_process_cmd}")
+ else()
+ if(_EP_LIST_SEPARATOR)
+ string(REPLACE "${_EP_LIST_SEPARATOR}" "\\;" cmd_arg "${cmd_arg}")
+ endif()
+ foreach(dir IN LISTS location_tags)
+ string(REPLACE "<${dir}>" "${_EP_${dir}}" cmd_arg "${cmd_arg}")
+ endforeach()
+ string(APPEND ${script_var} " [====[${cmd_arg}]====]")
+ endif()
+ endforeach()
+
+ string(APPEND ${script_var} "\n)")
+ set(${script_var} "${${script_var}}" PARENT_SCOPE)
+endfunction()
+
+
+function(_ep_add_download_command name)
+ set(noValueOptions )
+ set(singleValueOptions
+ SCRIPT_FILE # These should only be used by FetchContent
+ DEPENDS_VARIABLE #
+ )
+ set(multiValueOptions )
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${noValueOptions}" "${singleValueOptions}" "${multiValueOptions}"
+ )
+
+ # 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(step_script_contents)
+ set(depends)
+ set(comment)
+ set(work_dir)
+ set(extra_repo_info)
+
+ if(DEFINED _EP_DOWNLOAD_COMMAND)
+ set(work_dir ${download_dir})
+ set(method custom)
+ if(NOT "x${cmd}" STREQUAL "x" AND arg_SCRIPT_FILE)
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ endif()
+
+ 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}
+ )
+ if(arg_SCRIPT_FILE)
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ endif()
+
+ 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}
+ )
+ if(arg_SCRIPT_FILE)
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ endif()
+
+ 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.
+ #
+ set(clone_script ${tmp_dir}/${name}-gitclone.cmake)
+ _ep_write_gitclone_script(
+ ${clone_script}
+ ${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}
+ -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
+ -P ${clone_script}
+ )
+
+ if(arg_SCRIPT_FILE)
+ set(step_script_contents "include(\"${clone_script}\")")
+ list(APPEND depends ${clone_script})
+ endif()
+
+ 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.
+ #
+ set(clone_script ${tmp_dir}/${name}-hgclone.cmake)
+ _ep_write_hgclone_script(
+ ${clone_script}
+ ${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}
+ -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
+ -P ${clone_script}
+ )
+
+ if(arg_SCRIPT_FILE)
+ set(step_script_contents "include(\"${clone_script}\")")
+ list(APPEND depends ${clone_script})
+ endif()
+
+ 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}
+ )
+ if(arg_SCRIPT_FILE)
+ # While it may be tempting to implement the two operations directly
+ # with file(), the behavior is different. file(COPY) preserves input
+ # file timestamps, which we don't want. Therefore, still use the same
+ # external commands so that we get the same behavior.
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ endif()
+ else()
+ set(no_extract "${_EP_DOWNLOAD_NO_EXTRACT}")
+ string(APPEND extra_repo_info "no_extract=${no_extract}\n")
+ set(verify_script "${stamp_dir}/verify-${name}.cmake")
+ 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}
+ -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
+ -P "${download_script}"
+ COMMAND
+ )
+ if(arg_SCRIPT_FILE)
+ set(step_script_contents "include(\"${download_script}\")\n")
+ endif()
+
+ 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 "${verify_script}" "")
+
+ # 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(
+ "${verify_script}"
+ "${file}"
+ "${hash}"
+ )
+ endif()
+ list(APPEND cmd ${CMAKE_COMMAND}
+ -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
+ -P ${verify_script}
+ )
+ if(arg_SCRIPT_FILE)
+ string(APPEND step_script_contents "include(\"${verify_script}\")\n")
+ list(APPEND depends ${verify_script})
+ endif()
+ 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()
+ if(arg_SCRIPT_FILE)
+ # There's no target to record the location of the downloaded file.
+ # Instead, we copy it to the source directory within the script,
+ # which is what FetchContent always does in this situation.
+ cmake_path(SET safe_file NORMALIZE "${file}")
+ cmake_path(GET safe_file FILENAME filename)
+ string(APPEND step_script_contents
+ "file(COPY_FILE\n"
+ " \"${file}\"\n"
+ " \"${source_dir}/${filename}\"\n"
+ " ONLY_IF_DIFFERENT\n"
+ " INPUT_MAY_BE_RECENT\n"
+ ")"
+ )
+ list(APPEND depends ${source_dir}/${filename})
+ else()
+ set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file})
+ endif()
+ 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()
+ set(extract_script "${stamp_dir}/extract-${name}.cmake")
+ _ep_write_extractfile_script(
+ "${extract_script}"
+ "${name}"
+ "${file}"
+ "${source_dir}"
+ "${options}"
+ )
+ list(APPEND cmd
+ COMMAND ${CMAKE_COMMAND}
+ -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
+ -P ${extract_script}
+ )
+ if(arg_SCRIPT_FILE)
+ string(APPEND step_script_contents "include(\"${extract_script}\")\n")
+ list(APPEND depends ${extract_script})
+ endif()
+ 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()
+ if(arg_SCRIPT_FILE)
+ set(step_script_contents "message(VERBOSE [[Using SOURCE_DIR as is]])")
+ 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(arg_SCRIPT_FILE)
+ set(step_name download)
+ configure_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/stepscript.cmake.in"
+ "${arg_SCRIPT_FILE}"
+ @ONLY
+ )
+ set(${arg_DEPENDS_VARIABLE} "${depends}" PARENT_SCOPE)
+ return()
+ endif()
+
+ # Nothing below this point is applicable when we've been asked to put the
+ # download step in a script file (which is the FetchContent case).
+
+ 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)
+ set(noValueOptions )
+ set(singleValueOptions
+ SCRIPT_FILE # These should only be used by FetchContent
+ DEPEND_VARIABLE #
+ )
+ set(multiValueOptions )
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${noValueOptions}" "${singleValueOptions}" "${multiValueOptions}"
+ )
+
+ # 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)
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ 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)
+
+ if(arg_SCRIPT_FILE)
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ endif()
+
+ 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)
+
+ if(arg_SCRIPT_FILE)
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ endif()
+
+ 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
+ -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
+ -P ${update_script}
+ )
+ set(cmd_disconnected ${CMAKE_COMMAND}
+ -Dcan_fetch=NO
+ -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE
+ -P ${update_script}
+ )
+ set(always 1)
+
+ if(arg_SCRIPT_FILE)
+ if(update_disconnected)
+ set(can_fetch_default NO)
+ else()
+ set(can_fetch_default YES)
+ endif()
+ set(step_script_contents "include(\"${update_script}\")")
+ endif()
+
+ 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)
+
+ if(arg_SCRIPT_FILE)
+ # These commands are simple, and we know whether updates need to be
+ # disconnected or not for this case, so write them directly instead of
+ # forming them from "cmd" and "cmd_disconnected".
+ if(NOT update_disconnected)
+ string(APPEND step_script_contents
+ "execute_process(\n"
+ " WORKING_DIRECTORY \"${work_dir}\"\n"
+ " COMMAND_ERROR_IS_FATAL LAST\n"
+ " COMMAND \"${HG_EXECUTABLE}\" pull\n"
+ ")"
+ )
+ endif()
+ string(APPEND step_script_contents
+ "execute_process(\n"
+ " WORKING_DIRECTORY \"${work_dir}\"\n"
+ " COMMAND_ERROR_IS_FATAL LAST\n"
+ " COMMAND \"${HG_EXECUTABLE}\" update \"${hg_tag}\"\n"
+ ")"
+ )
+ endif()
+ 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(arg_SCRIPT_FILE)
+ set(step_name update)
+ configure_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/stepscript.cmake.in"
+ "${arg_SCRIPT_FILE}"
+ @ONLY
+ )
+ set(${arg_DEPENDS_VARIABLE} "${file_deps}" PARENT_SCOPE)
+ return()
+ endif()
+
+ # Nothing below this point is applicable when we've been asked to put the
+ # update step in a script file (which is the FetchContent case).
+
+ 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)
+ set(noValueOptions )
+ set(singleValueOptions
+ SCRIPT_FILE # These should only be used by FetchContent
+ )
+ set(multiValueOptions )
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${noValueOptions}" "${singleValueOptions}" "${multiValueOptions}"
+ )
+
+ # 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(step_script_contents "")
+
+ set(work_dir)
+ if(DEFINED _EP_PATCH_COMMAND)
+ set(work_dir ${source_dir})
+ if(arg_SCRIPT_FILE)
+ _ep_add_script_commands(
+ step_script_contents
+ "${work_dir}"
+ "${cmd}" # Must be a single quoted argument
+ )
+ endif()
+ 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(arg_SCRIPT_FILE)
+ set(step_name patch)
+ configure_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/stepscript.cmake.in"
+ "${arg_SCRIPT_FILE}"
+ @ONLY
+ )
+ return()
+ endif()
+
+ # Nothing below this point is applicable when we've been asked to put the
+ # patch step in a script file (which is the FetchContent case).
+
+ 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/Modules/ExternalProject/stepscript.cmake.in b/Modules/ExternalProject/stepscript.cmake.in
new file mode 100644
index 0000000..12e157e
--- /dev/null
+++ b/Modules/ExternalProject/stepscript.cmake.in
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.29)
+
+message(VERBOSE "Executing @step_name@ step for @name@")
+
+block(SCOPE_FOR VARIABLES)
+
+@step_script_contents@
+
+endblock()
diff --git a/Modules/ExternalProject/verify.cmake.in b/Modules/ExternalProject/verify.cmake.in
index c06da4e..30d0487 100644
--- a/Modules/ExternalProject/verify.cmake.in
+++ b/Modules/ExternalProject/verify.cmake.in
@@ -12,7 +12,7 @@ if(NOT EXISTS "@LOCAL@")
endif()
if("@ALGO@" STREQUAL "")
- message(WARNING "File will not be verified since no URL_HASH specified")
+ message(WARNING "File cannot be verified since no URL_HASH specified")
return()
endif()
@@ -20,7 +20,7 @@ if("@EXPECT_VALUE@" STREQUAL "")
message(FATAL_ERROR "EXPECT_VALUE can't be empty")
endif()
-message(STATUS "verifying file...
+message(VERBOSE "verifying file...
file='@LOCAL@'")
file("@ALGO@" "@LOCAL@" actual_value)
@@ -34,4 +34,4 @@ does not match expected value
")
endif()
-message(STATUS "verifying file... done")
+message(VERBOSE "verifying file... done")
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
index 3c01c2a..5006069 100644
--- a/Modules/FetchContent.cmake
+++ b/Modules/FetchContent.cmake
@@ -141,6 +141,11 @@ Commands
exception, see :command:`FetchContent_MakeAvailable` for details on how that
affects behavior.
+ .. versionchanged:: 3.30
+ When policy :policy:`CMP0168` is set to ``NEW``, some output-related and
+ directory-related options are ignored. See the policy documentation for
+ details.
+
In most cases, ``<contentOptions>`` will just be a couple of options defining
the download method and method-specific details like a commit tag or archive
hash. For example:
@@ -437,12 +442,13 @@ Commands
like variable or directory scope. Therefore, it doesn't matter where in the
project the details were previously declared, as long as they have been
declared before the call to ``FetchContent_Populate()``. Those saved details
- are then used to construct a call to :command:`ExternalProject_Add` in a
- private sub-build to perform the content population immediately. The
- implementation of ``ExternalProject_Add()`` ensures that if the content has
- already been populated in a previous CMake run, that content will be reused
- rather than repopulating them again. For the common case where population
- involves downloading content, the cost of the download is only paid once.
+ are then used to populate the content using a method based on
+ :command:`ExternalProject_Add` (see policy :policy:`CMP0168` for important
+ behavioral aspects of how that is done). The implementation ensures that if
+ the content has already been populated in a previous CMake run, that content
+ will be reused rather than repopulating them again. For the common case
+ where population involves downloading content, the cost of the download is
+ only paid once.
An internal global property records when a particular content population
request has been processed. If ``FetchContent_Populate()`` is called more
@@ -529,6 +535,13 @@ Commands
cache variable has no effect on ``FetchContent_Populate()`` calls where the
content details are provided directly.
+ .. versionchanged:: 3.30
+ The ``QUIET`` option and global ``FETCHCONTENT_QUIET`` variable have no
+ effect when policy :policy:`CMP0168` is set to ``NEW``. The output is
+ still quiet by default in that case, but verbosity is controlled by the
+ message logging level (see :variable:`CMAKE_MESSAGE_LOG_LEVEL` and
+ :option:`--log-level <cmake --log-level>`).
+
``SUBBUILD_DIR``
The ``SUBBUILD_DIR`` argument can be provided to change the location of the
sub-build created to perform the population. The default value is
@@ -538,6 +551,10 @@ Commands
This option should not be confused with the ``SOURCE_SUBDIR`` option which
only affects the :command:`FetchContent_MakeAvailable` command.
+ .. versionchanged:: 3.30
+ ``SUBBUILD_DIR`` is ignored when policy :policy:`CMP0168` is set to
+ ``NEW``, since there is no sub-build in that case.
+
``SOURCE_DIR``, ``BINARY_DIR``
The ``SOURCE_DIR`` and ``BINARY_DIR`` arguments are supported by
:command:`ExternalProject_Add`, but different default values are used by
@@ -548,7 +565,7 @@ Commands
:variable:`CMAKE_CURRENT_BINARY_DIR`.
In addition to the above explicit options, any other unrecognized options are
- passed through unmodified to :command:`ExternalProject_Add` to perform the
+ passed through unmodified to :command:`ExternalProject_Add` to set up the
download, patch and update steps. The following options are explicitly
prohibited (they are disabled by the ``FetchContent_Populate()`` command):
@@ -564,6 +581,11 @@ Commands
:variable:`CMAKE_MAKE_PROGRAM` variables will need to be set appropriately
on the command line invoking the script.
+ .. versionchanged:: 3.30
+ If policy :policy:`CMP0168` is set to ``NEW``, no sub-build is used.
+ Within CMake's script mode, that allows ``FetchContent_Populate()`` to be
+ called without any build tool or CMake generator.
+
.. versionadded:: 3.18
Added support for the ``DOWNLOAD_NO_EXTRACT`` option.
@@ -675,6 +697,13 @@ A number of cache variables can influence the behavior where details from a
problems with hung downloads, temporarily switching this option off may
help diagnose which content population is causing the issue.
+ .. versionchanged:: 3.30
+ ``FETCHCONTENT_QUIET`` is ignored if policy :policy:`CMP0168` is set to
+ ``NEW``. The output is still quiet by default in that case, but verbosity
+ is controlled by the message logging level (see
+ :variable:`CMAKE_MESSAGE_LOG_LEVEL` and
+ :option:`--log-level <cmake --log-level>`).
+
.. variable:: FETCHCONTENT_FULLY_DISCONNECTED
When this option is enabled, no attempt is made to download or update
@@ -682,7 +711,7 @@ A number of cache variables can influence the behavior where details from a
a previous run or the source directories have been pointed at existing
contents the developer has provided manually (using options described
further below). When the developer knows that no changes have been made to
- any content details, turning this option ``ON`` can significantly speed up
+ any content details, turning this option ``ON`` can speed up
the configure stage. It is ``OFF`` by default.
.. note::
@@ -1167,7 +1196,13 @@ function(__FetchContent_declareDetails contentName)
set(__findPackageArgs)
set(__sawQuietKeyword NO)
set(__sawGlobalKeyword NO)
+ set(__direct_population NO)
foreach(__item IN LISTS ARGN)
+ if(__item STREQUAL "__DIRECT_POPULATION")
+ set(__direct_population YES)
+ continue()
+ endif()
+
if(DEFINED __findPackageArgs)
# All remaining args are for find_package()
string(APPEND __findPackageArgs " [==[${__item}]==]")
@@ -1206,6 +1241,10 @@ function(__FetchContent_declareDetails contentName)
string(APPEND __cmdArgs " [==[${__item}]==]")
endforeach()
+ set_property(GLOBAL PROPERTY
+ "_FetchContent_${contentNameLower}_direct_population" ${__direct_population}
+ )
+
define_property(GLOBAL PROPERTY ${savedDetailsPropertyName})
cmake_language(EVAL CODE
"set_property(GLOBAL PROPERTY ${savedDetailsPropertyName} ${__cmdArgs})"
@@ -1372,16 +1411,24 @@ function(FetchContent_Declare contentName)
endif()
# Add back in the keyword args we pulled out and potentially tweaked/added
+ set(forward_args "${ARG_UNPARSED_ARGUMENTS}")
set(sep EXTERNALPROJECT_INTERNAL_ARGUMENT_SEPARATOR)
foreach(key IN LISTS oneValueArgs)
if(DEFINED ARG_${key})
- list(PREPEND ARG_UNPARSED_ARGUMENTS ${key} "${ARG_${key}}" ${sep})
+ list(PREPEND forward_args ${key} "${ARG_${key}}" ${sep})
set(sep "")
endif()
endforeach()
+ cmake_policy(GET CMP0168 cmp0168
+ PARENT_SCOPE # undocumented, do not use outside of CMake
+ )
+ if(cmp0168 STREQUAL "NEW")
+ list(PREPEND forward_args __DIRECT_POPULATION ${sep})
+ endif()
+
set(__argsQuoted)
- foreach(__item IN LISTS ARG_UNPARSED_ARGUMENTS)
+ foreach(__item IN LISTS forward_args)
string(APPEND __argsQuoted " [==[${__item}]==]")
endforeach()
cmake_language(EVAL CODE
@@ -1498,7 +1545,7 @@ endfunction()
# The value of contentName will always have been lowercased by the caller.
# All other arguments are assumed to be options that are understood by
# ExternalProject_Add(), except for QUIET and SUBBUILD_DIR.
-function(__FetchContent_directPopulate contentName)
+function(__FetchContent_doPopulation contentName)
set(options
QUIET
@@ -1533,8 +1580,14 @@ function(__FetchContent_directPopulate contentName)
cmake_parse_arguments(PARSE_ARGV 1 ARG
"${options}" "${oneValueArgs}" "${multiValueArgs}")
+ get_property(direct_population GLOBAL PROPERTY
+ "_FetchContent_${contentNameLower}_direct_population"
+ )
+
if(NOT ARG_SUBBUILD_DIR)
- message(FATAL_ERROR "Internal error: SUBBUILD_DIR not set")
+ if(NOT direct_population)
+ message(FATAL_ERROR "Internal error: SUBBUILD_DIR not set")
+ endif()
elseif(NOT IS_ABSOLUTE "${ARG_SUBBUILD_DIR}")
set(ARG_SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBBUILD_DIR}")
endif()
@@ -1558,6 +1611,148 @@ function(__FetchContent_directPopulate contentName)
set(${contentName}_SOURCE_DIR "${ARG_SOURCE_DIR}" PARENT_SCOPE)
set(${contentName}_BINARY_DIR "${ARG_BINARY_DIR}" PARENT_SCOPE)
+ if(direct_population)
+ __FetchContent_populateDirect()
+ else()
+ __FetchContent_populateSubbuild()
+ endif()
+endfunction()
+
+
+function(__FetchContent_populateDirect)
+ # Policies CMP0097, CMP0135 and CMP0150 are handled in FetchContent_Declare()
+ # and the stored arguments already account for them.
+ # For CMP0097, the arguments will always assume NEW behavior by the time
+ # we get to here, so ensure ExternalProject sees that.
+ set(_EP_CMP0097 NEW)
+
+ set(args_to_parse
+ "${ARG_UNPARSED_ARGUMENTS}"
+ SOURCE_DIR "${ARG_SOURCE_DIR}"
+ BINARY_DIR "${ARG_BINARY_DIR}"
+ )
+ if(ARG_DOWNLOAD_NO_EXTRACT)
+ list(APPEND args_to_parse DOWNLOAD_NO_EXTRACT YES)
+ endif()
+
+ get_property(cmake_role GLOBAL PROPERTY CMAKE_ROLE)
+ if(cmake_role STREQUAL "PROJECT")
+ # We don't support direct population where a project makes a direct call
+ # to FetchContent_Populate(). That always goes through ExternalProject and
+ # will soon be deprecated anyway.
+ set(function_for_args FetchContent_Declare)
+ elseif(cmake_role STREQUAL "SCRIPT")
+ set(function_for_args FetchContent_Populate)
+ else()
+ message(FATAL_ERROR "Unsupported context for direct population")
+ endif()
+
+ _ep_get_add_keywords(keywords)
+ _ep_parse_arguments_to_vars(
+ ${function_for_args}
+ "${keywords}"
+ ${contentName}
+ _EP_
+ "${args_to_parse}"
+ )
+
+ # We use a simplified set of directories here. We do not need the full set
+ # of directories that ExternalProject supports, and we don't need the
+ # extensive customization options it supports either. Note that
+ # _EP_SOURCE_DIR and _EP_BINARY_DIR are always included in the saved args,
+ # so we must not set them here.
+ set(_EP_STAMP_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-stamp")
+ set(_EP_TMP_DIR "${FETCHCONTENT_BASE_DIR}/${contentNameLower}-tmp")
+ set(_EP_DOWNLOAD_DIR "${_EP_TMP_DIR}")
+
+ file(MAKE_DIRECTORY
+ "${_EP_SOURCE_DIR}"
+ "${_EP_BINARY_DIR}"
+ "${_EP_STAMP_DIR}"
+ "${_EP_TMP_DIR}"
+ )
+
+ # We take over the stamp files and use our own for detecting whether each
+ # step is up-to-date. The method used by ExternalProject is specific to
+ # using a sub-build and is not appropriate for us here.
+
+ set(download_script ${_EP_TMP_DIR}/download.cmake)
+ set(update_script ${_EP_TMP_DIR}/upload.cmake)
+ set(patch_script ${_EP_TMP_DIR}/patch.cmake)
+ _ep_add_download_command(${contentName}
+ SCRIPT_FILE ${download_script}
+ DEPENDS_VARIABLE download_depends
+ )
+ _ep_add_update_command(${contentName}
+ SCRIPT_FILE ${update_script}
+ DEPENDS_VARIABLE update_depends
+ )
+ _ep_add_patch_command(${contentName}
+ SCRIPT_FILE ${patch_script}
+ # No additional dependencies for the patch step
+ )
+
+ set(download_stamp ${_EP_STAMP_DIR}/download.stamp)
+ set(update_stamp ${_EP_STAMP_DIR}/upload.stamp)
+ set(patch_stamp ${_EP_STAMP_DIR}/patch.stamp)
+ __FetchContent_doStepDirect(
+ SCRIPT_FILE ${download_script}
+ STAMP_FILE ${download_stamp}
+ DEPENDS ${download_depends}
+ )
+ __FetchContent_doStepDirect(
+ SCRIPT_FILE ${update_script}
+ STAMP_FILE ${update_stamp}
+ DEPENDS ${update_depends} ${download_stamp}
+ )
+ __FetchContent_doStepDirect(
+ SCRIPT_FILE ${patch_script}
+ STAMP_FILE ${patch_stamp}
+ DEPENDS ${update_stamp}
+ )
+
+endfunction()
+
+
+function(__FetchContent_doStepDirect)
+ set(noValueOptions )
+ set(singleValueOptions
+ SCRIPT_FILE
+ STAMP_FILE
+ )
+ set(multiValueOptions
+ DEPENDS
+ )
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${noValueOptions}" "${singleValueOptions}" "${multiValueOptions}"
+ )
+
+ if(NOT EXISTS ${arg_STAMP_FILE})
+ set(do_step YES)
+ else()
+ set(do_step NO)
+ foreach(dep_file IN LISTS arg_DEPENDS arg_SCRIPT_FILE)
+ if(NOT EXISTS "${arg_STAMP_FILE}" OR
+ NOT EXISTS "${dep_file}" OR
+ NOT "${arg_STAMP_FILE}" IS_NEWER_THAN "${dep_file}")
+ set(do_step YES)
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if(do_step)
+ include(${arg_SCRIPT_FILE})
+ file(TOUCH "${arg_STAMP_FILE}")
+ endif()
+endfunction()
+
+
+function(__FetchContent_populateSubbuild)
+ # All argument parsing is done in __FetchContent_doPopulate(), since it is
+ # common to both the subbuild and direct population strategies.
+ # Parsed arguments are in ARG_... variables.
+
# The unparsed arguments may contain spaces, so build up ARG_EXTRA
# in such a way that it correctly substitutes into the generated
# CMakeLists.txt file with each argument quoted.
@@ -1736,7 +1931,7 @@ function(FetchContent_Populate contentName)
if(ARGN)
# This is the direct population form with details fully specified
# as part of the call, so we already have everything we need
- __FetchContent_directPopulate(
+ __FetchContent_doPopulation(
${contentNameLower}
SUBBUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-subbuild"
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/${contentNameLower}-src"
@@ -1853,7 +2048,7 @@ function(FetchContent_Populate contentName)
endif()
endforeach()
cmake_language(EVAL CODE "
- __FetchContent_directPopulate(
+ __FetchContent_doPopulation(
${contentNameLower}
${quietFlag}
UPDATE_DISCONNECTED ${disconnectUpdates}