1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-17 15:32:10 +08:00

ExternalProject: Add DOWNLOAD_EXTRACT_TIMESTAMP option and policy

Add the option to keep the current filestamps when extracting an
archive in ExternalProject_Add.

Enabling this option makes the behavior consistent with how
ExternalProject_Add is used when checking out code from revision
control instead of an archive.

Fixes: #22746
This commit is contained in:
Kasper Laudrup
2022-04-01 20:18:33 +02:00
committed by Craig Scott
parent e0dbca93aa
commit a283e58b51
21 changed files with 149 additions and 5 deletions

View File

@@ -58,6 +58,7 @@ Policies Introduced by CMake 3.24
.. toctree::
:maxdepth: 1
CMP0135: ExternalProject ignores timestamps in archives by default for the URL download method. </policy/CMP0135>
CMP0134: Fallback to \"HOST\" Windows registry view when \"TARGET\" view is not usable. </policy/CMP0134>
CMP0133: The CPack module disables SLA by default in the CPack DragNDrop Generator. </policy/CMP0133>
CMP0132: Do not set compiler environment variables on first run. </policy/CMP0132>

29
Help/policy/CMP0135.rst Normal file
View File

@@ -0,0 +1,29 @@
CMP0135
-------
.. versionadded:: 3.24
When using the ``URL`` download method with the :command:`ExternalProject_Add`
command, CMake 3.23 and below sets the timestamps of the extracted contents
to the same as the timestamps in the archive. When the ``URL`` changes, the
new archive is downloaded and extracted, but the timestamps of the extracted
contents might not be newer than the previous contents. Anything that depends
on the extracted contents might not be rebuilt, even though the contents may
change.
CMake 3.24 and above prefers to set the timestamps of all extracted contents
to the time of the extraction. This ensures that anything that depends on the
extracted contents will be rebuilt whenever the ``URL`` changes.
The ``DOWNLOAD_EXTRACT_TIMESTAMP`` option to the
:command:`ExternalProject_Add` command can be used to explicitly specify how
timestamps should be handled. When ``DOWNLOAD_EXTRACT_TIMESTAMP`` is not
given, this policy controls the default behavior. The ``OLD`` behavior for
this policy is to restore the timestamps from the archive. The ``NEW``
behavior sets the timestamps of extracted contents to the time of extraction.
This policy was introduced in CMake version 3.24. CMake version |release|
warns when the policy is not set and uses ``OLD`` behavior. Use the
:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
.. include:: DEPRECATED.txt

View File

@@ -0,0 +1,8 @@
ExternalProject-no-extract-timestamp
------------------------------------
* The :command:`ExternalProject_Add` command gained a new
``DOWNLOAD_EXTRACT_TIMESTAMP`` option for controlling whether the timestamps
of extracted contents are set to match those in the archive when the ``URL``
download method is used. A new policy :policy:`CMP0135` was added to control
the default behavior when the new option is not used.

View File

@@ -170,6 +170,19 @@ External Project Definition
the default name is generally suitable and is not normally used outside
of code internal to the ``ExternalProject`` module.
``DOWNLOAD_EXTRACT_TIMESTAMP <bool>``
.. versionadded:: 3.24
When specified with a true value, the timestamps of the extracted
files will match those in the archive. When false, the timestamps of
the extracted files will reflect the time at which the extraction
was performed. If the download URL changes, timestamps based off
those in the archive can result in dependent targets not being rebuilt
when they potentially should have been. Therefore, unless the file
timestamps are significant to the project in some way, use a false
value for this option. If ``DOWNLOAD_EXTRACT_TIMESTAMP`` is not given,
the default is false. See policy :policy:`CMP0135`.
``DOWNLOAD_NO_EXTRACT <bool>``
.. versionadded:: 3.6
@@ -1534,7 +1547,7 @@ function(_ep_write_verifyfile_script script_filename LOCAL hash)
endfunction()
function(_ep_write_extractfile_script script_filename name filename directory)
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)$")
@@ -2761,16 +2774,51 @@ hash=${hash}
)
endif()
list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/verify-${name}.cmake)
if (NOT no_extract)
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)
else ()
set_property(TARGET ${name} PROPERTY _EP_DOWNLOADED_FILE ${file})
endif ()
endif()
else()
@@ -3438,6 +3486,9 @@ function(ExternalProject_Add name)
)
set(cmp0114 "NEW")
endif()
cmake_policy(GET CMP0135 _EP_CMP0135
PARENT_SCOPE # undocumented, do not use outside of CMake
)
_ep_get_configuration_subdir_suffix(cfgdir)
@@ -3483,6 +3534,7 @@ function(ExternalProject_Add name)
URL_HASH
URL_MD5
DOWNLOAD_NAME
DOWNLOAD_EXTRACT_TIMESTAMP
DOWNLOAD_NO_EXTRACT
DOWNLOAD_NO_PROGRESS
TIMEOUT

View File

@@ -29,7 +29,7 @@ file(MAKE_DIRECTORY "${ut_dir}")
# Extract it:
#
message(STATUS "extracting... [tar @args@]")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar @args@ ${filename}
execute_process(COMMAND ${CMAKE_COMMAND} -E tar @args@ ${filename} @options@
WORKING_DIRECTORY ${ut_dir}
RESULT_VARIABLE rv
)

View File

@@ -404,6 +404,10 @@ class cmMakefile;
SELECT(POLICY, CMP0134, \
"Fallback to \"HOST\" Windows registry view when \"TARGET\" view " \
"is not usable.", \
3, 24, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0135, \
"ExternalProject ignores timestamps in archives by default for the " \
"URL download method", \
3, 24, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)

View File

@@ -0,0 +1,18 @@
include(ExternalProject)
set(stamp_dir "${CMAKE_CURRENT_BINARY_DIR}/stamps")
ExternalProject_Add(fake_ext_proj
# We don't actually do a build, so we never try to download from this URL
URL https://example.com/something.zip
STAMP_DIR ${stamp_dir}
)
# Report whether the --touch option was added to the extraction script
set(extraction_script "${stamp_dir}/extract-fake_ext_proj.cmake")
file(STRINGS "${extraction_script}" results REGEX "--touch")
if("${results}" STREQUAL "")
message(STATUS "Using timestamps from archive")
else()
message(STATUS "Using extraction time for the timestamps")
endif()

View File

@@ -0,0 +1 @@
Using extraction time for the timestamps

View File

@@ -0,0 +1,2 @@
cmake_policy(SET CMP0135 NEW)
include(CMP0135-Common.cmake)

View File

@@ -0,0 +1 @@
Using timestamps from archive

View File

@@ -0,0 +1,2 @@
cmake_policy(SET CMP0135 OLD)
include(CMP0135-Common.cmake)

View File

@@ -0,0 +1,10 @@
CMake Warning \(dev\) at .*/Modules/ExternalProject.cmake:[0-9]+ \(message\):
The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy CMP0135 is
not set\. The policy's OLD behavior will be used\. When using a URL
download, the timestamps of extracted files should preferably be that of
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\.

View File

@@ -0,0 +1 @@
Using timestamps from archive

View File

@@ -0,0 +1,2 @@
include(CMP0135-Common.cmake)

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.23)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1,5 @@
include(RunCMake)
run_cmake(CMP0135-WARN)
run_cmake(CMP0135-OLD)
run_cmake(CMP0135-NEW)

View File

@@ -149,6 +149,7 @@ if("${CMAKE_C_COMPILER_ID}" STREQUAL "LCC" OR
endif()
add_RunCMake_test(CMP0132)
add_RunCMake_test(CMP0135)
# The test for Policy 65 requires the use of the
# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode

View File

@@ -4,6 +4,7 @@ if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
else()
cmake_policy(SET CMP0114 OLD) # Test deprecated behavior.
endif()
cmake_policy(SET CMP0135 NEW)
include(ExternalProject)

View File

@@ -4,6 +4,7 @@ if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
else()
cmake_policy(SET CMP0114 OLD) # Test deprecated behavior.
endif()
cmake_policy(SET CMP0135 NEW)
include(ExternalProject)

View File

@@ -3,4 +3,5 @@ project(${RunCMake_TEST} NONE)
if(CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12 AND NOT RunCMake_TEST STREQUAL "Xcode-CMP0114")
cmake_policy(SET CMP0114 NEW)
endif()
cmake_policy(SET CMP0135 NEW)
include(${RunCMake_TEST}.cmake)

View File

@@ -1,4 +1,5 @@
cmake_policy(SET CMP0114 NEW)
cmake_policy(SET CMP0135 NEW)
include(ExternalProject)
ExternalProject_Add(BAR SOURCE_DIR . TEST_COMMAND echo test)
ExternalProject_Add_StepTargets(BAR NO_DEPENDS test)