From a354f60ce07cd67bd60161824a4e74bf9068fea4 Mon Sep 17 00:00:00 2001
From: Tobias Hunger <tobias.hunger@qt.io>
Date: Wed, 20 Jul 2016 18:28:39 +0200
Subject: Refactor extra generator registration to use factories

This will allow additional information about the availability
and capabilities of extra generators to be queried without
actually creating them.

Instead of a static NewFactory() method like the main generator
factories have, use a static GetFactory() method to get a pointer to a
statically allocated extra generator factory.  This simplifies memory
management.
---
 Source/cmExternalMakefileProjectGenerator.cxx |  49 +++++----
 Source/cmExternalMakefileProjectGenerator.h   |  55 ++++++++--
 Source/cmExtraCodeBlocksGenerator.cxx         |  28 +++--
 Source/cmExtraCodeBlocksGenerator.h           |  13 +--
 Source/cmExtraCodeLiteGenerator.cxx           |  28 +++--
 Source/cmExtraCodeLiteGenerator.h             |  13 +--
 Source/cmExtraEclipseCDT4Generator.cxx        |  33 +++---
 Source/cmExtraEclipseCDT4Generator.h          |  14 +--
 Source/cmExtraKateGenerator.cxx               |  26 +++--
 Source/cmExtraKateGenerator.h                 |  13 +--
 Source/cmExtraSublimeTextGenerator.cxx        |  30 +++---
 Source/cmExtraSublimeTextGenerator.h          |  14 +--
 Source/cmGlobalKdevelopGenerator.cxx          |  24 +++--
 Source/cmGlobalKdevelopGenerator.h            |  13 +--
 Source/cmake.cxx                              | 145 +++++++++++++++-----------
 Source/cmake.h                                |  13 +--
 16 files changed, 276 insertions(+), 235 deletions(-)

diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx
index 0e42d75..a527e50 100644
--- a/Source/cmExternalMakefileProjectGenerator.cxx
+++ b/Source/cmExternalMakefileProjectGenerator.cxx
@@ -33,28 +33,37 @@ std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
   return fullName;
 }
 
-std::string cmExternalMakefileProjectGenerator::GetGlobalGeneratorName(
-  const std::string& fullName)
+cmExternalMakefileProjectGeneratorFactory::
+  cmExternalMakefileProjectGeneratorFactory(const std::string& n,
+                                            const std::string& doc)
+  : Name(n)
+  , Documentation(doc)
 {
-  // at least one global generator must be supported
-  assert(!this->SupportedGlobalGenerators.empty());
+}
 
-  if (fullName.empty()) {
-    return "";
-  }
+cmExternalMakefileProjectGeneratorFactory::
+  ~cmExternalMakefileProjectGeneratorFactory()
+{
+}
 
-  // if we get only the short name, take the first global generator as default
-  if (fullName == this->GetName()) {
-    return this->SupportedGlobalGenerators[0];
-  }
+std::string cmExternalMakefileProjectGeneratorFactory::GetName() const
+{
+  return this->Name;
+}
 
-  // otherwise search for the matching global generator
-  for (std::vector<std::string>::const_iterator it =
-         this->SupportedGlobalGenerators.begin();
-       it != this->SupportedGlobalGenerators.end(); ++it) {
-    if (this->CreateFullGeneratorName(*it, this->GetName()) == fullName) {
-      return *it;
-    }
-  }
-  return "";
+std::string cmExternalMakefileProjectGeneratorFactory::GetDocumentation() const
+{
+  return this->Documentation;
+}
+
+std::vector<std::string>
+cmExternalMakefileProjectGeneratorFactory::GetSupportedGlobalGenerators() const
+{
+  return this->SupportedGlobalGenerators;
+}
+
+void cmExternalMakefileProjectGeneratorFactory::AddSupportedGlobalGenerator(
+  const std::string& base)
+{
+  this->SupportedGlobalGenerators.push_back(base);
 }
diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h
index 5d4d54d..6ae5533 100644
--- a/Source/cmExternalMakefileProjectGenerator.h
+++ b/Source/cmExternalMakefileProjectGenerator.h
@@ -35,11 +35,6 @@ class cmExternalMakefileProjectGenerator
 public:
   virtual ~cmExternalMakefileProjectGenerator() {}
 
-  ///! Get the name for this generator.
-  virtual std::string GetName() const = 0;
-  /** Get the documentation entry for this generator.  */
-  virtual void GetDocumentation(cmDocumentationEntry& entry,
-                                const std::string& fullName) const = 0;
   virtual void EnableLanguage(std::vector<std::string> const& languages,
                               cmMakefile*, bool optional);
 
@@ -55,8 +50,6 @@ public:
     return this->SupportedGlobalGenerators;
   }
 
-  ///! Get the name of the global generator for the given full name
-  std::string GetGlobalGeneratorName(const std::string& fullName);
   /** Create a full name from the given global generator name and the
    * extra generator name
    */
@@ -66,11 +59,59 @@ public:
   ///! Generate the project files, the Makefiles have already been generated
   virtual void Generate() = 0;
 
+  void SetName(const std::string& n) { Name = n; }
+  std::string GetName() const { return Name; }
+
 protected:
   ///! Contains the names of the global generators support by this generator.
   std::vector<std::string> SupportedGlobalGenerators;
   ///! the global generator which creates the makefiles
   const cmGlobalGenerator* GlobalGenerator;
+
+  std::string Name;
+};
+
+class cmExternalMakefileProjectGeneratorFactory
+{
+public:
+  cmExternalMakefileProjectGeneratorFactory(const std::string& n,
+                                            const std::string& doc);
+  virtual ~cmExternalMakefileProjectGeneratorFactory();
+
+  std::string GetName() const;
+  std::string GetDocumentation() const;
+  std::vector<std::string> GetSupportedGlobalGenerators() const;
+  std::vector<std::string> Aliases;
+
+  virtual cmExternalMakefileProjectGenerator*
+  CreateExternalMakefileProjectGenerator() const = 0;
+
+  void AddSupportedGlobalGenerator(const std::string& base);
+
+private:
+  std::string Name;
+  std::string Documentation;
+  std::vector<std::string> SupportedGlobalGenerators;
+};
+
+template <class T>
+class cmExternalMakefileProjectGeneratorSimpleFactory
+  : public cmExternalMakefileProjectGeneratorFactory
+{
+public:
+  cmExternalMakefileProjectGeneratorSimpleFactory(const std::string& n,
+                                                  const std::string& doc)
+    : cmExternalMakefileProjectGeneratorFactory(n, doc)
+  {
+  }
+
+  cmExternalMakefileProjectGenerator* CreateExternalMakefileProjectGenerator()
+    const
+  {
+    T* p = new T;
+    p->SetName(GetName());
+    return p;
+  }
 };
 
 #endif
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index fbfbccc..3a9bb9b 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -36,24 +36,30 @@ Discussion:
 http://forums.codeblocks.org/index.php/topic,6789.0.html
 */
 
-void cmExtraCodeBlocksGenerator::GetDocumentation(cmDocumentationEntry& entry,
-                                                  const std::string&) const
+cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator()
+  : cmExternalMakefileProjectGenerator()
 {
-  entry.Name = this->GetName();
-  entry.Brief = "Generates CodeBlocks project files.";
 }
 
-cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator()
-  : cmExternalMakefileProjectGenerator()
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraCodeBlocksGenerator::GetFactory()
 {
+  static cmExternalMakefileProjectGeneratorSimpleFactory<
+    cmExtraCodeBlocksGenerator>
+    factory("CodeBlocks", "Generates CodeBlocks project files.");
+
+  if (factory.GetSupportedGlobalGenerators().empty()) {
 #if defined(_WIN32)
-  this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
-  this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+    factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+    factory.AddSupportedGlobalGenerator("NMake Makefiles");
 // disable until somebody actually tests it:
-//  this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
+// this->AddSupportedGlobalGenerator("MSYS Makefiles");
 #endif
-  this->SupportedGlobalGenerators.push_back("Ninja");
-  this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+    factory.AddSupportedGlobalGenerator("Ninja");
+    factory.AddSupportedGlobalGenerator("Unix Makefiles");
+  }
+
+  return &factory;
 }
 
 void cmExtraCodeBlocksGenerator::Generate()
diff --git a/Source/cmExtraCodeBlocksGenerator.h b/Source/cmExtraCodeBlocksGenerator.h
index 31ea500..b39080c 100644
--- a/Source/cmExtraCodeBlocksGenerator.h
+++ b/Source/cmExtraCodeBlocksGenerator.h
@@ -28,18 +28,7 @@ class cmExtraCodeBlocksGenerator : public cmExternalMakefileProjectGenerator
 public:
   cmExtraCodeBlocksGenerator();
 
-  std::string GetName() const CM_OVERRIDE
-  {
-    return cmExtraCodeBlocksGenerator::GetActualName();
-  }
-  static std::string GetActualName() { return "CodeBlocks"; }
-  static cmExternalMakefileProjectGenerator* New()
-  {
-    return new cmExtraCodeBlocksGenerator;
-  }
-  /** Get the documentation entry for this generator.  */
-  void GetDocumentation(cmDocumentationEntry& entry,
-                        const std::string& fullName) const CM_OVERRIDE;
+  static cmExternalMakefileProjectGeneratorFactory* GetFactory();
 
   void Generate() CM_OVERRIDE;
 
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index dd10b65..eda6867 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -27,24 +27,30 @@
 #include <cmsys/SystemInformation.hxx>
 #include <cmsys/SystemTools.hxx>
 
-void cmExtraCodeLiteGenerator::GetDocumentation(cmDocumentationEntry& entry,
-                                                const std::string&) const
-{
-  entry.Name = this->GetName();
-  entry.Brief = "Generates CodeLite project files.";
-}
-
 cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator()
   : cmExternalMakefileProjectGenerator()
   , ConfigName("NoConfig")
   , CpuCount(2)
 {
+}
+
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraCodeLiteGenerator::GetFactory()
+{
+  static cmExternalMakefileProjectGeneratorSimpleFactory<
+    cmExtraCodeLiteGenerator>
+    factory("CodeLite", "Generates CodeLite project files.");
+
+  if (factory.GetSupportedGlobalGenerators().empty()) {
 #if defined(_WIN32)
-  this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
-  this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+    factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+    factory.AddSupportedGlobalGenerator("NMake Makefiles");
 #endif
-  this->SupportedGlobalGenerators.push_back("Ninja");
-  this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+    factory.AddSupportedGlobalGenerator("Ninja");
+    factory.AddSupportedGlobalGenerator("Unix Makefiles");
+  }
+
+  return &factory;
 }
 
 void cmExtraCodeLiteGenerator::Generate()
diff --git a/Source/cmExtraCodeLiteGenerator.h b/Source/cmExtraCodeLiteGenerator.h
index f2ee85c..e20e745 100644
--- a/Source/cmExtraCodeLiteGenerator.h
+++ b/Source/cmExtraCodeLiteGenerator.h
@@ -36,18 +36,7 @@ protected:
 public:
   cmExtraCodeLiteGenerator();
 
-  std::string GetName() const CM_OVERRIDE
-  {
-    return cmExtraCodeLiteGenerator::GetActualName();
-  }
-  static std::string GetActualName() { return "CodeLite"; }
-  static cmExternalMakefileProjectGenerator* New()
-  {
-    return new cmExtraCodeLiteGenerator;
-  }
-  /** Get the documentation entry for this generator.  */
-  void GetDocumentation(cmDocumentationEntry& entry,
-                        const std::string& fullName) const CM_OVERRIDE;
+  static cmExternalMakefileProjectGeneratorFactory* GetFactory();
 
   void Generate() CM_OVERRIDE;
   void CreateProjectFile(const std::vector<cmLocalGenerator*>& lgs);
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index 93c55cc..8091bcf 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -46,16 +46,6 @@ void AppendDictionary(cmXMLWriter& xml, const char* key, T const& value)
 cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator()
   : cmExternalMakefileProjectGenerator()
 {
-// TODO: Verify if __CYGWIN__ should be checked.
-//#if defined(_WIN32) && !defined(__CYGWIN__)
-#if defined(_WIN32)
-  this->SupportedGlobalGenerators.push_back("NMake Makefiles");
-  this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
-//  this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
-#endif
-  this->SupportedGlobalGenerators.push_back("Ninja");
-  this->SupportedGlobalGenerators.push_back("Unix Makefiles");
-
   this->SupportsVirtualFolders = true;
   this->GenerateLinkedResources = true;
   this->SupportsGmakeErrorParser = true;
@@ -64,11 +54,26 @@ cmExtraEclipseCDT4Generator::cmExtraEclipseCDT4Generator()
   this->CXXEnabled = false;
 }
 
-void cmExtraEclipseCDT4Generator::GetDocumentation(cmDocumentationEntry& entry,
-                                                   const std::string&) const
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraEclipseCDT4Generator::GetFactory()
 {
-  entry.Name = this->GetName();
-  entry.Brief = "Generates Eclipse CDT 4.0 project files.";
+  static cmExternalMakefileProjectGeneratorSimpleFactory<
+    cmExtraEclipseCDT4Generator>
+    factory("Eclipse CDT4", "Generates Eclipse CDT 4.0 project files.");
+
+  if (factory.GetSupportedGlobalGenerators().empty()) {
+// TODO: Verify if __CYGWIN__ should be checked.
+//#if defined(_WIN32) && !defined(__CYGWIN__)
+#if defined(_WIN32)
+    factory.AddSupportedGlobalGenerator("NMake Makefiles");
+    factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+// factory.AddSupportedGlobalGenerator("MSYS Makefiles");
+#endif
+    factory.AddSupportedGlobalGenerator("Ninja");
+    factory.AddSupportedGlobalGenerator("Unix Makefiles");
+  }
+
+  return &factory;
 }
 
 void cmExtraEclipseCDT4Generator::EnableLanguage(
diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h
index 0400ad5..4b585c3 100644
--- a/Source/cmExtraEclipseCDT4Generator.h
+++ b/Source/cmExtraEclipseCDT4Generator.h
@@ -35,20 +35,8 @@ public:
 
   cmExtraEclipseCDT4Generator();
 
-  static cmExternalMakefileProjectGenerator* New()
-  {
-    return new cmExtraEclipseCDT4Generator;
-  }
-
-  std::string GetName() const CM_OVERRIDE
-  {
-    return cmExtraEclipseCDT4Generator::GetActualName();
-  }
-
-  static std::string GetActualName() { return "Eclipse CDT4"; }
+  static cmExternalMakefileProjectGeneratorFactory* GetFactory();
 
-  void GetDocumentation(cmDocumentationEntry& entry,
-                        const std::string& fullName) const CM_OVERRIDE;
   void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
                       bool optional) CM_OVERRIDE;
 
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index b757a49..4e72504 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -22,24 +22,28 @@
 
 #include <cmsys/SystemTools.hxx>
 
-void cmExtraKateGenerator::GetDocumentation(cmDocumentationEntry& entry,
-                                            const std::string&) const
+cmExtraKateGenerator::cmExtraKateGenerator()
+  : cmExternalMakefileProjectGenerator()
 {
-  entry.Name = this->GetName();
-  entry.Brief = "Generates Kate project files.";
 }
 
-cmExtraKateGenerator::cmExtraKateGenerator()
-  : cmExternalMakefileProjectGenerator()
+cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::GetFactory()
 {
+  static cmExternalMakefileProjectGeneratorSimpleFactory<cmExtraKateGenerator>
+    factory("Kate", "Generates Kate project files.");
+
+  if (factory.GetSupportedGlobalGenerators().empty()) {
 #if defined(_WIN32)
-  this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
-  this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+    factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+    factory.AddSupportedGlobalGenerator("NMake Makefiles");
 // disable until somebody actually tests it:
-//  this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
+// factory.AddSupportedGlobalGenerator("MSYS Makefiles");
 #endif
-  this->SupportedGlobalGenerators.push_back("Ninja");
-  this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+    factory.AddSupportedGlobalGenerator("Ninja");
+    factory.AddSupportedGlobalGenerator("Unix Makefiles");
+  }
+
+  return &factory;
 }
 
 void cmExtraKateGenerator::Generate()
diff --git a/Source/cmExtraKateGenerator.h b/Source/cmExtraKateGenerator.h
index 410d552..3d16052 100644
--- a/Source/cmExtraKateGenerator.h
+++ b/Source/cmExtraKateGenerator.h
@@ -26,18 +26,7 @@ class cmExtraKateGenerator : public cmExternalMakefileProjectGenerator
 public:
   cmExtraKateGenerator();
 
-  std::string GetName() const CM_OVERRIDE
-  {
-    return cmExtraKateGenerator::GetActualName();
-  }
-  static std::string GetActualName() { return "Kate"; }
-  static cmExternalMakefileProjectGenerator* New()
-  {
-    return new cmExtraKateGenerator;
-  }
-  /** Get the documentation entry for this generator.  */
-  void GetDocumentation(cmDocumentationEntry& entry,
-                        const std::string& fullName) const CM_OVERRIDE;
+  static cmExternalMakefileProjectGeneratorFactory* GetFactory();
 
   void Generate() CM_OVERRIDE;
 
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index c166e26..b6bad60 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -38,24 +38,30 @@ http://www.sublimetext.com/docs/2/projects.html
 http://sublimetext.info/docs/en/reference/build_systems.html
 */
 
-void cmExtraSublimeTextGenerator::GetDocumentation(cmDocumentationEntry& entry,
-                                                   const std::string&) const
+cmExternalMakefileProjectGeneratorFactory*
+cmExtraSublimeTextGenerator::GetFactory()
 {
-  entry.Name = this->GetName();
-  entry.Brief = "Generates Sublime Text 2 project files.";
+  static cmExternalMakefileProjectGeneratorSimpleFactory<
+    cmExtraSublimeTextGenerator>
+    factory("Sublime Text 2", "Generates Sublime Text 2 project files.");
+
+  if (factory.GetSupportedGlobalGenerators().empty()) {
+#if defined(_WIN32)
+    factory.AddSupportedGlobalGenerator("MinGW Makefiles");
+    factory.AddSupportedGlobalGenerator("NMake Makefiles");
+// disable until somebody actually tests it:
+// factory.AddSupportedGlobalGenerator("MSYS Makefiles");
+#endif
+    factory.AddSupportedGlobalGenerator("Ninja");
+    factory.AddSupportedGlobalGenerator("Unix Makefiles");
+  }
+
+  return &factory;
 }
 
 cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator()
   : cmExternalMakefileProjectGenerator()
 {
-#if defined(_WIN32)
-  this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
-  this->SupportedGlobalGenerators.push_back("NMake Makefiles");
-// disable until somebody actually tests it:
-//  this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
-#endif
-  this->SupportedGlobalGenerators.push_back("Ninja");
-  this->SupportedGlobalGenerators.push_back("Unix Makefiles");
 }
 
 void cmExtraSublimeTextGenerator::Generate()
diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h
index 26dd138..c087825 100644
--- a/Source/cmExtraSublimeTextGenerator.h
+++ b/Source/cmExtraSublimeTextGenerator.h
@@ -27,22 +27,10 @@ class cmGeneratorTarget;
 class cmExtraSublimeTextGenerator : public cmExternalMakefileProjectGenerator
 {
 public:
+  static cmExternalMakefileProjectGeneratorFactory* GetFactory();
   typedef std::map<std::string, std::vector<std::string> > MapSourceFileFlags;
   cmExtraSublimeTextGenerator();
 
-  std::string GetName() const CM_OVERRIDE
-  {
-    return cmExtraSublimeTextGenerator::GetActualName();
-  }
-  static std::string GetActualName() { return "Sublime Text 2"; }
-  static cmExternalMakefileProjectGenerator* New()
-  {
-    return new cmExtraSublimeTextGenerator;
-  }
-  /** Get the documentation entry for this generator.  */
-  void GetDocumentation(cmDocumentationEntry& entry,
-                        const std::string& fullName) const CM_OVERRIDE;
-
   void Generate() CM_OVERRIDE;
 
 private:
diff --git a/Source/cmGlobalKdevelopGenerator.cxx b/Source/cmGlobalKdevelopGenerator.cxx
index bbd6baa..daf7003 100644
--- a/Source/cmGlobalKdevelopGenerator.cxx
+++ b/Source/cmGlobalKdevelopGenerator.cxx
@@ -25,20 +25,28 @@
 #include <cmsys/FStream.hxx>
 #include <cmsys/SystemTools.hxx>
 
-void cmGlobalKdevelopGenerator::GetDocumentation(cmDocumentationEntry& entry,
-                                                 const std::string&) const
+cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator()
+  : cmExternalMakefileProjectGenerator()
 {
-  entry.Name = this->GetName();
-  entry.Brief = "Generates KDevelop 3 project files.";
 }
 
-cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator()
-  : cmExternalMakefileProjectGenerator()
+cmExternalMakefileProjectGeneratorFactory*
+cmGlobalKdevelopGenerator::GetFactory()
 {
-  this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+  static cmExternalMakefileProjectGeneratorSimpleFactory<
+    cmGlobalKdevelopGenerator>
+    factory("KDevelop3", "Generates KDevelop 3 project files.");
+
+  if (factory.GetSupportedGlobalGenerators().empty()) {
+    factory.AddSupportedGlobalGenerator("Unix Makefiles");
 #ifdef CMAKE_USE_NINJA
-  this->SupportedGlobalGenerators.push_back("Ninja");
+    factory.AddSupportedGlobalGenerator("Ninja");
 #endif
+
+    factory.Aliases.push_back("KDevelop3");
+  }
+
+  return &factory;
 }
 
 void cmGlobalKdevelopGenerator::Generate()
diff --git a/Source/cmGlobalKdevelopGenerator.h b/Source/cmGlobalKdevelopGenerator.h
index c61cafb..666527c 100644
--- a/Source/cmGlobalKdevelopGenerator.h
+++ b/Source/cmGlobalKdevelopGenerator.h
@@ -33,18 +33,7 @@ class cmGlobalKdevelopGenerator : public cmExternalMakefileProjectGenerator
 public:
   cmGlobalKdevelopGenerator();
 
-  std::string GetName() const CM_OVERRIDE
-  {
-    return cmGlobalKdevelopGenerator::GetActualName();
-  }
-  static std::string GetActualName() { return "KDevelop3"; }
-  static cmExternalMakefileProjectGenerator* New()
-  {
-    return new cmGlobalKdevelopGenerator;
-  }
-  /** Get the documentation entry for this generator.  */
-  void GetDocumentation(cmDocumentationEntry& entry,
-                        const std::string& fullName) const CM_OVERRIDE;
+  static cmExternalMakefileProjectGeneratorFactory* GetFactory();
 
   void Generate() CM_OVERRIDE;
 
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index cdc1284..fb77043 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -793,53 +793,21 @@ int cmake::AddCMakePaths()
   return 1;
 }
 
-void cmake::AddExtraGenerator(const std::string& name,
-                              CreateExtraGeneratorFunctionType newFunction)
-{
-  cmExternalMakefileProjectGenerator* extraGenerator = newFunction();
-  const std::vector<std::string>& supportedGlobalGenerators =
-    extraGenerator->GetSupportedGlobalGenerators();
-
-  for (std::vector<std::string>::const_iterator it =
-         supportedGlobalGenerators.begin();
-       it != supportedGlobalGenerators.end(); ++it) {
-    std::string fullName =
-      cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*it, name);
-    this->ExtraGenerators[fullName] = newFunction;
-  }
-  delete extraGenerator;
-}
-
 void cmake::AddDefaultExtraGenerators()
 {
 #if defined(CMAKE_BUILD_WITH_CMAKE)
-#if defined(_WIN32) && !defined(__CYGWIN__)
-// e.g. kdevelop4 ?
-#endif
-
-  this->AddExtraGenerator(cmExtraCodeBlocksGenerator::GetActualName(),
-                          &cmExtraCodeBlocksGenerator::New);
-  this->AddExtraGenerator(cmExtraCodeLiteGenerator::GetActualName(),
-                          &cmExtraCodeLiteGenerator::New);
-  this->AddExtraGenerator(cmExtraSublimeTextGenerator::GetActualName(),
-                          &cmExtraSublimeTextGenerator::New);
-  this->AddExtraGenerator(cmExtraKateGenerator::GetActualName(),
-                          &cmExtraKateGenerator::New);
+  this->ExtraGenerators.push_back(cmExtraCodeBlocksGenerator::GetFactory());
+  this->ExtraGenerators.push_back(cmExtraCodeLiteGenerator::GetFactory());
+  this->ExtraGenerators.push_back(cmExtraSublimeTextGenerator::GetFactory());
+  this->ExtraGenerators.push_back(cmExtraKateGenerator::GetFactory());
 
 #ifdef CMAKE_USE_ECLIPSE
-  this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(),
-                          &cmExtraEclipseCDT4Generator::New);
+  this->ExtraGenerators.push_back(cmExtraEclipseCDT4Generator::GetFactory());
 #endif
 
 #ifdef CMAKE_USE_KDEVELOP
-  this->AddExtraGenerator(cmGlobalKdevelopGenerator::GetActualName(),
-                          &cmGlobalKdevelopGenerator::New);
-  // for kdevelop also add the generator with just the name of the
-  // extra generator, since it was this way since cmake 2.2
-  this->ExtraGenerators[cmGlobalKdevelopGenerator::GetActualName()] =
-    &cmGlobalKdevelopGenerator::New;
+  this->ExtraGenerators.push_back(cmGlobalKdevelopGenerator::GetFactory());
 #endif
-
 #endif
 }
 
@@ -856,32 +824,74 @@ void cmake::GetRegisteredGenerators(std::vector<GeneratorInfo>& generators)
       info.supportsToolset = (*i)->SupportsToolset();
       info.supportsPlatform = (*i)->SupportsPlatform();
       info.name = names[j];
+      info.isAlias = false;
       generators.push_back(info);
     }
   }
 
-  for (RegisteredExtraGeneratorsMap::const_iterator
+  for (RegisteredExtraGeneratorsVector::const_iterator
          i = this->ExtraGenerators.begin(),
          e = this->ExtraGenerators.end();
        i != e; ++i) {
-    GeneratorInfo info;
-    info.name = i->first;
-    info.supportsToolset = false;
-    info.supportsPlatform = false;
-    generators.push_back(info);
+    const std::vector<std::string> genList =
+      (*i)->GetSupportedGlobalGenerators();
+    for (std::vector<std::string>::const_iterator gen = genList.begin();
+         gen != genList.end(); ++gen) {
+      GeneratorInfo info;
+      info.name = cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+        (*i)->GetName(), *gen);
+      info.supportsPlatform = false;
+      info.supportsToolset = false;
+      info.isAlias = false;
+      generators.push_back(info);
+    }
+    for (std::vector<std::string>::const_iterator a = (*i)->Aliases.begin();
+         a != (*i)->Aliases.end(); ++a) {
+      GeneratorInfo info;
+      info.name = *a;
+      info.supportsPlatform = false;
+      info.supportsToolset = false;
+      info.isAlias = true;
+      generators.push_back(info);
+    }
   }
 }
 
-cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname)
+static std::pair<cmExternalMakefileProjectGenerator*, std::string>
+createExtraGenerator(
+  const std::vector<cmExternalMakefileProjectGeneratorFactory*>& in,
+  const std::string& name)
 {
-  cmExternalMakefileProjectGenerator* extraGenerator = CM_NULLPTR;
-  std::string name = gname;
-  RegisteredExtraGeneratorsMap::const_iterator extraGenIt =
-    this->ExtraGenerators.find(name);
-  if (extraGenIt != this->ExtraGenerators.end()) {
-    extraGenerator = (extraGenIt->second)();
-    name = extraGenerator->GetGlobalGeneratorName(name);
+  for (std::vector<cmExternalMakefileProjectGeneratorFactory*>::const_iterator
+         i = in.begin();
+       i != in.end(); ++i) {
+    const std::vector<std::string> generators =
+      (*i)->GetSupportedGlobalGenerators();
+    if ((*i)->GetName() == name) { // Match aliases
+      return std::make_pair((*i)->CreateExternalMakefileProjectGenerator(),
+                            generators.at(0));
+    }
+    for (std::vector<std::string>::const_iterator g = generators.begin();
+         g != generators.end(); ++g) {
+      const std::string fullName =
+        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+          *g, (*i)->GetName());
+      if (fullName == name) {
+        return std::make_pair((*i)->CreateExternalMakefileProjectGenerator(),
+                              *g);
+      }
+    }
   }
+  return std::make_pair(
+    static_cast<cmExternalMakefileProjectGenerator*>(CM_NULLPTR), name);
+}
+
+cmGlobalGenerator* cmake::CreateGlobalGenerator(const std::string& gname)
+{
+  std::pair<cmExternalMakefileProjectGenerator*, std::string> extra =
+    createExtraGenerator(this->ExtraGenerators, gname);
+  cmExternalMakefileProjectGenerator* extraGenerator = extra.first;
+  const std::string name = extra.second;
 
   cmGlobalGenerator* generator = CM_NULLPTR;
   for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin();
@@ -1651,15 +1661,32 @@ void cmake::GetGeneratorDocumentation(std::vector<cmDocumentationEntry>& v)
     (*i)->GetDocumentation(e);
     v.push_back(e);
   }
-  for (RegisteredExtraGeneratorsMap::const_iterator i =
+  for (RegisteredExtraGeneratorsVector::const_iterator i =
          this->ExtraGenerators.begin();
        i != this->ExtraGenerators.end(); ++i) {
-    cmDocumentationEntry e;
-    cmExternalMakefileProjectGenerator* generator = (i->second)();
-    generator->GetDocumentation(e, i->first);
-    e.Name = i->first;
-    delete generator;
-    v.push_back(e);
+    const std::string doc = (*i)->GetDocumentation();
+    const std::string name = (*i)->GetName();
+
+    // Aliases:
+    for (std::vector<std::string>::const_iterator a = (*i)->Aliases.begin();
+         a != (*i)->Aliases.end(); ++a) {
+      cmDocumentationEntry e;
+      e.Name = *a;
+      e.Brief = doc;
+      v.push_back(e);
+    }
+
+    // Full names:
+    const std::vector<std::string> generators =
+      (*i)->GetSupportedGlobalGenerators();
+    for (std::vector<std::string>::const_iterator g = generators.begin();
+         g != generators.end(); ++g) {
+      cmDocumentationEntry e;
+      e.Name =
+        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*g, name);
+      e.Brief = doc;
+      v.push_back(e);
+    }
   }
 }
 
diff --git a/Source/cmake.h b/Source/cmake.h
index 4ca2a80..0fd2d31 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -27,7 +27,7 @@ class cmLocalGenerator;
 class cmMakefile;
 class cmVariableWatch;
 class cmFileTimeComparison;
-class cmExternalMakefileProjectGenerator;
+class cmExternalMakefileProjectGeneratorFactory;
 class cmDocumentationSection;
 class cmTarget;
 class cmGeneratedFileStream;
@@ -105,6 +105,7 @@ public:
     std::string name;
     bool supportsToolset;
     bool supportsPlatform;
+    bool isAlias;
   };
 
   typedef std::map<std::string, cmInstalledFile> InstalledFilesMap;
@@ -416,18 +417,14 @@ protected:
   void InitializeProperties();
   int HandleDeleteCacheVariables(const std::string& var);
 
-  typedef cmExternalMakefileProjectGenerator* (
-    *CreateExtraGeneratorFunctionType)();
-  typedef std::map<std::string, CreateExtraGeneratorFunctionType>
-    RegisteredExtraGeneratorsMap;
   typedef std::vector<cmGlobalGeneratorFactory*> RegisteredGeneratorsVector;
   RegisteredGeneratorsVector Generators;
-  RegisteredExtraGeneratorsMap ExtraGenerators;
+  typedef std::vector<cmExternalMakefileProjectGeneratorFactory*>
+    RegisteredExtraGeneratorsVector;
+  RegisteredExtraGeneratorsVector ExtraGenerators;
   void AddDefaultCommands();
   void AddDefaultGenerators();
   void AddDefaultExtraGenerators();
-  void AddExtraGenerator(const std::string& name,
-                         CreateExtraGeneratorFunctionType newFunction);
 
   cmGlobalGenerator* GlobalGenerator;
   std::map<std::string, DiagLevel> DiagLevels;
-- 
cgit v0.12