summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeInstallSignTool.cmake.in51
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmGlobalGenerator.cxx4
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx268
-rw-r--r--Source/cmGlobalNinjaGenerator.h31
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx10
-rw-r--r--Source/cmInstallDirectoryGenerator.cxx5
-rw-r--r--Source/cmInstallDirectoryGenerator.h2
-rw-r--r--Source/cmInstallExportAndroidMKGenerator.cxx3
-rw-r--r--Source/cmInstallExportAndroidMKGenerator.h2
-rw-r--r--Source/cmInstallExportGenerator.cxx3
-rw-r--r--Source/cmInstallExportGenerator.h2
-rw-r--r--Source/cmInstallFilesGenerator.cxx3
-rw-r--r--Source/cmInstallFilesGenerator.h2
-rw-r--r--Source/cmInstallGenerator.h2
-rw-r--r--Source/cmInstallScriptGenerator.cxx4
-rw-r--r--Source/cmInstallScriptGenerator.h2
-rw-r--r--Source/cmInstallSubdirectoryGenerator.cxx3
-rw-r--r--Source/cmInstallSubdirectoryGenerator.h2
-rw-r--r--Source/cmInstallTargetGenerator.cxx4
-rw-r--r--Source/cmInstallTargetGenerator.h2
-rw-r--r--Source/cmLocalNinjaGenerator.cxx9
-rw-r--r--Source/cmNinjaTargetGenerator.cxx152
-rw-r--r--Source/cmNinjaTargetGenerator.h4
-rw-r--r--Source/cmPolicies.h4
-rw-r--r--Source/cmQtAutoGenerator.cxx3
-rw-r--r--Source/cmQtAutoRcc.cxx123
-rw-r--r--Source/cmQtAutoRcc.h2
-rw-r--r--Source/cmRemoveCommand.cxx10
-rw-r--r--Source/cmSystemTools.cxx24
-rw-r--r--Source/cmSystemTools.h43
-rw-r--r--Source/cmUVHandlePtr.cxx8
-rw-r--r--Source/cmUVProcessChain.cxx395
-rw-r--r--Source/cmUVProcessChain.h100
-rw-r--r--Source/cmUVStreambuf.h8
-rw-r--r--Source/cmake.cxx5
37 files changed, 943 insertions, 356 deletions
diff --git a/Source/CMakeInstallSignTool.cmake.in b/Source/CMakeInstallSignTool.cmake.in
new file mode 100644
index 0000000..fca629c
--- /dev/null
+++ b/Source/CMakeInstallSignTool.cmake.in
@@ -0,0 +1,51 @@
+# The signtool. Default to PATH.
+set(CMake_INSTALL_SIGNTOOL "@CMake_INSTALL_SIGNTOOL@")
+if(NOT CMake_INSTALL_SIGNTOOL)
+ set(CMake_INSTALL_SIGNTOOL signtool)
+endif()
+
+# Select a certificate by Subject Name. Default to automatic selection.
+set(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME "@CMake_INSTALL_SIGNTOOL_SUBJECT_NAME@")
+if(CMake_INSTALL_SIGNTOOL_SUBJECT_NAME)
+ set(select_cert -n "${CMake_INSTALL_SIGNTOOL_SUBJECT_NAME}")
+else()
+ set(select_cert -a)
+endif()
+
+# Timestamp URL. Default to a common provider.
+set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "@CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL@")
+if(NOT CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL)
+ set(CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL "http://timestamp.digicert.com")
+endif()
+
+# Glob files that need a signature.
+file(GLOB files "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/*.exe")
+
+# Sign all files at once.
+if(files)
+ # Run the signtool through 'cmd /c' to enable password prompt popup.
+ # Some providers have trouble when signtool is invoked with SW_HIDE.
+ set(cmd cmd /c "${CMake_INSTALL_SIGNTOOL}" sign -v ${select_cert})
+
+ # Sign with SHA-1 for Windows 7 and below.
+ execute_process(
+ COMMAND ${cmd} -t "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+
+ # Sign with SHA-256 for Windows 8 and above.
+ execute_process(
+ COMMAND ${cmd} -tr "${CMake_INSTALL_SIGNTOOL_TIMESTAMP_URL}" -fd sha256 -td sha256 -as ${files}
+ RESULT_VARIABLE result
+ ERROR_VARIABLE stderr
+ )
+ if(NOT result EQUAL 0)
+ string(REPLACE "\n" "\n " stderr " ${stderr}")
+ message(WARNING "signtool failed:\n${stderr}")
+ endif()
+endif()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 01c6cd7..42eed4d 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -388,6 +388,8 @@ set(SRCS
cmUuid.cxx
cmUVHandlePtr.cxx
cmUVHandlePtr.h
+ cmUVProcessChain.cxx
+ cmUVProcessChain.h
cmUVStreambuf.h
cmUVSignalHackRAII.h
cmVariableWatch.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index f2b87cb..90dd14f 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 14)
-set(CMake_VERSION_PATCH 20190509)
+set(CMake_VERSION_PATCH 20190515)
#set(CMake_VERSION_RC 1)
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 8223dd1..b08dd1c 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1372,7 +1372,9 @@ bool cmGlobalGenerator::Compute()
for (cmLocalGenerator* localGen : this->LocalGenerators) {
cmMakefile* mf = localGen->GetMakefile();
for (cmInstallGenerator* g : mf->GetInstallGenerators()) {
- g->Compute(localGen);
+ if (!g->Compute(localGen)) {
+ return false;
+ }
}
}
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 522ffe6..67c22a7 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -136,17 +136,15 @@ void cmGlobalNinjaGenerator::WriteBuild(
{
// Make sure there is a rule.
if (rule.empty()) {
- cmSystemTools::Error("No rule for WriteBuildStatement! called "
- "with comment: " +
+ cmSystemTools::Error("No rule for WriteBuild! called with comment: " +
comment);
return;
}
// Make sure there is at least one output file.
if (outputs.empty()) {
- cmSystemTools::Error("No output files for WriteBuildStatement! called "
- "with comment: " +
- comment);
+ cmSystemTools::Error(
+ "No output files for WriteBuild! called with comment: " + comment);
return;
}
@@ -295,14 +293,8 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild(
void cmGlobalNinjaGenerator::AddMacOSXContentRule()
{
- cmLocalGenerator* lg = this->LocalGenerators[0];
-
- std::ostringstream cmd;
- cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -E copy $in $out";
-
- this->AddRule("COPY_OSX_CONTENT", cmd.str(), "Copying OS X Content $out",
+ this->AddRule("COPY_OSX_CONTENT", CMakeCmd() + " -E copy $in $out",
+ "Copying OS X Content $out",
"Rule for copying OS X bundle content file.",
/*depfile*/ "",
/*deptype*/ "",
@@ -335,71 +327,57 @@ void cmGlobalNinjaGenerator::WriteRule(
const std::string& rspfile, const std::string& rspcontent,
const std::string& restat, bool generator)
{
+ // -- Parameter checks
// Make sure the rule has a name.
if (name.empty()) {
- cmSystemTools::Error("No name given for WriteRuleStatement! called "
- "with comment: " +
+ cmSystemTools::Error("No name given for WriteRule! called with comment: " +
comment);
return;
}
// Make sure a command is given.
if (command.empty()) {
- cmSystemTools::Error("No command given for WriteRuleStatement! called "
- "with comment: " +
- comment);
+ cmSystemTools::Error(
+ "No command given for WriteRule! called with comment: " + comment);
return;
}
- cmGlobalNinjaGenerator::WriteComment(os, comment);
-
- // Write the rule.
- os << "rule " << name << "\n";
-
- // Write the depfile if any.
- if (!depfile.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "depfile = " << depfile << "\n";
- }
-
- // Write the deptype if any.
- if (!deptype.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "deps = " << deptype << "\n";
+ // Make sure response file content is given
+ if (!rspfile.empty() && rspcontent.empty()) {
+ cmSystemTools::Error("rspfile but no rspfile_content given for WriteRule! "
+ "called with comment: " +
+ comment);
+ return;
}
- // Write the command.
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "command = " << command << "\n";
-
- // Write the description if any.
- if (!description.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "description = " << description << "\n";
- }
+ // -- Write rule
+ // Write rule intro
+ cmGlobalNinjaGenerator::WriteComment(os, comment);
+ os << "rule " << name << '\n';
- if (!rspfile.empty()) {
- if (rspcontent.empty()) {
- cmSystemTools::Error("No rspfile_content given!" + comment);
- return;
+ // Write rule key/value pairs
+ auto writeKV = [&os](const char* key, std::string const& value) {
+ if (!value.empty()) {
+ cmGlobalNinjaGenerator::Indent(os, 1);
+ os << key << " = " << value << '\n';
}
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "rspfile = " << rspfile << "\n";
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "rspfile_content = " << rspcontent << "\n";
- }
+ };
- if (!restat.empty()) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "restat = " << restat << "\n";
+ writeKV("depfile", depfile);
+ writeKV("deps", deptype);
+ writeKV("command", command);
+ writeKV("description", description);
+ if (!rspfile.empty()) {
+ writeKV("rspfile", rspfile);
+ writeKV("rspfile_content", rspcontent);
}
-
+ writeKV("restat", restat);
if (generator) {
- cmGlobalNinjaGenerator::Indent(os, 1);
- os << "generator = 1\n";
+ writeKV("generator", "1");
}
- os << "\n";
+ // Finish rule
+ os << '\n';
}
void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
@@ -449,9 +427,6 @@ void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
: cmGlobalCommonGenerator(cm)
- , BuildFileStream(nullptr)
- , RulesFileStream(nullptr)
- , CompileCommandsStream(nullptr)
, UsingGCCOnWindows(false)
, ComputingUnknownDependencies(false)
, PolicyCMP0058(cmPolicies::WARN)
@@ -512,8 +487,12 @@ void cmGlobalNinjaGenerator::Generate()
msg.str());
return;
}
- this->OpenBuildFileStream();
- this->OpenRulesFileStream();
+ if (!this->OpenBuildFileStream()) {
+ return;
+ }
+ if (!this->OpenRulesFileStream()) {
+ return;
+ }
this->TargetDependsClosures.clear();
@@ -703,11 +682,7 @@ cmGlobalNinjaGenerator::GenerateBuildCommand(
makeCommand.Add(makeOptions.begin(), makeOptions.end());
for (const auto& tname : targetNames) {
if (!tname.empty()) {
- if (tname == "clean") {
- makeCommand.Add("-t", "clean");
- } else {
- makeCommand.Add(tname);
- }
+ makeCommand.Add(tname);
}
}
return { std::move(makeCommand) };
@@ -723,22 +698,20 @@ void cmGlobalNinjaGenerator::AddRule(
const std::string& restat, bool generator)
{
// Do not add the same rule twice.
- if (this->HasRule(name)) {
+ if (!this->Rules.insert(name).second) {
return;
}
-
- this->Rules.insert(name);
+ // Store command length
+ this->RuleCmdLength[name] = static_cast<int>(command.size());
+ // Write rule
cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, name, command,
description, comment, depfile, deptype,
rspfile, rspcontent, restat, generator);
-
- this->RuleCmdLength[name] = static_cast<int>(command.size());
}
bool cmGlobalNinjaGenerator::HasRule(const std::string& name)
{
- RulesSetType::const_iterator rule = this->Rules.find(name);
- return (rule != this->Rules.end());
+ return (this->Rules.find(name) != this->Rules.end());
}
// Private virtual overrides
@@ -764,7 +737,7 @@ void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory(
// Private methods
-void cmGlobalNinjaGenerator::OpenBuildFileStream()
+bool cmGlobalNinjaGenerator::OpenBuildFileStream()
{
// Compute Ninja's build file path.
std::string buildFilePath =
@@ -774,12 +747,12 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream()
// Get a stream where to generate things.
if (!this->BuildFileStream) {
- this->BuildFileStream = new cmGeneratedFileStream(
+ this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>(
buildFilePath, false, this->GetMakefileEncoding());
- if (!this->BuildFileStream) {
+ if (!(*this->BuildFileStream)) {
// An error message is generated by the constructor if it cannot
// open the file.
- return;
+ return false;
}
}
@@ -790,19 +763,20 @@ void cmGlobalNinjaGenerator::OpenBuildFileStream()
*this->BuildFileStream
<< "# This file contains all the build statements describing the\n"
<< "# compilation DAG.\n\n";
+
+ return true;
}
void cmGlobalNinjaGenerator::CloseBuildFileStream()
{
if (this->BuildFileStream) {
- delete this->BuildFileStream;
- this->BuildFileStream = nullptr;
+ this->BuildFileStream.reset();
} else {
cmSystemTools::Error("Build file stream was not open.");
}
}
-void cmGlobalNinjaGenerator::OpenRulesFileStream()
+bool cmGlobalNinjaGenerator::OpenRulesFileStream()
{
// Compute Ninja's build file path.
std::string rulesFilePath =
@@ -812,12 +786,12 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream()
// Get a stream where to generate things.
if (!this->RulesFileStream) {
- this->RulesFileStream = new cmGeneratedFileStream(
+ this->RulesFileStream = cm::make_unique<cmGeneratedFileStream>(
rulesFilePath, false, this->GetMakefileEncoding());
- if (!this->RulesFileStream) {
+ if (!(*this->RulesFileStream)) {
// An error message is generated by the constructor if it cannot
// open the file.
- return;
+ return false;
}
}
@@ -832,13 +806,13 @@ void cmGlobalNinjaGenerator::OpenRulesFileStream()
<< "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
;
/* clang-format on */
+ return true;
}
void cmGlobalNinjaGenerator::CloseRulesFileStream()
{
if (this->RulesFileStream) {
- delete this->RulesFileStream;
- this->RulesFileStream = nullptr;
+ this->RulesFileStream.reset();
} else {
cmSystemTools::Error("Rules file stream was not open.");
}
@@ -895,7 +869,8 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand(
}
// Get a stream where to generate things.
- this->CompileCommandsStream = new cmGeneratedFileStream(buildFilePath);
+ this->CompileCommandsStream =
+ cm::make_unique<cmGeneratedFileStream>(buildFilePath);
*this->CompileCommandsStream << "[";
} else {
*this->CompileCommandsStream << "," << std::endl;
@@ -923,8 +898,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
{
if (this->CompileCommandsStream) {
*this->CompileCommandsStream << "\n]";
- delete this->CompileCommandsStream;
- this->CompileCommandsStream = nullptr;
+ this->CompileCommandsStream.reset();
}
}
@@ -1021,8 +995,7 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
{
if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
// These depend only on other CMake-provided targets, e.g. "all".
- std::set<BT<std::string>> const& utils = target->GetUtilities();
- for (BT<std::string> const& util : utils) {
+ for (BT<std::string> const& util : target->GetUtilities()) {
std::string d =
target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" +
util.Value;
@@ -1030,8 +1003,8 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
}
} else {
cmNinjaDeps outs;
- cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target);
- for (cmTargetDepend const& targetDep : targetDeps) {
+ for (cmTargetDepend const& targetDep :
+ this->GetTargetDirectDepends(target)) {
if (targetDep->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -1065,10 +1038,9 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
// relevant for filling the cache entries properly isolated and a global
// result set that is relevant for the result of the top level call to
// AppendTargetDependsClosure.
- auto const& targetDeps = this->GetTargetDirectDepends(target);
cmNinjaOuts this_outs; // this will be the new cache entry
- for (auto const& dep_target : targetDeps) {
+ for (auto const& dep_target : this->GetTargetDirectDepends(target)) {
if (dep_target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
@@ -1164,9 +1136,7 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
// The directory-level rule should depend on the directory-level
// rules of the subdirectories.
- std::vector<cmStateSnapshot> const& children =
- lg->GetStateSnapshot().GetChildren();
- for (cmStateSnapshot const& state : children) {
+ for (cmStateSnapshot const& state : lg->GetStateSnapshot().GetChildren()) {
std::string const currentBinaryDir =
state.GetDirectory().GetCurrentBinary();
@@ -1227,26 +1197,21 @@ void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
for (cmLocalGenerator* lg : this->LocalGenerators) {
// get the vector of files created by this makefile and convert them
// to ninja paths, which are all relative in respect to the build directory
- const std::vector<std::string>& files =
- lg->GetMakefile()->GetOutputFiles();
- for (std::string const& file : files) {
+ for (std::string const& file : lg->GetMakefile()->GetOutputFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(file));
}
if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
// get list files which are implicit dependencies as well and will be
// phony for rebuild manifest
- std::vector<std::string> const& lf = lg->GetMakefile()->GetListFiles();
- for (std::string const& j : lf) {
+ for (std::string const& j : lg->GetMakefile()->GetListFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(j));
}
}
- std::vector<cmGeneratorExpressionEvaluationFile*> const& ef =
- lg->GetMakefile()->GetEvaluationFiles();
- for (cmGeneratorExpressionEvaluationFile* li : ef) {
+ for (cmGeneratorExpressionEvaluationFile* li :
+ lg->GetMakefile()->GetEvaluationFiles()) {
// get all the files created by generator expressions and convert them
// to ninja paths
- std::vector<std::string> evaluationFiles = li->GetFiles();
- for (std::string const& evaluationFile : evaluationFiles) {
+ for (std::string const& evaluationFile : li->GetFiles()) {
knownDependencies.insert(this->ConvertToNinjaPath(evaluationFile));
}
}
@@ -1352,30 +1317,28 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
}
cmLocalGenerator* lg = this->LocalGenerators[0];
- std::ostringstream cmd;
- cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -S"
- << lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
- cmOutputConverter::SHELL)
- << " -B"
- << lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
- cmOutputConverter::SHELL);
- WriteRule(*this->RulesFileStream, "RERUN_CMAKE", cmd.str(),
- "Re-running CMake...", "Rule for re-running cmake.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/true);
+ {
+ std::string cmd = CMakeCmd();
+ cmd += " -S";
+ cmd += lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
+ cmOutputConverter::SHELL);
+ cmd += " -B";
+ cmd += lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
+ cmOutputConverter::SHELL);
+ WriteRule(*this->RulesFileStream, "RERUN_CMAKE", cmd,
+ "Re-running CMake...", "Rule for re-running cmake.",
+ /*depfile=*/"",
+ /*deptype=*/"",
+ /*rspfile=*/"",
+ /*rspcontent*/ "",
+ /*restat=*/"",
+ /*generator=*/true);
+ }
cmNinjaDeps implicitDeps;
cmNinjaDeps explicitDeps;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
- std::vector<std::string> const& lf =
- localGen->GetMakefile()->GetListFiles();
- for (std::string const& fi : lf) {
+ for (std::string const& fi : localGen->GetMakefile()->GetListFiles()) {
implicitDeps.push_back(this->ConvertToNinjaPath(fi));
}
}
@@ -1390,22 +1353,22 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
cmake* cm = this->GetCMakeInstance();
if (this->SupportsManifestRestat() && cm->DoWriteGlobVerifyTarget()) {
- std::ostringstream verify_cmd;
- verify_cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
- cmOutputConverter::SHELL)
- << " -P "
- << lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
- cmOutputConverter::SHELL);
-
- WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", verify_cmd.str(),
- "Re-checking globbed directories...",
- "Rule for re-checking globbed directories.",
- /*depfile=*/"",
- /*deptype=*/"",
- /*rspfile=*/"",
- /*rspcontent*/ "",
- /*restat=*/"",
- /*generator=*/true);
+ {
+ std::string cmd = CMakeCmd();
+ cmd += " -P ";
+ cmd += lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
+ cmOutputConverter::SHELL);
+
+ WriteRule(*this->RulesFileStream, "VERIFY_GLOBS", cmd,
+ "Re-checking globbed directories...",
+ "Rule for re-checking globbed directories.",
+ /*depfile=*/"",
+ /*deptype=*/"",
+ /*rspfile=*/"",
+ /*rspcontent*/ "",
+ /*restat=*/"",
+ /*generator=*/true);
+ }
std::string verifyForce = cm->GetGlobVerifyScript() + "_force";
cmNinjaDeps verifyForceDeps(1, this->NinjaOutputPath(verifyForce));
@@ -1468,10 +1431,17 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
missingInputs, cmNinjaDeps());
}
-std::string cmGlobalNinjaGenerator::ninjaCmd() const
+std::string cmGlobalNinjaGenerator::CMakeCmd() const
+{
+ cmLocalGenerator* lgen = this->LocalGenerators.at(0);
+ return lgen->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(),
+ cmOutputConverter::SHELL);
+}
+
+std::string cmGlobalNinjaGenerator::NinjaCmd() const
{
cmLocalGenerator* lgen = this->LocalGenerators[0];
- if (lgen) {
+ if (lgen != nullptr) {
return lgen->ConvertToOutputFormat(this->NinjaCommand,
cmOutputConverter::SHELL);
}
@@ -1500,7 +1470,7 @@ bool cmGlobalNinjaGenerator::SupportsMultilineDepfile() const
void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
{
- WriteRule(*this->RulesFileStream, "CLEAN", ninjaCmd() + " -t clean",
+ WriteRule(*this->RulesFileStream, "CLEAN", NinjaCmd() + " -t clean",
"Cleaning all built files...",
"Rule for cleaning all built files.",
/*depfile=*/"",
@@ -1520,7 +1490,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
{
- WriteRule(*this->RulesFileStream, "HELP", ninjaCmd() + " -t targets",
+ WriteRule(*this->RulesFileStream, "HELP", NinjaCmd() + " -t targets",
"All primary targets available:",
"Rule for printing all primary targets available.",
/*depfile=*/"",
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 3ab4171..cd232b3 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -7,12 +7,15 @@
#include <iosfwd>
#include <map>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <utility>
#include <vector>
+#include "cmGeneratedFileStream.h"
#include "cmGlobalCommonGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalGeneratorFactory.h"
@@ -21,7 +24,6 @@
#include "cm_codecvt.hxx"
class cmCustomCommand;
-class cmGeneratedFileStream;
class cmGeneratorTarget;
class cmLinkLineComputer;
class cmLocalGenerator;
@@ -41,8 +43,6 @@ struct cmDocumentationEntry;
* it is handle by Ninja's -v option.
* - We don't care about computing any progress status since Ninja manages
* it itself.
- * - We don't care about generating a clean target since Ninja already have
- * a clean tool.
* - We generate one build.ninja and one rules.ninja per project.
* - We try to minimize the number of generated rules: one per target and
* language.
@@ -234,12 +234,12 @@ public:
cmGeneratedFileStream* GetBuildFileStream() const
{
- return this->BuildFileStream;
+ return this->BuildFileStream.get();
}
cmGeneratedFileStream* GetRulesFileStream() const
{
- return this->RulesFileStream;
+ return this->RulesFileStream.get();
}
std::string const& ConvertToNinjaPath(const std::string& path) const;
@@ -379,12 +379,12 @@ private:
cmMakefile* mf) const override;
bool CheckFortran(cmMakefile* mf) const;
- void OpenBuildFileStream();
+ bool OpenBuildFileStream();
void CloseBuildFileStream();
void CloseCompileCommandsStream();
- void OpenRulesFileStream();
+ bool OpenRulesFileStream();
void CloseRulesFileStream();
/// Write the common disclaimer text at the top of each build file.
@@ -406,25 +406,22 @@ private:
cmGeneratorTarget const* target,
std::set<cmGeneratorTarget const*>& depends);
- std::string ninjaCmd() const;
+ std::string CMakeCmd() const;
+ std::string NinjaCmd() const;
/// The file containing the build statement. (the relationship of the
/// compilation DAG).
- cmGeneratedFileStream* BuildFileStream;
+ std::unique_ptr<cmGeneratedFileStream> BuildFileStream;
/// The file containing the rule statements. (The action attached to each
/// edge of the compilation DAG).
- cmGeneratedFileStream* RulesFileStream;
- cmGeneratedFileStream* CompileCommandsStream;
-
- /// The type used to store the set of rules added to the generated build
- /// system.
- typedef std::set<std::string> RulesSetType;
+ std::unique_ptr<cmGeneratedFileStream> RulesFileStream;
+ std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream;
/// The set of rules added to the generated build system.
- RulesSetType Rules;
+ std::unordered_set<std::string> Rules;
/// Length of rule command, used by rsp file evaluation
- std::map<std::string, int> RuleCmdLength;
+ std::unordered_map<std::string, int> RuleCmdLength;
/// The set of dependencies to add to the "all" target.
cmNinjaDeps AllDependencies;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 69cf2b7..d5a59c7 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -2485,12 +2485,10 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
cmGeneratorTarget* gtgt)
{
- std::string configTypes =
- this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
- std::vector<std::string> configVectorIn;
- std::vector<std::string> configVector;
- configVectorIn.push_back(configTypes);
- cmSystemTools::ExpandList(configVectorIn, configVector);
+ std::vector<std::string> const configVector =
+ cmSystemTools::ExpandedListArgument(
+ this->CurrentMakefile->GetRequiredDefinition(
+ "CMAKE_CONFIGURATION_TYPES"));
cmXCodeObject* configlist =
this->CreateObject(cmXCodeObject::XCConfigurationList);
cmXCodeObject* buildConfigurations =
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index 62ce9f2..14288f6 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -43,9 +43,10 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
cmInstallDirectoryGenerator::~cmInstallDirectoryGenerator() = default;
-void cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg)
{
- LocalGenerator = lg;
+ this->LocalGenerator = lg;
+ return true;
}
void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os,
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
index ac6e504..e30849f 100644
--- a/Source/cmInstallDirectoryGenerator.h
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -29,7 +29,7 @@ public:
bool optional = false);
~cmInstallDirectoryGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
std::string GetDestination(std::string const& config) const;
diff --git a/Source/cmInstallExportAndroidMKGenerator.cxx b/Source/cmInstallExportAndroidMKGenerator.cxx
index 186b9df..7de3dd4 100644
--- a/Source/cmInstallExportAndroidMKGenerator.cxx
+++ b/Source/cmInstallExportAndroidMKGenerator.cxx
@@ -30,10 +30,11 @@ cmInstallExportAndroidMKGenerator::~cmInstallExportAndroidMKGenerator()
{
}
-void cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
this->ExportSet->Compute(lg);
+ return true;
}
void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os)
diff --git a/Source/cmInstallExportAndroidMKGenerator.h b/Source/cmInstallExportAndroidMKGenerator.h
index 189084a..a92ff27 100644
--- a/Source/cmInstallExportAndroidMKGenerator.h
+++ b/Source/cmInstallExportAndroidMKGenerator.h
@@ -24,7 +24,7 @@ public:
const char* name_space, bool exportOld);
~cmInstallExportAndroidMKGenerator();
- void Compute(cmLocalGenerator* lg);
+ bool Compute(cmLocalGenerator* lg) override;
protected:
virtual void GenerateScript(std::ostream& os);
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 73a37cb..f5bedab 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -45,10 +45,11 @@ cmInstallExportGenerator::~cmInstallExportGenerator()
delete this->EFGen;
}
-void cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallExportGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
this->ExportSet->Compute(lg);
+ return true;
}
void cmInstallExportGenerator::ComputeTempDir()
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index d23cf06..c4d252c 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -34,7 +34,7 @@ public:
cmExportSet* GetExportSet() { return this->ExportSet; }
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
cmLocalGenerator* GetLocalGenerator() const { return this->LocalGenerator; }
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index 9eb8ad4..2ed9f73 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -42,9 +42,10 @@ cmInstallFilesGenerator::cmInstallFilesGenerator(
cmInstallFilesGenerator::~cmInstallFilesGenerator() = default;
-void cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallFilesGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
+ return true;
}
std::string cmInstallFilesGenerator::GetDestination(
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
index 0ef2a06..ac462d4 100644
--- a/Source/cmInstallFilesGenerator.h
+++ b/Source/cmInstallFilesGenerator.h
@@ -29,7 +29,7 @@ public:
bool optional = false);
~cmInstallFilesGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
std::string GetDestination(std::string const& config) const;
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 9bd7ac3..dbe707d 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -60,7 +60,7 @@ public:
/** Select message level from CMAKE_INSTALL_MESSAGE or 'never'. */
static MessageLevel SelectMessageLevel(cmMakefile* mf, bool never = false);
- virtual void Compute(cmLocalGenerator*) {}
+ virtual bool Compute(cmLocalGenerator*) { return true; }
protected:
void GenerateScript(std::ostream& os) override;
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
index a513958..5832d27 100644
--- a/Source/cmInstallScriptGenerator.cxx
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -29,7 +29,7 @@ cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script,
cmInstallScriptGenerator::~cmInstallScriptGenerator() = default;
-void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
@@ -49,6 +49,8 @@ void cmInstallScriptGenerator::Compute(cmLocalGenerator* lg)
break;
}
}
+
+ return true;
}
void cmInstallScriptGenerator::AddScriptInstallRule(std::ostream& os,
diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h
index 05199d7..6af7371 100644
--- a/Source/cmInstallScriptGenerator.h
+++ b/Source/cmInstallScriptGenerator.h
@@ -23,7 +23,7 @@ public:
const char* component, bool exclude_from_all);
~cmInstallScriptGenerator() override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
protected:
void GenerateScriptActions(std::ostream& os, Indent indent) override;
diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx
index ad7121f..1c0512c 100644
--- a/Source/cmInstallSubdirectoryGenerator.cxx
+++ b/Source/cmInstallSubdirectoryGenerator.cxx
@@ -41,9 +41,10 @@ void cmInstallSubdirectoryGenerator::CheckCMP0082(
}
}
-void cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg)
{
this->LocalGenerator = lg;
+ return true;
}
void cmInstallSubdirectoryGenerator::GenerateScript(std::ostream& os)
diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h
index 35471dd..22759d9 100644
--- a/Source/cmInstallSubdirectoryGenerator.h
+++ b/Source/cmInstallSubdirectoryGenerator.h
@@ -28,7 +28,7 @@ public:
void CheckCMP0082(bool& haveSubdirectoryInstall,
bool& haveInstallAfterSubdirectory) override;
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
protected:
void GenerateScript(std::ostream& os) override;
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 4fefe23..7c5a55b 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -430,7 +430,7 @@ std::string cmInstallTargetGenerator::GetInstallFilename(
return fname;
}
-void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
+bool cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
{
// Lookup this target in the current directory.
this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName);
@@ -439,6 +439,8 @@ void cmInstallTargetGenerator::Compute(cmLocalGenerator* lg)
this->Target =
lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName);
}
+
+ return true;
}
void cmInstallTargetGenerator::AddTweak(std::ostream& os, Indent indent,
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 6df5b1a..ed3ab52 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -58,7 +58,7 @@ public:
const std::string& config,
NameType nameType = NameNormal);
- void Compute(cmLocalGenerator* lg) override;
+ bool Compute(cmLocalGenerator* lg) override;
cmGeneratorTarget* GetTarget() const { return this->Target; }
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 3704864..869d25d 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -79,19 +79,17 @@ void cmLocalNinjaGenerator::Generate()
}
}
- const std::vector<cmGeneratorTarget*>& targets = this->GetGeneratorTargets();
- for (cmGeneratorTarget* target : targets) {
+ for (cmGeneratorTarget* target : this->GetGeneratorTargets()) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
continue;
}
- cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(target);
+ auto tg = cmNinjaTargetGenerator::New(target);
if (tg) {
tg->Generate();
// Add the target to "all" if required.
if (!this->GetGlobalNinjaGenerator()->IsExcluded(target)) {
this->GetGlobalNinjaGenerator()->AddDependencyToAll(target);
}
- delete tg;
}
}
@@ -283,8 +281,7 @@ void cmLocalNinjaGenerator::AppendTargetDepends(cmGeneratorTarget* target,
void cmLocalNinjaGenerator::AppendCustomCommandDeps(
cmCustomCommandGenerator const& ccg, cmNinjaDeps& ninjaDeps)
{
- const std::vector<std::string>& deps = ccg.GetDepends();
- for (std::string const& i : deps) {
+ for (std::string const& i : ccg.GetDepends()) {
std::string dep;
if (this->GetRealDependency(i, this->GetConfigName(), dep)) {
ninjaDeps.push_back(
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 2324839..506711a 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -9,7 +9,7 @@
#include <iterator>
#include <map>
#include <memory> // IWYU pragma: keep
-#include <sstream>
+#include <ostream>
#include <utility>
#include "cmAlgorithms.h"
@@ -33,7 +33,8 @@
#include "cmSystemTools.h"
#include "cmake.h"
-cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
+std::unique_ptr<cmNinjaTargetGenerator> cmNinjaTargetGenerator::New(
+ cmGeneratorTarget* target)
{
switch (target->GetType()) {
case cmStateEnums::EXECUTABLE:
@@ -41,14 +42,14 @@ cmNinjaTargetGenerator* cmNinjaTargetGenerator::New(cmGeneratorTarget* target)
case cmStateEnums::STATIC_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::OBJECT_LIBRARY:
- return new cmNinjaNormalTargetGenerator(target);
+ return cm::make_unique<cmNinjaNormalTargetGenerator>(target);
case cmStateEnums::UTILITY:
case cmStateEnums::GLOBAL_TARGET:
- return new cmNinjaUtilityTargetGenerator(target);
+ return cm::make_unique<cmNinjaUtilityTargetGenerator>(target);
default:
- return nullptr;
+ return std::unique_ptr<cmNinjaTargetGenerator>();
}
}
@@ -496,12 +497,11 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
launcher += " ";
}
- if (explicitPP) {
- // Lookup the explicit preprocessing rule.
- std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
- std::string const& ppCmd =
- this->GetMakefile()->GetRequiredDefinition(ppVar);
+ std::string const cmakeCmd =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ if (explicitPP) {
// Explicit preprocessing always uses a depfile.
std::string const ppDeptype; // no deps= for multiple outputs
std::string const ppDepfile = "$DEP_FILE";
@@ -535,8 +535,12 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
std::string ppRspContent;
if (!responseFlag.empty()) {
ppRspFile = "$RSP_FILE";
- ppRspContent = std::string(" ") + ppVars.Defines + " " +
- ppVars.Includes + " " + ppFlags;
+ ppRspContent = " ";
+ ppRspContent += ppVars.Defines;
+ ppRspContent += " ";
+ ppRspContent += ppVars.Includes;
+ ppRspContent += " ";
+ ppRspContent += ppFlags;
ppFlags = responseFlag + ppRspFile;
ppVars.Defines = "";
ppVars.Includes = "";
@@ -546,7 +550,13 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
// Rule for preprocessing source file.
std::vector<std::string> ppCmds;
- cmSystemTools::ExpandListArgument(ppCmd, ppCmds);
+ {
+ // Lookup the explicit preprocessing rule.
+ std::string ppVar = "CMAKE_" + lang;
+ ppVar += "_PREPROCESS_SOURCE";
+ cmSystemTools::ExpandListArgument(
+ this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds);
+ }
for (std::string& i : ppCmds) {
i = launcher + i;
@@ -555,67 +565,73 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
}
// Run CMake dependency scanner on preprocessed output.
- std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- ppCmds.push_back(
- cmake +
- " -E cmake_ninja_depends"
- " --tdi=" +
- tdi + " --lang=" + lang +
- " --pp=$out"
- " --dep=$DEP_FILE" +
- (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
-
+ {
+ std::string ccmd = cmakeCmd;
+ ccmd += " -E cmake_ninja_depends --tdi=";
+ ccmd += tdi;
+ ccmd += " --lang=";
+ ccmd += lang;
+ ccmd += " --pp=$out --dep=$DEP_FILE";
+ if (needDyndep) {
+ ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE";
+ }
+ ppCmds.emplace_back(std::move(ccmd));
+ }
std::string const ppCmdLine =
this->GetLocalGenerator()->BuildCommandLine(ppCmds);
// Write the rule for preprocessing file of the given language.
- std::ostringstream ppComment;
- ppComment << "Rule for preprocessing " << lang << " files.";
- std::ostringstream ppDesc;
- ppDesc << "Building " << lang << " preprocessed $out";
+ std::string ppComment = "Rule for preprocessing ";
+ ppComment += lang;
+ ppComment += " files.";
+ std::string ppDesc = "Building ";
+ ppDesc += lang;
+ ppDesc += " preprocessed $out";
this->GetGlobalGenerator()->AddRule(
- this->LanguagePreprocessRule(lang), ppCmdLine, ppDesc.str(),
- ppComment.str(), ppDepfile, ppDeptype, ppRspFile, ppRspContent,
+ this->LanguagePreprocessRule(lang), ppCmdLine, ppDesc, ppComment,
+ ppDepfile, ppDeptype, ppRspFile, ppRspContent,
/*restat*/ "",
/*generator*/ false);
}
if (needDyndep) {
// Write the rule for ninja dyndep file generation.
- std::vector<std::string> ddCmds;
// Command line length is almost always limited -> use response file for
// dyndep rules
std::string ddRspFile = "$out.rsp";
std::string ddRspContent = "$in";
- std::string ddInput = "@" + ddRspFile;
+ std::string ddCmdLine;
// Run CMake dependency scanner on the source file (using the preprocessed
// source if that was performed).
- std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
- ddCmds.push_back(cmake +
- " -E cmake_ninja_dyndep"
- " --tdi=" +
- tdi + " --lang=" + lang +
- " --dd=$out"
- " " +
- ddInput);
-
- std::string const ddCmdLine =
- this->GetLocalGenerator()->BuildCommandLine(ddCmds);
-
- std::ostringstream ddComment;
- ddComment << "Rule to generate ninja dyndep files for " << lang << ".";
- std::ostringstream ddDesc;
- ddDesc << "Generating " << lang << " dyndep file $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(),
- /*depfile*/ "",
- /*deps*/ "", ddRspFile, ddRspContent,
- /*restat*/ "",
- /*generator*/ false);
+ {
+ std::vector<std::string> ddCmds;
+ {
+ std::string ccmd = cmakeCmd;
+ ccmd += " -E cmake_ninja_dyndep --tdi=";
+ ccmd += tdi;
+ ccmd += " --lang=";
+ ccmd += lang;
+ ccmd += " --dd=$out ";
+ ccmd += "@";
+ ccmd += ddRspFile;
+ ddCmds.emplace_back(std::move(ccmd));
+ }
+ ddCmdLine = this->GetLocalGenerator()->BuildCommandLine(ddCmds);
+ }
+ std::string ddComment = "Rule to generate ninja dyndep files for ";
+ ddComment += lang;
+ ddComment += ".";
+ std::string ddDesc = "Generating ";
+ ddDesc += lang;
+ ddDesc += " dyndep file $out";
+ this->GetGlobalGenerator()->AddRule(this->LanguageDyndepRule(lang),
+ ddCmdLine, ddDesc, ddComment,
+ /*depfile*/ "",
+ /*deps*/ "", ddRspFile, ddRspContent,
+ /*restat*/ "",
+ /*generator*/ false);
}
// If using a response file, move defines, includes, and flags into it.
@@ -716,8 +732,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
const char* cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
if ((iwyu && *iwyu) || (tidy && *tidy) || (cpplint && *cpplint) ||
(cppcheck && *cppcheck)) {
- std::string run_iwyu = this->GetLocalGenerator()->ConvertToOutputFormat(
- cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
+ std::string run_iwyu = cmakeCmd;
run_iwyu += " -E __run_co_compile";
if (!compilerLauncher.empty()) {
// In __run_co_compile case the launcher command is supplied
@@ -776,15 +791,17 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
this->GetLocalGenerator()->BuildCommandLine(compileCmds);
// Write the rule for compiling file of the given language.
- std::ostringstream comment;
- comment << "Rule for compiling " << lang << " files.";
- std::ostringstream description;
- description << "Building " << lang << " object $out";
- this->GetGlobalGenerator()->AddRule(
- this->LanguageCompilerRule(lang), cmdLine, description.str(),
- comment.str(), depfile, deptype, rspfile, rspcontent,
- /*restat*/ "",
- /*generator*/ false);
+ std::string comment = "Rule for compiling ";
+ comment += lang;
+ comment += " files.";
+ std::string description = "Building ";
+ description += lang;
+ description += " object $out";
+ this->GetGlobalGenerator()->AddRule(this->LanguageCompilerRule(lang),
+ cmdLine, description, comment, depfile,
+ deptype, rspfile, rspcontent,
+ /*restat*/ "",
+ /*generator*/ false);
}
void cmNinjaTargetGenerator::WriteObjectBuildStatements()
@@ -1212,8 +1229,7 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
Json::arrayValue;
- std::vector<std::string> linked = this->GetLinkedTargetDirectories();
- for (std::string const& l : linked) {
+ for (std::string const& l : this->GetLinkedTargetDirectories()) {
tdi_linked_target_dirs.append(l);
}
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 51c9ac7..3dbc1b5 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -11,6 +11,7 @@
#include "cmOSXBundleGenerator.h"
#include <map>
+#include <memory> // IWYU pragma: keep
#include <set>
#include <string>
#include <vector>
@@ -26,7 +27,8 @@ class cmNinjaTargetGenerator : public cmCommonTargetGenerator
{
public:
/// Create a cmNinjaTargetGenerator according to the @a target's type.
- static cmNinjaTargetGenerator* New(cmGeneratorTarget* target);
+ static std::unique_ptr<cmNinjaTargetGenerator> New(
+ cmGeneratorTarget* target);
/// Build a NinjaTargetGenerator.
cmNinjaTargetGenerator(cmGeneratorTarget* target);
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 0e42295..4bb4c53 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -273,7 +273,9 @@ class cmMakefile;
0, cmPolicies::WARN) \
SELECT(POLICY, CMP0092, \
"MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.", 3, \
- 15, 0, cmPolicies::WARN)
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0093, "FindBoost reports Boost_VERSION in x.y.z format.", \
+ 3, 15, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index f7e377d..e1c435b 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -279,10 +279,11 @@ bool cmQtAutoGenerator::Run(std::string const& infoFile,
InfoFile_ = infoFile;
cmSystemTools::ConvertToUnixSlashes(InfoFile_);
if (!InfoFileTime_.Load(InfoFile_)) {
- std::string msg = "Autogen: The info file ";
+ std::string msg = "AutoGen: The info file ";
msg += Quoted(InfoFile_);
msg += " is not readable\n";
cmSystemTools::Stderr(msg);
+ return false;
}
InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
InfoConfig_ = config;
diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx
index bb40c39..7ac7339 100644
--- a/Source/cmQtAutoRcc.cxx
+++ b/Source/cmQtAutoRcc.cxx
@@ -3,6 +3,8 @@
#include "cmQtAutoRcc.h"
#include "cmQtAutoGen.h"
+#include <sstream>
+
#include "cmAlgorithms.h"
#include "cmCryptoHash.h"
#include "cmDuration.h"
@@ -49,11 +51,16 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile)
cmSystemTools::ExpandListArgument(InfoGetConfig(key), list);
return list;
};
+ auto LogInfoError = [this](std::string const& msg) -> bool {
+ std::ostringstream err;
+ err << "In " << Quoted(this->InfoFile()) << ":\n" << msg;
+ this->Log().Error(GenT::RCC, err.str());
+ return false;
+ };
// -- Read info file
if (!makefile->ReadListFile(InfoFile())) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "File processing failed.");
- return false;
+ return LogInfoError("File processing failed.");
}
// - Configurations
@@ -63,18 +70,22 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile)
// - Directories
AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR");
if (AutogenBuildDir_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "Build directory empty.");
- return false;
+ return LogInfoError("Build directory empty.");
}
IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR");
if (IncludeDir_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "Include directory empty.");
- return false;
+ return LogInfoError("Include directory empty.");
}
// - Rcc executable
RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE");
+ if (!RccExecutableTime_.Load(RccExecutable_)) {
+ std::string error = "The rcc executable ";
+ error += Quoted(RccExecutable_);
+ error += " does not exist.";
+ return LogInfoError(error);
+ }
RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS");
// - Job
@@ -92,28 +103,22 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile)
// - Validity checks
if (LockFile_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "Lock file name missing.");
- return false;
+ return LogInfoError("Lock file name missing.");
}
if (SettingsFile_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "Settings file name missing.");
- return false;
+ return LogInfoError("Settings file name missing.");
}
if (AutogenBuildDir_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "Autogen build directory missing.");
- return false;
+ return LogInfoError("Autogen build directory missing.");
}
if (RccExecutable_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "rcc executable missing.");
- return false;
+ return LogInfoError("rcc executable missing.");
}
if (QrcFile_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "rcc input file missing.");
- return false;
+ return LogInfoError("rcc input file missing.");
}
if (RccFileName_.empty()) {
- Log().ErrorFile(GenT::RCC, InfoFile(), "rcc output file missing.");
- return false;
+ return LogInfoError("rcc output file missing.");
}
// Init derived information
@@ -301,12 +306,10 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate)
// Test if the rcc output file exists
if (!RccFileTime_.Load(RccFileOutput_)) {
if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from its source file ";
- reason += Quoted(QrcFile_);
- reason += " because it doesn't exist";
- Log().Info(GenT::RCC, reason);
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it doesn't exist, from ";
+ Reason += Quoted(QrcFile_);
}
generate = true;
return true;
@@ -315,12 +318,10 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate)
// Test if the settings changed
if (SettingsChanged_) {
if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from ";
- reason += Quoted(QrcFile_);
- reason += " because the RCC settings changed";
- Log().Info(GenT::RCC, reason);
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because the rcc settings changed, from ";
+ Reason += Quoted(QrcFile_);
}
generate = true;
return true;
@@ -329,11 +330,24 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate)
// Test if the rcc output file is older than the .qrc file
if (RccFileTime_.Older(QrcFileTime_)) {
if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " because it is older than ";
- reason += Quoted(QrcFile_);
- Log().Info(GenT::RCC, reason);
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than ";
+ Reason += Quoted(QrcFile_);
+ Reason += ", from ";
+ Reason += Quoted(QrcFile_);
+ }
+ generate = true;
+ return true;
+ }
+
+ // Test if the rcc output file is older than the rcc executable
+ if (RccFileTime_.Older(RccExecutableTime_)) {
+ if (Log().Verbose()) {
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than the rcc executable, from ";
+ Reason += Quoted(QrcFile_);
}
generate = true;
return true;
@@ -354,6 +368,7 @@ bool cmQtAutoRcc::TestResources(bool& generate)
}
}
+ // Check if any resource file is newer than the rcc output file
for (std::string const& resFile : Inputs_) {
// Check if the resource file exists
cmFileTime fileTime;
@@ -365,16 +380,15 @@ bool cmQtAutoRcc::TestResources(bool& generate)
Log().ErrorFile(GenT::RCC, QrcFile_, error);
return false;
}
- // Check if the resource file is newer than the build file
+ // Check if the resource file is newer than the rcc output file
if (RccFileTime_.Older(fileTime)) {
if (Log().Verbose()) {
- std::string reason = "Generating ";
- reason += Quoted(RccFileOutput_);
- reason += " from ";
- reason += Quoted(QrcFile_);
- reason += " because it is older than ";
- reason += Quoted(resFile);
- Log().Info(GenT::RCC, reason);
+ Reason = "Generating ";
+ Reason += Quoted(RccFileOutput_);
+ Reason += ", because it is older than ";
+ Reason += Quoted(resFile);
+ Reason += ", from ";
+ Reason += Quoted(QrcFile_);
}
generate = true;
break;
@@ -386,17 +400,7 @@ bool cmQtAutoRcc::TestResources(bool& generate)
bool cmQtAutoRcc::TestInfoFile()
{
// Test if the rcc output file is older than the info file
-
- cmFileTime infoFileTime;
- if (!infoFileTime.Load(InfoFile())) {
- std::string error;
- error = "Could not find the info file ";
- error += Quoted(InfoFile());
- error += '\n';
- Log().ErrorFile(GenT::RCC, QrcFile_, error);
- return false;
- }
- if (RccFileTime_.Older(infoFileTime)) {
+ if (RccFileTime_.Older(InfoFileTime())) {
if (Log().Verbose()) {
std::string reason = "Touching ";
reason += Quoted(RccFileOutput_);
@@ -424,7 +428,7 @@ bool cmQtAutoRcc::GenerateRcc()
return false;
}
- // Start a rcc process
+ // Compose rcc command
std::vector<std::string> cmd;
cmd.push_back(RccExecutable_);
cmd.insert(cmd.end(), Options_.begin(), Options_.end());
@@ -432,12 +436,15 @@ bool cmQtAutoRcc::GenerateRcc()
cmd.push_back(RccFileOutput_);
cmd.push_back(QrcFile_);
- // Log command
+ // Log reason and command
if (Log().Verbose()) {
- std::string msg = "Running command:\n";
+ std::string msg = Reason;
+ if (!msg.empty() && (msg.back() != '\n')) {
+ msg += '\n';
+ }
msg += QuotedCommand(cmd);
msg += '\n';
- cmSystemTools::Stdout(msg);
+ Log().Info(GenT::RCC, msg);
}
std::string rccStdOut;
diff --git a/Source/cmQtAutoRcc.h b/Source/cmQtAutoRcc.h
index 01c3fb9..636a667 100644
--- a/Source/cmQtAutoRcc.h
+++ b/Source/cmQtAutoRcc.h
@@ -54,6 +54,7 @@ private:
std::string IncludeDir_;
// -- Qt environment
std::string RccExecutable_;
+ cmFileTime RccExecutableTime_;
std::vector<std::string> RccListOptions_;
// -- Job
std::string LockFile_;
@@ -67,6 +68,7 @@ private:
std::string RccFileOutput_;
std::string RccFilePublic_;
cmFileTime RccFileTime_;
+ std::string Reason;
std::vector<std::string> Options_;
std::vector<std::string> Inputs_;
// -- Settings file
diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx
index bb14e68..a64ad8c 100644
--- a/Source/cmRemoveCommand.cxx
+++ b/Source/cmRemoveCommand.cxx
@@ -25,15 +25,13 @@ bool cmRemoveCommand::InitialPass(std::vector<std::string> const& args,
}
// expand the variable
- std::vector<std::string> varArgsExpanded;
- cmSystemTools::ExpandListArgument(cacheValue, varArgsExpanded);
+ std::vector<std::string> const varArgsExpanded =
+ cmSystemTools::ExpandedListArgument(cacheValue);
// expand the args
// check for REMOVE(VAR v1 v2 ... vn)
- std::vector<std::string> argsExpanded;
- std::vector<std::string> temp;
- temp.insert(temp.end(), args.begin() + 1, args.end());
- cmSystemTools::ExpandList(temp, argsExpanded);
+ std::vector<std::string> const argsExpanded =
+ cmSystemTools::ExpandedLists(args.begin() + 1, args.end());
// now create the new value
std::string value;
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 17ed3f6..545e6c5 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1208,16 +1208,8 @@ void cmSystemTools::GlobDirs(const std::string& path,
}
}
-void cmSystemTools::ExpandList(std::vector<std::string> const& arguments,
- std::vector<std::string>& newargs)
-{
- for (std::string const& arg : arguments) {
- cmSystemTools::ExpandListArgument(arg, newargs);
- }
-}
-
void cmSystemTools::ExpandListArgument(const std::string& arg,
- std::vector<std::string>& newargs,
+ std::vector<std::string>& argsOut,
bool emptyArgs)
{
// If argument is empty, it is an empty list.
@@ -1226,7 +1218,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
}
// if there are no ; in the name then just copy the current string
if (arg.find(';') == std::string::npos) {
- newargs.push_back(arg);
+ argsOut.push_back(arg);
return;
}
std::string newArg;
@@ -1260,7 +1252,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
last = c + 1;
if (!newArg.empty() || emptyArgs) {
// Add the last argument if the string is not empty.
- newargs.push_back(newArg);
+ argsOut.push_back(newArg);
newArg.clear();
}
}
@@ -1273,10 +1265,18 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
newArg.append(last);
if (!newArg.empty() || emptyArgs) {
// Add the last argument if the string is not empty.
- newargs.push_back(newArg);
+ argsOut.push_back(newArg);
}
}
+std::vector<std::string> cmSystemTools::ExpandedListArgument(
+ const std::string& arg, bool emptyArgs)
+{
+ std::vector<std::string> argsOut;
+ ExpandListArgument(arg, argsOut, emptyArgs);
+ return argsOut;
+}
+
bool cmSystemTools::SimpleGlob(const std::string& glob,
std::vector<std::string>& files,
int type /* = 0 */)
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 8a87a37..d145d47 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -29,17 +29,50 @@ public:
typedef cmsys::SystemTools Superclass;
typedef cmProcessOutput::Encoding Encoding;
- /** Expand out any arguments in the vector that have ; separated
- * strings into multiple arguments. A new vector is created
- * containing the expanded versions of all arguments in argsIn.
+ /**
+ * Expand the ; separated string @a arg into multiple arguments.
+ * All found arguments are appended to @a argsOut.
*/
- static void ExpandList(std::vector<std::string> const& argsIn,
- std::vector<std::string>& argsOut);
static void ExpandListArgument(const std::string& arg,
std::vector<std::string>& argsOut,
bool emptyArgs = false);
/**
+ * Expand out any arguments in the string range [@a first, @a last) that have
+ * ; separated strings into multiple arguments. All found arguments are
+ * appended to @a argsOut.
+ */
+ template <class InputIt>
+ static void ExpandLists(InputIt first, InputIt last,
+ std::vector<std::string>& argsOut)
+ {
+ for (; first != last; ++first) {
+ cmSystemTools::ExpandListArgument(*first, argsOut);
+ }
+ }
+
+ /**
+ * Same as ExpandListArgument but a new vector is created containing
+ * the expanded arguments from the string @a arg.
+ */
+ static std::vector<std::string> ExpandedListArgument(const std::string& arg,
+ bool emptyArgs = false);
+
+ /**
+ * Same as ExpandList but a new vector is created containing the expanded
+ * versions of all arguments in the string range [@a first, @a last).
+ */
+ template <class InputIt>
+ static std::vector<std::string> ExpandedLists(InputIt first, InputIt last)
+ {
+ std::vector<std::string> argsOut;
+ for (; first != last; ++first) {
+ cmSystemTools::ExpandListArgument(*first, argsOut);
+ }
+ return argsOut;
+ }
+
+ /**
* Look for and replace registry values in a string
*/
static void ExpandRegistryValues(std::string& source,
diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx
index 27069ee..db67463 100644
--- a/Source/cmUVHandlePtr.cxx
+++ b/Source/cmUVHandlePtr.cxx
@@ -211,7 +211,6 @@ uv_pipe_ptr::operator uv_stream_t*() const
return reinterpret_cast<uv_stream_t*>(handle.get());
}
-#ifdef CMAKE_BUILD_WITH_CMAKE
int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options,
void* data)
{
@@ -231,6 +230,7 @@ int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
return uv_timer_start(*this, cb, timeout, repeat);
}
+#ifdef CMAKE_BUILD_WITH_CMAKE
uv_tty_ptr::operator uv_stream_t*() const
{
return reinterpret_cast<uv_stream_t*>(handle.get());
@@ -255,13 +255,13 @@ UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe)
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream)
-#ifdef CMAKE_BUILD_WITH_CMAKE
-UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
-
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process)
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer)
+#ifdef CMAKE_BUILD_WITH_CMAKE
+UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async)
+
UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty)
#endif
}
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
new file mode 100644
index 0000000..90ece0b
--- /dev/null
+++ b/Source/cmUVProcessChain.cxx
@@ -0,0 +1,395 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmUVProcessChain.h"
+
+#include "cmAlgorithms.h"
+#include "cmGetPipes.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStreambuf.h"
+#include "cm_uv.h"
+
+#include <assert.h>
+
+#include <iterator>
+#include <memory>
+#include <utility>
+
+struct cmUVProcessChain::InternalData
+{
+ struct BasicStreamData
+ {
+ cmUVStreambuf Streambuf;
+ cm::uv_pipe_ptr BuiltinStream;
+ uv_stdio_container_t Stdio;
+ };
+
+ template <typename IOStream>
+ struct StreamData : public BasicStreamData
+ {
+ StreamData()
+ : BuiltinIOStream(&this->Streambuf)
+ {
+ }
+
+ IOStream BuiltinIOStream;
+
+ IOStream* GetBuiltinStream()
+ {
+ if (this->BuiltinStream.get()) {
+ return &this->BuiltinIOStream;
+ }
+ return nullptr;
+ }
+ };
+
+ struct ProcessData
+ {
+ cmUVProcessChain::InternalData* Data;
+ cm::uv_process_ptr Process;
+ cm::uv_pipe_ptr OutputPipe;
+ bool Finished = false;
+ Status ProcessStatus;
+ };
+
+ const cmUVProcessChainBuilder* Builder = nullptr;
+
+ bool Valid = false;
+
+ cm::uv_loop_ptr Loop;
+
+ StreamData<std::istream> OutputStreamData;
+ StreamData<std::istream> ErrorStreamData;
+
+ unsigned int ProcessesCompleted = 0;
+ std::vector<std::unique_ptr<ProcessData>> Processes;
+
+ bool Prepare(const cmUVProcessChainBuilder* builder);
+ bool AddCommand(const cmUVProcessChainBuilder::ProcessConfiguration& config,
+ bool first, bool last);
+ bool Finish();
+
+ static const Status* GetStatus(const ProcessData& data);
+};
+
+cmUVProcessChainBuilder::cmUVProcessChainBuilder()
+{
+ this->SetNoStream(Stream_INPUT)
+ .SetNoStream(Stream_OUTPUT)
+ .SetNoStream(Stream_ERROR);
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand(
+ const std::vector<std::string>& arguments)
+{
+ if (!arguments.empty()) {
+ this->Processes.emplace_back();
+ this->Processes.back().Arguments = arguments;
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetNoStream(Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = None;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinStream(
+ Stream stdio)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = Builtin;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
+ Stream stdio, int fd)
+{
+ switch (stdio) {
+ case Stream_INPUT:
+ // FIXME
+ break;
+
+ case Stream_OUTPUT:
+ case Stream_ERROR: {
+ auto& streamData = this->Stdio[stdio];
+ streamData.Type = External;
+ streamData.FileDescriptor = fd;
+ break;
+ }
+ }
+ return *this;
+}
+
+cmUVProcessChain cmUVProcessChainBuilder::Start() const
+{
+ cmUVProcessChain chain;
+
+ if (!chain.Data->Prepare(this)) {
+ return chain;
+ }
+
+ for (auto it = this->Processes.begin(); it != this->Processes.end(); ++it) {
+ if (!chain.Data->AddCommand(*it, it == this->Processes.begin(),
+ it == std::prev(this->Processes.end()))) {
+ return chain;
+ }
+ }
+
+ chain.Data->Finish();
+
+ return chain;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::InternalData::GetStatus(
+ const cmUVProcessChain::InternalData::ProcessData& data)
+{
+ if (data.Finished) {
+ return &data.ProcessStatus;
+ }
+ return nullptr;
+}
+
+bool cmUVProcessChain::InternalData::Prepare(
+ const cmUVProcessChainBuilder* builder)
+{
+ this->Builder = builder;
+
+ auto const& output =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT];
+ auto& outputData = this->OutputStreamData;
+ switch (output.Type) {
+ case cmUVProcessChainBuilder::None:
+ outputData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin:
+ outputData.BuiltinStream.init(*this->Loop, 0);
+ outputData.Stdio.flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ outputData.Stdio.data.stream = outputData.BuiltinStream;
+ break;
+
+ case cmUVProcessChainBuilder::External:
+ outputData.Stdio.flags = UV_INHERIT_FD;
+ outputData.Stdio.data.fd = output.FileDescriptor;
+ break;
+ }
+
+ auto const& error =
+ this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR];
+ auto& errorData = this->ErrorStreamData;
+ switch (error.Type) {
+ case cmUVProcessChainBuilder::None:
+ errorData.Stdio.flags = UV_IGNORE;
+ break;
+
+ case cmUVProcessChainBuilder::Builtin: {
+ int pipeFd[2];
+ if (cmGetPipes(pipeFd) < 0) {
+ return false;
+ }
+
+ errorData.BuiltinStream.init(*this->Loop, 0);
+ if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) {
+ return false;
+ }
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = pipeFd[1];
+ break;
+ }
+
+ case cmUVProcessChainBuilder::External:
+ errorData.Stdio.flags = UV_INHERIT_FD;
+ errorData.Stdio.data.fd = error.FileDescriptor;
+ break;
+ }
+
+ return true;
+}
+
+bool cmUVProcessChain::InternalData::AddCommand(
+ const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first,
+ bool last)
+{
+ this->Processes.emplace_back(cm::make_unique<ProcessData>());
+ auto& process = *this->Processes.back();
+ process.Data = this;
+
+ auto options = uv_process_options_t();
+
+ // Bounds were checked at add time, first element is guaranteed to exist
+ options.file = config.Arguments[0].c_str();
+
+ std::vector<const char*> arguments;
+ for (auto const& arg : config.Arguments) {
+ arguments.push_back(arg.c_str());
+ }
+ arguments.push_back(nullptr);
+ options.args = const_cast<char**>(arguments.data());
+ options.flags = UV_PROCESS_WINDOWS_HIDE;
+
+ std::array<uv_stdio_container_t, 3> stdio;
+ stdio[0] = uv_stdio_container_t();
+ if (first) {
+ stdio[0].flags = UV_IGNORE;
+ } else {
+ assert(this->Processes.size() >= 2);
+ auto& prev = *this->Processes[this->Processes.size() - 2];
+ stdio[0].flags = UV_INHERIT_STREAM;
+ stdio[0].data.stream = prev.OutputPipe;
+ }
+ if (last) {
+ stdio[1] = this->OutputStreamData.Stdio;
+ } else {
+ if (process.OutputPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ stdio[1] = uv_stdio_container_t();
+ stdio[1].flags =
+ static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+ stdio[1].data.stream = process.OutputPipe;
+ }
+ stdio[2] = this->ErrorStreamData.Stdio;
+
+ options.stdio = stdio.data();
+ options.stdio_count = 3;
+ options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
+ int termSignal) {
+ auto* processData = static_cast<ProcessData*>(handle->data);
+ processData->Finished = true;
+ processData->ProcessStatus.ExitStatus = exitStatus;
+ processData->ProcessStatus.TermSignal = termSignal;
+ processData->Data->ProcessesCompleted++;
+ };
+
+ return process.Process.spawn(*this->Loop, options, &process) >= 0;
+}
+
+bool cmUVProcessChain::InternalData::Finish()
+{
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ this->OutputStreamData.Streambuf.open(
+ this->OutputStreamData.BuiltinStream);
+ }
+
+ if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR].Type ==
+ cmUVProcessChainBuilder::Builtin) {
+ cm::uv_pipe_ptr tmpPipe;
+ if (tmpPipe.init(*this->Loop, 0) < 0) {
+ return false;
+ }
+ if (uv_pipe_open(tmpPipe, this->ErrorStreamData.Stdio.data.fd) < 0) {
+ return false;
+ }
+ tmpPipe.reset();
+
+ this->ErrorStreamData.Streambuf.open(this->ErrorStreamData.BuiltinStream);
+ }
+
+ this->Valid = true;
+ return true;
+}
+
+cmUVProcessChain::cmUVProcessChain()
+ : Data(cm::make_unique<InternalData>())
+{
+ this->Data->Loop.init();
+}
+
+cmUVProcessChain::cmUVProcessChain(cmUVProcessChain&& other) noexcept
+ : Data(std::move(other.Data))
+{
+}
+
+cmUVProcessChain::~cmUVProcessChain() = default;
+
+cmUVProcessChain& cmUVProcessChain::operator=(
+ cmUVProcessChain&& other) noexcept
+{
+ this->Data = std::move(other.Data);
+ return *this;
+}
+
+uv_loop_t& cmUVProcessChain::GetLoop()
+{
+ return *this->Data->Loop;
+}
+
+std::istream* cmUVProcessChain::OutputStream()
+{
+ return this->Data->OutputStreamData.GetBuiltinStream();
+}
+
+std::istream* cmUVProcessChain::ErrorStream()
+{
+ return this->Data->ErrorStreamData.GetBuiltinStream();
+}
+
+bool cmUVProcessChain::Valid() const
+{
+ return this->Data->Valid;
+}
+
+bool cmUVProcessChain::Wait(int64_t milliseconds)
+{
+ bool timeout = false;
+ cm::uv_timer_ptr timer;
+
+ if (milliseconds >= 0) {
+ timer.init(*this->Data->Loop, &timeout);
+ timer.start(
+ [](uv_timer_t* handle) {
+ auto* timeoutPtr = static_cast<bool*>(handle->data);
+ *timeoutPtr = true;
+ },
+ milliseconds, 0);
+ }
+
+ while (!timeout &&
+ this->Data->ProcessesCompleted < this->Data->Processes.size()) {
+ uv_run(this->Data->Loop, UV_RUN_ONCE);
+ }
+
+ return !timeout;
+}
+
+std::vector<const cmUVProcessChain::Status*> cmUVProcessChain::GetStatus()
+ const
+{
+ std::vector<const cmUVProcessChain::Status*> statuses(
+ this->Data->Processes.size(), nullptr);
+ for (std::size_t i = 0; i < statuses.size(); i++) {
+ statuses[i] = this->GetStatus(i);
+ }
+ return statuses;
+}
+
+const cmUVProcessChain::Status* cmUVProcessChain::GetStatus(
+ std::size_t index) const
+{
+ auto const& process = *this->Data->Processes[index];
+ if (process.Finished) {
+ return &process.ProcessStatus;
+ }
+ return nullptr;
+}
diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h
new file mode 100644
index 0000000..2b33520
--- /dev/null
+++ b/Source/cmUVProcessChain.h
@@ -0,0 +1,100 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmUVProcessChain_h
+#define cmUVProcessChain_h
+
+#include "cm_uv.h"
+
+#include <array>
+#include <iosfwd>
+#include <memory> // IWYU pragma: keep
+#include <string>
+#include <vector>
+
+#include <stdint.h>
+
+class cmUVProcessChain;
+
+class cmUVProcessChainBuilder
+{
+public:
+ enum Stream
+ {
+ Stream_INPUT = 0,
+ Stream_OUTPUT = 1,
+ Stream_ERROR = 2,
+ };
+
+ cmUVProcessChainBuilder();
+
+ cmUVProcessChainBuilder& AddCommand(
+ const std::vector<std::string>& arguments);
+ cmUVProcessChainBuilder& SetNoStream(Stream stdio);
+ cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio);
+ cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd);
+
+ cmUVProcessChain Start() const;
+
+private:
+ enum StdioType
+ {
+ None,
+ Builtin,
+ External,
+ };
+
+ friend class cmUVProcessChain;
+
+ struct StdioConfiguration
+ {
+ StdioType Type;
+ int FileDescriptor;
+ };
+
+ struct ProcessConfiguration
+ {
+ std::vector<std::string> Arguments;
+ };
+
+ std::array<StdioConfiguration, 3> Stdio;
+ std::vector<ProcessConfiguration> Processes;
+};
+
+class cmUVProcessChain
+{
+public:
+ struct Status
+ {
+ int64_t ExitStatus;
+ int TermSignal;
+ };
+
+ cmUVProcessChain(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain(cmUVProcessChain&& other) noexcept;
+
+ ~cmUVProcessChain();
+
+ cmUVProcessChain& operator=(const cmUVProcessChain& other) = delete;
+ cmUVProcessChain& operator=(cmUVProcessChain&& other) noexcept;
+
+ uv_loop_t& GetLoop();
+
+ // FIXME: Add stdin support
+ std::istream* OutputStream();
+ std::istream* ErrorStream();
+
+ bool Valid() const;
+ bool Wait(int64_t milliseconds = -1);
+ std::vector<const Status*> GetStatus() const;
+ const Status* GetStatus(std::size_t index) const;
+
+private:
+ friend class cmUVProcessChainBuilder;
+
+ cmUVProcessChain();
+
+ struct InternalData;
+ std::unique_ptr<InternalData> Data;
+};
+
+#endif
diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h
index 29e4fde..873352b 100644
--- a/Source/cmUVStreambuf.h
+++ b/Source/cmUVStreambuf.h
@@ -68,10 +68,10 @@ protected:
private:
uv_stream_t* Stream = nullptr;
- void* OldStreamData;
- const std::size_t PutBack;
+ void* OldStreamData = nullptr;
+ const std::size_t PutBack = 0;
std::vector<CharT> InputBuffer;
- bool EndOfFile;
+ bool EndOfFile = false;
void StreamReadStartStop();
@@ -208,7 +208,7 @@ void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread)
this->setg(this->eback(), this->gptr(),
this->egptr() + nread / sizeof(CharT));
uv_read_stop(this->Stream);
- } else if (nread < 0 || nread == UV_EOF) {
+ } else if (nread < 0 /*|| nread == UV_EOF*/) {
this->EndOfFile = true;
uv_read_stop(this->Stream);
}
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 121d12d..d19de21 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1733,6 +1733,11 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure)
return ret;
}
ret = this->Generate();
+ if (ret) {
+ cmSystemTools::Message("CMake Generate step failed. "
+ "Build files cannot be regenerated correctly.");
+ return ret;
+ }
std::string message = "Build files have been written to: ";
message += this->GetHomeOutputDirectory();
this->UpdateProgress(message, -1);