Merge topic 'ninja-many-subdirs'

5a36d0c9e7 Ninja: Fix regression with a large number of subdirectories
a30cf4a66a Tests/RunCMake/Configure: Split ninja-specific RerunCMake case

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !10420
This commit is contained in:
Brad King 2025-03-05 13:22:13 +00:00 committed by Kitware Robot
commit 2586a2ce82
6 changed files with 57 additions and 22 deletions

View File

@ -7,11 +7,11 @@
#include <cctype>
#include <cstdio>
#include <functional>
#include <iterator>
#include <sstream>
#include <type_traits>
#include <utility>
#include <cm/iterator>
#include <cm/memory>
#include <cm/optional>
#include <cm/string_view>
@ -662,6 +662,7 @@ void cmGlobalNinjaGenerator::Generate()
void cmGlobalNinjaGenerator::CleanMetaData()
{
constexpr size_t ninja_tool_arg_size = 8; // 2 `-_` flags and 4 separators
auto run_ninja_tool = [this](std::vector<char const*> const& args) {
std::vector<std::string> command;
command.push_back(this->NinjaCommand);
@ -704,19 +705,27 @@ void cmGlobalNinjaGenerator::CleanMetaData()
run_ninja_tool({ "recompact" });
}
if (this->NinjaSupportsRestatTool && this->OutputPathPrefix.empty()) {
// XXX(ninja): We only list `build.ninja` entry files here because CMake
// *always* rewrites these files on a reconfigure. If CMake ever gets
// smarter about this, all CMake-time created/edited files listed as
// outputs for the reconfigure build statement will need to be listed here.
cmNinjaDeps outputs;
this->AddRebuildManifestOutputs(outputs);
std::vector<char const*> args;
args.reserve(outputs.size() + 1);
args.push_back("restat");
for (auto const& output : outputs) {
args.push_back(output.c_str());
auto output_it = outputs.begin();
size_t static_arg_size = ninja_tool_arg_size + this->NinjaCommand.size() +
this->GetCMakeInstance()->GetHomeOutputDirectory().size();
// The Windows command-line length limit is 32768. Leave plenty.
constexpr size_t maximum_arg_size = 30000;
while (output_it != outputs.end()) {
size_t total_arg_size = static_arg_size;
std::vector<char const*> args;
args.reserve(std::distance(output_it, outputs.end()) + 1);
args.push_back("restat");
total_arg_size += 7; // restat + 1
while (output_it != outputs.end() &&
total_arg_size + output_it->size() + 1 < maximum_arg_size) {
args.push_back(output_it->c_str());
total_arg_size += output_it->size() + 1;
++output_it;
}
run_ninja_tool(args);
}
run_ninja_tool(args);
}
}

View File

@ -1,4 +0,0 @@
file(READ ${stamp} content)
if(NOT content STREQUAL 5)
set(RunCMake_TEST_FAILED "Expected stamp '5' but got: '${content}'")
endif()

View File

@ -0,0 +1,4 @@
file(READ ${stamp} content)
if(NOT content STREQUAL 1)
set(RunCMake_TEST_FAILED "Expected stamp '1' but got: '${content}'")
endif()

View File

@ -0,0 +1,16 @@
set(input ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
set(stamp ${CMAKE_CURRENT_BINARY_DIR}/stamp.txt)
file(READ ${input} content)
file(WRITE ${stamp} "${content}")
# Add enough subdirectories to make the total list of paths to 'cmake_install.cmake'
# files exceed the Windows command-line length limit.
set(length 0)
foreach(i RANGE 1 1000)
if(length GREATER_EQUAL 32678)
break()
endif()
add_subdirectory(RerunCMakeNinja RerunCMakeNinja${i})
string(LENGTH "${CMAKE_CURRENT_BINARY_DIR}/RerunCMakeNinja${i}/cmake_install.cmake" subdir_length)
math(EXPR length "${length} + ${subdir_length}")
endforeach()

View File

@ -0,0 +1 @@
# Empty subdirectory, but it has a 'cmake_install.cmake'.

View File

@ -37,16 +37,25 @@ block()
set(RunCMake_TEST_OUTPUT_MERGE 0)
run_cmake_command(RerunCMake-build4 ${CMAKE_COMMAND} --build .)
endif()
if(RunCMake_GENERATOR MATCHES "^Ninja")
file(REMOVE "${error}")
run_cmake(RerunCMake)
endblock()
if(RunCMake_GENERATOR MATCHES "^Ninja")
block()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/RerunCMakeNinja-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
set(input "${RunCMake_TEST_BINARY_DIR}/input.txt")
set(stamp "${RunCMake_TEST_BINARY_DIR}/stamp.txt")
file(WRITE "${input}" "0")
run_cmake(RerunCMakeNinja)
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1) # handle 1s resolution
# remove cmake_install.cmake to trigger rerun
file(REMOVE "${RunCMake_TEST_BINARY_DIR}/cmake_install.cmake")
file(WRITE "${input}" "5")
run_cmake_command(RerunCMake-build5 ${CMAKE_COMMAND} --build .)
endif()
endblock()
file(WRITE "${input}" "1")
run_cmake_command(RerunCMakeNinja-build1 ${CMAKE_COMMAND} --build .)
endblock()
endif()
block()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/RemoveCache-build)