[Cmake-commits] CMake branch, master, updated. v3.11.2-853-gf248f8a

Kitware Robot kwrobot at kitware.com
Tue May 29 10:15:05 EDT 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, master has been updated
       via  f248f8ad7898816a5a627e288d3a04fed993967f (commit)
       via  1ab3881ec9e809ac5f6cad5cd84048310b8683e2 (commit)
      from  42752d0c11df67a9ca4f5e71efa58965c58552f8 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f248f8ad7898816a5a627e288d3a04fed993967f
commit f248f8ad7898816a5a627e288d3a04fed993967f
Merge: 42752d0 1ab3881
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Tue May 29 14:02:09 2018 +0000
Commit:     Kitware Robot <kwrobot at kitware.com>
CommitDate: Tue May 29 10:05:09 2018 -0400

    Merge topic 'parallel_build_option'
    
    1ab3881ec9 cmake: Add options for parallel builds to --build mode
    
    Acked-by: Kitware Robot <kwrobot at kitware.com>
    Acked-by: Henry Schreiner <henryschreineriii at gmail.com>
    Merge-request: !1962


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1ab3881ec9e809ac5f6cad5cd84048310b8683e2
commit 1ab3881ec9e809ac5f6cad5cd84048310b8683e2
Author:     Florian Maushart <FloriansGit at online.ms>
AuthorDate: Sat Apr 14 22:50:19 2018 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Fri May 25 09:42:20 2018 -0400

    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.

diff --git a/Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst b/Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst
new file mode 100644
index 0000000..198dc51
--- /dev/null
+++ b/Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst
@@ -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.
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index 2d8869f..2d17bb5 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -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
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 577d321..177acd4 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -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.
 
diff --git a/Help/release/dev/parallel_build_option.rst b/Help/release/dev/parallel_build_option.rst
new file mode 100644
index 0000000..2451fd0
--- /dev/null
+++ b/Help/release/dev/parallel_build_option.rst
@@ -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.
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
 }
 
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-stderr.txt
new file mode 100644
index 0000000..e73d760
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-stderr.txt
@@ -0,0 +1,3 @@
+^'--parallel' invalid number '12ab' given\.
++
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing--target-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing--target-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing--target-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing--target-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing--target-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing--target-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-result.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-stderr.txt
new file mode 100644
index 0000000..c810087
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-stderr.txt
@@ -0,0 +1,3 @@
+^'-j' invalid number '12ab' given\.
++
+Usage: cmake --build <dir> \[options\] \[-- \[native-options\]\]
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing--target-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing--target-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing--target-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing--target-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing--target-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing--target-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing-stderr.txt b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing-stderr.txt
new file mode 100644
index 0000000..3c2c808
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing-stderr.txt
@@ -0,0 +1 @@
+(^$|^Warning: .* does not support parallel builds\. Ignoring parallel build command line option\.)
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index d8dbeec..3bb2a89 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -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()
 

-----------------------------------------------------------------------

Summary of changes:
 Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst         |    9 ++++
 Help/manual/cmake-env-variables.7.rst              |    1 +
 Help/manual/cmake.1.rst                            |    7 +++
 Help/release/dev/parallel_build_option.rst         |    6 +++
 Source/CTest/cmCTestBuildAndTestHandler.cxx        |    6 +--
 Source/cmCoreTryCompile.cxx                        |    3 +-
 Source/cmGlobalBorlandMakefileGenerator.cxx        |   29 ++++++++++++
 Source/cmGlobalBorlandMakefileGenerator.h          |   24 +++++++---
 Source/cmGlobalGenerator.cxx                       |   21 +++++---
 Source/cmGlobalGenerator.h                         |   13 +++--
 Source/cmGlobalGhsMultiGenerator.cxx               |    9 +++-
 Source/cmGlobalGhsMultiGenerator.h                 |    2 +-
 Source/cmGlobalJOMMakefileGenerator.cxx            |   26 ++++++++++
 Source/cmGlobalJOMMakefileGenerator.h              |   18 +++++--
 Source/cmGlobalNMakeMakefileGenerator.cxx          |   37 +++++++++++++++
 Source/cmGlobalNMakeMakefileGenerator.h            |   20 ++++++--
 Source/cmGlobalNinjaGenerator.cxx                  |    8 +++-
 Source/cmGlobalNinjaGenerator.h                    |   12 ++---
 Source/cmGlobalUnixMakefileGenerator3.cxx          |   45 +++++++++---------
 Source/cmGlobalUnixMakefileGenerator3.h            |   12 ++---
 Source/cmGlobalVisualStudio10Generator.cxx         |   16 ++++++-
 Source/cmGlobalVisualStudio10Generator.h           |   12 ++---
 Source/cmGlobalVisualStudio7Generator.cxx          |    2 +-
 Source/cmGlobalVisualStudio7Generator.h            |   12 ++---
 Source/cmGlobalWatcomWMakeGenerator.cxx            |   30 ++++++++++++
 Source/cmGlobalWatcomWMakeGenerator.h              |   11 +++++
 Source/cmGlobalXCodeGenerator.cxx                  |   10 +++-
 Source/cmGlobalXCodeGenerator.h                    |   12 ++---
 Source/cmMakefile.cxx                              |    4 +-
 Source/cmMakefile.h                                |    3 +-
 Source/cmake.cxx                                   |    6 ++-
 Source/cmake.h                                     |    5 +-
 Source/cmakemain.cxx                               |   50 +++++++++++++++++++-
 ...uildDir--build--parallel-bad-number-result.txt} |    0
 ...BuildDir--build--parallel-bad-number-stderr.txt |    3 ++
 ...uildDir--build--parallel-good-number-stderr.txt |    1 +
 ...arallel-good-number-trailing--target-stderr.txt |    1 +
 ...build--parallel-good-number-trailing-stderr.txt |    1 +
 .../BuildDir--build--parallel-no-number-stderr.txt |    1 +
 ...-parallel-no-number-trailing--target-stderr.txt |    1 +
 ...--build--parallel-no-number-trailing-stderr.txt |    1 +
 .../BuildDir--build-jobs-bad-number-result.txt}    |    0
 .../BuildDir--build-jobs-bad-number-stderr.txt     |    3 ++
 .../BuildDir--build-jobs-good-number-stderr.txt    |    1 +
 ...ld-jobs-good-number-trailing--target-stderr.txt |    1 +
 ...Dir--build-jobs-good-number-trailing-stderr.txt |    1 +
 .../BuildDir--build-jobs-no-number-stderr.txt      |    1 +
 ...uild-jobs-no-number-trailing--target-stderr.txt |    1 +
 ...ldDir--build-jobs-no-number-trailing-stderr.txt |    1 +
 Tests/RunCMake/CommandLine/RunCMakeTest.cmake      |   23 +++++++++
 50 files changed, 422 insertions(+), 100 deletions(-)
 create mode 100644 Help/envvar/CMAKE_BUILD_PARALLEL_LEVEL.rst
 create mode 100644 Help/release/dev/parallel_build_option.rst
 copy Tests/RunCMake/{Android/BadSYSROOT-result.txt => CommandLine/BuildDir--build--parallel-bad-number-result.txt} (100%)
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build--parallel-bad-number-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing--target-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build--parallel-good-number-trailing-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing--target-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build--parallel-no-number-trailing-stderr.txt
 copy Tests/RunCMake/{Android/BadSYSROOT-result.txt => CommandLine/BuildDir--build-jobs-bad-number-result.txt} (100%)
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build-jobs-bad-number-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing--target-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build-jobs-good-number-trailing-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing--target-stderr.txt
 create mode 100644 Tests/RunCMake/CommandLine/BuildDir--build-jobs-no-number-trailing-stderr.txt


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list