cmake: Add options for parallel builds to --build mode

While we already support `cmake --build . -- -j`, the options after `--`
are specific to the native build tool.  Add new options `--parallel
[<N>]` and `-j [<N>]` to abstract this and map to the proper option
for the native build tool.
This commit is contained in:
Florian Maushart 2018-04-14 22:50:19 +02:00 committed by Brad King
parent dfc6923428
commit 1ab3881ec9
50 changed files with 424 additions and 100 deletions

View File

@ -0,0 +1,9 @@
CMAKE_BUILD_PARALLEL_LEVEL
--------------------------
Specifies the maximum number of concurrent processes to use when building
using the ``cmake --build`` command line
:ref:`Build Tool Mode <Build Tool Mode>`.
If this variable is defined empty the native build tool's default number is
used.

View File

@ -13,6 +13,7 @@ Environment Variables that Control the Build
.. toctree::
:maxdepth: 1
/envvar/CMAKE_BUILD_PARALLEL_LEVEL
/envvar/CMAKE_CONFIG_TYPE
/envvar/CMAKE_MSVCIDE_RUN_PATH
/envvar/CMAKE_OSX_ARCHITECTURES

View File

@ -159,6 +159,13 @@ following options:
``--build <dir>``
Project binary directory to be built. This is required and must be first.
``-j [<jobs>], --parallel [<jobs>]``
The maximum number of concurrent processes to use when building.
If ``<jobs>`` is omitted the native build tool's default number is used.
The :envvar:`CMAKE_BUILD_PARALLEL_LEVEL` environment variable, if set,
specifies a default parallel level when this option is not given.
``--target <tgt>``
Build ``<tgt>`` instead of default targets. May only be specified once.

View File

@ -0,0 +1,6 @@
parallel_build_option
---------------------
* The :manual:`cmake(1)` :ref:`Build Tool Mode` (``cmake --build``) gained
``--parallel [<jobs>]`` and ``-j [<jobs>]`` options to specify a parallel
build level. They map to corresponding options of the native build tool.

View File

@ -253,9 +253,9 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
config = "Debug";
}
int retVal = cm.GetGlobalGenerator()->Build(
this->SourceDir, this->BinaryDir, this->BuildProject, tar, output,
this->BuildMakeProgram, config, !this->BuildNoClean, false, false,
remainingTime);
cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
this->BuildProject, tar, output, this->BuildMakeProgram, config,
!this->BuildNoClean, false, false, remainingTime);
out << output;
// if the build failed then return
if (retVal) {

View File

@ -818,7 +818,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
// actually do the try compile now that everything is setup
int res = this->Makefile->TryCompile(
sourceDirectory, this->BinaryDirectory, projectName, targetName,
this->SrcFileSignature, &cmakeFlags, output);
this->SrcFileSignature, cmake::NO_BUILD_PARALLEL_LEVEL, &cmakeFlags,
output);
if (erroroc) {
cmSystemTools::SetErrorOccured();
}

View File

@ -51,3 +51,32 @@ void cmGlobalBorlandMakefileGenerator::GetDocumentation(
entry.Name = cmGlobalBorlandMakefileGenerator::GetActualName();
entry.Brief = "Generates Borland makefiles.";
}
void cmGlobalBorlandMakefileGenerator::GenerateBuildCommand(
std::vector<std::string>& 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)
{
this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
makeCommand, makeProgram, projectName, projectDir, targetName, config,
fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
}
void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(
std::ostream& os, int jobs) const
{
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
// Borland's make does not support parallel builds
// see http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Make
/* clang-format off */
os <<
"Warning: Borland's make does not support parallel builds. "
"Ignoring parallel build command line option.\n";
/* clang-format on */
}
this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
os, cmake::NO_BUILD_PARALLEL_LEVEL);
}

View File

@ -5,6 +5,8 @@
#include "cmGlobalNMakeMakefileGenerator.h"
#include <iosfwd>
/** \class cmGlobalBorlandMakefileGenerator
* \brief Write a Borland makefiles.
*
@ -21,7 +23,7 @@ public:
}
///! Get the name for the generator.
virtual std::string GetName() const
std::string GetName() const override
{
return cmGlobalBorlandMakefileGenerator::GetActualName();
}
@ -31,17 +33,27 @@ public:
static void GetDocumentation(cmDocumentationEntry& entry);
///! Create a local generator appropriate to this Global Generator
virtual cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf);
cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override;
/**
* Try to determine system information such as shared library
* extension, pthreads, byte order etc.
*/
virtual void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile*, bool optional);
void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
bool optional) override;
virtual bool AllowNotParallel() const { return false; }
virtual bool AllowDeleteOnError() const { return false; }
bool AllowNotParallel() const override { return false; }
bool AllowDeleteOnError() const override { return false; }
protected:
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
};
#endif

View File

@ -1741,7 +1741,7 @@ void cmGlobalGenerator::CheckTargetProperties()
}
}
int cmGlobalGenerator::TryCompile(const std::string& srcdir,
int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir,
const std::string& bindir,
const std::string& projectName,
const std::string& target, bool fast,
@ -1782,7 +1782,7 @@ int cmGlobalGenerator::TryCompile(const std::string& srcdir,
}
std::string config =
mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION");
return this->Build(srcdir, bindir, projectName, newTarget, output, "",
return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "",
config, false, fast, false, this->TryCompileTimeout);
}
@ -1790,13 +1790,21 @@ void cmGlobalGenerator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& /*unused*/,
const std::string& /*unused*/, const std::string& /*unused*/,
const std::string& /*unused*/, const std::string& /*unused*/,
bool /*unused*/, bool /*unused*/, std::vector<std::string> const& /*unused*/)
bool /*unused*/, int /*unused*/, bool /*unused*/,
std::vector<std::string> const& /*unused*/)
{
makeCommand.push_back(
"cmGlobalGenerator::GenerateBuildCommand not implemented");
}
int cmGlobalGenerator::Build(const std::string& /*unused*/,
void cmGlobalGenerator::PrintBuildCommandAdvice(std::ostream& /*os*/,
int /*jobs*/) const
{
// Subclasses override this method if they e.g want to give a warning that
// they do not support certain build command line options
}
int cmGlobalGenerator::Build(int jobs, const std::string& /*unused*/,
const std::string& bindir,
const std::string& projectName,
const std::string& target, std::string& output,
@ -1832,7 +1840,8 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/,
std::vector<std::string> makeCommand;
this->GenerateBuildCommand(makeCommand, makeCommandCSTR, projectName, bindir,
target, config, fast, verbose, nativeOptions);
target, config, fast, jobs, verbose,
nativeOptions);
// Workaround to convince VCExpress.exe to produce output.
if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
@ -1846,7 +1855,7 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/,
if (clean) {
std::vector<std::string> cleanCommand;
this->GenerateBuildCommand(cleanCommand, makeCommandCSTR, projectName,
bindir, "clean", config, fast, verbose);
bindir, "clean", config, fast, jobs, verbose);
output += "\nRun Clean Command:";
output += cmSystemTools::PrintSingleCommand(cleanCommand);
output += "\n";

View File

@ -147,9 +147,10 @@ public:
* Try running cmake and building a file. This is used for dynamically
* loaded commands, not as part of the usual build process.
*/
int TryCompile(const std::string& srcdir, const std::string& bindir,
const std::string& projectName, const std::string& targetName,
bool fast, std::string& output, cmMakefile* mf);
int TryCompile(int jobs, const std::string& srcdir,
const std::string& bindir, const std::string& projectName,
const std::string& targetName, bool fast, std::string& output,
cmMakefile* mf);
/**
* Build a file given the following information. This is a more direct call
@ -157,7 +158,7 @@ public:
* empty then all is assumed. clean indicates if a "make clean" should be
* done first.
*/
int Build(const std::string& srcdir, const std::string& bindir,
int Build(int jobs, const std::string& srcdir, const std::string& bindir,
const std::string& projectName, const std::string& targetName,
std::string& output, const std::string& makeProgram,
const std::string& config, bool clean, bool fast, bool verbose,
@ -176,9 +177,11 @@ public:
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& projectDir,
const std::string& targetName, const std::string& config, bool fast,
bool verbose,
int jobs, bool verbose,
std::vector<std::string> const& makeOptions = std::vector<std::string>());
virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
/** Generate a "cmake --build" call for a given target and config. */
std::string GenerateCMakeBuildCommand(const std::string& target,
const std::string& config,

View File

@ -273,11 +273,18 @@ void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& /*projectName*/, const std::string& /*projectDir*/,
const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
bool /*verbose*/, std::vector<std::string> const& makeOptions)
int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
{
makeCommand.push_back(
this->SelectMakeProgram(makeProgram, this->GetGhsBuildCommand()));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
makeCommand.push_back("-parallel");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
makeCommand.push_back(std::to_string(jobs));
}
}
makeCommand.insert(makeCommand.end(), makeOptions.begin(),
makeOptions.end());
if (!targetName.empty()) {

View File

@ -89,7 +89,7 @@ protected:
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& projectDir,
const std::string& targetName, const std::string& config, bool fast,
bool verbose,
int jobs, bool verbose,
std::vector<std::string> const& makeOptions = std::vector<std::string>());
private:

View File

@ -52,3 +52,29 @@ void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(
}
this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
}
void cmGlobalJOMMakefileGenerator::GenerateBuildCommand(
std::vector<std::string>& 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)
{
std::vector<std::string> jomMakeOptions;
// Since we have full control over the invocation of JOM, let us
// make it quiet.
jomMakeOptions.push_back(this->MakeSilentFlag);
jomMakeOptions.insert(jomMakeOptions.end(), makeOptions.begin(),
makeOptions.end());
// JOM does parallel builds by default, the -j is only needed if a specific
// number is given
// see https://github.com/qt-labs/jom/blob/v1.1.2/src/jomlib/options.cpp
if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
}
cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
makeCommand, makeProgram, projectName, projectDir, targetName, config,
fast, jobs, verbose, jomMakeOptions);
}

View File

@ -5,6 +5,8 @@
#include "cmGlobalUnixMakefileGenerator3.h"
#include <iosfwd>
/** \class cmGlobalJOMMakefileGenerator
* \brief Write a JOM makefiles.
*
@ -19,7 +21,7 @@ public:
return new cmGlobalGeneratorSimpleFactory<cmGlobalJOMMakefileGenerator>();
}
///! Get the name for the generator.
virtual std::string GetName() const
std::string GetName() const override
{
return cmGlobalJOMMakefileGenerator::GetActualName();
}
@ -34,12 +36,20 @@ public:
* Try to determine system information such as shared library
* extension, pthreads, byte order etc.
*/
virtual void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile*, bool optional);
void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
bool optional) override;
protected:
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
private:
void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
const char* envVar) const;
const char* envVar) const override;
};
#endif

View File

@ -52,3 +52,40 @@ void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice(
}
this->cmGlobalUnixMakefileGenerator3::PrintCompilerAdvice(os, lang, envVar);
}
void cmGlobalNMakeMakefileGenerator::GenerateBuildCommand(
std::vector<std::string>& 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)
{
std::vector<std::string> nmakeMakeOptions;
// Since we have full control over the invocation of nmake, let us
// make it quiet.
nmakeMakeOptions.push_back(this->MakeSilentFlag);
nmakeMakeOptions.insert(nmakeMakeOptions.end(), makeOptions.begin(),
makeOptions.end());
this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
makeCommand, makeProgram, projectName, projectDir, targetName, config,
fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions);
}
void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os,
int jobs) const
{
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
// nmake does not support parallel build level
// see https://msdn.microsoft.com/en-us/library/afyyse50.aspx
/* clang-format off */
os <<
"Warning: NMake does not support parallel builds. "
"Ignoring parallel build command line option.\n";
/* clang-format on */
}
this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
os, cmake::NO_BUILD_PARALLEL_LEVEL);
}

View File

@ -5,6 +5,8 @@
#include "cmGlobalUnixMakefileGenerator3.h"
#include <iosfwd>
/** \class cmGlobalNMakeMakefileGenerator
* \brief Write a NMake makefiles.
*
@ -20,7 +22,7 @@ public:
cmGlobalNMakeMakefileGenerator>();
}
///! Get the name for the generator.
virtual std::string GetName() const
std::string GetName() const override
{
return cmGlobalNMakeMakefileGenerator::GetActualName();
}
@ -39,12 +41,22 @@ public:
* Try to determine system information such as shared library
* extension, pthreads, byte order etc.
*/
virtual void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile*, bool optional);
void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
bool optional) override;
protected:
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
private:
void PrintCompilerAdvice(std::ostream& os, std::string const& lang,
const char* envVar) const;
const char* envVar) const override;
};
#endif

View File

@ -674,7 +674,7 @@ void cmGlobalNinjaGenerator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& /*projectName*/, const std::string& /*projectDir*/,
const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
bool verbose, std::vector<std::string> const& makeOptions)
int jobs, bool verbose, std::vector<std::string> const& makeOptions)
{
makeCommand.push_back(this->SelectMakeProgram(makeProgram));
@ -682,6 +682,12 @@ void cmGlobalNinjaGenerator::GenerateBuildCommand(
makeCommand.push_back("-v");
}
if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) &&
(jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) {
makeCommand.push_back("-j");
makeCommand.push_back(std::to_string(jobs));
}
makeCommand.insert(makeCommand.end(), makeOptions.begin(),
makeOptions.end());
if (!targetName.empty()) {

View File

@ -202,13 +202,11 @@ public:
void EnableLanguage(std::vector<std::string> const& languages,
cmMakefile* mf, bool optional) override;
void GenerateBuildCommand(std::vector<std::string>& makeCommand,
const std::string& makeProgram,
const std::string& projectName,
const std::string& projectDir,
const std::string& targetName,
const std::string& config, bool fast, bool verbose,
std::vector<std::string> const& makeOptions =
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
// Setup target names

View File

@ -7,7 +7,6 @@
#include <sstream>
#include <utility>
#include "cmAlgorithms.h"
#include "cmDocumentationEntry.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
@ -494,31 +493,33 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& /*projectName*/, const std::string& /*projectDir*/,
const std::string& targetName, const std::string& /*config*/, bool fast,
bool /*verbose*/, std::vector<std::string> const& makeOptions)
int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
{
cmMakefile* mf;
if (!this->Makefiles.empty()) {
mf = this->Makefiles[0];
} else {
cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentSource(
this->CMakeInstance->GetHomeDirectory());
snapshot.GetDirectory().SetCurrentBinary(
this->CMakeInstance->GetHomeOutputDirectory());
snapshot.SetDefaultDefinitions();
mf = new cmMakefile(this, snapshot);
}
makeCommand.push_back(this->SelectMakeProgram(makeProgram));
// Since we have full control over the invocation of nmake, let us
// make it quiet.
if (cmHasLiteralPrefix(this->GetName(), "NMake Makefiles")) {
makeCommand.push_back("/NOLOGO");
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
makeCommand.push_back("-j");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
makeCommand.push_back(std::to_string(jobs));
}
}
makeCommand.insert(makeCommand.end(), makeOptions.begin(),
makeOptions.end());
if (!targetName.empty()) {
cmMakefile* mf;
if (!this->Makefiles.empty()) {
mf = this->Makefiles[0];
} else {
cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentSource(
this->CMakeInstance->GetHomeDirectory());
snapshot.GetDirectory().SetCurrentBinary(
this->CMakeInstance->GetHomeOutputDirectory());
snapshot.SetDefaultDefinitions();
mf = new cmMakefile(this, snapshot);
}
std::string tname = targetName;
if (fast) {
tname += "/fast";
@ -528,9 +529,9 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
conv.ConvertToRelativePath(mf->GetState()->GetBinaryDirectory(), tname);
cmSystemTools::ConvertToOutputSlashes(tname);
makeCommand.push_back(std::move(tname));
if (this->Makefiles.empty()) {
delete mf;
}
}
if (this->Makefiles.empty()) {
delete mf;
}
}

View File

@ -127,13 +127,11 @@ public:
std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
// change the build command for speed
void GenerateBuildCommand(std::vector<std::string>& makeCommand,
const std::string& makeProgram,
const std::string& projectName,
const std::string& projectDir,
const std::string& targetName,
const std::string& config, bool fast, bool verbose,
std::vector<std::string> const& makeOptions =
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
/** Record per-target progress information. */

View File

@ -764,7 +764,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& projectDir,
const std::string& targetName, const std::string& config, bool fast,
bool verbose, std::vector<std::string> const& makeOptions)
int jobs, bool verbose, std::vector<std::string> const& makeOptions)
{
// Select the caller- or user-preferred make program, else MSBuild.
std::string makeProgramSelected =
@ -805,7 +805,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
// Use devenv to build solutions containing Intel Fortran projects.
cmGlobalVisualStudio7Generator::GenerateBuildCommand(
makeCommand, makeProgram, projectName, projectDir, targetName, config,
fast, verbose, makeOptions);
fast, jobs, verbose, makeOptions);
return;
}
@ -813,6 +813,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
std::string realTarget = targetName;
// msbuild.exe CxxOnly.sln /t:Build /p:Configuration=Debug /target:ALL_BUILD
// /m
if (realTarget.empty()) {
realTarget = "ALL_BUILD";
}
@ -841,6 +842,17 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
makeCommand.push_back(configArg);
makeCommand.push_back(std::string("/p:VisualStudioVersion=") +
this->GetIDEVersion());
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
makeCommand.push_back("/m");
} else {
makeCommand.push_back(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.insert(makeCommand.end(), makeOptions.begin(),
makeOptions.end());
}

View File

@ -24,13 +24,11 @@ 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,
const std::string& makeProgram,
const std::string& projectName,
const std::string& projectDir,
const std::string& targetName,
const std::string& config, bool fast, bool verbose,
std::vector<std::string> const& makeOptions =
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
///! create the correct local generator

View File

@ -199,7 +199,7 @@ void cmGlobalVisualStudio7Generator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& /*projectDir*/,
const std::string& targetName, const std::string& config, bool /*fast*/,
bool /*verbose*/, std::vector<std::string> const& makeOptions)
int /*jobs*/, bool /*verbose*/, std::vector<std::string> const& makeOptions)
{
// Select the caller- or user-preferred make program, else devenv.
std::string makeProgramSelected =

View File

@ -55,13 +55,11 @@ 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,
const std::string& makeProgram,
const std::string& projectName,
const std::string& projectDir,
const std::string& targetName,
const std::string& config, bool fast, bool verbose,
std::vector<std::string> const& makeOptions =
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
/**

View File

@ -7,6 +7,8 @@
#include "cmState.h"
#include "cmake.h"
#include <ostream>
cmGlobalWatcomWMakeGenerator::cmGlobalWatcomWMakeGenerator(cmake* cm)
: cmGlobalUnixMakefileGenerator3(cm)
{
@ -47,3 +49,31 @@ void cmGlobalWatcomWMakeGenerator::GetDocumentation(
entry.Name = cmGlobalWatcomWMakeGenerator::GetActualName();
entry.Brief = "Generates Watcom WMake makefiles.";
}
void cmGlobalWatcomWMakeGenerator::GenerateBuildCommand(
std::vector<std::string>& 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)
{
this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
makeCommand, makeProgram, projectName, projectDir, targetName, config,
fast, cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions);
}
void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,
int jobs) const
{
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
// wmake does not support parallel build level
/* clang-format off */
os <<
"Warning: Watcom's WMake does not support parallel builds. "
"Ignoring parallel build command line option.\n";
/* clang-format on */
}
this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice(
os, cmake::NO_BUILD_PARALLEL_LEVEL);
}

View File

@ -8,6 +8,7 @@
#include "cmGlobalGeneratorFactory.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include <iosfwd>
#include <string>
#include <vector>
@ -47,6 +48,16 @@ public:
bool AllowNotParallel() const override { return false; }
bool AllowDeleteOnError() const override { return false; }
protected:
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override;
};
#endif

View File

@ -325,7 +325,7 @@ void cmGlobalXCodeGenerator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& /*projectDir*/,
const std::string& targetName, const std::string& config, bool /*fast*/,
bool /*verbose*/, std::vector<std::string> const& makeOptions)
int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
{
// now build the test
makeCommand.push_back(
@ -356,6 +356,14 @@ void cmGlobalXCodeGenerator::GenerateBuildCommand(
}
makeCommand.push_back("-configuration");
makeCommand.push_back(!config.empty() ? config : "Debug");
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
makeCommand.push_back("-jobs");
if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
makeCommand.push_back(std::to_string(jobs));
}
}
makeCommand.insert(makeCommand.end(), makeOptions.begin(),
makeOptions.end());
}

View File

@ -66,13 +66,11 @@ 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,
const std::string& makeProgram,
const std::string& projectName,
const std::string& projectDir,
const std::string& targetName,
const std::string& config, bool fast, bool verbose,
std::vector<std::string> const& makeOptions =
void GenerateBuildCommand(
std::vector<std::string>& 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 =
std::vector<std::string>()) override;
/** Append the subdirectory for the given configuration. */

View File

@ -3269,7 +3269,7 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
int cmMakefile::TryCompile(const std::string& srcdir,
const std::string& bindir,
const std::string& projectName,
const std::string& targetName, bool fast,
const std::string& targetName, bool fast, int jobs,
const std::vector<std::string>* cmakeArgs,
std::string& output)
{
@ -3381,7 +3381,7 @@ int cmMakefile::TryCompile(const std::string& srcdir,
// finally call the generator to actually build the resulting project
int ret = this->GetGlobalGenerator()->TryCompile(
srcdir, bindir, projectName, targetName, fast, output, this);
jobs, srcdir, bindir, projectName, targetName, fast, output, this);
this->IsSourceFileTryCompile = false;
return ret;

View File

@ -102,7 +102,8 @@ public:
*/
int TryCompile(const std::string& srcdir, const std::string& bindir,
const std::string& projectName, const std::string& targetName,
bool fast, const std::vector<std::string>* cmakeArgs,
bool fast, int jobs,
const std::vector<std::string>* cmakeArgs,
std::string& output);
bool GetIsSourceFileTryCompile() const;

View File

@ -2398,7 +2398,7 @@ cmMessenger* cmake::GetMessenger() const
return this->Messenger;
}
int cmake::Build(const std::string& dir, const std::string& target,
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)
{
@ -2508,7 +2508,9 @@ int cmake::Build(const std::string& dir, const std::string& target,
}
#endif
return gen->Build("", dir, projName, target, output, "", config, clean,
gen->PrintBuildCommandAdvice(std::cerr, jobs);
return gen->Build(jobs, "", dir, projName, target, output, "", config, clean,
false, verbose, cmDuration::zero(),
cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
}

View File

@ -119,6 +119,9 @@ public:
typedef std::map<std::string, cmInstalledFile> InstalledFilesMap;
static const int NO_BUILD_PARALLEL_LEVEL = -1;
static const int DEFAULT_BUILD_PARALLEL_LEVEL = 0;
/// Default constructor
cmake(Role role);
/// Destructor
@ -430,7 +433,7 @@ public:
cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
///! run the --build option
int Build(const std::string& dir, const std::string& target,
int Build(int jobs, const std::string& dir, const std::string& target,
const std::string& config,
const std::vector<std::string>& nativeOptions, bool clean);

View File

@ -22,6 +22,8 @@
#if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
#include "cmsys/ConsoleBuf.hxx"
#endif
#include <ctype.h>
#include <iostream>
#include <string.h>
#include <string>
@ -49,6 +51,12 @@ static const char* cmDocumentationUsageNote[][2] = {
#define CMAKE_BUILD_OPTIONS \
" <dir> = Project binary directory to be built.\n" \
" -j [<jobs>] --parallel [<jobs>] = Build in parallel using\n" \
" the given number of jobs. If <jobs> is omitted\n" \
" the native build tool's default number is used.\n" \
" The CMAKE_BUILD_PARALLEL_LEVEL environment variable\n" \
" specifies a default parallel level when this option\n" \
" is not given.\n" \
" --target <tgt> = Build <tgt> instead of default targets.\n" \
" May only be specified once.\n" \
" --config <cfg> = For multi-configuration tools, choose <cfg>.\n" \
@ -338,6 +346,7 @@ static int do_build(int ac, char const* const* av)
std::cerr << "This cmake does not support --build\n";
return -1;
#else
int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
std::string target;
std::string config = "Debug";
std::string dir;
@ -348,6 +357,7 @@ static int do_build(int ac, char const* const* av)
enum Doing
{
DoingNone,
DoingJobs,
DoingDir,
DoingTarget,
DoingConfig,
@ -357,6 +367,13 @@ static int do_build(int ac, char const* const* av)
for (int i = 2; i < ac; ++i) {
if (doing == DoingNative) {
nativeOptions.push_back(av[i]);
} else if ((strcmp(av[i], "-j") == 0) ||
(strcmp(av[i], "--parallel") == 0)) {
jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
/* does the next argument start with a number? */
if ((i + 1 < ac) && (isdigit(*av[i + 1]))) {
doing = DoingJobs;
}
} else if (strcmp(av[i], "--target") == 0) {
if (!hasTarget) {
doing = DoingTarget;
@ -377,6 +394,18 @@ static int do_build(int ac, char const* const* av)
doing = DoingNative;
} else {
switch (doing) {
case DoingJobs: {
unsigned long numJobs = 0;
if (cmSystemTools::StringToULong(av[i], &numJobs)) {
jobs = int(numJobs);
doing = DoingNone;
} else {
std::cerr << "'" << av[i - 1] << "' invalid number '" << av[i]
<< "' given.\n\n";
dir.clear();
break;
}
} break;
case DoingDir:
dir = cmSystemTools::CollapseFullPath(av[i]);
doing = DoingNone;
@ -396,6 +425,25 @@ static int do_build(int ac, char const* const* av)
}
}
}
if (jobs == cmake::NO_BUILD_PARALLEL_LEVEL) {
std::string parallel;
if (cmSystemTools::GetEnv("CMAKE_BUILD_PARALLEL_LEVEL", parallel)) {
if (parallel.empty()) {
jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
} else {
unsigned long numJobs = 0;
if (cmSystemTools::StringToULong(parallel.c_str(), &numJobs)) {
jobs = int(numJobs);
} else {
std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n"
<< "invalid number '" << parallel << "' given.\n\n";
dir.clear();
}
}
}
}
if (dir.empty()) {
/* clang-format off */
std::cerr <<
@ -410,7 +458,7 @@ static int do_build(int ac, char const* const* av)
cmake cm(cmake::RoleInternal);
cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm);
cm.SetProgressCallback(cmakemainProgressCallback, &cm);
return cm.Build(dir, target, config, nativeOptions, clean);
return cm.Build(jobs, dir, target, config, nativeOptions, clean);
#endif
}

View File

@ -0,0 +1,3 @@
^'--parallel' invalid number '12ab' given\.
+
Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1,3 @@
^'-j' invalid number '12ab' given\.
+
Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -0,0 +1 @@
(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)

View File

@ -59,6 +59,29 @@ function(run_BuildDir)
${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget)
run_cmake_command(BuildDir--build-multiple-targets ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --target CustomTarget2 --target CustomTarget3)
run_cmake_command(BuildDir--build-jobs-bad-number ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build -j 12ab)
run_cmake_command(BuildDir--build-jobs-good-number ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build -j 2)
run_cmake_command(BuildDir--build-jobs-good-number-trailing--target ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build -j 2 --target CustomTarget)
run_cmake_command(BuildDir--build--parallel-bad-number ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --parallel 12ab)
run_cmake_command(BuildDir--build--parallel-good-number ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --parallel 2)
run_cmake_command(BuildDir--build--parallel-good-number-trailing--target ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --parallel 2 --target CustomTarget)
# No default jobs for Xcode and FreeBSD build command
if(NOT RunCMake_GENERATOR MATCHES "Xcode" AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
run_cmake_command(BuildDir--build-jobs-no-number ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build -j)
run_cmake_command(BuildDir--build-jobs-no-number-trailing--target ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build -j --target CustomTarget)
run_cmake_command(BuildDir--build--parallel-no-number ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --parallel)
run_cmake_command(BuildDir--build--parallel-no-number-trailing--target ${CMAKE_COMMAND} -E chdir ..
${CMAKE_COMMAND} --build BuildDir-build --parallel --target CustomTarget)
endif()
endfunction()
run_BuildDir()