diff options
author | Florian Maushart <FloriansGit@online.ms> | 2018-04-14 20:50:19 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2018-05-25 13:42:20 (GMT) |
commit | 1ab3881ec9e809ac5f6cad5cd84048310b8683e2 (patch) | |
tree | 2b5c7c5a9ad2e38a584de50b5f019056883c3877 /Source | |
parent | dfc692342831186053bd385605c8a21239e2e77d (diff) | |
download | CMake-1ab3881ec9e809ac5f6cad5cd84048310b8683e2.zip CMake-1ab3881ec9e809ac5f6cad5cd84048310b8683e2.tar.gz CMake-1ab3881ec9e809ac5f6cad5cd84048310b8683e2.tar.bz2 |
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.
Diffstat (limited to 'Source')
29 files changed, 358 insertions, 100 deletions
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index b2c68e7..fccbc95 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -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) { diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 26e0db9..a9b7adf 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -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(); } diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx index d2372a7..2389103 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -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); +} diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h index 5578d76..85fee74 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -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; + + 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; - virtual bool AllowNotParallel() const { return false; } - virtual bool AllowDeleteOnError() const { return false; } + void PrintBuildCommandAdvice(std::ostream& os, int jobs) const override; }; #endif diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index cf277d5..8a89f36 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -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"; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 34ed5b0..62c5441 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -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, diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index 946ed80..f4ecff2 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -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()) { diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h index 7d4b2ba..c5388ad 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -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: diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx index 18c45e0..0f41ea1 100644 --- a/Source/cmGlobalJOMMakefileGenerator.cxx +++ b/Source/cmGlobalJOMMakefileGenerator.cxx @@ -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); +} diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h index 2e8ee29..65f340c 100644 --- a/Source/cmGlobalJOMMakefileGenerator.h +++ b/Source/cmGlobalJOMMakefileGenerator.h @@ -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 diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index da683fb..eb66bd1 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -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); +} diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h index 05ab904..4b6382e 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.h +++ b/Source/cmGlobalNMakeMakefileGenerator.h @@ -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 diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index c19a61c..69bc3be 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -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()) { diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index bfff3d9..17b9a7d 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -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 diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index c07f10f..641b760 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -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; } } diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index f9ce88c..097678f 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -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. */ diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 205e0d0..51e9ab1 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -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()); } diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index f2501c2..098c8d4 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -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 diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 7ff007f..158f484 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -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 = diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 8d1bdc0..77d4a96 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -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; /** diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index 94cdb38..558ef15 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -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); +} diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h index e8b3a73..1729bf1 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.h +++ b/Source/cmGlobalWatcomWMakeGenerator.h @@ -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 diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 4481bdc..f69f23e 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -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()); } diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 7c51177..f7f4428 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -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. */ diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 33e76b2..f41c2f0 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -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; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 9f32c4f..ac7baae 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -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; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 5bae4e7..801d52d 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -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); } diff --git a/Source/cmake.h b/Source/cmake.h index 63dbe9f..6c0d77c 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -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); diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index b185a1b..9c9f65c 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -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 } |