From 1a45266cb544d73a7d7e46d6129ead1faf71fa85 Mon Sep 17 00:00:00 2001
From: Robert Maynard <robert.maynard@kitware.com>
Date: Tue, 30 Oct 2018 16:13:33 -0400
Subject: cmGlobalGenerator: Add a class that represent the build command

This refactors a std::vector<std::string> into a class so that
we can extend the features to represent things such as multiple
chained commands in the future.
---
 Source/cmGlobalBorlandMakefileGenerator.cxx |  2 +-
 Source/cmGlobalBorlandMakefileGenerator.h   |  2 +-
 Source/cmGlobalGenerator.cxx                | 31 ++++++++---------
 Source/cmGlobalGenerator.h                  | 54 ++++++++++++++++++++++++++++-
 Source/cmGlobalGhsMultiGenerator.cxx        | 21 +++++------
 Source/cmGlobalGhsMultiGenerator.h          |  2 +-
 Source/cmGlobalJOMMakefileGenerator.cxx     |  2 +-
 Source/cmGlobalJOMMakefileGenerator.h       |  2 +-
 Source/cmGlobalNMakeMakefileGenerator.cxx   |  2 +-
 Source/cmGlobalNMakeMakefileGenerator.h     |  2 +-
 Source/cmGlobalNinjaGenerator.cxx           | 17 ++++-----
 Source/cmGlobalNinjaGenerator.h             |  2 +-
 Source/cmGlobalUnixMakefileGenerator3.cxx   | 13 ++++---
 Source/cmGlobalUnixMakefileGenerator3.h     |  2 +-
 Source/cmGlobalVisualStudio10Generator.cxx  | 31 +++++++++--------
 Source/cmGlobalVisualStudio10Generator.h    |  2 +-
 Source/cmGlobalVisualStudio7Generator.cxx   | 34 +++++++-----------
 Source/cmGlobalVisualStudio7Generator.h     |  2 +-
 Source/cmGlobalWatcomWMakeGenerator.cxx     |  2 +-
 Source/cmGlobalWatcomWMakeGenerator.h       |  2 +-
 Source/cmGlobalXCodeGenerator.cxx           | 32 ++++++-----------
 Source/cmGlobalXCodeGenerator.h             |  2 +-
 22 files changed, 143 insertions(+), 118 deletions(-)

diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 56714b1..c2eb583 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -54,7 +54,7 @@ void cmGlobalBorlandMakefileGenerator::GetDocumentation(
 }
 
 void cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& projectDir,
   const std::string& targetName, const std::string& config, bool fast,
   int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index 27de6cc..ca04b7b 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -46,7 +46,7 @@ public:
   bool AllowDeleteOnError() const override { return false; }
 
 protected:
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index b2b0e38..239b326 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1751,14 +1751,13 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
 }
 
 void cmGlobalGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& /*unused*/,
+  GeneratedMakeCommand& makeCommand, const std::string& /*unused*/,
   const std::string& /*unused*/, const std::string& /*unused*/,
   const std::string& /*unused*/, const std::string& /*unused*/,
   bool /*unused*/, int /*unused*/, bool /*unused*/,
   std::vector<std::string> const& /*unused*/)
 {
-  makeCommand.emplace_back(
-    "cmGlobalGenerator::GenerateBuildCommand not implemented");
+  makeCommand.add("cmGlobalGenerator::GenerateBuildCommand not implemented");
 }
 
 void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
@@ -1802,31 +1801,29 @@ int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
   std::string outputBuffer;
   std::string* outputPtr = &outputBuffer;
 
-  std::vector<std::string> makeCommand;
+  GeneratedMakeCommand makeCommand;
   this->GenerateBuildCommand(makeCommand, makeCommandCSTR, projectName, bindir,
                              target, config, fast, jobs, verbose,
                              nativeOptions);
 
-  // Workaround to convince VCExpress.exe to produce output.
+  // Workaround to convince some commands to produce output.
   if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
-      !makeCommand.empty() &&
-      cmSystemTools::LowerCase(
-        cmSystemTools::GetFilenameName(makeCommand[0])) == "vcexpress.exe") {
+      makeCommand.RequiresOutputForward) {
     outputflag = cmSystemTools::OUTPUT_FORWARD;
   }
 
   // should we do a clean first?
   if (clean) {
-    std::vector<std::string> cleanCommand;
+    GeneratedMakeCommand cleanCommand;
     this->GenerateBuildCommand(cleanCommand, makeCommandCSTR, projectName,
                                bindir, "clean", config, fast, jobs, verbose);
     output += "\nRun Clean Command:";
-    output += cmSystemTools::PrintSingleCommand(cleanCommand);
+    output += cleanCommand.printable();
     output += "\n";
 
-    if (!cmSystemTools::RunSingleCommand(cleanCommand, outputPtr, outputPtr,
-                                         &retVal, nullptr, outputflag,
-                                         timeout)) {
+    if (!cmSystemTools::RunSingleCommand(cleanCommand.PrimaryCommand,
+                                         outputPtr, outputPtr, &retVal,
+                                         nullptr, outputflag, timeout)) {
       cmSystemTools::SetRunCommandHideConsole(hideconsole);
       cmSystemTools::Error("Generator: execution of make clean failed.");
       output += *outputPtr;
@@ -1838,13 +1835,13 @@ int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
   }
 
   // now build
-  std::string makeCommandStr = cmSystemTools::PrintSingleCommand(makeCommand);
-  output += "\nRun Build Command:";
+  std::string makeCommandStr = makeCommand.printable();
+  output += "\nRun Build Command(s):";
   output += makeCommandStr;
   output += "\n";
 
-  if (!cmSystemTools::RunSingleCommand(makeCommand, outputPtr, outputPtr,
-                                       &retVal, nullptr, outputflag,
+  if (!cmSystemTools::RunSingleCommand(makeCommand.PrimaryCommand, outputPtr,
+                                       outputPtr, &retVal, nullptr, outputflag,
                                        timeout)) {
     cmSystemTools::SetRunCommandHideConsole(hideconsole);
     cmSystemTools::Error(
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 36d3d10..ca5708b 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -41,6 +41,54 @@ class cmSourceFile;
 class cmStateDirectory;
 class cmake;
 
+namespace detail {
+inline void AppendStrs(std::vector<std::string>&)
+{
+}
+template <typename T, typename... Ts>
+inline void AppendStrs(std::vector<std::string>& command, T&& s, Ts&&... ts)
+{
+  command.emplace_back(std::forward<T>(s));
+  AppendStrs(command, std::forward<Ts>(ts)...);
+}
+
+struct GeneratedMakeCommand
+{
+  // Add each argument as a separate element to the vector
+  template <typename... T>
+  void add(T&&... args)
+  {
+    // iterate the args and append each one
+    AppendStrs(PrimaryCommand, std::forward<T>(args)...);
+  }
+
+  // Add each value in the iterators as a separate element to the vector
+  void add(std::vector<std::string>::const_iterator start,
+           std::vector<std::string>::const_iterator end)
+  {
+    PrimaryCommand.insert(PrimaryCommand.end(), start, end);
+  }
+
+  std::string printable() const
+  {
+    std::size_t size = PrimaryCommand.size();
+    for (auto&& i : PrimaryCommand) {
+      size += i.size();
+    }
+    std::string buffer;
+    buffer.reserve(size);
+    for (auto&& i : PrimaryCommand) {
+      buffer.append(i);
+      buffer.append(1, ' ');
+    }
+    return buffer;
+  }
+
+  std::vector<std::string> PrimaryCommand;
+  bool RequiresOutputForward = false;
+};
+}
+
 /** \class cmGlobalGenerator
  * \brief Responsible for overseeing the generation process for the entire tree
  *
@@ -182,8 +230,12 @@ public:
   virtual bool Open(const std::string& bindir, const std::string& projectName,
                     bool dryRun);
 
+  struct GeneratedMakeCommand final : public detail::GeneratedMakeCommand
+  {
+  };
+
   virtual void GenerateBuildCommand(
-    std::vector<std::string>& makeCommand, const std::string& makeProgram,
+    GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
     const std::string& projectName, const std::string& projectDir,
     const std::string& targetName, const std::string& config, bool fast,
     int jobs, bool verbose,
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 557efec..2a1506f 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -370,25 +370,23 @@ void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
 }
 
 void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& projectDir,
   const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
   int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
 {
   const char* gbuild =
     this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM");
-  makeCommand.push_back(
-    this->SelectMakeProgram(makeProgram, (std::string)gbuild));
+  makeCommand.add(this->SelectMakeProgram(makeProgram, (std::string)gbuild));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.push_back("-parallel");
+    makeCommand.add("-parallel");
     if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.push_back(std::to_string(jobs));
+      makeCommand.add(std::to_string(jobs));
     }
   }
 
-  makeCommand.insert(makeCommand.end(), makeOptions.begin(),
-                     makeOptions.end());
+  makeCommand.add(makeOptions.begin(), makeOptions.end());
 
   /* determine which top-project file to use */
   std::string proj = projectName + ".top" + FILE_EXTENSION;
@@ -401,16 +399,15 @@ void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
     }
   }
 
-  makeCommand.push_back("-top");
-  makeCommand.push_back(proj);
+  makeCommand.add("-top", proj);
   if (!targetName.empty()) {
     if (targetName == "clean") {
-      makeCommand.push_back("-clean");
+      makeCommand.add("-clean");
     } else {
       if (targetName.compare(targetName.size() - 4, 4, ".gpj") == 0) {
-        makeCommand.push_back(targetName);
+        makeCommand.add(targetName);
       } else {
-        makeCommand.push_back(targetName + ".gpj");
+        makeCommand.add(targetName + ".gpj");
       }
     }
   }
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index 9332567..bc2b199 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -88,7 +88,7 @@ public:
 
 protected:
   void Generate() override;
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index 9c805a8..2b7f486 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -55,7 +55,7 @@ void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(
 }
 
 void cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& projectDir,
   const std::string& targetName, const std::string& config, bool fast,
   int jobs, bool verbose, std::vector<std::string> const& makeOptions)
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index bcf46d0..aa8b5fb 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -40,7 +40,7 @@ public:
                       bool optional) override;
 
 protected:
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index 5235be7..ffe95f9 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -55,7 +55,7 @@ void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
 }
 
 void cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& projectDir,
   const std::string& targetName, const std::string& config, bool fast,
   int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index 62dea6e..06c48e2 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -45,7 +45,7 @@ public:
                       bool optional) override;
 
 protected:
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 23dbd76..abeecc7 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -673,31 +673,28 @@ void cmGlobalNinjaGenerator::EnableLanguage(
 // Called by:
 //   cmGlobalGenerator::Build()
 void cmGlobalNinjaGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& /*projectName*/, const std::string& /*projectDir*/,
   const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
   int jobs, bool verbose, std::vector<std::string> const& makeOptions)
 {
-  makeCommand.push_back(this->SelectMakeProgram(makeProgram));
+  makeCommand.add(this->SelectMakeProgram(makeProgram));
 
   if (verbose) {
-    makeCommand.emplace_back("-v");
+    makeCommand.add("-v");
   }
 
   if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
       (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
-    makeCommand.emplace_back("-j");
-    makeCommand.push_back(std::to_string(jobs));
+    makeCommand.add("-j", std::to_string(jobs));
   }
 
-  makeCommand.insert(makeCommand.end(), makeOptions.begin(),
-                     makeOptions.end());
+  makeCommand.add(makeOptions.begin(), makeOptions.end());
   if (!targetName.empty()) {
     if (targetName == "clean") {
-      makeCommand.emplace_back("-t");
-      makeCommand.emplace_back("clean");
+      makeCommand.add("-t", "clean");
     } else {
-      makeCommand.push_back(targetName);
+      makeCommand.add(targetName);
     }
   }
 }
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 00fa348..63b2f38 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -202,7 +202,7 @@ public:
   void EnableLanguage(std::vector<std::string> const& languages,
                       cmMakefile* mf, bool optional) override;
 
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 52bb046..9fc60e7 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -490,7 +490,7 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
 }
 
 void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& /*projectName*/, const std::string& /*projectDir*/,
   const std::string& targetName, const std::string& /*config*/, bool fast,
   int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
@@ -510,17 +510,16 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
     mf = mfu.get();
   }
 
-  makeCommand.push_back(this->SelectMakeProgram(makeProgram));
+  makeCommand.add(this->SelectMakeProgram(makeProgram));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.emplace_back("-j");
+    makeCommand.add("-j");
     if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.push_back(std::to_string(jobs));
+      makeCommand.add(std::to_string(jobs));
     }
   }
 
-  makeCommand.insert(makeCommand.end(), makeOptions.begin(),
-                     makeOptions.end());
+  makeCommand.add(makeOptions.begin(), makeOptions.end());
   if (!targetName.empty()) {
     std::string tname = targetName;
     if (fast) {
@@ -530,7 +529,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
     tname =
       conv.ConvertToRelativePath(mf->GetState()->GetBinaryDirectory(), tname);
     cmSystemTools::ConvertToOutputSlashes(tname);
-    makeCommand.push_back(std::move(tname));
+    makeCommand.add(std::move(tname));
   }
 }
 
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 6199586..9fd407f 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -127,7 +127,7 @@ public:
   std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
 
   // change the build command for speed
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index dbe582b..051ef18 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -864,7 +864,7 @@ bool cmGlobalVisualStudio10Generator::FindVCTargetsPath(cmMakefile* mf)
 }
 
 void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& projectDir,
   const std::string& targetName, const std::string& config, bool fast,
   int jobs, bool verbose, std::vector<std::string> const& makeOptions)
@@ -879,6 +879,10 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
   bool useDevEnv = (makeProgramLower.find("devenv") != std::string::npos ||
                     makeProgramLower.find("vcexpress") != std::string::npos);
 
+  // Workaround to convince VCExpress.exe to produce output.
+  makeCommand.RequiresOutputForward =
+    (makeProgramLower.find("vcexpress") != std::string::npos);
+
   // MSBuild is preferred (and required for VS Express), but if the .sln has
   // an Intel Fortran .vfproj then we have to use devenv. Parse it to find out.
   cmSlnData slnData;
@@ -912,7 +916,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
     return;
   }
 
-  makeCommand.push_back(makeProgramSelected);
+  makeCommand.add(makeProgramSelected);
 
   std::string realTarget = targetName;
   // msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug /target:ALL_BUILD
@@ -921,8 +925,8 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
     realTarget = "ALL_BUILD";
   }
   if (realTarget == "clean") {
-    makeCommand.push_back(std::string(projectName) + ".sln");
-    makeCommand.push_back("/t:Clean");
+    makeCommand.add(std::string(projectName) + ".sln");
+    makeCommand.add("/t:Clean");
   } else {
     std::string targetProject(realTarget);
     targetProject += ".vcxproj";
@@ -934,7 +938,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
         cmSystemTools::ConvertToUnixSlashes(targetProject);
       }
     }
-    makeCommand.push_back(targetProject);
+    makeCommand.add(std::move(targetProject));
   }
   std::string configArg = "/p:Configuration=";
   if (!config.empty()) {
@@ -942,23 +946,22 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
   } else {
     configArg += "Debug";
   }
-  makeCommand.push_back(configArg);
-  makeCommand.push_back("/p:Platform=" + this->GetPlatformName());
-  makeCommand.push_back(std::string("/p:VisualStudioVersion=") +
-                        this->GetIDEVersion());
+  makeCommand.add(configArg);
+  makeCommand.add(std::string("/p:Platform=") + this->GetPlatformName());
+  makeCommand.add(std::string("/p:VisualStudioVersion=") +
+                  this->GetIDEVersion());
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
     if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.push_back("/m");
+      makeCommand.add("/m");
     } else {
-      makeCommand.push_back(std::string("/m:") + std::to_string(jobs));
+      makeCommand.add(std::string("/m:") + std::to_string(jobs));
     }
     // Having msbuild.exe and cl.exe using multiple jobs is discouraged
-    makeCommand.push_back("/p:CL_MPCount=1");
+    makeCommand.add("/p:CL_MPCount=1");
   }
 
-  makeCommand.insert(makeCommand.end(), makeOptions.begin(),
-                     makeOptions.end());
+  makeCommand.add(makeOptions.begin(), makeOptions.end());
 }
 
 bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 7c8918a..0b11569 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -22,7 +22,7 @@ public:
   bool SetGeneratorPlatform(std::string const& p, cmMakefile* mf) override;
   bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) override;
 
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index cae46e1..997d33f 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -191,7 +191,7 @@ const char* cmGlobalVisualStudio7Generator::ExternalProjectType(
   return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942";
 }
 void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& /*projectDir*/,
   const std::string& targetName, const std::string& config, bool /*fast*/,
   int /*jobs*/, bool /*verbose*/, std::vector<std::string> const& makeOptions)
@@ -209,35 +209,25 @@ void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
     makeProgramSelected = this->GetDevEnvCommand();
   }
 
-  makeCommand.push_back(makeProgramSelected);
+  // Workaround to convince VCExpress.exe to produce output.
+  makeCommand.RequiresOutputForward =
+    (makeProgramLower.find("vcexpress") != std::string::npos);
 
-  makeCommand.push_back(std::string(projectName) + ".sln");
+  makeCommand.add(makeProgramSelected);
+
+  makeCommand.add(std::string(projectName) + ".sln");
   std::string realTarget = targetName;
   bool clean = false;
   if (realTarget == "clean") {
     clean = true;
     realTarget = "ALL_BUILD";
   }
-  if (clean) {
-    makeCommand.push_back("/clean");
-  } else {
-    makeCommand.push_back("/build");
-  }
-
-  if (!config.empty()) {
-    makeCommand.push_back(config);
-  } else {
-    makeCommand.push_back("Debug");
-  }
-  makeCommand.push_back("/project");
 
-  if (!realTarget.empty()) {
-    makeCommand.push_back(realTarget);
-  } else {
-    makeCommand.push_back("ALL_BUILD");
-  }
-  makeCommand.insert(makeCommand.end(), makeOptions.begin(),
-                     makeOptions.end());
+  makeCommand.add((clean ? "/clean" : "/build"));
+  makeCommand.add((config.empty() ? "Debug" : config));
+  makeCommand.add("/project");
+  makeCommand.add((realTarget.empty() ? "ALL_BUILD" : realTarget));
+  makeCommand.add(makeOptions.begin(), makeOptions.end());
 }
 
 ///! Create a local generator appropriate to this Global Generator
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index d2a2a38..3f1c173 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -52,7 +52,7 @@ public:
    * Try running cmake and building a file. This is used for dynamically
    * loaded commands, not as part of the usual build process.
    */
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
index 558ef15..c02c471 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.cxx
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -51,7 +51,7 @@ void cmGlobalWatcomWMakeGenerator::GetDocumentation(
 }
 
 void cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& projectDir,
   const std::string& targetName, const std::string& config, bool fast,
   int /*jobs*/, bool verbose, std::vector<std::string> const& makeOptions)
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index 0d10d58..6680b19 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -50,7 +50,7 @@ public:
   bool AllowDeleteOnError() const override { return false; }
 
 protected:
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 79d77e7..b8aa5a6 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -339,20 +339,20 @@ bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
 }
 
 void cmGlobalXCodeGenerator::GenerateBuildCommand(
-  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& /*projectDir*/,
   const std::string& targetName, const std::string& config, bool /*fast*/,
   int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
 {
   // now build the test
-  makeCommand.emplace_back(
+  makeCommand.add(
     this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
 
-  makeCommand.emplace_back("-project");
+  makeCommand.add("-project");
   std::string projectArg = projectName;
   projectArg += ".xcode";
   projectArg += "proj";
-  makeCommand.emplace_back(projectArg);
+  makeCommand.add(projectArg);
 
   bool clean = false;
   std::string realTarget = targetName;
@@ -360,29 +360,19 @@ void cmGlobalXCodeGenerator::GenerateBuildCommand(
     clean = true;
     realTarget = "ALL_BUILD";
   }
-  if (clean) {
-    makeCommand.emplace_back("clean");
-  } else {
-    makeCommand.emplace_back("build");
-  }
-  makeCommand.emplace_back("-target");
-  if (!realTarget.empty()) {
-    makeCommand.emplace_back(realTarget);
-  } else {
-    makeCommand.emplace_back("ALL_BUILD");
-  }
-  makeCommand.emplace_back("-configuration");
-  makeCommand.emplace_back(!config.empty() ? config : "Debug");
+
+  makeCommand.add((clean ? "clean" : "build"));
+  makeCommand.add("-target", (realTarget.empty() ? "ALL_BUILD" : realTarget));
+  makeCommand.add("-configuration", (config.empty() ? "Debug" : config));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.emplace_back("-jobs");
+    makeCommand.add("-jobs");
     if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.emplace_back(std::to_string(jobs));
+      makeCommand.add(std::to_string(jobs));
     }
   }
 
-  makeCommand.insert(makeCommand.end(), makeOptions.begin(),
-                     makeOptions.end());
+  makeCommand.add(makeOptions.begin(), makeOptions.end());
 }
 
 ///! Create a local generator appropriate to this Global Generator
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 9b0d4fe..92ff258 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -66,7 +66,7 @@ public:
    * Try running cmake and building a file. This is used for dynalically
    * loaded commands, not as part of the usual build process.
    */
-  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+  void GenerateBuildCommand(GeneratedMakeCommand& makeCommand,
                             const std::string& makeProgram,
                             const std::string& projectName,
                             const std::string& projectDir,
-- 
cgit v0.12


From cb6c233eccfbb600ec16716224062627df2ff2c0 Mon Sep 17 00:00:00 2001
From: Florian Maushart <FloriansGit@online.ms>
Date: Sun, 10 Jun 2018 21:39:01 +0200
Subject: cmake: Add -hideShellScriptEnvironment xcodebuild option

For CMake's build tool mode add -hideShellScriptEnvironment if version
is XCode 7.0 or above
---
 Source/cmGlobalXCodeGenerator.cxx | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index b8aa5a6..e9b82cf 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -372,6 +372,9 @@ void cmGlobalXCodeGenerator::GenerateBuildCommand(
     }
   }
 
+  if (this->XcodeVersion >= 70) {
+    makeCommand.add("-hideShellScriptEnvironment");
+  }
   makeCommand.add(makeOptions.begin(), makeOptions.end());
 }
 
-- 
cgit v0.12


From 3ca44029668c057fb208c5f153c4d398bee954cb Mon Sep 17 00:00:00 2001
From: Florian Maushart <FloriansGit@online.ms>
Date: Tue, 26 Jun 2018 21:24:19 +0200
Subject: ctest: Fix --build-and-test without --build-target on Xcode

---
 Source/cmGlobalXCodeGenerator.cxx | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index e9b82cf..97d8bdb 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -348,11 +348,13 @@ void cmGlobalXCodeGenerator::GenerateBuildCommand(
   makeCommand.add(
     this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
 
-  makeCommand.add("-project");
-  std::string projectArg = projectName;
-  projectArg += ".xcode";
-  projectArg += "proj";
-  makeCommand.add(projectArg);
+  if (!projectName.empty()) {
+    makeCommand.add("-project");
+    std::string projectArg = projectName;
+    projectArg += ".xcode";
+    projectArg += "proj";
+    makeCommand.add(projectArg);
+  }
 
   bool clean = false;
   std::string realTarget = targetName;
-- 
cgit v0.12


From 638667efa2b0e5fff5c63bf936748a60b602ae90 Mon Sep 17 00:00:00 2001
From: Florian Maushart <FloriansGit@online.ms>
Date: Sun, 15 Jul 2018 08:44:23 +0200
Subject: cmake: cmcmd.cxx fix "The arguments are" comments

Changed "argv" to "args" in comments to match parameter names
---
 Source/cmcmd.cxx | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 26f7509..5ae0ea4 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1351,8 +1351,8 @@ static void cmcmdProgressReport(std::string const& dir, std::string const& num)
 int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
 {
   // The arguments are
-  //   argv[0] == <cmake-executable>
-  //   argv[1] == cmake_echo_color
+  //   args[0] == <cmake-executable>
+  //   args[1] == cmake_echo_color
 
   bool enabled = true;
   int color = cmsysTerminal_Color_Normal;
@@ -1409,10 +1409,10 @@ int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
 int cmcmd::ExecuteLinkScript(std::vector<std::string>& args)
 {
   // The arguments are
-  //   argv[0] == <cmake-executable>
-  //   argv[1] == cmake_link_script
-  //   argv[2] == <link-script-name>
-  //   argv[3] == --verbose=?
+  //   args[0] == <cmake-executable>
+  //   args[1] == cmake_link_script
+  //   args[2] == <link-script-name>
+  //   args[3] == --verbose=?
   bool verbose = false;
   if (args.size() >= 4) {
     if (args[3].find("--verbose=") == 0) {
-- 
cgit v0.12


From 439fe2e253410305ff7018416ff5ff26aa851d53 Mon Sep 17 00:00:00 2001
From: Florian Maushart <FloriansGit@online.ms>
Date: Thu, 24 Jan 2019 13:31:18 -0500
Subject: cmake: Add options for verbose output to --build mode

While we already support `VERBOSE` environment variable and
`CMAKE_VERBOSE_MAKEFILE` cached variable, add `-v` and `--verbose`
command line options to be able to activate verbose output directly from
CMake's build tool mode command line.

Also make `msbuild` honor the verbosity setting. `xcodebuild` still
doesn't honor the verbosity setting as it will need a policy added
and reworking of cmGlobalGenerator and cmsys to support
multiple command invocation.
---
 Help/envvar/CMAKE_NO_VERBOSE.rst           |  8 ++++++++
 Help/envvar/VERBOSE.rst                    | 10 ++++++++++
 Help/manual/cmake-env-variables.7.rst      |  2 ++
 Help/manual/cmake.1.rst                    |  8 ++++++++
 Help/release/dev/cmake-build-verbose.rst   |  6 ++++++
 Source/cmGlobalUnixMakefileGenerator3.cxx  |  9 ++++++++-
 Source/cmGlobalVisualStudio10Generator.cxx |  4 ++++
 Source/cmake.cxx                           |  9 +++++----
 Source/cmake.h                             |  3 ++-
 Source/cmakemain.cxx                       |  9 ++++++++-
 10 files changed, 61 insertions(+), 7 deletions(-)
 create mode 100644 Help/envvar/CMAKE_NO_VERBOSE.rst
 create mode 100644 Help/envvar/VERBOSE.rst
 create mode 100644 Help/release/dev/cmake-build-verbose.rst

diff --git a/Help/envvar/CMAKE_NO_VERBOSE.rst b/Help/envvar/CMAKE_NO_VERBOSE.rst
new file mode 100644
index 0000000..149efbd
--- /dev/null
+++ b/Help/envvar/CMAKE_NO_VERBOSE.rst
@@ -0,0 +1,8 @@
+CMAKE_NO_VERBOSE
+----------------
+
+Disables verbose output from CMake when :envvar:`VERBOSE` environment variable
+is set.
+
+Only your build tool of choice will still print verbose output when you start
+to actually build your project.
diff --git a/Help/envvar/VERBOSE.rst b/Help/envvar/VERBOSE.rst
new file mode 100644
index 0000000..2d775a5
--- /dev/null
+++ b/Help/envvar/VERBOSE.rst
@@ -0,0 +1,10 @@
+VERBOSE
+-------
+
+Activates verbose output from CMake and your build tools of choice when
+you start to actually build your project.
+
+Note that any given value is ignored. It's just checked for existence.
+
+See also :ref:`Build Tool Mode <Build Tool Mode>` and
+:envvar:`CMAKE_NO_VERBOSE` environment variable
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index edf80f4..c433412 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -24,11 +24,13 @@ Environment Variables that Control the Build
    /envvar/CMAKE_BUILD_PARALLEL_LEVEL
    /envvar/CMAKE_CONFIG_TYPE
    /envvar/CMAKE_MSVCIDE_RUN_PATH
+   /envvar/CMAKE_NO_VERBOSE
    /envvar/CMAKE_OSX_ARCHITECTURES
    /envvar/DESTDIR
    /envvar/LDFLAGS
    /envvar/MACOSX_DEPLOYMENT_TARGET
    /envvar/PackageName_ROOT
+   /envvar/VERBOSE
 
 Environment Variables for Languages
 ===================================
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 915e0d4..77178b8 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -289,6 +289,14 @@ following options:
 ``--use-stderr``
   Ignored.  Behavior is default in CMake >= 3.0.
 
+``-v, --verbose``
+  Enable verbose output - if supported - including the build commands to be
+  executed.
+
+  This option can be omitted if :envvar:`VERBOSE` environment variable or
+  :variable:`CMAKE_VERBOSE_MAKEFILE` cached variable is set.
+
+
 ``--``
   Pass remaining options to the native tool.
 
diff --git a/Help/release/dev/cmake-build-verbose.rst b/Help/release/dev/cmake-build-verbose.rst
new file mode 100644
index 0000000..dee212e
--- /dev/null
+++ b/Help/release/dev/cmake-build-verbose.rst
@@ -0,0 +1,6 @@
+cmake-build-verbose
+-------------------
+
+* The :manual:`cmake(1)` :ref:`Build Tool Mode` (``cmake --build``) gained
+  ``--verbose`` and ``-v`` options to specify verbose build output. Some
+  generators such as Xcode don't support this option currently.
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 9fc60e7..6989b51 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -493,7 +493,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   GeneratedMakeCommand& makeCommand, const std::string& makeProgram,
   const std::string& /*projectName*/, const std::string& /*projectDir*/,
   const std::string& targetName, const std::string& /*config*/, bool fast,
-  int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
+  int jobs, bool verbose, std::vector<std::string> const& makeOptions)
 {
   std::unique_ptr<cmMakefile> mfu;
   cmMakefile* mf;
@@ -510,6 +510,13 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
     mf = mfu.get();
   }
 
+  // Make it possible to set verbosity also from command line
+  if (verbose) {
+    makeCommand.add(cmSystemTools::GetCMakeCommand());
+    makeCommand.add("-E");
+    makeCommand.add("env");
+    makeCommand.add("VERBOSE=1");
+  }
   makeCommand.add(this->SelectMakeProgram(makeProgram));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 051ef18..60b2258 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -961,6 +961,10 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
     makeCommand.add("/p:CL_MPCount=1");
   }
 
+  // Respect the verbosity: 'n' normal will show build commands
+  //                        'm' minimal only the build step's title
+  makeCommand.add(std::string("/v:") + ((verbose) ? "n" : "m"));
+
   makeCommand.add(makeOptions.begin(), makeOptions.end());
 }
 
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 914c3b0..411ba3a 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -2539,7 +2539,8 @@ cmMessenger* cmake::GetMessenger() const
 
 int cmake::Build(int jobs, const std::string& dir, const std::string& target,
                  const std::string& config,
-                 const std::vector<std::string>& nativeOptions, bool clean)
+                 const std::vector<std::string>& nativeOptions, bool clean,
+                 bool verbose)
 {
 
   this->SetHomeDirectory("");
@@ -2592,11 +2593,11 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
     return 1;
   }
   projName = cachedProjectName;
-  bool verbose = false;
+
   const char* cachedVerbose =
     this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE");
-  if (cachedVerbose) {
-    verbose = cmSystemTools::IsOn(cachedVerbose);
+  if (cmSystemTools::IsOn(cachedVerbose)) {
+    verbose = true;
   }
 
 #ifdef CMAKE_HAVE_VS_GENERATORS
diff --git a/Source/cmake.h b/Source/cmake.h
index 9478ad0e..7ec1b64 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -430,7 +430,8 @@ public:
   ///! run the --build option
   int Build(int jobs, const std::string& dir, const std::string& target,
             const std::string& config,
-            const std::vector<std::string>& nativeOptions, bool clean);
+            const std::vector<std::string>& nativeOptions, bool clean,
+            bool verbose);
 
   ///! run the --open option
   bool Open(const std::string& dir, bool dryRun);
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 0c25498..0ec2552 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -68,6 +68,8 @@ static const char* cmDocumentationUsageNote[][2] = {
     "  --clean-first  = Build target 'clean' first, then build.\n"            \
     "                   (To clean only, use --target 'clean'.)\n"             \
     "  --use-stderr   = Ignored.  Behavior is default in CMake >= 3.0.\n"     \
+    "  -v --verbose   = Enable verbose output - if supported - including\n"   \
+    "                   the build commands to be executed. \n"                \
     "  --             = Pass remaining options to the native tool.\n"
 
 static const char* cmDocumentationOptions[][2] = {
@@ -395,6 +397,7 @@ static int do_build(int ac, char const* const* av)
   std::string dir;
   std::vector<std::string> nativeOptions;
   bool clean = false;
+  bool verbose = cmSystemTools::HasEnv("VERBOSE");
   bool hasTarget = false;
 
   enum Doing
@@ -435,6 +438,10 @@ static int do_build(int ac, char const* const* av)
     } else if (strcmp(av[i], "--clean-first") == 0) {
       clean = true;
       doing = DoingNone;
+    } else if ((strcmp(av[i], "--verbose") == 0) ||
+               (strcmp(av[i], "-v") == 0)) {
+      verbose = true;
+      doing = DoingNone;
     } else if (strcmp(av[i], "--use-stderr") == 0) {
       /* tolerate legacy option */
     } else if (strcmp(av[i], "--") == 0) {
@@ -493,7 +500,7 @@ static int do_build(int ac, char const* const* av)
   cmake cm(cmake::RoleInternal, cmState::Unknown);
   cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm);
   cm.SetProgressCallback(cmakemainProgressCallback, &cm);
-  return cm.Build(jobs, dir, target, config, nativeOptions, clean);
+  return cm.Build(jobs, dir, target, config, nativeOptions, clean, verbose);
 #endif
 }
 
-- 
cgit v0.12


From 66801f4d40227c46904ad54848bd1da959604cbf Mon Sep 17 00:00:00 2001
From: Robert Maynard <robert.maynard@kitware.com>
Date: Thu, 24 Jan 2019 13:31:32 -0500
Subject: cmake: Add tests for verbose output to --build mode

---
 Tests/RunCMake/CMakeLists.txt                           |  2 +-
 Tests/RunCMake/Make/RunCMakeTest.cmake                  | 17 +++++++++++++++++
 Tests/RunCMake/Make/VerboseBuild-build-stdout.txt       |  1 +
 .../RunCMake/Make/VerboseBuild-build-watcom-stdout.txt  |  1 +
 Tests/RunCMake/Make/VerboseBuild-nowork-gnu-stdout.txt  |  1 +
 Tests/RunCMake/Make/VerboseBuild.cmake                  |  8 ++++++++
 Tests/RunCMake/Make/hello.c                             |  7 +++++++
 Tests/RunCMake/Ninja/RunCMakeTest.cmake                 |  9 +++++++++
 Tests/RunCMake/Ninja/VerboseBuild-build-stdout.txt      |  1 +
 Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt     |  1 +
 Tests/RunCMake/Ninja/VerboseBuild.cmake                 |  3 +++
 11 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 Tests/RunCMake/Make/VerboseBuild-build-stdout.txt
 create mode 100644 Tests/RunCMake/Make/VerboseBuild-build-watcom-stdout.txt
 create mode 100644 Tests/RunCMake/Make/VerboseBuild-nowork-gnu-stdout.txt
 create mode 100644 Tests/RunCMake/Make/VerboseBuild.cmake
 create mode 100644 Tests/RunCMake/Make/hello.c
 create mode 100644 Tests/RunCMake/Ninja/VerboseBuild-build-stdout.txt
 create mode 100644 Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt
 create mode 100644 Tests/RunCMake/Ninja/VerboseBuild.cmake

diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index bf18efe..76dd997 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -123,7 +123,7 @@ if(NOT CMAKE_GENERATOR MATCHES "Visual Studio|Xcode")
   add_RunCMake_test(CMP0065)
 endif()
 if(CMAKE_GENERATOR MATCHES "Make")
-  add_RunCMake_test(Make)
+  add_RunCMake_test(Make -DMAKE_IS_GNU=${MAKE_IS_GNU})
 endif()
 if(CMAKE_GENERATOR STREQUAL "Ninja")
   set(Ninja_ARGS
diff --git a/Tests/RunCMake/Make/RunCMakeTest.cmake b/Tests/RunCMake/Make/RunCMakeTest.cmake
index 3b2b8f5..82db6b7 100644
--- a/Tests/RunCMake/Make/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Make/RunCMakeTest.cmake
@@ -16,5 +16,22 @@ run_TargetMessages(OFF)
 run_TargetMessages(VAR-ON -DCMAKE_TARGET_MESSAGES=ON)
 run_TargetMessages(VAR-OFF -DCMAKE_TARGET_MESSAGES=OFF)
 
+function(run_VerboseBuild)
+  run_cmake(VerboseBuild)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VerboseBuild-build)
+  if(RunCMake_GENERATOR STREQUAL "Watcom WMake")
+    # wmake does not actually show the verbose output.
+    set(RunCMake-stdout-file VerboseBuild-build-watcom-stdout.txt)
+  endif()
+  run_cmake_command(VerboseBuild-build ${CMAKE_COMMAND} --build . -v --clean-first)
+  unset(RunCMake-stdout-file)
+  if(MAKE_IS_GNU)
+    set(RunCMake-stdout-file VerboseBuild-nowork-gnu-stdout.txt)
+  endif()
+  run_cmake_command(VerboseBuild-nowork ${CMAKE_COMMAND} --build . --verbose)
+endfunction()
+run_VerboseBuild()
+
 run_cmake(CustomCommandDepfile-ERROR)
 run_cmake(IncludeRegexSubdir)
diff --git a/Tests/RunCMake/Make/VerboseBuild-build-stdout.txt b/Tests/RunCMake/Make/VerboseBuild-build-stdout.txt
new file mode 100644
index 0000000..884bf95
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuild-build-stdout.txt
@@ -0,0 +1 @@
+.*DEFINE_FOR_VERBOSE_DETECTION.*hello.dir.*
diff --git a/Tests/RunCMake/Make/VerboseBuild-build-watcom-stdout.txt b/Tests/RunCMake/Make/VerboseBuild-build-watcom-stdout.txt
new file mode 100644
index 0000000..9c558e3
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuild-build-watcom-stdout.txt
@@ -0,0 +1 @@
+.
diff --git a/Tests/RunCMake/Make/VerboseBuild-nowork-gnu-stdout.txt b/Tests/RunCMake/Make/VerboseBuild-nowork-gnu-stdout.txt
new file mode 100644
index 0000000..3e65cd9
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuild-nowork-gnu-stdout.txt
@@ -0,0 +1 @@
+.*Nothing to be done for.*hello.*
diff --git a/Tests/RunCMake/Make/VerboseBuild.cmake b/Tests/RunCMake/Make/VerboseBuild.cmake
new file mode 100644
index 0000000..70a971d
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuild.cmake
@@ -0,0 +1,8 @@
+enable_language(C)
+
+# Make sure compile command is not hidden in a temp file.
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}")
+
+add_executable(hello hello.c)
+target_compile_definitions(hello PRIVATE "DEFINE_FOR_VERBOSE_DETECTION")
diff --git a/Tests/RunCMake/Make/hello.c b/Tests/RunCMake/Make/hello.c
new file mode 100644
index 0000000..aac8b4e
--- /dev/null
+++ b/Tests/RunCMake/Make/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+  printf("Hello world!\n");
+  return 0;
+}
diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
index 9e1e9a5..8fa650a 100644
--- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
@@ -30,6 +30,15 @@ function(run_NoWorkToDo)
 endfunction()
 run_NoWorkToDo()
 
+function(run_VerboseBuild)
+  run_cmake(VerboseBuild)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VerboseBuild-build)
+  run_cmake_command(VerboseBuild-build ${CMAKE_COMMAND} --build . -v --clean-first)
+  run_cmake_command(VerboseBuild-nowork ${CMAKE_COMMAND} --build . --verbose)
+endfunction()
+run_VerboseBuild()
+
 function(run_CMP0058 case)
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0058-${case}-build)
diff --git a/Tests/RunCMake/Ninja/VerboseBuild-build-stdout.txt b/Tests/RunCMake/Ninja/VerboseBuild-build-stdout.txt
new file mode 100644
index 0000000..884bf95
--- /dev/null
+++ b/Tests/RunCMake/Ninja/VerboseBuild-build-stdout.txt
@@ -0,0 +1 @@
+.*DEFINE_FOR_VERBOSE_DETECTION.*hello.dir.*
diff --git a/Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt b/Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt
new file mode 100644
index 0000000..60a9228
--- /dev/null
+++ b/Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt
@@ -0,0 +1 @@
+^ninja: no work to do
diff --git a/Tests/RunCMake/Ninja/VerboseBuild.cmake b/Tests/RunCMake/Ninja/VerboseBuild.cmake
new file mode 100644
index 0000000..424e54e
--- /dev/null
+++ b/Tests/RunCMake/Ninja/VerboseBuild.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+add_executable(hello hello.c)
+target_compile_definitions(hello PRIVATE "DEFINE_FOR_VERBOSE_DETECTION")
-- 
cgit v0.12