From 264313ec90e7eaf3797833d715d3c4aa1e40d60b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Peter=20K=C3=BCmmel?= <syntheticpp@gmx.net>
Date: Tue, 2 Oct 2012 17:46:12 +0200
Subject: [PATCH] CMake: add Ninja support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The cmake wizard proposes also ninja if ninja support is available

Ninja must be in PATH, but it is only called once, so it doesn't hurt.

Task-number: QTCREATORBUG-7720
Reviewed-by: Daniel Teske <daniel.teske@digia.com>

Change-Id: If3c9c7ae55e6990fa16b031fc2998a8d8d9ed17a
Reviewed-by: Peter Kümmel <syntheticpp@gmx.net>
Reviewed-by: Yuchen Deng <loaden@gmail.com>
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
---
 .../cmakebuildconfiguration.cpp               | 21 ++++-
 .../cmakebuildconfiguration.h                 |  7 ++
 .../cmakeopenprojectwizard.cpp                | 77 ++++++++++++----
 .../cmakeopenprojectwizard.h                  | 10 ++-
 .../cmakeprojectmanager/cmakeproject.cpp      |  8 +-
 .../cmakeprojectmanager.cpp                   | 20 ++++-
 .../cmakeprojectmanager/cmakeprojectmanager.h |  3 +
 src/plugins/cmakeprojectmanager/makestep.cpp  | 87 +++++++++++++++++--
 src/plugins/cmakeprojectmanager/makestep.h    | 17 ++++
 9 files changed, 212 insertions(+), 38 deletions(-)

diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index ac933cb48b0..d18e3e8fd35 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -55,7 +55,7 @@ const char BUILD_DIRECTORY_KEY[] = "CMakeProjectManager.CMakeBuildConfiguration.
 } // namespace
 
 CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent) :
-    BuildConfiguration(parent, Core::Id(CMAKE_BC_ID))
+    BuildConfiguration(parent, Core::Id(CMAKE_BC_ID)), m_useNinja(false)
 {
     m_buildDirectory = static_cast<CMakeProject *>(parent->project())->defaultBuildDirectory();
 }
@@ -64,7 +64,8 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent
                                                  CMakeBuildConfiguration *source) :
     BuildConfiguration(parent, source),
     m_buildDirectory(source->m_buildDirectory),
-    m_msvcVersion(source->m_msvcVersion)
+    m_msvcVersion(source->m_msvcVersion),
+    m_useNinja(false)
 {
     Q_ASSERT(parent);
     cloneSteps(source);
@@ -87,6 +88,19 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
     return true;
 }
 
+bool CMakeBuildConfiguration::useNinja() const
+{
+    return m_useNinja;
+}
+
+void CMakeBuildConfiguration::setUseNinja(bool useNninja)
+{
+    if (m_useNinja != useNninja) {
+        m_useNinja = useNninja;
+        emit useNinjaChanged(m_useNinja);
+    }
+}
+
 CMakeBuildConfiguration::~CMakeBuildConfiguration()
 { }
 
@@ -202,7 +216,7 @@ CMakeBuildConfiguration *CMakeBuildConfigurationFactory::create(ProjectExplorer:
     CMakeOpenProjectWizard copw(project->projectManager(),
                                 project->projectDirectory(),
                                 bc->buildDirectory(),
-                                bc->environment());
+                                bc);
     if (copw.exec() != QDialog::Accepted) {
         delete bc;
         return 0;
@@ -284,3 +298,4 @@ ProjectExplorer::BuildConfiguration::BuildType CMakeBuildConfiguration::buildTyp
 
     return Unknown;
 }
+
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
index 655e1b3b9dc..e264e6090f7 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h
@@ -65,6 +65,12 @@ public:
 
     BuildType buildType() const;
 
+    bool useNinja() const;
+    void setUseNinja(bool);
+
+signals:
+    void useNinjaChanged(bool);
+
 protected:
     CMakeBuildConfiguration(ProjectExplorer::Target *parent, CMakeBuildConfiguration *source);
     virtual bool fromMap(const QVariantMap &map);
@@ -72,6 +78,7 @@ protected:
 private:
     QString m_buildDirectory;
     QString m_msvcVersion;
+    bool m_useNinja;
 };
 
 class CMakeBuildConfigurationFactory : public ProjectExplorer::IBuildConfigurationFactory
diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp
index 433f5fc61c9..de167758545 100644
--- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp
@@ -30,6 +30,7 @@
 
 #include "cmakeopenprojectwizard.h"
 #include "cmakeprojectmanager.h"
+#include "cmakebuildconfiguration.h"
 
 #include <coreplugin/icore.h>
 #include <utils/pathchooser.h>
@@ -63,11 +64,37 @@ using namespace CMakeProjectManager::Internal;
 //                                   |--> Already existing cbp file (and new enough) --> Page: Ready to load the project
 //                                   |--> Page: Ask for cmd options, run generator
 
-CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const Utils::Environment &env)
+
+namespace CMakeProjectManager {
+namespace Internal {
+
+    class GeneratorInfo
+    {
+    public:
+        GeneratorInfo()
+            : m_kit(0), m_isNinja(false) {}
+        explicit GeneratorInfo(ProjectExplorer::Kit *kit, bool ninja = false)
+            : m_kit(kit), m_isNinja(ninja) {}
+
+        ProjectExplorer::Kit *kit() const { return m_kit; }
+        bool isNinja() const { return m_isNinja; }
+
+    private:
+        ProjectExplorer::Kit *m_kit;
+        bool m_isNinja;
+    };
+
+}
+}
+
+Q_DECLARE_METATYPE(CMakeProjectManager::Internal::GeneratorInfo);
+
+
+CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, CMakeBuildConfiguration *bc)
     : m_cmakeManager(cmakeManager),
       m_sourceDirectory(sourceDirectory),
       m_creatingCbpFiles(false),
-      m_environment(env)
+      m_buildConfiguration(bc)
 {
     int startid;
     if (hasInSourceBuild()) {
@@ -95,11 +122,11 @@ CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const
 
 CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory,
                                                const QString &buildDirectory, CMakeOpenProjectWizard::Mode mode,
-                                               const Utils::Environment &env)
+                                               CMakeBuildConfiguration *bc)
     : m_cmakeManager(cmakeManager),
       m_sourceDirectory(sourceDirectory),
       m_creatingCbpFiles(true),
-      m_environment(env)
+      m_buildConfiguration(bc)
 {
 
     CMakeRunPage::Mode rmode;
@@ -115,11 +142,11 @@ CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const
 
 CMakeOpenProjectWizard::CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory,
                                                const QString &oldBuildDirectory,
-                                               const Utils::Environment &env)
+                                               CMakeBuildConfiguration *bc)
     : m_cmakeManager(cmakeManager),
       m_sourceDirectory(sourceDirectory),
       m_creatingCbpFiles(true),
-      m_environment(env)
+      m_buildConfiguration(bc)
 {
     m_buildDirectory = oldBuildDirectory;
     addPage(new ShadowBuildPage(this, true));
@@ -201,9 +228,13 @@ void CMakeOpenProjectWizard::setArguments(const QString &args)
 
 Utils::Environment CMakeOpenProjectWizard::environment() const
 {
-    return m_environment;
+    return m_buildConfiguration->environment();
 }
 
+CMakeBuildConfiguration *CMakeOpenProjectWizard::buildConfiguration() const
+{
+    return m_buildConfiguration;
+}
 
 InSourceBuildPage::InSourceBuildPage(CMakeOpenProjectWizard *cmakeWizard)
     : QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard)
@@ -409,8 +440,6 @@ void CMakeRunPage::initializePage()
             ProjectExplorer::KitManager::instance()->kits();
 
     foreach (ProjectExplorer::Kit *k, kitList) {
-        QVariant kitVariant = qVariantFromValue(static_cast<void *>(k));
-
         ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(k);
         if (!tc)
             continue;
@@ -421,22 +450,24 @@ void CMakeRunPage::initializePage()
                     || targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2010Flavor
                     || targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2012Flavor) {
                 if (hasCodeBlocksGenerator && (cachedGenerator.isEmpty() || cachedGenerator == "NMake Makefiles"))
-                    m_generatorComboBox->addItem(tr("NMake Generator (%1)").arg(k->displayName()), kitVariant);
+                    m_generatorComboBox->addItem(tr("NMake Generator (%1)").arg(k->displayName()), qVariantFromValue(GeneratorInfo(k)));
              } else if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
 #ifdef Q_OS_WIN
                 if (cachedGenerator.isEmpty() || cachedGenerator == "MinGW Makefiles")
-                    m_generatorComboBox->addItem(tr("MinGW Generator (%1)").arg(k->displayName()), kitVariant);
+                    m_generatorComboBox->addItem(tr("MinGW Generator (%1)").arg(k->displayName()), qVariantFromValue(GeneratorInfo(k)));
 #else
                 if (cachedGenerator.isEmpty() || cachedGenerator == "Unix Makefiles")
-                    m_generatorComboBox->addItem(tr("Unix Generator (%1)").arg(k->displayName()), kitVariant);
+                    m_generatorComboBox->addItem(tr("Unix Generator (%1)").arg(k->displayName()), qVariantFromValue(GeneratorInfo(k)));
 #endif
-
             }
         } else {
             // Non windows
             if (cachedGenerator.isEmpty() || cachedGenerator == "Unix Makefiles")
-                m_generatorComboBox->addItem(tr("Unix Generator (%1)").arg(k->displayName()), kitVariant);
+                m_generatorComboBox->addItem(tr("Unix Generator (%1)").arg(k->displayName()), qVariantFromValue(GeneratorInfo(k)));
         }
+        if (m_cmakeWizard->cmakeManager()->hasCodeBlocksNinjaGenerator() &&
+                (cachedGenerator.isEmpty() || cachedGenerator == "Ninja"))
+            m_generatorComboBox->addItem(tr("Ninja (%1)").arg(k->displayName()), qVariantFromValue(GeneratorInfo(k, true)));
     }
 }
 
@@ -449,8 +480,11 @@ void CMakeRunPage::runCMake()
     int index = m_generatorComboBox->currentIndex();
 
     ProjectExplorer::Kit *k = 0;
-    if (index >= 0)
-        k = static_cast<ProjectExplorer::Kit *>(m_generatorComboBox->itemData(index).value<void *>());
+    GeneratorInfo generatorInfo;
+    if (index >= 0) {
+        generatorInfo = m_generatorComboBox->itemData(index).value<GeneratorInfo>();
+        k = generatorInfo.kit();
+    }
     if (!k) {
         m_output->appendPlainText(tr("No generator selected."));
         return;
@@ -464,15 +498,20 @@ void CMakeRunPage::runCMake()
     CMakeManager *cmakeManager = m_cmakeWizard->cmakeManager();
 
     QString generator = QLatin1String("-GCodeBlocks - Unix Makefiles");
-    if (tc->targetAbi().os() == ProjectExplorer::Abi::WindowsOS) {
-        if (tc->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor)
+    if (generatorInfo.isNinja()) {
+        m_cmakeWizard->buildConfiguration()->setUseNinja(true);
+        generator = "-GCodeBlocks - Ninja";
+    } else if (tc->targetAbi().os() == ProjectExplorer::Abi::WindowsOS) {
+        m_cmakeWizard->buildConfiguration()->setUseNinja(false);
+        if (tc->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
 #ifdef Q_OS_WIN
             generator = QLatin1String("-GCodeBlocks - MinGW Makefiles");
 #else
             generator = QLatin1String("-GCodeBlocks - Unix Makefiles");
 #endif
-        else
+        } else {
             generator = QLatin1String("-GCodeBlocks - NMake Makefiles");
+        }
     }
 
     Utils::Environment env = m_cmakeWizard->environment();
diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h
index 7c3781f1a2c..9b2c629259a 100644
--- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h
+++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.h
@@ -54,6 +54,7 @@ namespace CMakeProjectManager {
 namespace Internal {
 
 class CMakeManager;
+class CMakeBuildConfiguration;
 
 class CMakeOpenProjectWizard : public Utils::Wizard
 {
@@ -73,14 +74,14 @@ public:
     };
 
     // used at importing a project without a .user file
-    CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const Utils::Environment &env);
+    CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, CMakeBuildConfiguration *bc);
     /// used to update if we have already a .user file
     /// recreates or updates the cbp file
-    CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const QString &buildDirectory, Mode mode, const Utils::Environment &env);
+    CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const QString &buildDirectory, Mode mode, CMakeBuildConfiguration *bc);
     /// used to change the build directory of one buildconfiguration
     /// shows a page for selecting a directory
     /// then the run cmake page
-    CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const QString &oldBuildDirectory, const Utils::Environment &env);
+    CMakeOpenProjectWizard(CMakeManager *cmakeManager, const QString &sourceDirectory, const QString &oldBuildDirectory, CMakeBuildConfiguration *bc);
 
     virtual int nextId() const;
     QString buildDirectory() const;
@@ -90,6 +91,7 @@ public:
     QString arguments() const;
     void setArguments(const QString &args);
     Utils::Environment environment() const;
+    CMakeBuildConfiguration *buildConfiguration() const;
     bool existsUpToDateXmlFile() const;
 
 private:
@@ -100,7 +102,7 @@ private:
     QString m_sourceDirectory;
     QString m_arguments;
     bool m_creatingCbpFiles;
-    Utils::Environment m_environment;
+    CMakeBuildConfiguration *m_buildConfiguration;
 };
 
 class InSourceBuildPage : public QWizardPage
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
index b536af7c821..e33c7deef48 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
@@ -166,7 +166,7 @@ void CMakeProject::changeActiveBuildConfiguration(ProjectExplorer::BuildConfigur
                                     sourceFileInfo.absolutePath(),
                                     cmakebc->buildDirectory(),
                                     mode,
-                                    cmakebc->environment());
+                                    cmakebc);
         copw.exec();
     }
     // reparse
@@ -555,7 +555,7 @@ bool CMakeProject::fromMap(const QVariantMap &map)
                                     sourceFileInfo.absolutePath(),
                                     activeBC->buildDirectory(),
                                     mode,
-                                    activeBC->environment());
+                                    activeBC);
         if (copw.exec() != QDialog::Accepted)
             return false;
     }
@@ -906,7 +906,7 @@ void CMakeBuildSettingsWidget::openChangeBuildDirectoryDialog()
     CMakeOpenProjectWizard copw(project->projectManager(),
                                 project->projectDirectory(),
                                 m_buildConfiguration->buildDirectory(),
-                                m_buildConfiguration->environment());
+                                m_buildConfiguration);
     if (copw.exec() == QDialog::Accepted) {
         project->changeBuildDirectory(m_buildConfiguration, copw.buildDirectory());
         m_pathLineEdit->setText(m_buildConfiguration->buildDirectory());
@@ -921,7 +921,7 @@ void CMakeBuildSettingsWidget::runCMake()
                                 project->projectDirectory(),
                                 m_buildConfiguration->buildDirectory(),
                                 CMakeOpenProjectWizard::WantToUpdate,
-                                m_buildConfiguration->environment());
+                                m_buildConfiguration);
     if (copw.exec() == QDialog::Accepted)
         project->parseCMakeLists();
 }
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
index 6fe9cbb8056..98ee2ea3822 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp
@@ -123,7 +123,7 @@ void CMakeManager::runCMake(ProjectExplorer::Project *project)
                                 cmakeProject->projectDirectory(),
                                 bc->buildDirectory(),
                                 CMakeOpenProjectWizard::WantToUpdate,
-                                bc->environment());
+                                bc);
     if (copw.exec() == QDialog::Accepted)
         cmakeProject->parseCMakeLists();
 }
@@ -160,6 +160,11 @@ bool CMakeManager::hasCodeBlocksMsvcGenerator() const
     return m_settingsPage->hasCodeBlocksMsvcGenerator();
 }
 
+bool CMakeManager::hasCodeBlocksNinjaGenerator() const
+{
+    return m_settingsPage->hasCodeBlocksNinjaGenerator();
+}
+
 // need to refactor this out
 // we probably want the process instead of this function
 // cmakeproject then could even run the cmake process in the background, adding the files afterwards
@@ -253,6 +258,8 @@ CMakeSettingsPage::CMakeSettingsPage()
     m_pathCmake.process = 0;
     m_userCmake.hasCodeBlocksMsvcGenerator = false;
     m_pathCmake.hasCodeBlocksMsvcGenerator = false;
+    m_userCmake.hasCodeBlocksNinjaGenerator = false;
+    m_pathCmake.hasCodeBlocksNinjaGenerator = false;
     QSettings *settings = Core::ICore::settings();
     settings->beginGroup(QLatin1String("CMakeSettings"));
     m_userCmake.executable = settings->value(QLatin1String("cmakeExecutable")).toString();
@@ -297,6 +304,7 @@ void CMakeSettingsPage::cmakeFinished(CMakeValidator *cmakeValidator) const
         versionRegexp.indexIn(response);
 
         //m_supportsQtCreator = response.contains(QLatin1String("QtCreator"));
+        cmakeValidator->hasCodeBlocksNinjaGenerator = response.contains(QLatin1String("CodeBlocks - Ninja"));
         cmakeValidator->hasCodeBlocksMsvcGenerator = response.contains(QLatin1String("CodeBlocks - NMake Makefiles"));
         cmakeValidator->version = versionRegexp.cap(1);
         if (!(versionRegexp.capturedTexts().size() > 3))
@@ -426,3 +434,13 @@ bool CMakeSettingsPage::hasCodeBlocksMsvcGenerator() const
     else
         return m_pathCmake.hasCodeBlocksMsvcGenerator;
 }
+
+bool CMakeSettingsPage::hasCodeBlocksNinjaGenerator() const
+{
+    if (!isCMakeExecutableValid())
+        return false;
+    if (m_userCmake.state == CMakeValidator::VALID)
+        return m_userCmake.hasCodeBlocksNinjaGenerator;
+    else
+        return m_pathCmake.hasCodeBlocksNinjaGenerator;
+}
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h
index 071963ac67f..0f52093e2a9 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h
@@ -78,6 +78,7 @@ public:
                        const Utils::Environment &env,
                        const QString &generator);
     bool hasCodeBlocksMsvcGenerator() const;
+    bool hasCodeBlocksNinjaGenerator() const;
     static QString findCbpFile(const QDir &);
 
     static QString findDumperLibrary(const Utils::Environment &env);
@@ -101,6 +102,7 @@ struct CMakeValidator
     STATE state;
     QProcess *process;
     bool hasCodeBlocksMsvcGenerator;
+    bool hasCodeBlocksNinjaGenerator;
     QString version;
     QString executable;
 };
@@ -121,6 +123,7 @@ public:
     void setCMakeExecutable(const QString &executable);
     bool isCMakeExecutableValid() const;
     bool hasCodeBlocksMsvcGenerator() const;
+    bool hasCodeBlocksNinjaGenerator() const;
 
 private slots:
     void userCmakeFinished();
diff --git a/src/plugins/cmakeprojectmanager/makestep.cpp b/src/plugins/cmakeprojectmanager/makestep.cpp
index ee3ebde7e9b..7c9bcd4b40f 100644
--- a/src/plugins/cmakeprojectmanager/makestep.cpp
+++ b/src/plugins/cmakeprojectmanager/makestep.cpp
@@ -63,6 +63,7 @@ const char MS_ID[] = "CMakeProjectManager.MakeStep";
 const char CLEAN_KEY[] = "CMakeProjectManager.MakeStep.Clean";
 const char BUILD_TARGETS_KEY[] = "CMakeProjectManager.MakeStep.BuildTargets";
 const char ADDITIONAL_ARGUMENTS_KEY[] = "CMakeProjectManager.MakeStep.AdditionalArguments";
+const char USE_NINJA_KEY[] = "CMakeProjectManager.MakeStep.UseNinja";
 }
 
 MakeStep::MakeStep(BuildStepList *bsl) :
@@ -92,8 +93,24 @@ MakeStep::MakeStep(BuildStepList *bsl, MakeStep *bs) :
 void MakeStep::ctor()
 {
     m_percentProgress = QRegExp("^\\[\\s*(\\d*)%\\]");
+    m_useNinja = false;
+    m_ninjaProgress = QRegExp ("^\\[\\s*(\\d*)/\\s*(\\d*)");
+    m_ninjaProgressString = QLatin1String("[%s/%t "); // ninja: [33/100
     //: Default display name for the cmake make step.
     setDefaultDisplayName(tr("Make"));
+
+    BuildConfiguration *bc = cmakeBuildConfiguration();
+    if (bc) {
+        m_activeConfiguration = 0;
+        connect(bc, SIGNAL(useNinjaChanged(bool)), this, SLOT(setUseNinja(bool)));
+    } else {
+        // That means the step is in the deploylist, so we listen to the active build config
+        // changed signal and react to the activeBuildConfigurationChanged() signal of the buildconfiguration
+        m_activeConfiguration = targetsActiveBuildConfiguration();
+        connect (target(), SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
+                 this, SLOT(activeBuildConfigurationChanged()));
+        activeBuildConfigurationChanged();
+    }
 }
 
 MakeStep::~MakeStep()
@@ -105,6 +122,24 @@ CMakeBuildConfiguration *MakeStep::cmakeBuildConfiguration() const
     return static_cast<CMakeBuildConfiguration *>(buildConfiguration());
 }
 
+CMakeBuildConfiguration *MakeStep::targetsActiveBuildConfiguration() const
+{
+    return static_cast<CMakeBuildConfiguration *>(target()->activeBuildConfiguration());
+}
+
+void MakeStep::activeBuildConfigurationChanged()
+{
+    if (m_activeConfiguration)
+        disconnect(m_activeConfiguration, SIGNAL(useNinjaChanged(bool)), this, SLOT(setUseNinja(bool)));
+
+    m_activeConfiguration = targetsActiveBuildConfiguration();
+
+    if (m_activeConfiguration) {
+        connect(m_activeConfiguration, SIGNAL(useNinjaChanged(bool)), this, SLOT(setUseNinja(bool)));
+        setUseNinja(m_activeConfiguration->useNinja());
+    }
+}
+
 void MakeStep::setClean(bool clean)
 {
     m_clean = clean;
@@ -116,6 +151,7 @@ QVariantMap MakeStep::toMap() const
     map.insert(QLatin1String(CLEAN_KEY), m_clean);
     map.insert(QLatin1String(BUILD_TARGETS_KEY), m_buildTargets);
     map.insert(QLatin1String(ADDITIONAL_ARGUMENTS_KEY), m_additionalArguments);
+    map.insert(QLatin1String(USE_NINJA_KEY), m_useNinja);
     return map;
 }
 
@@ -124,6 +160,7 @@ bool MakeStep::fromMap(const QVariantMap &map)
     m_clean = map.value(QLatin1String(CLEAN_KEY)).toBool();
     m_buildTargets = map.value(QLatin1String(BUILD_TARGETS_KEY)).toStringList();
     m_additionalArguments = map.value(QLatin1String(ADDITIONAL_ARGUMENTS_KEY)).toString();
+    m_useNinja = map.value(QLatin1String(USE_NINJA_KEY)).toBool();
 
     return BuildStep::fromMap(map);
 }
@@ -151,12 +188,16 @@ bool MakeStep::init()
 
     ProcessParameters *pp = processParameters();
     pp->setMacroExpander(bc->macroExpander());
-    pp->setEnvironment(bc->environment());
+    if (m_useNinja) {
+        Utils::Environment env = bc->environment();
+        if (!env.value(QLatin1String("NINJA_STATUS")).startsWith(m_ninjaProgressString))
+            env.set(QLatin1String("NINJA_STATUS"), m_ninjaProgressString + QLatin1String("%o/sec] "));
+        pp->setEnvironment(env);
+    } else {
+        pp->setEnvironment(bc->environment());
+    }
     pp->setWorkingDirectory(bc->buildDirectory());
-    if (tc)
-        pp->setCommand(tc->makeCommand(bc->environment()));
-    else
-        pp->setCommand(QLatin1String("make"));
+    pp->setCommand(makeCommand(tc, bc->environment()));
     pp->setArguments(arguments);
 
     setOutputParser(new ProjectExplorer::GnuMakeParser());
@@ -209,8 +250,21 @@ void MakeStep::stdOutput(const QString &line)
         int percent = m_percentProgress.cap(1).toInt(&ok);;
         if (ok)
             m_futureInterface->setProgressValue(percent);
+    } else if (m_ninjaProgress.indexIn(line) != -1) {
+        bool ok = false;
+        int done = m_ninjaProgress.cap(1).toInt(&ok);
+        if (ok) {
+            int all = m_ninjaProgress.cap(2).toInt(&ok);
+            if (ok && all != 0) {
+                int percent = 100.0 * done/all;
+                m_futureInterface->setProgressValue(percent);
+            }
+        }
     }
-    AbstractProcessStep::stdOutput(line);
+    if (m_useNinja)
+        AbstractProcessStep::stdError(line);
+    else
+        AbstractProcessStep::stdOutput(line);
 }
 
 QStringList MakeStep::buildTargets() const
@@ -253,6 +307,24 @@ void MakeStep::setAdditionalArguments(const QString &list)
     m_additionalArguments = list;
 }
 
+QString MakeStep::makeCommand(ProjectExplorer::ToolChain *tc, const Utils::Environment &env) const
+{
+    if (m_useNinja)
+        return QLatin1String("ninja");
+    if (tc)
+        return tc->makeCommand(env);
+
+    return QLatin1String("make");
+}
+
+void MakeStep::setUseNinja(bool useNinja)
+{
+    if (m_useNinja != useNinja) {
+        m_useNinja = useNinja;
+        emit makeCommandChanged();
+    }
+}
+
 //
 // MakeStepConfigWidget
 //
@@ -291,6 +363,7 @@ MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
     connect(pro, SIGNAL(buildTargetsChanged()),
             this, SLOT(buildTargetsChanged()));
     connect(pro, SIGNAL(environmentChanged()), this, SLOT(updateDetails()));
+    connect(m_makeStep, SIGNAL(makeCommandChanged()), this, SLOT(updateDetails()));
 }
 
 void MakeStepConfigWidget::additionalArgumentsEdited()
@@ -344,7 +417,7 @@ void MakeStepConfigWidget::updateDetails()
         param.setMacroExpander(bc->macroExpander());
         param.setEnvironment(bc->environment());
         param.setWorkingDirectory(bc->buildDirectory());
-        param.setCommand(tc->makeCommand(bc->environment()));
+        param.setCommand(m_makeStep->makeCommand(tc, bc->environment()));
         param.setArguments(arguments);
         m_summaryText = param.summary(displayName());
     } else {
diff --git a/src/plugins/cmakeprojectmanager/makestep.h b/src/plugins/cmakeprojectmanager/makestep.h
index b8342705e1a..d3c6a73c482 100644
--- a/src/plugins/cmakeprojectmanager/makestep.h
+++ b/src/plugins/cmakeprojectmanager/makestep.h
@@ -39,6 +39,10 @@ class QListWidget;
 class QListWidgetItem;
 QT_END_NAMESPACE
 
+namespace ProjectExplorer {
+class ToolChain;
+}
+
 namespace CMakeProjectManager {
 namespace Internal {
 
@@ -72,10 +76,18 @@ public:
     QString additionalArguments() const;
     void setAdditionalArguments(const QString &list);
 
+    QString makeCommand(ProjectExplorer::ToolChain *tc, const Utils::Environment &env) const;
+
     void setClean(bool clean);
 
     QVariantMap toMap() const;
 
+public slots:
+    void setUseNinja(bool);
+    void activeBuildConfigurationChanged();
+
+signals:
+    void makeCommandChanged();
 
 protected:
     MakeStep(ProjectExplorer::BuildStepList *bsl, MakeStep *bs);
@@ -88,13 +100,18 @@ protected:
 
 private:
     void ctor();
+    CMakeBuildConfiguration *targetsActiveBuildConfiguration() const;
 
     bool m_clean;
     QRegExp m_percentProgress;
+    QRegExp m_ninjaProgress;
+    QString m_ninjaProgressString;
     QFutureInterface<bool> *m_futureInterface;
     QStringList m_buildTargets;
     QString m_additionalArguments;
     QList<ProjectExplorer::Task> m_tasks;
+    bool m_useNinja;
+    CMakeBuildConfiguration *m_activeConfiguration;
 };
 
 class MakeStepConfigWidget :public ProjectExplorer::BuildStepConfigWidget
-- 
GitLab