mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 10:50:16 -06:00
FetchContent: Invoke steps directly and avoid a separate sub-build
The cost of setting up and executing a separate sub-build to do the download, update and patch steps required for FetchContent population can be significant with some platforms and CMake generators. Avoid the sub-build altogether by invoking the step scripts directly. Previously, if no generator was set (e.g. population was being done in script mode), a generator needed to be available on the default PATH. Since we no longer use a sub-build, this restriction is also now gone. Fixes: #21703
This commit is contained in:
@@ -5,3 +5,9 @@ fetchcontent-performance
|
||||
significantly refactored. The patch step gained support for
|
||||
using the terminal with a new ``USES_TERMINAL_PATCH`` keyword
|
||||
as a by-product of that work.
|
||||
* The :module:`FetchContent` module no longer creates a separate
|
||||
sub-build to implement the content population. It now invokes
|
||||
the step scripts directly from within the main project's
|
||||
configure stage. This significantly speeds up the configure
|
||||
phase when the required content is already populated and
|
||||
up-to-date.
|
||||
|
||||
@@ -1200,46 +1200,46 @@ function(_ep_parse_arguments keywords name ns args)
|
||||
|
||||
endfunction()
|
||||
|
||||
if(NOT DEFINED CMAKE_SCRIPT_MODE_FILE)
|
||||
define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED
|
||||
BRIEF_DOCS "Base directory for External Project storage."
|
||||
FULL_DOCS
|
||||
"See documentation of the ExternalProject_Add() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
|
||||
define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED
|
||||
BRIEF_DOCS "Base directory for External Project storage."
|
||||
FULL_DOCS
|
||||
"See documentation of the ExternalProject_Add() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
|
||||
BRIEF_DOCS "Top prefix for External Project storage."
|
||||
FULL_DOCS
|
||||
"See documentation of the ExternalProject_Add() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
|
||||
define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
|
||||
BRIEF_DOCS "Top prefix for External Project storage."
|
||||
FULL_DOCS
|
||||
"See documentation of the ExternalProject_Add() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
|
||||
BRIEF_DOCS
|
||||
"List of ExternalProject steps that automatically get corresponding targets"
|
||||
FULL_DOCS
|
||||
"These targets will be dependent on the main target dependencies. "
|
||||
"See documentation of the ExternalProject_Add_StepTargets() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
|
||||
define_property(DIRECTORY PROPERTY "EP_STEP_TARGETS" INHERITED
|
||||
BRIEF_DOCS
|
||||
"List of ExternalProject steps that automatically get corresponding targets"
|
||||
FULL_DOCS
|
||||
"These targets will be dependent on the main target dependencies. "
|
||||
"See documentation of the ExternalProject_Add_StepTargets() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
|
||||
define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED
|
||||
BRIEF_DOCS
|
||||
"List of ExternalProject steps that automatically get corresponding targets"
|
||||
FULL_DOCS
|
||||
"These targets will not be dependent on the main target dependencies. "
|
||||
"See documentation of the ExternalProject_Add_StepTargets() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
|
||||
define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED
|
||||
BRIEF_DOCS "Never update automatically from the remote repo."
|
||||
FULL_DOCS
|
||||
"See documentation of the ExternalProject_Add() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
define_property(DIRECTORY PROPERTY "EP_INDEPENDENT_STEP_TARGETS" INHERITED
|
||||
BRIEF_DOCS
|
||||
"List of ExternalProject steps that automatically get corresponding targets"
|
||||
FULL_DOCS
|
||||
"These targets will not be dependent on the main target dependencies. "
|
||||
"See documentation of the ExternalProject_Add_StepTargets() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
|
||||
define_property(DIRECTORY PROPERTY "EP_UPDATE_DISCONNECTED" INHERITED
|
||||
BRIEF_DOCS "Never update automatically from the remote repo."
|
||||
FULL_DOCS
|
||||
"See documentation of the ExternalProject_Add() function in the "
|
||||
"ExternalProject module."
|
||||
)
|
||||
endif()
|
||||
|
||||
function(_ep_write_gitclone_script
|
||||
script_filename
|
||||
@@ -1258,7 +1258,8 @@ function(_ep_write_gitclone_script
|
||||
work_dir
|
||||
gitclone_infofile
|
||||
gitclone_stampfile
|
||||
tls_verify)
|
||||
tls_verify
|
||||
quiet)
|
||||
|
||||
if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
|
||||
# Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
|
||||
@@ -1322,7 +1323,8 @@ function(_ep_write_hgclone_script
|
||||
src_name
|
||||
work_dir
|
||||
hgclone_infofile
|
||||
hgclone_stampfile)
|
||||
hgclone_stampfile
|
||||
quiet)
|
||||
|
||||
if("${hg_tag}" STREQUAL "")
|
||||
message(FATAL_ERROR "Tag for hg checkout should not be empty.")
|
||||
@@ -1347,7 +1349,8 @@ function(_ep_write_gitupdate_script
|
||||
git_submodules
|
||||
git_repository
|
||||
work_dir
|
||||
git_update_strategy)
|
||||
git_update_strategy
|
||||
quiet)
|
||||
|
||||
if("${git_tag}" STREQUAL "")
|
||||
message(FATAL_ERROR "Tag for git checkout should not be empty.")
|
||||
@@ -1372,7 +1375,8 @@ function(_ep_write_hgupdate_script
|
||||
script_filename
|
||||
hg_EXECUTABLE
|
||||
hg_tag
|
||||
work_dir)
|
||||
work_dir
|
||||
quiet)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/hgupdate.cmake.in
|
||||
@@ -1408,7 +1412,8 @@ function(_ep_write_downloadfile_script
|
||||
http_headers
|
||||
netrc
|
||||
netrc_file
|
||||
extract_script_filename)
|
||||
extract_script_filename
|
||||
quiet)
|
||||
|
||||
if(timeout)
|
||||
set(TIMEOUT_ARGS TIMEOUT ${timeout})
|
||||
@@ -1426,7 +1431,7 @@ function(_ep_write_downloadfile_script
|
||||
endif()
|
||||
|
||||
|
||||
if(no_progress)
|
||||
if(no_progress OR quiet)
|
||||
set(SHOW_PROGRESS "")
|
||||
else()
|
||||
set(SHOW_PROGRESS "SHOW_PROGRESS")
|
||||
@@ -1523,7 +1528,8 @@ function(_ep_write_verifyfile_script
|
||||
script_filename
|
||||
LOCAL
|
||||
hash
|
||||
extract_script_filename)
|
||||
extract_script_filename
|
||||
quiet)
|
||||
|
||||
_ep_get_hash_regex(_ep_hash_regex)
|
||||
if("${hash}" MATCHES "${_ep_hash_regex}")
|
||||
@@ -1551,7 +1557,8 @@ function(_ep_write_extractfile_script
|
||||
script_filename
|
||||
name
|
||||
filename
|
||||
directory)
|
||||
directory
|
||||
quiet)
|
||||
|
||||
set(args "")
|
||||
|
||||
@@ -1578,7 +1585,8 @@ function(_ep_write_extractfile_script
|
||||
endfunction()
|
||||
|
||||
|
||||
# This function is an implementation detail of ExternalProject_Add().
|
||||
# This function is an implementation detail of ExternalProject_Add() and
|
||||
# _ep_do_preconfigure_steps_now().
|
||||
#
|
||||
# The function expects keyword arguments to have already been parsed into
|
||||
# variables of the form _EP_<keyword>. It will create the various directories
|
||||
@@ -2059,7 +2067,7 @@ if(result)
|
||||
message(FATAL_ERROR \"\${msg}\")
|
||||
endif()
|
||||
else()
|
||||
if(NOT \"${CMAKE_GENERATOR}\" MATCHES \"Ninja\")
|
||||
if(NOT \"${CMAKE_GENERATOR}\" MATCHES \"Ninja\" AND NOT \"${_EP_QUIET}\")
|
||||
set(msg \"${name} ${step} command succeeded. See also ${logbase}-*.log\")
|
||||
message(STATUS \"\${msg}\")
|
||||
endif()
|
||||
@@ -2523,6 +2531,7 @@ function(_ep_write_command_script
|
||||
commands
|
||||
work_dir
|
||||
genex_supported
|
||||
quiet
|
||||
have_commands_var)
|
||||
|
||||
set(sep "${_EP_LIST_SEPARATOR}")
|
||||
@@ -2531,6 +2540,10 @@ function(_ep_write_command_script
|
||||
endif()
|
||||
_ep_replace_location_tags_from_vars(commands)
|
||||
|
||||
file(READ
|
||||
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/customcommand.cmake.in
|
||||
exec_command_template
|
||||
)
|
||||
set(script_content)
|
||||
set(this_command)
|
||||
foreach(token IN LISTS commands)
|
||||
@@ -2539,13 +2552,8 @@ function(_ep_write_command_script
|
||||
# Silently skip empty commands
|
||||
continue()
|
||||
endif()
|
||||
string(APPEND script_content "
|
||||
execute_process(
|
||||
COMMAND ${this_command}
|
||||
COMMAND_ERROR_IS_FATAL LAST
|
||||
WORKING_DIRECTORY [==[${work_dir}]==]
|
||||
)
|
||||
")
|
||||
string(CONFIGURE "${exec_command_template}" content @ONLY)
|
||||
string(APPEND script_content "${content}")
|
||||
set(this_command)
|
||||
else()
|
||||
# Ensure we quote every token so we preserve empty items, quotes, etc
|
||||
@@ -2554,20 +2562,20 @@ execute_process(
|
||||
endforeach()
|
||||
|
||||
if(NOT "${this_command}" STREQUAL "")
|
||||
string(APPEND script_content "
|
||||
execute_process(
|
||||
COMMAND ${this_command}
|
||||
COMMAND_ERROR_IS_FATAL LAST
|
||||
WORKING_DIRECTORY [==[${work_dir}]==]
|
||||
)
|
||||
")
|
||||
string(CONFIGURE "${exec_command_template}" content @ONLY)
|
||||
string(APPEND script_content "${content}")
|
||||
endif()
|
||||
|
||||
if(script_content STREQUAL "")
|
||||
set(${have_commands_var} FALSE PARENT_SCOPE)
|
||||
else()
|
||||
set(${have_commands_var} TRUE PARENT_SCOPE)
|
||||
string(PREPEND script_content "cmake_minimum_required(VERSION 3.19)\n")
|
||||
file(READ
|
||||
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ExternalProject/customcommand_preamble.cmake.in
|
||||
exec_command_preamble
|
||||
)
|
||||
string(CONFIGURE "${exec_command_preamble}" exec_command_preamble @ONLY)
|
||||
string(PREPEND script_content "${exec_command_preamble}")
|
||||
endif()
|
||||
|
||||
if(genex_supported)
|
||||
@@ -2603,7 +2611,8 @@ function(_ep_add_preconfigure_command name step)
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# This function is an implementation detail of ExternalProject_Add().
|
||||
# This function is an implementation detail of ExternalProject_Add() and
|
||||
# _ep_do_preconfigure_steps_now().
|
||||
#
|
||||
# The function expects keyword arguments to have already been parsed into
|
||||
# variables of the form _EP_<keyword>. It will populate the variable
|
||||
@@ -2619,6 +2628,7 @@ function(_ep_prepare_download name genex_supported)
|
||||
set(tmp_dir "${_EP_TMP_DIR}")
|
||||
set(source_dir "${_EP_SOURCE_DIR}")
|
||||
set(download_dir "${_EP_DOWNLOAD_DIR}")
|
||||
set(quiet "${_EP_QUIET}")
|
||||
|
||||
set(comment)
|
||||
|
||||
@@ -2628,6 +2638,7 @@ function(_ep_prepare_download name genex_supported)
|
||||
if(log)
|
||||
set(script_filename ${tmp_dir}/${name}-download-impl.cmake)
|
||||
set(log TRUE)
|
||||
set(quiet FALSE) # Already quiet as a result of log being enabled
|
||||
else()
|
||||
set(script_filename ${tmp_dir}/${name}-download.cmake)
|
||||
set(log FALSE)
|
||||
@@ -2660,6 +2671,7 @@ work_dir=${work_dir}
|
||||
"${_EP_DOWNLOAD_COMMAND}"
|
||||
"${work_dir}"
|
||||
"${genex_supported}"
|
||||
"${quiet}"
|
||||
script_does_something
|
||||
)
|
||||
set(comment "Performing download step (custom command) for '${name}'")
|
||||
@@ -2698,6 +2710,7 @@ source_dir=${source_dir}
|
||||
"${cmd}"
|
||||
"${work_dir}"
|
||||
"${genex_supported}"
|
||||
"${quiet}"
|
||||
script_does_something
|
||||
)
|
||||
set(comment "Performing download step (CVS checkout) for '${name}'")
|
||||
@@ -2750,6 +2763,7 @@ source_dir=${source_dir}
|
||||
"${cmd}"
|
||||
"${work_dir}"
|
||||
"${genex_supported}"
|
||||
"${quiet}"
|
||||
script_does_something
|
||||
)
|
||||
set(comment "Performing download step (SVN checkout) for '${name}'")
|
||||
@@ -2835,6 +2849,7 @@ source_dir=${source_dir}
|
||||
"${repo_info_file}"
|
||||
"${last_run_file}"
|
||||
"${tls_verify}"
|
||||
"${quiet}"
|
||||
)
|
||||
set(comment "Performing download step (git clone) for '${name}'")
|
||||
|
||||
@@ -2880,6 +2895,7 @@ source_dir=${source_dir}
|
||||
"${work_dir}"
|
||||
"${repo_info_file}"
|
||||
"${last_run_file}"
|
||||
"${quiet}"
|
||||
)
|
||||
set(comment "Performing download step (hg clone) for '${name}'")
|
||||
|
||||
@@ -2982,6 +2998,7 @@ source_dir=${source_dir}
|
||||
"${_EP_NETRC}"
|
||||
"${_EP_NETRC_FILE}"
|
||||
"${extract_script}"
|
||||
"${quiet}"
|
||||
)
|
||||
if(no_extract)
|
||||
set(steps "download and verify")
|
||||
@@ -2995,6 +3012,7 @@ source_dir=${source_dir}
|
||||
"${file}"
|
||||
"${hash}"
|
||||
"${extract_script}"
|
||||
"${quiet}"
|
||||
)
|
||||
if(no_extract)
|
||||
set(steps "verify")
|
||||
@@ -3012,6 +3030,7 @@ source_dir=${source_dir}
|
||||
"${name}"
|
||||
"${file}"
|
||||
"${source_dir}"
|
||||
"${quiet}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -3079,7 +3098,8 @@ function(_ep_get_update_disconnected var)
|
||||
set(${var} "${update_disconnected}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# This function is an implementation detail of ExternalProject_Add().
|
||||
# This function is an implementation detail of ExternalProject_Add() and
|
||||
# _ep_do_preconfigure_steps_now().
|
||||
#
|
||||
# The function expects keyword arguments to have already been parsed into
|
||||
# variables of the form _EP_<keyword>.
|
||||
@@ -3091,6 +3111,7 @@ function(_ep_prepare_update name genex_supported)
|
||||
|
||||
set(tmp_dir "${_EP_TMP_DIR}")
|
||||
set(source_dir "${_EP_SOURCE_DIR}")
|
||||
set(quiet "${_EP_QUIET}")
|
||||
|
||||
set(comment)
|
||||
|
||||
@@ -3102,6 +3123,7 @@ function(_ep_prepare_update name genex_supported)
|
||||
if(log)
|
||||
set(script_filename ${tmp_dir}/${name}-update-impl.cmake)
|
||||
set(log TRUE)
|
||||
set(quiet FALSE) # Already quiet as a result of log being enabled
|
||||
else()
|
||||
set(script_filename ${tmp_dir}/${name}-update.cmake)
|
||||
set(log FALSE)
|
||||
@@ -3114,6 +3136,7 @@ function(_ep_prepare_update name genex_supported)
|
||||
"${_EP_UPDATE_COMMAND}"
|
||||
"${work_dir}"
|
||||
"${genex_supported}"
|
||||
"${quiet}"
|
||||
script_does_something
|
||||
)
|
||||
set(comment "Performing update step (custom command) for '${name}'")
|
||||
@@ -3132,6 +3155,7 @@ function(_ep_prepare_update name genex_supported)
|
||||
"${cmd}"
|
||||
"${work_dir}"
|
||||
"${genex_supported}"
|
||||
"${quiet}"
|
||||
script_does_something
|
||||
)
|
||||
set(comment "Performing update step (CVS update) for '${name}'")
|
||||
@@ -3165,6 +3189,7 @@ function(_ep_prepare_update name genex_supported)
|
||||
"${cmd}"
|
||||
"${work_dir}"
|
||||
"${genex_supported}"
|
||||
"${quiet}"
|
||||
script_does_something
|
||||
)
|
||||
set(comment "Performing update step (SVN update) for '${name}'")
|
||||
@@ -3222,6 +3247,7 @@ function(_ep_prepare_update name genex_supported)
|
||||
"${_EP_GIT_REPOSITORY}"
|
||||
"${work_dir}"
|
||||
"${git_update_strategy}"
|
||||
"${quiet}"
|
||||
)
|
||||
set(script_does_something TRUE)
|
||||
set(comment "Performing update step (git update) for '${name}'")
|
||||
@@ -3250,6 +3276,7 @@ Update to Mercurial >= 2.1.1.
|
||||
"${HG_EXECUTABLE}"
|
||||
"${hg_tag}"
|
||||
"${work_dir}"
|
||||
"${quiet}"
|
||||
)
|
||||
set(script_does_something TRUE)
|
||||
set(comment "Performing update step (hg pull) for '${name}'")
|
||||
@@ -3280,7 +3307,8 @@ Update to Mercurial >= 2.1.1.
|
||||
|
||||
endfunction()
|
||||
|
||||
# This function is an implementation detail of ExternalProject_Add().
|
||||
# This function is an implementation detail of ExternalProject_Add() and
|
||||
# _ep_do_preconfigure_steps_now().
|
||||
#
|
||||
# The function expects keyword arguments to have already been parsed into
|
||||
# variables of the form _EP_<keyword>.
|
||||
@@ -3292,6 +3320,7 @@ function(_ep_prepare_patch name genex_supported)
|
||||
|
||||
set(tmp_dir "${_EP_TMP_DIR}")
|
||||
set(source_dir "${_EP_SOURCE_DIR}")
|
||||
set(quiet "${_EP_QUIET}")
|
||||
|
||||
_ep_get_update_disconnected(update_disconnected)
|
||||
if(update_disconnected)
|
||||
@@ -3306,6 +3335,7 @@ function(_ep_prepare_patch name genex_supported)
|
||||
if(log)
|
||||
set(script_filename ${tmp_dir}/${name}-patch-impl.cmake)
|
||||
set(log TRUE)
|
||||
set(quiet FALSE) # Already quiet as a result of log being enabled
|
||||
else()
|
||||
set(script_filename ${tmp_dir}/${name}-patch.cmake)
|
||||
set(log FALSE)
|
||||
@@ -3318,6 +3348,7 @@ function(_ep_prepare_patch name genex_supported)
|
||||
"${_EP_PATCH_COMMAND}"
|
||||
"${work_dir}"
|
||||
"${genex_supported}"
|
||||
"${quiet}"
|
||||
script_does_something
|
||||
)
|
||||
if(script_does_something)
|
||||
@@ -3837,6 +3868,73 @@ macro(_ep_get_add_keywords out_var)
|
||||
endmacro()
|
||||
|
||||
|
||||
# Internal function called by FetchContent to populate immediately.
|
||||
# It only executes steps up to and including "patch". It takes the same
|
||||
# arguments as ExternalProject_Add() plus one additional argument: QUIET.
|
||||
#
|
||||
# Not to be used outside of CMake.
|
||||
#
|
||||
function(_ep_do_preconfigure_steps_now name)
|
||||
|
||||
cmake_policy(GET CMP0097 _EP_CMP0097
|
||||
PARENT_SCOPE # undocumented, do not use outside of CMake
|
||||
)
|
||||
|
||||
set(genex_supported FALSE)
|
||||
|
||||
_ep_get_add_keywords(keywords)
|
||||
_ep_parse_arguments_to_vars("${keywords};QUIET" ${name} _EP_ "${ARGN}")
|
||||
|
||||
_ep_get_update_disconnected(update_disconnected)
|
||||
|
||||
_ep_prepare_directories(${name})
|
||||
_ep_prepare_download(${name} ${genex_supported})
|
||||
_ep_prepare_update(${name} ${genex_supported})
|
||||
_ep_prepare_patch(${name} ${genex_supported})
|
||||
|
||||
set(stamp_dir "${_EP_STAMP_DIR}")
|
||||
set(tmp_dir "${_EP_TMP_DIR}")
|
||||
|
||||
# Once any step has to run, all later steps have to be run too
|
||||
set(need_to_run FALSE)
|
||||
foreach(step IN ITEMS download update parse)
|
||||
if(update_disconnected AND "${step}" STREQUAL "update")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
string(TOUPPER "${step}" STEP)
|
||||
if("${_EPcommand_${STEP}}" STREQUAL "")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
set(stamp_file "${stamp_dir}/${name}-${step}")
|
||||
set(script_file ${tmp_dir}/${name}-${step}.cmake)
|
||||
|
||||
if(NOT EXISTS ${stamp_file})
|
||||
set(need_to_run TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT need_to_run)
|
||||
foreach(dep_file ${script_file} ${_EPdepends_${STEP}})
|
||||
if(NOT EXISTS ${dep_file} OR ${dep_file} IS_NEWER_THAN ${stamp_file})
|
||||
set(need_to_run TRUE)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(need_to_run)
|
||||
include(${script_file})
|
||||
file(TOUCH ${stamp_file})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if("${_EP_DOWNLOAD_NO_EXTRACT}")
|
||||
file(COPY "${_EP_DOWNLOADED_FILE}" DESTINATION "${_EP_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
function(ExternalProject_Add name)
|
||||
cmake_policy(GET CMP0097 _EP_CMP0097
|
||||
PARENT_SCOPE # undocumented, do not use outside of CMake
|
||||
|
||||
55
Modules/ExternalProject/captured_process_setup.cmake
Normal file
55
Modules/ExternalProject/captured_process_setup.cmake
Normal file
@@ -0,0 +1,55 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
if(quiet)
|
||||
set(capture_output
|
||||
OUTPUT_VARIABLE out_var
|
||||
ERROR_VARIABLE out_var
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
set(capture_error_only
|
||||
ERROR_VARIABLE out_var
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else()
|
||||
unset(capture_output)
|
||||
unset(capture_error_only)
|
||||
endif()
|
||||
|
||||
set(out_var "")
|
||||
set(accumulated_output "")
|
||||
|
||||
macro(_ep_message_quiet_capture mode)
|
||||
if("${mode}" STREQUAL "FATAL_ERROR")
|
||||
string(JOIN "" detail "${ARGN}")
|
||||
if(NOT detail STREQUAL "" AND NOT accumulated_output STREQUAL "")
|
||||
string(PREPEND detail "\n")
|
||||
endif()
|
||||
message(FATAL_ERROR "${accumulated_output}${detail}")
|
||||
endif()
|
||||
|
||||
if(quiet)
|
||||
if("${mode}" MATCHES "WARNING")
|
||||
# We can't provide the full CMake backtrace, but we can at least record
|
||||
# the warning message with a sensible prefix
|
||||
string(APPEND accumulated_output "${mode}: ")
|
||||
endif()
|
||||
string(APPEND accumulated_output "${ARGN}\n")
|
||||
else()
|
||||
message(${mode} ${ARGN})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(_ep_accumulate_captured_output)
|
||||
if(NOT "${out_var}" STREQUAL "")
|
||||
string(APPEND accumulated_output "${out_var}\n")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(_ep_command_check_result result)
|
||||
_ep_accumulate_captured_output()
|
||||
if(result)
|
||||
_ep_message_quiet_capture(FATAL_ERROR ${ARGN})
|
||||
endif()
|
||||
endmacro()
|
||||
8
Modules/ExternalProject/customcommand.cmake.in
Normal file
8
Modules/ExternalProject/customcommand.cmake.in
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
execute_process(
|
||||
COMMAND @this_command@
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE result
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(result)
|
||||
8
Modules/ExternalProject/customcommand_preamble.cmake.in
Normal file
8
Modules/ExternalProject/customcommand_preamble.cmake.in
Normal file
@@ -0,0 +1,8 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
@@ -3,13 +3,17 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
|
||||
function(check_file_hash has_hash hash_is_good)
|
||||
if("${has_hash}" STREQUAL "")
|
||||
message(FATAL_ERROR "has_hash Can't be empty")
|
||||
_ep_message_quiet_capture(FATAL_ERROR "has_hash Can't be empty")
|
||||
endif()
|
||||
|
||||
if("${hash_is_good}" STREQUAL "")
|
||||
message(FATAL_ERROR "hash_is_good Can't be empty")
|
||||
_ep_message_quiet_capture(FATAL_ERROR "hash_is_good Can't be empty")
|
||||
endif()
|
||||
|
||||
if("@ALGO@" STREQUAL "")
|
||||
@@ -21,18 +25,20 @@ function(check_file_hash has_hash hash_is_good)
|
||||
|
||||
set("${has_hash}" TRUE PARENT_SCOPE)
|
||||
|
||||
message(STATUS "verifying file...
|
||||
_ep_message_quiet_capture(STATUS "verifying file...
|
||||
file='@LOCAL@'")
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
|
||||
file("@ALGO@" "@LOCAL@" actual_value)
|
||||
|
||||
if(NOT "${actual_value}" STREQUAL "@EXPECT_VALUE@")
|
||||
set("${hash_is_good}" FALSE PARENT_SCOPE)
|
||||
message(STATUS "@ALGO@ hash of
|
||||
_ep_message_quiet_capture(STATUS "@ALGO@ hash of
|
||||
@LOCAL@
|
||||
does not match expected value
|
||||
expected: '@EXPECT_VALUE@'
|
||||
actual: '${actual_value}'")
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
else()
|
||||
set("${hash_is_good}" TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
@@ -44,7 +50,8 @@ function(sleep_before_download attempt)
|
||||
endif()
|
||||
|
||||
if(attempt EQUAL 1)
|
||||
message(STATUS "Retrying...")
|
||||
_ep_message_quiet_capture(STATUS "Retrying...")
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
@@ -66,7 +73,10 @@ function(sleep_before_download attempt)
|
||||
set(sleep_seconds 1200)
|
||||
endif()
|
||||
|
||||
message(STATUS "Retry after ${sleep_seconds} seconds (attempt #${attempt}) ...")
|
||||
_ep_message_quiet_capture(STATUS
|
||||
"Retry after ${sleep_seconds} seconds (attempt #${attempt}) ..."
|
||||
)
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep "${sleep_seconds}")
|
||||
endfunction()
|
||||
@@ -84,18 +94,22 @@ function(download_and_verify)
|
||||
check_file_hash(has_hash hash_is_good)
|
||||
if(has_hash)
|
||||
if(hash_is_good)
|
||||
message(STATUS
|
||||
_ep_message_quiet_capture(STATUS
|
||||
"File already exists and hash match (skip download):
|
||||
file='@LOCAL@'
|
||||
@ALGO@='@EXPECT_VALUE@'"
|
||||
)
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
return()
|
||||
else()
|
||||
message(STATUS "File already exists but hash mismatch. Removing...")
|
||||
_ep_message_quiet_capture(STATUS
|
||||
"File already exists but hash mismatch. Removing..."
|
||||
)
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
file(REMOVE "@LOCAL@")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS
|
||||
_ep_message_quiet_capture(STATUS
|
||||
"File already exists but no hash specified (use URL_HASH):
|
||||
file='@LOCAL@'
|
||||
Old file will be removed and new file downloaded from URL."
|
||||
@@ -106,11 +120,12 @@ Old file will be removed and new file downloaded from URL."
|
||||
|
||||
set(retry_number 5)
|
||||
|
||||
message(STATUS "Downloading...
|
||||
_ep_message_quiet_capture(STATUS "Downloading...
|
||||
dst='@LOCAL@'
|
||||
timeout='@TIMEOUT_MSG@'
|
||||
inactivity timeout='@INACTIVITY_TIMEOUT_MSG@'"
|
||||
)
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
set(download_retry_codes 7 6 8 15)
|
||||
set(skip_url_list)
|
||||
set(status_code)
|
||||
@@ -120,7 +135,8 @@ Old file will be removed and new file downloaded from URL."
|
||||
endif()
|
||||
foreach(url @REMOTE@)
|
||||
if(NOT url IN_LIST skip_url_list)
|
||||
message(STATUS "Using src='${url}'")
|
||||
_ep_message_quiet_capture(STATUS "Using src='${url}'")
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
|
||||
@TLS_VERIFY_CODE@
|
||||
@TLS_CAINFO_CODE@
|
||||
@@ -145,10 +161,12 @@ Old file will be removed and new file downloaded from URL."
|
||||
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...")
|
||||
_ep_message_quiet_capture(STATUS "Hash mismatch, removing...")
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
file(REMOVE "@LOCAL@")
|
||||
else()
|
||||
message(STATUS "Downloading... done")
|
||||
_ep_message_quiet_capture(STATUS "Downloading... done")
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
else()
|
||||
@@ -171,7 +189,7 @@ Old file will be removed and new file downloaded from URL."
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
message(FATAL_ERROR
|
||||
_ep_message_quiet_capture(FATAL_ERROR
|
||||
"Each download failed!
|
||||
${logFailedURLs}
|
||||
"
|
||||
|
||||
@@ -3,17 +3,24 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
|
||||
# Make file names absolute:
|
||||
#
|
||||
get_filename_component(filename "@filename@" ABSOLUTE)
|
||||
get_filename_component(directory "@directory@" ABSOLUTE)
|
||||
|
||||
message(STATUS "extracting...
|
||||
_ep_message_quiet_capture(STATUS "extracting...
|
||||
src='${filename}'
|
||||
dst='${directory}'")
|
||||
dst='${directory}'"
|
||||
)
|
||||
|
||||
if(NOT EXISTS "${filename}")
|
||||
message(FATAL_ERROR "File to extract does not exist: '${filename}'")
|
||||
_ep_message_quiet_capture(FATAL_ERROR
|
||||
"File to extract does not exist: '${filename}'"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Prepare a space for extracting:
|
||||
@@ -27,20 +34,23 @@ file(MAKE_DIRECTORY "${ut_dir}")
|
||||
|
||||
# Extract it:
|
||||
#
|
||||
message(STATUS "extracting... [tar @args@]")
|
||||
_ep_message_quiet_capture(STATUS "extracting... [tar @args@]")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar @args@ ${filename}
|
||||
WORKING_DIRECTORY ${ut_dir}
|
||||
RESULT_VARIABLE rv)
|
||||
RESULT_VARIABLE rv
|
||||
${capture_output}
|
||||
)
|
||||
_ep_accumulate_captured_output()
|
||||
|
||||
if(NOT rv EQUAL 0)
|
||||
message(STATUS "extracting... [error clean up]")
|
||||
_ep_message_quiet_capture(STATUS "extracting... [error clean up]")
|
||||
file(REMOVE_RECURSE "${ut_dir}")
|
||||
message(FATAL_ERROR "Extract of '${filename}' failed")
|
||||
_ep_message_quiet_capture(FATAL_ERROR "Extract of '${filename}' failed")
|
||||
endif()
|
||||
|
||||
# Analyze what came out of the tar file:
|
||||
#
|
||||
message(STATUS "extracting... [analysis]")
|
||||
_ep_message_quiet_capture(STATUS "extracting... [analysis]")
|
||||
file(GLOB contents "${ut_dir}/*")
|
||||
list(REMOVE_ITEM contents "${ut_dir}/.DS_Store")
|
||||
list(LENGTH contents n)
|
||||
@@ -50,14 +60,14 @@ endif()
|
||||
|
||||
# Move "the one" directory to the final directory:
|
||||
#
|
||||
message(STATUS "extracting... [rename]")
|
||||
_ep_message_quiet_capture(STATUS "extracting... [rename]")
|
||||
file(REMOVE_RECURSE ${directory})
|
||||
get_filename_component(contents ${contents} ABSOLUTE)
|
||||
file(RENAME ${contents} ${directory})
|
||||
|
||||
# Clean up:
|
||||
#
|
||||
message(STATUS "extracting... [clean up]")
|
||||
_ep_message_quiet_capture(STATUS "extracting... [clean up]")
|
||||
file(REMOVE_RECURSE "${ut_dir}")
|
||||
|
||||
message(STATUS "extracting... done")
|
||||
_ep_message_quiet_capture(STATUS "extracting... done")
|
||||
|
||||
@@ -3,57 +3,81 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
|
||||
if(NOT "@gitclone_infofile@" IS_NEWER_THAN "@gitclone_stampfile@")
|
||||
message(STATUS "Avoiding repeated git clone, stamp file is up to date: '@gitclone_stampfile@'")
|
||||
if(NOT quiet)
|
||||
message(STATUS
|
||||
"Avoiding repeated git clone, stamp file is up to date: "
|
||||
"'@gitclone_stampfile@'"
|
||||
)
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "@source_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to remove directory: '@source_dir@'")
|
||||
endif()
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to remove directory: '@source_dir@'"
|
||||
)
|
||||
|
||||
# try the clone 3 times in case there is an odd git clone issue
|
||||
set(error_code 1)
|
||||
set(number_of_tries 0)
|
||||
while(error_code AND number_of_tries LESS 3)
|
||||
# If you are seeing the following call hang and you have QUIET enabled, try
|
||||
# turning QUIET off to show any output immediately. The command may be
|
||||
# blocking while waiting for user input (e.g. a password to a SSH key).
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" @git_options@ clone @git_clone_options@ "@git_repository@" "@src_name@"
|
||||
COMMAND "@git_EXECUTABLE@" @git_options@
|
||||
clone @git_clone_options@ "@git_repository@" "@src_name@"
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
${capture_output}
|
||||
)
|
||||
if(NOT "${out_var}" STREQUAL "")
|
||||
string(APPEND accumulated_output "${out_var}\n")
|
||||
endif()
|
||||
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.")
|
||||
endif()
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to clone repository: '@git_repository@'")
|
||||
set(msg "Had to git clone more than once: ${number_of_tries} times.")
|
||||
if(quiet)
|
||||
string(APPEND accumulated_output "${msg}\n")
|
||||
else()
|
||||
message(STATUS "${msg}")
|
||||
endif()
|
||||
endif()
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to clone repository: '@git_repository@'"
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" @git_options@ checkout "@git_tag@" @git_checkout_explicit--@
|
||||
COMMAND "@git_EXECUTABLE@" @git_options@
|
||||
checkout "@git_tag@" @git_checkout_explicit--@
|
||||
WORKING_DIRECTORY "@work_dir@/@src_name@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to checkout tag: '@git_tag@'")
|
||||
endif()
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code "Failed to checkout tag: '@git_tag@'")
|
||||
|
||||
set(init_submodules @init_submodules@)
|
||||
if(init_submodules)
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" @git_options@ submodule update @git_submodules_recurse@ --init @git_submodules@
|
||||
COMMAND "@git_EXECUTABLE@" @git_options@
|
||||
submodule update @git_submodules_recurse@ --init @git_submodules@
|
||||
WORKING_DIRECTORY "@work_dir@/@src_name@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
endif()
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to update submodules in: '@work_dir@/@src_name@'")
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to update submodules in: '@work_dir@/@src_name@'"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Complete success, update the script-last-run stamp file:
|
||||
@@ -61,7 +85,8 @@ endif()
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "@gitclone_infofile@" "@gitclone_stampfile@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to copy script-last-run stamp file: '@gitclone_stampfile@'")
|
||||
endif()
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to copy script-last-run stamp file: '@gitclone_stampfile@'"
|
||||
)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
|
||||
function(get_hash_for_ref ref out_var err_var)
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" rev-parse "${ref}"
|
||||
@@ -49,7 +53,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}")
|
||||
_ep_message_quiet_capture(VERBOSE "Already at requested tag: ${tag_sha}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
@@ -65,7 +69,7 @@ else()
|
||||
get_hash_for_ref("@git_tag@" tag_sha error_msg)
|
||||
if(tag_sha STREQUAL head_sha)
|
||||
# Have the right commit checked out already
|
||||
message(VERBOSE "Already at requested ref: ${tag_sha}")
|
||||
_ep_message_quiet_capture(VERBOSE "Already at requested ref: ${tag_sha}")
|
||||
return()
|
||||
|
||||
elseif(tag_sha STREQUAL "")
|
||||
@@ -76,7 +80,7 @@ else()
|
||||
set(fetch_required YES)
|
||||
set(checkout_name "@git_tag@")
|
||||
if(NOT error_msg STREQUAL "")
|
||||
message(VERBOSE "${error_msg}")
|
||||
_ep_message_quiet_capture(VERBOSE "${error_msg}")
|
||||
endif()
|
||||
|
||||
else()
|
||||
@@ -86,18 +90,22 @@ else()
|
||||
set(fetch_required NO)
|
||||
set(checkout_name "@git_tag@")
|
||||
if(NOT error_msg STREQUAL "")
|
||||
message(WARNING "${error_msg}")
|
||||
_ep_message_quiet_capture(WARNING "${error_msg}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(fetch_required)
|
||||
message(VERBOSE "Fetching latest from the remote @git_remote_name@")
|
||||
_ep_message_quiet_capture(VERBOSE "Fetching latest from the remote @git_remote_name@")
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" fetch --tags --force "@git_remote_name@"
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to fetch from the remote @git_remote_name@'"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -128,12 +136,15 @@ if(git_update_strategy MATCHES "^REBASE(_CHECKOUT)?$")
|
||||
|
||||
else()
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" for-each-ref "--format='%(upstream:short)'" "${current_branch}"
|
||||
COMMAND "@git_EXECUTABLE@" for-each-ref
|
||||
"--format='%(upstream:short)'" "${current_branch}"
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code # There is no error if no upstream is set
|
||||
OUTPUT_VARIABLE upstream_branch
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
COMMAND_ERROR_IS_FATAL ANY # There is no error if no upstream is set
|
||||
${capture_error_only}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
if(NOT upstream_branch STREQUAL checkout_name)
|
||||
# Not safe to rebase when asked to checkout a different branch to the one
|
||||
# we are tracking. If we did rebase, we could end up with arbitrary
|
||||
@@ -145,7 +156,9 @@ if(git_update_strategy MATCHES "^REBASE(_CHECKOUT)?$")
|
||||
|
||||
endif()
|
||||
elseif(NOT git_update_strategy STREQUAL "CHECKOUT")
|
||||
message(FATAL_ERROR "Unsupported git update strategy: ${git_update_strategy}")
|
||||
_ep_message_quiet_capture(FATAL_ERROR
|
||||
"Unsupported git update strategy: ${git_update_strategy}"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -155,10 +168,9 @@ execute_process(
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
OUTPUT_VARIABLE repo_status
|
||||
${capture_error_only}
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to get the status")
|
||||
endif()
|
||||
_ep_command_check_result(error_code "Failed to get the status")
|
||||
string(LENGTH "${repo_status}" need_stash)
|
||||
|
||||
# If not in clean state, stash changes in order to be able to perform a
|
||||
@@ -167,16 +179,20 @@ if(need_stash)
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" stash save @git_stash_save_options@
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
endif()
|
||||
|
||||
if(git_update_strategy STREQUAL "CHECKOUT")
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}"
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
else()
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" rebase "${checkout_name}"
|
||||
@@ -198,12 +214,14 @@ else()
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
)
|
||||
)
|
||||
endif()
|
||||
message(FATAL_ERROR "\nFailed to rebase in: '@work_dir@'."
|
||||
"\nOutput from the attempted rebase follows:"
|
||||
"\n${rebase_output}"
|
||||
"\n\nYou will have to resolve the conflicts manually")
|
||||
_ep_message_quiet_capture(FATAL_ERROR
|
||||
"\nFailed to rebase in: '@work_dir@'."
|
||||
"\nOutput from the attempted rebase follows:"
|
||||
"\n${rebase_output}"
|
||||
"\n\nYou will have to resolve the conflicts manually"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Fall back to checkout. We create an annotated tag so that the user
|
||||
@@ -215,21 +233,27 @@ else()
|
||||
set(tag_name _cmake_ExternalProject_moved_from_here_${tag_timestamp}Z)
|
||||
set(error_log_file ${CMAKE_CURRENT_LIST_DIR}/rebase_error_${tag_timestamp}Z.log)
|
||||
file(WRITE ${error_log_file} "${rebase_output}")
|
||||
message(WARNING "Rebase failed, output has been saved to ${error_log_file}"
|
||||
"\nFalling back to checkout, previous commit tagged as ${tag_name}")
|
||||
_ep_message_quiet_capture(WARNING
|
||||
"Rebase failed, output has been saved to ${error_log_file}"
|
||||
"\nFalling back to checkout, previous commit tagged as ${tag_name}"
|
||||
)
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" tag -a
|
||||
-m "ExternalProject attempting to move from here to ${checkout_name}"
|
||||
${tag_name}
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" checkout "${checkout_name}"
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -239,30 +263,42 @@ if(need_stash)
|
||||
COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
${capture_output}
|
||||
)
|
||||
_ep_accumulate_captured_output()
|
||||
if(error_code)
|
||||
# Stash pop --index failed: Try again dropping the index
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" reset --hard --quiet
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
${capture_output}
|
||||
)
|
||||
_ep_accumulate_captured_output()
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" stash pop --quiet
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_accumulate_captured_output()
|
||||
if(error_code)
|
||||
# Stash pop failed: Restore previous state.
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" reset --hard --quiet ${head_sha}
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
${capture_output}
|
||||
)
|
||||
_ep_accumulate_captured_output()
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" stash pop --index --quiet
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
${capture_output}
|
||||
)
|
||||
_ep_accumulate_captured_output()
|
||||
_ep_message_quiet_capture(FATAL_ERROR
|
||||
"Failed to unstash changes in: '@work_dir@'.\n"
|
||||
"You will have to resolve the conflicts manually"
|
||||
)
|
||||
message(FATAL_ERROR "\nFailed to unstash changes in: '@work_dir@'."
|
||||
"\nYou will have to resolve the conflicts manually")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -272,6 +308,8 @@ if(init_submodules)
|
||||
execute_process(
|
||||
COMMAND "@git_EXECUTABLE@" submodule update @git_submodules_recurse@ --init @git_submodules@
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
endif()
|
||||
|
||||
@@ -3,43 +3,56 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
|
||||
if(NOT "@hgclone_infofile@" IS_NEWER_THAN "@hgclone_stampfile@")
|
||||
message(STATUS "Avoiding repeated hg clone, stamp file is up to date: '@hgclone_stampfile@'")
|
||||
if(NOT quiet)
|
||||
message(STATUS
|
||||
"Avoiding repeated hg clone, stamp file is up to date: "
|
||||
"'@hgclone_stampfile@'"
|
||||
)
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf "@source_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to remove directory: '@source_dir@'")
|
||||
endif()
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to remove directory: '@source_dir@'"
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND "@hg_EXECUTABLE@" clone -U "@hg_repository@" "@src_name@"
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to clone repository: '@hg_repository@'")
|
||||
endif()
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to clone repository: '@hg_repository@'"
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND "@hg_EXECUTABLE@" update @hg_tag@
|
||||
WORKING_DIRECTORY "@work_dir@/@src_name@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to checkout tag: '@hg_tag@'")
|
||||
endif()
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to checkout tag: '@hg_tag@'"
|
||||
)
|
||||
|
||||
# Complete success, update the script-last-run stamp file:
|
||||
#
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "@hgclone_infofile@" "@hgclone_stampfile@"
|
||||
RESULT_VARIABLE error_code
|
||||
)
|
||||
if(error_code)
|
||||
message(FATAL_ERROR "Failed to copy script-last-run stamp file: '@hgclone_stampfile@'")
|
||||
endif()
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(
|
||||
error_code "Failed to copy script-last-run stamp file: '@hgclone_stampfile@'"
|
||||
)
|
||||
|
||||
@@ -3,14 +3,22 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.19)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
|
||||
execute_process(
|
||||
COMMAND "@hg_EXECUTABLE@" pull
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
|
||||
execute_process(
|
||||
COMMAND "@hg_EXECUTABLE@" update @hg_tag@
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
WORKING_DIRECTORY "@work_dir@"
|
||||
RESULT_VARIABLE error_code
|
||||
${capture_output}
|
||||
)
|
||||
_ep_command_check_result(error_code)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(quiet "@quiet@")
|
||||
set(script_dir "@CMAKE_CURRENT_FUNCTION_LIST_DIR@/ExternalProject")
|
||||
include(${script_dir}/captured_process_setup.cmake)
|
||||
|
||||
if("@LOCAL@" STREQUAL "")
|
||||
message(FATAL_ERROR "LOCAL can't be empty")
|
||||
endif()
|
||||
@@ -13,22 +17,27 @@ endif()
|
||||
|
||||
function(do_verify)
|
||||
if("@ALGO@" STREQUAL "")
|
||||
message(WARNING "File will not be verified since no URL_HASH specified")
|
||||
_ep_message_quiet_capture(WARNING
|
||||
"File will not be verified since no URL_HASH specified"
|
||||
)
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if("@EXPECT_VALUE@" STREQUAL "")
|
||||
message(FATAL_ERROR "EXPECT_VALUE can't be empty")
|
||||
_ep_message_quiet_capture(FATAL_ERROR "EXPECT_VALUE can't be empty")
|
||||
endif()
|
||||
|
||||
message(STATUS
|
||||
_ep_message_quiet_capture(STATUS
|
||||
"verifying file...
|
||||
file='@LOCAL@'")
|
||||
file='@LOCAL@'"
|
||||
)
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
|
||||
file("@ALGO@" "@LOCAL@" actual_value)
|
||||
|
||||
if(NOT "${actual_value}" STREQUAL "@EXPECT_VALUE@")
|
||||
message(FATAL_ERROR
|
||||
_ep_message_quiet_capture(FATAL_ERROR
|
||||
"error: @ALGO@ hash of
|
||||
@LOCAL@
|
||||
does not match expected value
|
||||
@@ -37,7 +46,8 @@ does not match expected value
|
||||
")
|
||||
endif()
|
||||
|
||||
message(STATUS "verifying file... done")
|
||||
_ep_message_quiet_capture(STATUS "verifying file... done")
|
||||
set(accumulated_output "${accumulated_output}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
do_verify()
|
||||
|
||||
@@ -849,8 +849,6 @@ function(__FetchContent_directPopulate contentName)
|
||||
SUBBUILD_DIR
|
||||
SOURCE_DIR
|
||||
BINARY_DIR
|
||||
# We need special processing if DOWNLOAD_NO_EXTRACT is true
|
||||
DOWNLOAD_NO_EXTRACT
|
||||
# Prevent the following from being passed through
|
||||
CONFIGURE_COMMAND
|
||||
BUILD_COMMAND
|
||||
@@ -894,123 +892,28 @@ function(__FetchContent_directPopulate contentName)
|
||||
set(${contentName}_SOURCE_DIR "${ARG_SOURCE_DIR}" PARENT_SCOPE)
|
||||
set(${contentName}_BINARY_DIR "${ARG_BINARY_DIR}" PARENT_SCOPE)
|
||||
|
||||
# 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.
|
||||
unset(ARG_EXTRA)
|
||||
foreach(arg IN LISTS ARG_UNPARSED_ARGUMENTS)
|
||||
set(ARG_EXTRA "${ARG_EXTRA} \"${arg}\"")
|
||||
endforeach()
|
||||
|
||||
if(ARG_DOWNLOAD_NO_EXTRACT)
|
||||
set(ARG_EXTRA "${ARG_EXTRA} DOWNLOAD_NO_EXTRACT YES")
|
||||
set(__FETCHCONTENT_COPY_FILE
|
||||
"
|
||||
ExternalProject_Get_Property(${contentName}-populate DOWNLOADED_FILE)
|
||||
get_filename_component(dlFileName \"\${DOWNLOADED_FILE}\" NAME)
|
||||
|
||||
ExternalProject_Add_Step(${contentName}-populate copyfile
|
||||
COMMAND \"${CMAKE_COMMAND}\" -E copy_if_different
|
||||
\"<DOWNLOADED_FILE>\" \"${ARG_SOURCE_DIR}\"
|
||||
DEPENDEES patch
|
||||
DEPENDERS configure
|
||||
BYPRODUCTS \"${ARG_SOURCE_DIR}/\${dlFileName}\"
|
||||
COMMENT \"Copying file to SOURCE_DIR\"
|
||||
)
|
||||
")
|
||||
if(ARG_QUIET)
|
||||
set(quiet TRUE)
|
||||
else()
|
||||
unset(__FETCHCONTENT_COPY_FILE)
|
||||
endif()
|
||||
|
||||
# Hide output if requested, but save it to a variable in case there's an
|
||||
# error so we can show the output upon failure. When not quiet, don't
|
||||
# capture the output to a variable because the user may want to see the
|
||||
# output as it happens (e.g. progress during long downloads). Combine both
|
||||
# stdout and stderr in the one capture variable so the output stays in order.
|
||||
if (ARG_QUIET)
|
||||
set(outputOptions
|
||||
OUTPUT_VARIABLE capturedOutput
|
||||
ERROR_VARIABLE capturedOutput
|
||||
)
|
||||
else()
|
||||
set(capturedOutput)
|
||||
set(outputOptions)
|
||||
set(quiet FALSE)
|
||||
message(STATUS "Populating ${contentName}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_GENERATOR)
|
||||
set(subCMakeOpts "-G${CMAKE_GENERATOR}")
|
||||
if(CMAKE_GENERATOR_PLATFORM)
|
||||
list(APPEND subCMakeOpts "-A${CMAKE_GENERATOR_PLATFORM}")
|
||||
endif()
|
||||
if(CMAKE_GENERATOR_TOOLSET)
|
||||
list(APPEND subCMakeOpts "-T${CMAKE_GENERATOR_TOOLSET}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_MAKE_PROGRAM)
|
||||
list(APPEND subCMakeOpts "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}")
|
||||
endif()
|
||||
|
||||
else()
|
||||
# Likely we've been invoked via CMake's script mode where no
|
||||
# generator is set (and hence CMAKE_MAKE_PROGRAM could not be
|
||||
# trusted even if provided). We will have to rely on being
|
||||
# able to find the default generator and build tool.
|
||||
unset(subCMakeOpts)
|
||||
endif()
|
||||
|
||||
if(DEFINED CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY)
|
||||
list(APPEND subCMakeOpts
|
||||
"-DCMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY=${CMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY}")
|
||||
endif()
|
||||
|
||||
# Avoid using if(... IN_LIST ...) so we don't have to alter policy settings
|
||||
set(__FETCHCONTENT_CACHED_INFO "")
|
||||
list(FIND ARG_UNPARSED_ARGUMENTS GIT_REPOSITORY indexResult)
|
||||
if(indexResult GREATER_EQUAL 0)
|
||||
find_package(Git QUIET)
|
||||
set(__FETCHCONTENT_CACHED_INFO
|
||||
"# Pass through things we've already detected in the main project to avoid
|
||||
# paying the cost of redetecting them again in ExternalProject_Add()
|
||||
set(GIT_EXECUTABLE [==[${GIT_EXECUTABLE}]==])
|
||||
set(GIT_VERSION_STRING [==[${GIT_VERSION_STRING}]==])
|
||||
set_property(GLOBAL PROPERTY _CMAKE_FindGit_GIT_EXECUTABLE_VERSION
|
||||
[==[${GIT_EXECUTABLE};${GIT_VERSION_STRING}]==]
|
||||
)
|
||||
")
|
||||
endif()
|
||||
|
||||
# Create and build a separate CMake project to carry out the population.
|
||||
# If we've already previously done these steps, they will not cause
|
||||
# anything to be updated, so extra rebuilds of the project won't occur.
|
||||
# Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
|
||||
# has this set to something not findable on the PATH.
|
||||
configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/FetchContent/CMakeLists.cmake.in"
|
||||
"${ARG_SUBBUILD_DIR}/CMakeLists.txt")
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} ${subCMakeOpts} .
|
||||
RESULT_VARIABLE result
|
||||
${outputOptions}
|
||||
WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
|
||||
include(ExternalProject)
|
||||
set(argsQuoted)
|
||||
foreach(__item IN LISTS ARG_UNPARSED_ARGUMENTS)
|
||||
string(APPEND argsQuoted " [==[${__item}]==]")
|
||||
endforeach()
|
||||
cmake_language(EVAL CODE "
|
||||
_ep_do_preconfigure_steps_now(${contentName}
|
||||
${argsQuoted}
|
||||
QUIET ${quiet}
|
||||
SOURCE_DIR [==[${ARG_SOURCE_DIR}]==]
|
||||
BINARY_DIR [==[${ARG_BINARY_DIR}]==]
|
||||
USES_TERMINAL_DOWNLOAD YES
|
||||
USES_TERMINAL_UPDATE YES
|
||||
)"
|
||||
)
|
||||
if(result)
|
||||
if(capturedOutput)
|
||||
message("${capturedOutput}")
|
||||
endif()
|
||||
message(FATAL_ERROR "CMake step for ${contentName} failed: ${result}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
${outputOptions}
|
||||
WORKING_DIRECTORY "${ARG_SUBBUILD_DIR}"
|
||||
)
|
||||
if(result)
|
||||
if(capturedOutput)
|
||||
message("${capturedOutput}")
|
||||
endif()
|
||||
message(FATAL_ERROR "Build step for ${contentName} failed: ${result}")
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
cmake_minimum_required(VERSION ${CMAKE_VERSION})
|
||||
|
||||
# We name the project and the target for the ExternalProject_Add() call
|
||||
# to something that will highlight to the user what we are working on if
|
||||
# something goes wrong and an error message is produced.
|
||||
|
||||
project(${contentName}-populate NONE)
|
||||
|
||||
@__FETCHCONTENT_CACHED_INFO@
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(${contentName}-populate
|
||||
${ARG_EXTRA}
|
||||
SOURCE_DIR "${ARG_SOURCE_DIR}"
|
||||
BINARY_DIR "${ARG_BINARY_DIR}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
USES_TERMINAL_DOWNLOAD YES
|
||||
USES_TERMINAL_UPDATE YES
|
||||
)
|
||||
|
||||
@__FETCHCONTENT_COPY_FILE@
|
||||
@@ -7,7 +7,6 @@ run_cmake(DirectIgnoresDetails)
|
||||
run_cmake(FirstDetailsWin)
|
||||
run_cmake(DownloadTwice)
|
||||
run_cmake(DownloadFile)
|
||||
run_cmake(SameGenerator)
|
||||
run_cmake(VarDefinitions)
|
||||
run_cmake(GetProperties)
|
||||
run_cmake(UsesTerminalOverride)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
t1
|
||||
DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "Download command executed"
|
||||
)
|
||||
|
||||
FetchContent_Populate(t1)
|
||||
|
||||
file(STRINGS "${FETCHCONTENT_BASE_DIR}/t1-subbuild/CMakeCache.txt"
|
||||
matchLine REGEX "^CMAKE_GENERATOR:.*="
|
||||
LIMIT_COUNT 1
|
||||
)
|
||||
if(NOT matchLine MATCHES "${CMAKE_GENERATOR}")
|
||||
message(FATAL_ERROR "Generator line mismatch: ${matchLine}\n"
|
||||
" Expected type: ${CMAKE_GENERATOR}")
|
||||
endif()
|
||||
Reference in New Issue
Block a user