From d410092ece373985088c1c68f0a4d03e547d38d0 Mon Sep 17 00:00:00 2001 From: Craig Scott Date: Sun, 13 Sep 2026 15:30:50 +1000 Subject: [PATCH] FetchContent: Move log level detection into step script A step with a custom command shouldn't be seen as out-of-date just because the user re-runs configure with a different log level. Previously, the log level was written directly to the step scripts, but that meant the script changes if the user specifies a different effective log level to the previous configure. Now we move the log level detection into the script so that the script remains the same no matter what log level the user asks for. This was most noticeable with the PATCH step, since that always uses a custom command when present. Changing the log level would cause the PATCH step to re-run, which usually results in an error because PATCH typically only expects to run once after a DOWNLOAD. But the underlying problem would affect any step with a custom command, not just PATCH. Fixes: #28055 --- .../shared_internal_commands.cmake | 20 +++++++++++++------ Tests/RunCMake/FetchContent/LogLevel.cmake | 19 ++++++++++++++++++ .../RunCMake/FetchContent/LogLevelPatch.cmake | 7 +++++++ .../RunCMake/FetchContent/RunCMakeTest.cmake | 11 ++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 Tests/RunCMake/FetchContent/LogLevel.cmake create mode 100644 Tests/RunCMake/FetchContent/LogLevelPatch.cmake diff --git a/Modules/ExternalProject/shared_internal_commands.cmake b/Modules/ExternalProject/shared_internal_commands.cmake index 1ee015378c..d74d2dc78a 100644 --- a/Modules/ExternalProject/shared_internal_commands.cmake +++ b/Modules/ExternalProject/shared_internal_commands.cmake @@ -766,18 +766,26 @@ function(_ep_add_script_commands script_var work_dir cmd) # There can be multiple COMMANDs, but we have to split those up to # one command per call to execute_process() + string(CONCAT execute_process_precmd + "cmake_language(GET_MESSAGE_LOG_LEVEL _ep_step_log_level)\n" + "if(_ep_step_log_level MATCHES \"VERBOSE|DEBUG|TRACE\")\n" + " set(_ep_step_maybe_command_echo COMMAND_ECHO STDOUT)\n" + "else()\n" + " set(_ep_step_maybe_command_echo)\n" + "endif()\n" + ) string(CONCAT execute_process_cmd "execute_process(\n" " WORKING_DIRECTORY \"${work_dir}\"\n" " COMMAND_ERROR_IS_FATAL LAST\n" + " \${_ep_step_maybe_command_echo}\n" + " COMMAND " ) - 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}") + string(APPEND ${script_var} + "${execute_process_precmd}" + "${execute_process_cmd}" + ) foreach(cmd_arg IN LISTS cmd) if(cmd_arg STREQUAL "COMMAND") diff --git a/Tests/RunCMake/FetchContent/LogLevel.cmake b/Tests/RunCMake/FetchContent/LogLevel.cmake new file mode 100644 index 0000000000..f0f278d3be --- /dev/null +++ b/Tests/RunCMake/FetchContent/LogLevel.cmake @@ -0,0 +1,19 @@ +cmake_policy(SET CMP0168 NEW) + +include(FetchContent) + +set(patch_count_file "${CMAKE_CURRENT_BINARY_DIR}/patch-count.txt") + +FetchContent_Declare( + t1 + DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E make_directory + PATCH_COMMAND ${CMAKE_COMMAND} + -DPATCH_COUNT_FILE=${patch_count_file} + -P ${CMAKE_CURRENT_LIST_DIR}/LogLevelPatch.cmake +) +FetchContent_MakeAvailable(t1) + +file(READ "${patch_count_file}" patch_count) +if(NOT patch_count EQUAL 1) + message(SEND_ERROR "Patch step ran ${patch_count} times, expected once") +endif() diff --git a/Tests/RunCMake/FetchContent/LogLevelPatch.cmake b/Tests/RunCMake/FetchContent/LogLevelPatch.cmake new file mode 100644 index 0000000000..cd5b3cefed --- /dev/null +++ b/Tests/RunCMake/FetchContent/LogLevelPatch.cmake @@ -0,0 +1,7 @@ +if(EXISTS "${PATCH_COUNT_FILE}") + file(READ "${PATCH_COUNT_FILE}" patch_count) +else() + set(patch_count 0) +endif() +math(EXPR patch_count "${patch_count} + 1") +file(WRITE "${PATCH_COUNT_FILE}" "${patch_count}") diff --git a/Tests/RunCMake/FetchContent/RunCMakeTest.cmake b/Tests/RunCMake/FetchContent/RunCMakeTest.cmake index 9eb40b98b3..d4b0c3fcf0 100644 --- a/Tests/RunCMake/FetchContent/RunCMakeTest.cmake +++ b/Tests/RunCMake/FetchContent/RunCMakeTest.cmake @@ -36,6 +36,17 @@ run_cmake_with_cmp0168(MakeAvailable) run_cmake_with_cmp0168(MakeAvailableTwice) run_cmake_with_cmp0168(MakeAvailableUndeclared) run_cmake_with_cmp0168(VerifyHeaderSet) +block(SCOPE_FOR VARIABLES) + # The direct-population scripts must be independent of the configure-time + # log level. Steps should not be seen as out-of-date just because the user + # re-ran configure with a different verbosity. + # Reuse the build tree for a quiet then verbose configuration. + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LogLevel-direct-build) + run_cmake(LogLevel) + set(RunCMake_TEST_VARIANT_DESCRIPTION "-verbose") + run_cmake_with_options(LogLevel --log-level=VERBOSE) +endblock() run_cmake_with_cmp0168(FindDependencyExport -D "CMAKE_PROJECT_TOP_LEVEL_INCLUDES=${CMAKE_CURRENT_LIST_DIR}/FindDependencyExportDP.cmake"