summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2020-12-16 20:39:35 (GMT)
committerDaan De Meyer <daan.j.demeyer@gmail.com>2021-01-12 07:50:02 (GMT)
commit7155e358c9c0cdf7aa32f6c0dd6e67e112ebbac4 (patch)
tree033efdad67fd0f025f71e64c7cb2e77e723216a5
parent0f61fac6f028214d64ef6a407c6b98d4503ee2fe (diff)
downloadCMake-7155e358c9c0cdf7aa32f6c0dd6e67e112ebbac4.zip
CMake-7155e358c9c0cdf7aa32f6c0dd6e67e112ebbac4.tar.gz
CMake-7155e358c9c0cdf7aa32f6c0dd6e67e112ebbac4.tar.bz2
ExternalProject: Add CONFIGURE_HANDLED_BY_BUILD option
Fixes #21592.
-rw-r--r--Help/release/dev/external-project-configure-handled-by-build.rst8
-rw-r--r--Modules/ExternalProject.cmake56
-rw-r--r--Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake19
-rw-r--r--Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake28
-rw-r--r--Tests/RunCMake/ExternalProject/RunCMakeTest.cmake30
5 files changed, 129 insertions, 12 deletions
diff --git a/Help/release/dev/external-project-configure-handled-by-build.rst b/Help/release/dev/external-project-configure-handled-by-build.rst
new file mode 100644
index 0000000..4a1fac8
--- /dev/null
+++ b/Help/release/dev/external-project-configure-handled-by-build.rst
@@ -0,0 +1,8 @@
+external-project-configure-handled-by-build
+-------------------------------------------
+
+* The :module:`ExternalProject` function ``ExternalProject_Add`` learned a new
+ ``CONFIGURE_HANDLED_BY_BUILD`` option to have subsequent runs of the configure
+ step be triggered by the build step when an external project dependency
+ rebuilds instead of always rerunning the configure step when an external
+ project dependency rebuilds.
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index f0ce7d4..2d4f602 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -543,6 +543,18 @@ External Project Definition
When ``BUILD_IN_SOURCE`` option is enabled, the ``BUILD_COMMAND``
is used to point to an alternative directory within the source tree.
+ ``CONFIGURE_HANDLED_BY_BUILD <bool>``
+ .. versionadded:: 3.20
+
+ Enabling this option relaxes the dependencies of the configure step on
+ other external projects to order-only. This means the configure step will
+ be executed after its external project dependencies are built but it will
+ not be marked dirty when one of its external project dependencies is
+ rebuilt. This option can be enabled when the build step is smart enough
+ to figure out if the configure step needs to be rerun. CMake and Meson are
+ examples of build systems whose build step is smart enough to know if the
+ configure step needs to be rerun.
+
**Build Step Options:**
If the configure step assumed the external project uses CMake as its build
system, the build step will also. Otherwise, the build step will assume a
@@ -3081,6 +3093,23 @@ function(_ep_add_patch_command name)
)
endfunction()
+function(_ep_get_file_deps var name)
+ set(file_deps)
+
+ get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
+ foreach(dep IN LISTS deps)
+ get_property(dep_type TARGET ${dep} PROPERTY TYPE)
+ if(dep_type STREQUAL "UTILITY")
+ get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
+ if(is_ep)
+ _ep_get_step_stampfile(${dep} "done" done_stamp_file)
+ list(APPEND file_deps ${done_stamp_file})
+ endif()
+ endif()
+ endforeach()
+
+ set("${var}" "${file_deps}" PARENT_SCOPE)
+endfunction()
function(_ep_extract_configure_command var name)
get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
@@ -3189,19 +3218,13 @@ endfunction()
function(_ep_add_configure_command name)
ExternalProject_Get_Property(${name} binary_dir tmp_dir)
- # Depend on other external projects (file-level).
set(file_deps)
- get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
- foreach(dep IN LISTS deps)
- get_property(dep_type TARGET ${dep} PROPERTY TYPE)
- if(dep_type STREQUAL "UTILITY")
- get_property(is_ep TARGET ${dep} PROPERTY _EP_IS_EXTERNAL_PROJECT)
- if(is_ep)
- _ep_get_step_stampfile(${dep} "done" done_stamp_file)
- list(APPEND file_deps ${done_stamp_file})
- endif()
- endif()
- endforeach()
+ get_property(configure_handled_by_build TARGET ${name}
+ PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+ if(NOT configure_handled_by_build)
+ # Depend on other external projects (file-level)
+ _ep_get_file_deps(file_deps ${name})
+ endif()
_ep_extract_configure_command(cmd ${name})
@@ -3252,6 +3275,14 @@ endfunction()
function(_ep_add_build_command name)
ExternalProject_Get_Property(${name} binary_dir)
+ set(file_deps)
+ get_property(configure_handled_by_build TARGET ${name}
+ PROPERTY _EP_CONFIGURE_HANDLED_BY_BUILD)
+ if(configure_handled_by_build)
+ # Depend on other external projects (file-level)
+ _ep_get_file_deps(file_deps ${name})
+ endif()
+
get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
if(cmd_set)
get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
@@ -3294,6 +3325,7 @@ function(_ep_add_build_command name)
BYPRODUCTS \${build_byproducts}
WORKING_DIRECTORY \${binary_dir}
DEPENDEES configure
+ DEPENDS \${file_deps}
ALWAYS \${always}
${log}
${uses_terminal}
diff --git a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
new file mode 100644
index 0000000..887da0f
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
@@ -0,0 +1,19 @@
+file(TIMESTAMP "${STAMP_DIR}/proj1-configure" PROJ1_CONFIGURE_TIMESTAMP_AFTER "%s")
+# When BUILD_ALWAYS is set, the build stamp is never created.
+file(TIMESTAMP "${STAMP_DIR}/proj2-configure" PROJ2_CONFIGURE_TIMESTAMP_AFTER "%s")
+file(TIMESTAMP "${STAMP_DIR}/proj2-build" PROJ2_BUILD_TIMESTAMP_AFTER "%s")
+
+if(NOT PROJ1_CONFIGURE_TIMESTAMP_BEFORE EQUAL PROJ1_CONFIGURE_TIMESTAMP_AFTER)
+ set(RunCMake_TEST_FAILED "Unexpected rebuild of proj1 configure step (${PROJ1_CONFIGURE_TIMESTAMP_BEFORE} != ${PROJ1_CONFIGURE_TIMESTAMP_AFTER})")
+ return()
+endif()
+
+if(NOT PROJ2_CONFIGURE_TIMESTAMP_BEFORE EQUAL PROJ2_CONFIGURE_TIMESTAMP_AFTER)
+ set(RunCMake_TEST_FAILED "Unexpected rebuild of proj2 configure step (${PROJ2_CONFIGURE_TIMESTAMP_BEFORE} != ${PROJ2_CONFIGURE_TIMESTAMP_AFTER})")
+ return()
+endif()
+
+if(PROJ2_BUILD_TIMESTAMP_BEFORE EQUAL PROJ2_BUILD_TIMESTAMP_AFTER)
+ set(RunCMake_TEST_FAILED "proj2 build step did not rebuild (${PROJ2_BUILD_TIMESTAMP_BEFORE} != ${PROJ2_BUILD_TIMESTAMP_AFTER})")
+ return()
+endif()
diff --git a/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake
new file mode 100644
index 0000000..c86a60e
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/CONFIGURE_HANDLED_BY_BUILD.cmake
@@ -0,0 +1,28 @@
+include(ExternalProject)
+
+# Given this setup, on the first build, both configure steps and both build
+# steps will run. On a noop rebuild, only the build steps will run. Without
+# CONFIGURE_HANDLED_BY_BUILD, the configure step of proj2 would also run on a
+# noop rebuild.
+
+ExternalProject_Add(proj1
+ DOWNLOAD_COMMAND ""
+ SOURCE_DIR ""
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something"
+ # file(TIMESTAMP) gives back the timestamp in seconds so we sleep a second to
+ # make sure we get a different timestamp on the stamp file
+ BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1
+ INSTALL_COMMAND ""
+ BUILD_ALWAYS ON
+ STAMP_DIR "stamp"
+)
+ExternalProject_Add(proj2
+ DOWNLOAD_COMMAND ""
+ SOURCE_DIR ""
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "Doing something"
+ BUILD_COMMAND ${CMAKE_COMMAND} -E sleep 1
+ INSTALL_COMMAND ""
+ CONFIGURE_HANDLED_BY_BUILD ON
+ DEPENDS proj1
+ STAMP_DIR "stamp"
+)
diff --git a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
index 598671f..22b8d24 100644
--- a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
@@ -151,3 +151,33 @@ endif()
if(doSubstitutionTest)
__ep_test_with_build(Substitutions)
endif()
+
+function(__ep_test_CONFIGURE_HANDLED_BY_BUILD)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CONFIGURE_HANDLED_BY_BUILD-build)
+ run_cmake(CONFIGURE_HANDLED_BY_BUILD)
+
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(BUILD_CONFIG --config Debug)
+ set(STAMP_DIR "${RunCMake_TEST_BINARY_DIR}/stamp/Debug")
+ else()
+ set(BUILD_CONFIG "")
+ set(STAMP_DIR "${RunCMake_TEST_BINARY_DIR}/stamp")
+ endif()
+
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(CONFIGURE_HANDLED_BY_BUILD-build ${CMAKE_COMMAND} --build . ${BUILD_CONFIG})
+
+ # Calculate timestamps before rebuilding so we can compare before and after in
+ # CONFIGURE_HANDLED_BY_BUILD-rebuild-check.cmake
+
+ file(TIMESTAMP "${STAMP_DIR}/proj1-configure" PROJ1_CONFIGURE_TIMESTAMP_BEFORE "%s")
+ # When BUILD_ALWAYS is set, the build stamp is never created.
+ file(TIMESTAMP "${STAMP_DIR}/proj2-configure" PROJ2_CONFIGURE_TIMESTAMP_BEFORE "%s")
+ file(TIMESTAMP "${STAMP_DIR}/proj2-build" PROJ2_BUILD_TIMESTAMP_BEFORE "%s")
+
+ run_cmake_command(CONFIGURE_HANDLED_BY_BUILD-rebuild ${CMAKE_COMMAND} --build . ${BUILD_CONFIG})
+endfunction()
+
+if(NOT RunCMake_GENERATOR MATCHES "Visual Studio 9 ")
+ __ep_test_CONFIGURE_HANDLED_BY_BUILD()
+endif()