mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-06 06:10:04 -05:00
Merge topic 'autogen-rsp'
232610e60eAutogen: Use new API for limiting autogen command line lengths7a07887055Autogen: Add support for response files for moc predef targets7eb5ab2c63Autogen: Generalize MaybeWriteMocResponseFile to MaybeWriteResponseFile Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Merge-request: !8944
This commit is contained in:
@@ -70,6 +70,7 @@ syn keyword cmakeProperty contained
|
||||
\ ATTACHED_FILES
|
||||
\ ATTACHED_FILES_ON_FAIL
|
||||
\ AUTOGEN_BUILD_DIR
|
||||
\ AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
\ AUTOGEN_ORIGIN_DEPENDS
|
||||
\ AUTOGEN_PARALLEL
|
||||
\ AUTOGEN_SOURCE_GROUP
|
||||
@@ -764,6 +765,7 @@ syn keyword cmakeVariable contained
|
||||
\ CMAKE_ASM_STANDARD_REQUIRED
|
||||
\ CMAKE_ASM_SUPPORTED
|
||||
\ CMAKE_ASM_VISIBILITY_PRESET
|
||||
\ CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
\ CMAKE_AUTOGEN_ORIGIN_DEPENDS
|
||||
\ CMAKE_AUTOGEN_PARALLEL
|
||||
\ CMAKE_AUTOGEN_USE_SYSTEM_INCLUDE
|
||||
|
||||
@@ -130,6 +130,7 @@ Properties on Targets
|
||||
/prop_tgt/ARCHIVE_OUTPUT_NAME
|
||||
/prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG
|
||||
/prop_tgt/AUTOGEN_BUILD_DIR
|
||||
/prop_tgt/AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
/prop_tgt/AUTOGEN_ORIGIN_DEPENDS
|
||||
/prop_tgt/AUTOGEN_PARALLEL
|
||||
/prop_tgt/AUTOGEN_TARGET_DEPENDS
|
||||
|
||||
@@ -400,6 +400,7 @@ Variables that Control the Build
|
||||
/variable/CMAKE_APPLE_SILICON_PROCESSOR
|
||||
/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY
|
||||
/variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG
|
||||
/variable/CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
/variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS
|
||||
/variable/CMAKE_AUTOGEN_PARALLEL
|
||||
/variable/CMAKE_AUTOGEN_USE_SYSTEM_INCLUDE
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
-------------------------------
|
||||
|
||||
.. versionadded:: 3.29
|
||||
|
||||
Command line length limit for autogen targets, i.e. ``moc`` or ``uic``,
|
||||
that triggers the use of response files on Windows instead of passing all
|
||||
arguments to the command line.
|
||||
|
||||
- An empty (or unset) value sets the limit to 32000
|
||||
- A positive non zero integer value sets the exact command line length
|
||||
limit.
|
||||
|
||||
By default ``AUTOGEN_COMMAND_LINE_LENGTH_MAX`` is initialized from
|
||||
:variable:`CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX`.
|
||||
|
||||
See the :manual:`cmake-qt(7)` manual for more information on using CMake
|
||||
with Qt.
|
||||
@@ -247,5 +247,9 @@ will be generated when this variable is ``ON``.
|
||||
This target property controls the number of ``moc`` or ``uic`` processes to
|
||||
start in parallel during builds.
|
||||
|
||||
:prop_tgt:`AUTOGEN_COMMAND_LINE_LENGTH_MAX`:
|
||||
This target property controls the limit when to use response files for
|
||||
``moc`` or ``uic`` processes on Windows.
|
||||
|
||||
See the :manual:`cmake-qt(7)` manual for more information on using CMake
|
||||
with Qt.
|
||||
|
||||
@@ -81,5 +81,9 @@ will be generated when this variable is ``ON``.
|
||||
This target property controls the number of ``moc`` or ``uic`` processes to
|
||||
start in parallel during builds.
|
||||
|
||||
:prop_tgt:`AUTOGEN_COMMAND_LINE_LENGTH_MAX`:
|
||||
This target property controls the limit when to use response files for
|
||||
``moc`` or ``uic`` processes on Windows.
|
||||
|
||||
See the :manual:`cmake-qt(7)` manual for more information on using CMake
|
||||
with Qt.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX
|
||||
-------------------------------------
|
||||
|
||||
.. versionadded:: 3.29
|
||||
|
||||
Command line length limit for autogen targets, i.e. ``moc`` or ``uic``,
|
||||
that triggers the use of response files on Windows instead of passing all
|
||||
arguments to the command line.
|
||||
|
||||
By default ``CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX`` is unset.
|
||||
@@ -76,13 +76,6 @@ static void MergeOptions(std::vector<std::string>& baseOpts,
|
||||
|
||||
unsigned int const cmQtAutoGen::ParallelMax = 64;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Actually 32767 (see
|
||||
// https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553) but we
|
||||
// allow for a small margin
|
||||
size_t const cmQtAutoGen::CommandLineLengthMax = 32000;
|
||||
#endif
|
||||
|
||||
cm::string_view cmQtAutoGen::GeneratorName(GenT genType)
|
||||
{
|
||||
switch (genType) {
|
||||
|
||||
@@ -64,11 +64,6 @@ public:
|
||||
/// @brief Maximum number of parallel threads/processes in a generator
|
||||
static unsigned int const ParallelMax;
|
||||
|
||||
#ifdef _WIN32
|
||||
/// @brief Maximum number of characters on command line
|
||||
static size_t const CommandLineLengthMax;
|
||||
#endif
|
||||
|
||||
/// @brief Returns the generator name
|
||||
static cm::string_view GeneratorName(GenT genType);
|
||||
/// @brief Returns the generator name in upper case
|
||||
|
||||
@@ -485,6 +485,38 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
const auto& value =
|
||||
this->GenTarget->GetProperty("AUTOGEN_COMMAND_LINE_LENGTH_MAX");
|
||||
if (value.IsSet()) {
|
||||
using maxCommandLineLengthType =
|
||||
decltype(this->AutogenTarget.MaxCommandLineLength);
|
||||
unsigned long propInt = 0;
|
||||
if (cmStrToULong(value, &propInt) && propInt > 0 &&
|
||||
propInt <= std::numeric_limits<maxCommandLineLengthType>::max()) {
|
||||
this->AutogenTarget.MaxCommandLineLength =
|
||||
static_cast<maxCommandLineLengthType>(propInt);
|
||||
} else {
|
||||
// Warn the project author that AUTOGEN_PARALLEL is not valid.
|
||||
this->Makefile->IssueMessage(
|
||||
MessageType::AUTHOR_WARNING,
|
||||
cmStrCat("AUTOGEN_COMMAND_LINE_LENGTH_MAX=\"", *value,
|
||||
"\" for target \"", this->GenTarget->GetName(),
|
||||
"\" is not valid. Using no limit for "
|
||||
"AUTOGEN_COMMAND_LINE_LENGTH_MAX"));
|
||||
this->AutogenTarget.MaxCommandLineLength =
|
||||
std::numeric_limits<maxCommandLineLengthType>::max();
|
||||
}
|
||||
} else {
|
||||
// Actually 32767 (see
|
||||
// https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553) but
|
||||
// we allow for a small margin
|
||||
this->AutogenTarget.MaxCommandLineLength = 32000;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Autogen target info and settings files
|
||||
{
|
||||
// Info file
|
||||
@@ -1692,6 +1724,10 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
|
||||
// General
|
||||
info.SetBool("MULTI_CONFIG", this->MultiConfig);
|
||||
info.SetUInt("PARALLEL", this->AutogenTarget.Parallel);
|
||||
#ifdef _WIN32
|
||||
info.SetUInt("AUTOGEN_COMMAND_LINE_LENGTH_MAX",
|
||||
this->AutogenTarget.MaxCommandLineLength);
|
||||
#endif
|
||||
info.SetUInt("VERBOSITY", this->Verbosity);
|
||||
|
||||
// Directories
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -194,6 +195,8 @@ private:
|
||||
bool GlobalTarget = false;
|
||||
// Settings
|
||||
unsigned int Parallel = 1;
|
||||
unsigned int MaxCommandLineLength =
|
||||
std::numeric_limits<unsigned int>::max();
|
||||
// Configuration files
|
||||
std::string InfoFile;
|
||||
ConfigString SettingsFile;
|
||||
|
||||
+62
-50
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
@@ -172,6 +173,8 @@ public:
|
||||
bool MultiConfig = false;
|
||||
IntegerVersion QtVersion = { 4, 0 };
|
||||
unsigned int ThreadCount = 0;
|
||||
unsigned int MaxCommandLineLength =
|
||||
std::numeric_limits<unsigned int>::max();
|
||||
// - Directories
|
||||
std::string AutogenBuildDir;
|
||||
std::string AutogenIncludeDir;
|
||||
@@ -333,6 +336,13 @@ public:
|
||||
std::vector<std::string> const& command,
|
||||
std::string const& output) const;
|
||||
|
||||
/*
|
||||
* Check if command line exceeds maximum length supported by OS
|
||||
* (if on Windows) and switch to using a response file instead.
|
||||
*/
|
||||
void MaybeWriteResponseFile(std::string const& outputFile,
|
||||
std::vector<std::string>& cmd) const;
|
||||
|
||||
/** @brief Run an external process. Use only during Process() call! */
|
||||
bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result,
|
||||
std::vector<std::string> const& command,
|
||||
@@ -498,10 +508,6 @@ public:
|
||||
|
||||
protected:
|
||||
ParseCacheT::FileHandleT CacheEntry;
|
||||
|
||||
private:
|
||||
void MaybeWriteMocResponseFile(std::string const& outputFile,
|
||||
std::vector<std::string>& cmd) const;
|
||||
};
|
||||
|
||||
/** uic compiles a file. */
|
||||
@@ -795,6 +801,51 @@ void cmQtAutoMocUicT::JobT::LogCommandError(
|
||||
this->Gen()->Log().ErrorCommand(genType, message, command, output);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if command line exceeds maximum length supported by OS
|
||||
* (if on Windows) and switch to using a response file instead.
|
||||
*/
|
||||
void cmQtAutoMocUicT::JobT::MaybeWriteResponseFile(
|
||||
std::string const& outputFile, std::vector<std::string>& cmd) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Ensure cmd is less than CommandLineLengthMax characters
|
||||
size_t commandLineLength = cmd.size(); // account for separating spaces
|
||||
for (std::string const& str : cmd) {
|
||||
commandLineLength += str.length();
|
||||
}
|
||||
if (commandLineLength >= this->BaseConst().MaxCommandLineLength) {
|
||||
// Command line exceeds maximum size allowed by OS
|
||||
// => create response file
|
||||
std::string const responseFile = cmStrCat(outputFile, ".rsp");
|
||||
|
||||
cmsys::ofstream fout(responseFile.c_str());
|
||||
if (!fout) {
|
||||
this->LogError(
|
||||
GenT::MOC,
|
||||
cmStrCat("AUTOMOC was unable to create a response file at\n ",
|
||||
this->MessagePath(responseFile)));
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = cmd.begin();
|
||||
while (++it != cmd.end()) {
|
||||
fout << *it << "\n";
|
||||
}
|
||||
fout.close();
|
||||
|
||||
// Keep all but executable
|
||||
cmd.resize(1);
|
||||
|
||||
// Specify response file
|
||||
cmd.emplace_back(cmStrCat('@', responseFile));
|
||||
}
|
||||
#else
|
||||
static_cast<void>(outputFile);
|
||||
static_cast<void>(cmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType,
|
||||
cmWorkerPool::ProcessResultT& result,
|
||||
std::vector<std::string> const& command,
|
||||
@@ -836,6 +887,8 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process()
|
||||
cm::append(cmd, this->MocConst().OptionsDefinitions);
|
||||
// Add includes
|
||||
cm::append(cmd, this->MocConst().OptionsIncludes);
|
||||
// Check if response file is necessary
|
||||
MaybeWriteResponseFile(this->MocConst().PredefsFileAbs, cmd);
|
||||
// Execute command
|
||||
if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) {
|
||||
this->LogCommandError(GenT::MOC,
|
||||
@@ -2034,7 +2087,7 @@ void cmQtAutoMocUicT::JobCompileMocT::Process()
|
||||
// Add source file
|
||||
cmd.push_back(sourceFile);
|
||||
|
||||
MaybeWriteMocResponseFile(outputFile, cmd);
|
||||
MaybeWriteResponseFile(outputFile, cmd);
|
||||
}
|
||||
|
||||
// Execute moc command
|
||||
@@ -2080,51 +2133,6 @@ void cmQtAutoMocUicT::JobCompileMocT::Process()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if command line exceeds maximum length supported by OS
|
||||
* (if on Windows) and switch to using a response file instead.
|
||||
*/
|
||||
void cmQtAutoMocUicT::JobCompileMocT::MaybeWriteMocResponseFile(
|
||||
std::string const& outputFile, std::vector<std::string>& cmd) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Ensure cmd is less than CommandLineLengthMax characters
|
||||
size_t commandLineLength = cmd.size(); // account for separating spaces
|
||||
for (std::string const& str : cmd) {
|
||||
commandLineLength += str.length();
|
||||
}
|
||||
if (commandLineLength >= CommandLineLengthMax) {
|
||||
// Command line exceeds maximum size allowed by OS
|
||||
// => create response file
|
||||
std::string const responseFile = cmStrCat(outputFile, ".rsp");
|
||||
|
||||
cmsys::ofstream fout(responseFile.c_str());
|
||||
if (!fout) {
|
||||
this->LogError(
|
||||
GenT::MOC,
|
||||
cmStrCat("AUTOMOC was unable to create a response file at\n ",
|
||||
this->MessagePath(responseFile)));
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = cmd.begin();
|
||||
while (++it != cmd.end()) {
|
||||
fout << *it << "\n";
|
||||
}
|
||||
fout.close();
|
||||
|
||||
// Keep all but executable
|
||||
cmd.resize(1);
|
||||
|
||||
// Specify response file
|
||||
cmd.emplace_back(cmStrCat('@', responseFile));
|
||||
}
|
||||
#else
|
||||
static_cast<void>(outputFile);
|
||||
static_cast<void>(cmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cmQtAutoMocUicT::JobCompileUicT::Process()
|
||||
{
|
||||
std::string const& sourceFile = this->Mapping->SourceFile->FileName;
|
||||
@@ -2377,6 +2385,10 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info)
|
||||
!info.GetUInt("QT_VERSION_MINOR", this->BaseConst_.QtVersion.Minor,
|
||||
true) ||
|
||||
!info.GetUInt("PARALLEL", this->BaseConst_.ThreadCount, false) ||
|
||||
#ifdef _WIN32
|
||||
!info.GetUInt("AUTOGEN_COMMAND_LINE_LENGTH_MAX",
|
||||
this->BaseConst_.MaxCommandLineLength, false) ||
|
||||
#endif
|
||||
!info.GetString("BUILD_DIR", this->BaseConst_.AutogenBuildDir, true) ||
|
||||
!info.GetStringConfig("INCLUDE_DIR", this->BaseConst_.AutogenIncludeDir,
|
||||
true) ||
|
||||
|
||||
@@ -551,6 +551,7 @@ TargetProperty const StaticTargetProperties[] = {
|
||||
{ "ANDROID_PROCESS_MAX"_s, IC::CanCompileSources },
|
||||
{ "ANDROID_SKIP_ANT_STEP"_s, IC::CanCompileSources },
|
||||
// -- Autogen
|
||||
{ "AUTOGEN_COMMAND_LINE_LENGTH_MAX"_s, IC::CanCompileSources },
|
||||
{ "AUTOGEN_ORIGIN_DEPENDS"_s, IC::CanCompileSources },
|
||||
{ "AUTOGEN_PARALLEL"_s, IC::CanCompileSources },
|
||||
{ "AUTOGEN_USE_SYSTEM_INCLUDE"_s, IC::CanCompileSources },
|
||||
|
||||
Reference in New Issue
Block a user