Commit 9620cb93 authored by Brad King's avatar Brad King Committed by Kitware Robot

Merge topic 'add_consistent_verbose_build_flag'

66801f4d cmake: Add tests for verbose output to --build mode
439fe2e2 cmake: Add options for verbose output to --build mode
638667ef cmake: cmcmd.cxx fix "The arguments are" comments
3ca44029 ctest: Fix --build-and-test without --build-target on Xcode
cb6c233e cmake: Add -hideShellScriptEnvironment xcodebuild option
1a45266c cmGlobalGenerator: Add a class that represent the build command
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !2708
parents 60c06620 66801f4d
Pipeline #128869 passed with stage
in 0 seconds
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.
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
......@@ -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
===================================
......
......@@ -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.
......
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.
......@@ -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)
......
......@@ -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,
......
......@@ -1753,14 +1753,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*/,
......@@ -1804,31 +1803,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;
......@@ -1840,13 +1837,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(
......
......@@ -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,
......
......@@ -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");
}
}
}
......
......@@ -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,
......
......@@ -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)
......
......@@ -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,
......
......@@ -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)
......
......@@ -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,
......
......@@ -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);
}
}
}
......
......@@ -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,
......
......@@ -495,10 +495,10 @@ 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)
int jobs, bool verbose, std::vector<std::string> const& makeOptions)
{
std::unique_ptr<cmMakefile> mfu;
cmMakefile* mf;
......@@ -515,17 +515,23 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
mf = mfu.get();
}
makeCommand.push_back(this->SelectMakeProgram(makeProgram));
// 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) {
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) {
......@@ -535,7 +541,7 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfNotContained(
mf->GetState()->GetBinaryDirectory(), tname);
cmSystemTools::ConvertToOutputSlashes(tname);
makeCommand.push_back(std::move(tname));
makeCommand.add(std::move(tname));
}
}
......
......@@ -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,
......
......@@ -879,7 +879,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)
......@@ -894,6 +894,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;
......@@ -927,7 +931,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
......@@ -936,8 +940,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";
......@@ -949,7 +953,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
cmSystemTools::ConvertToUnixSlashes(targetProject);
}
}
makeCommand.push_back(targetProject);
makeCommand.add(std::move(targetProject));
}
std::string configArg = "/p:Configuration=";
if (!config.empty()) {
......@@ -957,23 +961,26 @@ 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());
// 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());
}
bool cmGlobalVisualStudio10Generator::Find64BitTools(cmMakefile* mf)
......
......@@ -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,
......
......@@ -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
......
......@@ -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,
......
......@@ -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)<