mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-18 00:02:21 +08:00
Ninja: Fix regression with a large number of subdirectories
Since commit f50fb77a4f
(Ninja: Regenerate when test or install scripts
are missing, 2024-10-29, v4.0.0-rc1~516^2) the list of paths we pass to
`ninja -t restat` scales with the number of project subdirectories.
Run it in blocks to avoid "command line too long" errors, particularly
on Windows.
Fixes: #26738
This commit is contained in:
@@ -7,11 +7,11 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iterator>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <cm/iterator>
|
|
||||||
#include <cm/memory>
|
#include <cm/memory>
|
||||||
#include <cm/optional>
|
#include <cm/optional>
|
||||||
#include <cm/string_view>
|
#include <cm/string_view>
|
||||||
@@ -663,6 +663,7 @@ void cmGlobalNinjaGenerator::Generate()
|
|||||||
|
|
||||||
void cmGlobalNinjaGenerator::CleanMetaData()
|
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) {
|
auto run_ninja_tool = [this](std::vector<char const*> const& args) {
|
||||||
std::vector<std::string> command;
|
std::vector<std::string> command;
|
||||||
command.push_back(this->NinjaCommand);
|
command.push_back(this->NinjaCommand);
|
||||||
@@ -705,19 +706,27 @@ void cmGlobalNinjaGenerator::CleanMetaData()
|
|||||||
run_ninja_tool({ "recompact" });
|
run_ninja_tool({ "recompact" });
|
||||||
}
|
}
|
||||||
if (this->NinjaSupportsRestatTool && this->OutputPathPrefix.empty()) {
|
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;
|
cmNinjaDeps outputs;
|
||||||
this->AddRebuildManifestOutputs(outputs);
|
this->AddRebuildManifestOutputs(outputs);
|
||||||
std::vector<char const*> args;
|
auto output_it = outputs.begin();
|
||||||
args.reserve(outputs.size() + 1);
|
size_t static_arg_size = ninja_tool_arg_size + this->NinjaCommand.size() +
|
||||||
args.push_back("restat");
|
this->GetCMakeInstance()->GetHomeOutputDirectory().size();
|
||||||
for (auto const& output : outputs) {
|
// The Windows command-line length limit is 32768. Leave plenty.
|
||||||
args.push_back(output.c_str());
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,3 +2,15 @@ set(input ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
|
|||||||
set(stamp ${CMAKE_CURRENT_BINARY_DIR}/stamp.txt)
|
set(stamp ${CMAKE_CURRENT_BINARY_DIR}/stamp.txt)
|
||||||
file(READ ${input} content)
|
file(READ ${input} content)
|
||||||
file(WRITE ${stamp} "${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()
|
||||||
|
1
Tests/RunCMake/Configure/RerunCMakeNinja/CMakeLists.txt
Normal file
1
Tests/RunCMake/Configure/RerunCMakeNinja/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Empty subdirectory, but it has a 'cmake_install.cmake'.
|
Reference in New Issue
Block a user