From 81d45dabc4534f15b8c61935060cd4d10f258f15 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 16 May 2023 11:27:06 -0400 Subject: cmOutputConverter: add a `static` version of `EscapeForShell` --- Source/cmOutputConverter.cxx | 15 ++++++++++----- Source/cmOutputConverter.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 53cb21e..02981ae 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -243,11 +243,6 @@ std::string cmOutputConverter::EscapeForShell(cm::string_view str, bool unescapeNinjaConfiguration, bool forResponse) const { - // Do not escape shell operators. - if (cmOutputConverterIsShellOperator(str)) { - return std::string(str); - } - // Compute the flags for the target shell environment. int flags = 0; if (this->GetState()->UseWindowsVSIDE()) { @@ -283,6 +278,16 @@ std::string cmOutputConverter::EscapeForShell(cm::string_view str, flags |= Shell_Flag_IsUnix; } + return cmOutputConverter::EscapeForShell(str, flags); +} + +std::string cmOutputConverter::EscapeForShell(cm::string_view str, int flags) +{ + // Do not escape shell operators. + if (cmOutputConverterIsShellOperator(str)) { + return std::string(str); + } + return Shell_GetArgument(str, flags); } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 625d897..0ee7afb 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -107,6 +107,7 @@ public: bool forEcho = false, bool useWatcomQuote = false, bool unescapeNinjaConfiguration = false, bool forResponse = false) const; + static std::string EscapeForShell(cm::string_view str, int flags); enum class WrapQuotes { -- cgit v0.12 From 465ab8d872aeabfffab0c1dd0510bad1bb49fa92 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 16 May 2023 10:50:03 -0400 Subject: cmGlobalGenerator: use `cmStrCat` in `::Build` Also replace some single-char strings with character literals. --- Source/cmGlobalGenerator.cxx | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 040f500..f8f9442 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2096,16 +2096,13 @@ int cmGlobalGenerator::Build( * Run an executable command and put the stdout in output. */ cmWorkingDirectory workdir(bindir); - output += "Change Dir: "; - output += bindir; - output += "\n"; + output += cmStrCat("Change Dir: ", bindir, '\n'); if (workdir.Failed()) { cmSystemTools::SetRunCommandHideConsole(hideconsole); std::string err = cmStrCat("Failed to change directory: ", std::strerror(workdir.GetLastResult())); cmSystemTools::Error(err); - output += err; - output += "\n"; + output += cmStrCat(err, '\n'); return 1; } std::string realConfig = config; @@ -2134,9 +2131,8 @@ int cmGlobalGenerator::Build( this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, { "clean" }, realConfig, jobs, verbose, buildOptions); - output += "\nRun Clean Command:"; - output += cleanCommand.front().Printable(); - output += "\n"; + output += + cmStrCat("\nRun Clean Command:", cleanCommand.front().Printable(), '\n'); if (cleanCommand.size() != 1) { this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR, "The generator did not produce " @@ -2149,8 +2145,8 @@ int cmGlobalGenerator::Build( nullptr, outputflag, timeout)) { cmSystemTools::SetRunCommandHideConsole(hideconsole); cmSystemTools::Error("Generator: execution of make clean failed."); - output += *outputPtr; - output += "\nGenerator: execution of make clean failed.\n"; + output += + cmStrCat(*outputPtr, "\nGenerator: execution of make clean failed.\n"); return 1; } @@ -2177,9 +2173,10 @@ int cmGlobalGenerator::Build( cmSystemTools::Error( "Generator: execution of make failed. Make command was: " + makeCommandStr); - output += *outputPtr; - output += "\nGenerator: execution of make failed. Make command was: " + - makeCommandStr + "\n"; + output += + cmStrCat(*outputPtr, + "\nGenerator: execution of make failed. Make command was: ", + makeCommandStr, '\n'); return 1; } -- cgit v0.12 From 28ee3bef3467bb05f9ca4fa74c51e566177ad1c9 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 16 May 2023 12:44:29 -0400 Subject: cmGlobalGenerator: add missing spaces in output The preludes to commands should have a space to separate them from the first argument of the command sequence. --- Source/cmGlobalGenerator.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index f8f9442..3e4d657 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2131,8 +2131,8 @@ int cmGlobalGenerator::Build( this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, { "clean" }, realConfig, jobs, verbose, buildOptions); - output += - cmStrCat("\nRun Clean Command:", cleanCommand.front().Printable(), '\n'); + output += cmStrCat( + "\nRun Clean Command: ", cleanCommand.front().Printable(), '\n'); if (cleanCommand.size() != 1) { this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR, "The generator did not produce " @@ -2155,7 +2155,7 @@ int cmGlobalGenerator::Build( // now build std::string makeCommandStr; - output += "\nRun Build Command(s):"; + output += "\nRun Build Command(s): "; retVal = 0; for (auto command = makeCommand.begin(); -- cgit v0.12 From d6c0e827bc0f49ee6aa6deb5c0ee3838475fe3fe Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 16 May 2023 11:31:26 -0400 Subject: cmGlobalGenerator: add a `QuotedPrintable` method for commands --- Source/cmGlobalGenerator.cxx | 18 ++++++++++++++++++ Source/cmGlobalGenerator.h | 1 + 2 files changed, 19 insertions(+) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 3e4d657..0e672e6 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -47,6 +47,7 @@ #include "cmMSVC60LinkLineComputer.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmRange.h" #include "cmSourceFile.h" @@ -73,6 +74,23 @@ const std::string kCMAKE_PLATFORM_INFO_INITIALIZED = class cmInstalledFile; +namespace detail { +std::string GeneratedMakeCommand::QuotedPrintable() const +{ + std::string output; + const char* sep = ""; + int flags = 0; +#if !defined(_WIN32) + flags |= cmOutputConverter::Shell_Flag_IsUnix; +#endif + for (auto const& arg : this->PrimaryCommand) { + output += cmStrCat(sep, cmOutputConverter::EscapeForShell(arg, flags)); + sep = " "; + } + return output; +} +} + bool cmTarget::StrictTargetComparison::operator()(cmTarget const* t1, cmTarget const* t2) const { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 79fe52c..f24465a 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -85,6 +85,7 @@ struct GeneratedMakeCommand } std::string Printable() const { return cmJoin(this->PrimaryCommand, " "); } + std::string QuotedPrintable() const; std::vector PrimaryCommand; bool RequiresOutputForward = false; -- cgit v0.12 From c715fd8d767d44381a682ec7e85bd53f727fbd2b Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 16 May 2023 11:32:58 -0400 Subject: cmGlobalGenerator: quote commands in `::Build` output Now that these are going to be visible when running with `--verbose`, properly quote things so that they can be used as-is. --- Source/cmGlobalGenerator.cxx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 0e672e6..769a7db 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2114,7 +2114,7 @@ int cmGlobalGenerator::Build( * Run an executable command and put the stdout in output. */ cmWorkingDirectory workdir(bindir); - output += cmStrCat("Change Dir: ", bindir, '\n'); + output += cmStrCat("Change Dir: '", bindir, "'\n"); if (workdir.Failed()) { cmSystemTools::SetRunCommandHideConsole(hideconsole); std::string err = cmStrCat("Failed to change directory: ", @@ -2150,7 +2150,7 @@ int cmGlobalGenerator::Build( { "clean" }, realConfig, jobs, verbose, buildOptions); output += cmStrCat( - "\nRun Clean Command: ", cleanCommand.front().Printable(), '\n'); + "\nRun Clean Command: ", cleanCommand.front().QuotedPrintable(), '\n'); if (cleanCommand.size() != 1) { this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR, "The generator did not produce " @@ -2173,17 +2173,20 @@ int cmGlobalGenerator::Build( // now build std::string makeCommandStr; + std::string outputMakeCommandStr; output += "\nRun Build Command(s): "; retVal = 0; for (auto command = makeCommand.begin(); command != makeCommand.end() && retVal == 0; ++command) { makeCommandStr = command->Printable(); + outputMakeCommandStr = command->QuotedPrintable(); if (command != makeCommand.end()) { makeCommandStr += " && "; + outputMakeCommandStr += " && "; } - output += makeCommandStr; + output += outputMakeCommandStr; if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr, outputPtr, &retVal, nullptr, outputflag, timeout)) { @@ -2194,7 +2197,7 @@ int cmGlobalGenerator::Build( output += cmStrCat(*outputPtr, "\nGenerator: execution of make failed. Make command was: ", - makeCommandStr, '\n'); + outputMakeCommandStr, '\n'); return 1; } -- cgit v0.12 From b017c9f12758ea169aa6009a4146e1562946e3a0 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 16 May 2023 12:14:58 -0400 Subject: cmGlobalGenerator: fix off-by-one for `&&` command joining Only add `&&` if there is another command after the current one. --- Source/cmGlobalGenerator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 769a7db..874c98d 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2181,7 +2181,7 @@ int cmGlobalGenerator::Build( command != makeCommand.end() && retVal == 0; ++command) { makeCommandStr = command->Printable(); outputMakeCommandStr = command->QuotedPrintable(); - if (command != makeCommand.end()) { + if ((command + 1) != makeCommand.end()) { makeCommandStr += " && "; outputMakeCommandStr += " && "; } -- cgit v0.12 From e06066653124f4fd8d1f9ca1c3e1cd8a4ceac7f9 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 8 Feb 2023 14:12:40 -0500 Subject: cmake: write the build command itself with `--verbose` --- Help/release/dev/cmake-verbose-print-build-tool-command.rst | 5 +++++ Source/cmake.cxx | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/cmake-verbose-print-build-tool-command.rst diff --git a/Help/release/dev/cmake-verbose-print-build-tool-command.rst b/Help/release/dev/cmake-verbose-print-build-tool-command.rst new file mode 100644 index 0000000..4f13231 --- /dev/null +++ b/Help/release/dev/cmake-verbose-print-build-tool-command.rst @@ -0,0 +1,5 @@ +cmake-verbose-print-build-tool-command +-------------------------------------- + +* ``cmake --build $dir --verbose`` will now print the working directory and + command line used to perform the build. diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 0fd7461..868728f 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -3699,10 +3699,19 @@ int cmake::Build(int jobs, std::string dir, std::vector targets, } this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs); - return this->GlobalGenerator->Build( + int buildresult = this->GlobalGenerator->Build( jobs, "", dir, projName, targets, output, "", config, buildOptions, verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions); + + if (verbose) { + // `cmGlobalGenerator::Build` logs metadata about what directory and + // commands are being executed to the `output` parameter. If CMake is + // verbose, print this out. + std::cout << output; + } + + return buildresult; } bool cmake::Open(const std::string& dir, bool dryRun) -- cgit v0.12 From 8451a3f0b545347a812288e66d757692c770097d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 26 May 2023 14:30:18 -0400 Subject: cmGlobalGenerator: use a stream for output in `Build` This allows output to show up in output immediately instead of being batched. --- Source/CTest/cmCTestBuildAndTestHandler.cxx | 4 +- Source/cmGlobalGenerator.cxx | 50 +++++++++++++--------- Source/cmGlobalGenerator.h | 2 +- Source/cmake.cxx | 15 +++---- .../RunCMake/Ninja/VerboseBuild-nowork-stdout.txt | 2 +- 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index cece98e..5feb953 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -246,7 +246,6 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) return 1; } } - std::string output; const char* config = nullptr; if (!this->CTest->GetConfigType().empty()) { config = this->CTest->GetConfigType().c_str(); @@ -259,9 +258,8 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) PackageResolveMode::Disable); int retVal = cm.GetGlobalGenerator()->Build( cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir, - this->BuildProject, { tar }, output, this->BuildMakeProgram, config, + this->BuildProject, { tar }, out, this->BuildMakeProgram, config, buildOptions, false, remainingTime); - out << output; // if the build failed then return if (retVal) { if (outstring) { diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 874c98d..ced19af 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2076,9 +2076,12 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir, mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"); cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable); - return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "", - config, defaultBuildOptions, true, - this->TryCompileTimeout); + std::stringstream ostr; + auto ret = + this->Build(jobs, srcdir, bindir, projectName, newTarget, ostr, "", config, + defaultBuildOptions, true, this->TryCompileTimeout); + output = ostr.str(); + return ret; } std::vector @@ -2103,7 +2106,7 @@ void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/, int cmGlobalGenerator::Build( int jobs, const std::string& /*unused*/, const std::string& bindir, const std::string& projectName, const std::vector& targets, - std::string& output, const std::string& makeCommandCSTR, + std::ostream& ostr, const std::string& makeCommandCSTR, const std::string& config, const cmBuildOptions& buildOptions, bool verbose, cmDuration timeout, cmSystemTools::OutputOption outputflag, std::vector const& nativeOptions) @@ -2114,13 +2117,13 @@ int cmGlobalGenerator::Build( * Run an executable command and put the stdout in output. */ cmWorkingDirectory workdir(bindir); - output += cmStrCat("Change Dir: '", bindir, "'\n"); + ostr << "Change Dir: '" << bindir << '\'' << std::endl; if (workdir.Failed()) { cmSystemTools::SetRunCommandHideConsole(hideconsole); std::string err = cmStrCat("Failed to change directory: ", std::strerror(workdir.GetLastResult())); cmSystemTools::Error(err); - output += cmStrCat(err, '\n'); + ostr << err << std::endl; return 1; } std::string realConfig = config; @@ -2149,8 +2152,8 @@ int cmGlobalGenerator::Build( this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, { "clean" }, realConfig, jobs, verbose, buildOptions); - output += cmStrCat( - "\nRun Clean Command: ", cleanCommand.front().QuotedPrintable(), '\n'); + ostr << "\nRun Clean Command: " << cleanCommand.front().QuotedPrintable() + << std::endl; if (cleanCommand.size() != 1) { this->GetCMakeInstance()->IssueMessage(MessageType::INTERNAL_ERROR, "The generator did not produce " @@ -2163,18 +2166,21 @@ int cmGlobalGenerator::Build( nullptr, outputflag, timeout)) { cmSystemTools::SetRunCommandHideConsole(hideconsole); cmSystemTools::Error("Generator: execution of make clean failed."); - output += - cmStrCat(*outputPtr, "\nGenerator: execution of make clean failed.\n"); + ostr << *outputPtr << "\nGenerator: execution of make clean failed." + << std::endl; return 1; } - output += *outputPtr; + ostr << *outputPtr; } // now build std::string makeCommandStr; std::string outputMakeCommandStr; - output += "\nRun Build Command(s): "; + bool isWatcomWMake = this->CMakeInstance->GetState()->UseWatcomWMake(); + bool needBuildOutput = isWatcomWMake; + std::string buildOutput; + ostr << "\nRun Build Command(s): "; retVal = 0; for (auto command = makeCommand.begin(); @@ -2186,7 +2192,7 @@ int cmGlobalGenerator::Build( outputMakeCommandStr += " && "; } - output += outputMakeCommandStr; + ostr << outputMakeCommandStr << std::endl; if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr, outputPtr, &retVal, nullptr, outputflag, timeout)) { @@ -2194,22 +2200,24 @@ int cmGlobalGenerator::Build( cmSystemTools::Error( "Generator: execution of make failed. Make command was: " + makeCommandStr); - output += - cmStrCat(*outputPtr, - "\nGenerator: execution of make failed. Make command was: ", - outputMakeCommandStr, '\n'); + ostr << *outputPtr + << "\nGenerator: execution of make failed. Make command was: " + << outputMakeCommandStr << std::endl; return 1; } - output += *outputPtr; + ostr << *outputPtr << std::flush; + if (needBuildOutput) { + buildOutput += *outputPtr; + } } - output += "\n"; + ostr << std::endl; cmSystemTools::SetRunCommandHideConsole(hideconsole); // The OpenWatcom tools do not return an error code when a link // library is not found! - if (this->CMakeInstance->GetState()->UseWatcomWMake() && retVal == 0 && - output.find("W1008: cannot open") != std::string::npos) { + if (isWatcomWMake && retVal == 0 && + buildOutput.find("W1008: cannot open") != std::string::npos) { retVal = 1; } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index f24465a..532fa44 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -234,7 +234,7 @@ public: int Build( int jobs, const std::string& srcdir, const std::string& bindir, const std::string& projectName, - std::vector const& targetNames, std::string& output, + std::vector const& targetNames, std::ostream& ostr, const std::string& makeProgram, const std::string& config, const cmBuildOptions& buildOptions, bool verbose, cmDuration timeout, cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE, diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 868728f..12b9b24 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -3625,7 +3625,6 @@ int cmake::Build(int jobs, std::string dir, std::vector targets, return 1; } } - std::string output; std::string projName; cmValue cachedProjectName = this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME"); @@ -3699,18 +3698,16 @@ int cmake::Build(int jobs, std::string dir, std::vector targets, } this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs); + std::stringstream ostr; + // `cmGlobalGenerator::Build` logs metadata about what directory and commands + // are being executed to the `output` parameter. If CMake is verbose, print + // this out. + std::ostream& verbose_ostr = verbose ? std::cout : ostr; int buildresult = this->GlobalGenerator->Build( - jobs, "", dir, projName, targets, output, "", config, buildOptions, + jobs, "", dir, projName, targets, verbose_ostr, "", config, buildOptions, verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions); - if (verbose) { - // `cmGlobalGenerator::Build` logs metadata about what directory and - // commands are being executed to the `output` parameter. If CMake is - // verbose, print this out. - std::cout << output; - } - return buildresult; } diff --git a/Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt b/Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt index 60a9228..40b4527 100644 --- a/Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt +++ b/Tests/RunCMake/Ninja/VerboseBuild-nowork-stdout.txt @@ -1 +1 @@ -^ninja: no work to do +ninja: no work to do -- cgit v0.12