[cmake-developers] [PATCH 3/3] Add the Ninja generator

Peter Collingbourne peter at pcc.me.uk
Fri Nov 11 21:36:07 EST 2011


---
 Modules/CMakeNinjaFindMake.cmake                   |   17 +
 Modules/Compiler/GNU.cmake                         |    9 +
 Modules/ExternalProject.cmake                      |   19 +-
 Source/CMakeLists.txt                              |   18 +
 Source/cmGlobalNinjaGenerator.cxx                  |  772 ++++++++++++++++++++
 Source/cmGlobalNinjaGenerator.h                    |  329 +++++++++
 Source/cmLocalNinjaGenerator.cxx                   |  413 +++++++++++
 Source/cmLocalNinjaGenerator.h                     |  134 ++++
 Source/cmNinjaNormalTargetGenerator.cxx            |  402 ++++++++++
 Source/cmNinjaNormalTargetGenerator.h              |   47 ++
 Source/cmNinjaTargetGenerator.cxx                  |  445 +++++++++++
 Source/cmNinjaTargetGenerator.h                    |  115 +++
 Source/cmNinjaTypes.h                              |   19 +
 Source/cmNinjaUtilityTargetGenerator.cxx           |   99 +++
 Source/cmNinjaUtilityTargetGenerator.h             |   30 +
 Source/cmake.cxx                                   |    8 +
 Tests/BuildDepends/CMakeLists.txt                  |    2 +
 Tests/CMakeLists.txt                               |   14 +-
 Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt |    6 +
 19 files changed, 2894 insertions(+), 4 deletions(-)
 create mode 100644 Modules/CMakeNinjaFindMake.cmake
 create mode 100644 Source/cmGlobalNinjaGenerator.cxx
 create mode 100644 Source/cmGlobalNinjaGenerator.h
 create mode 100644 Source/cmLocalNinjaGenerator.cxx
 create mode 100644 Source/cmLocalNinjaGenerator.h
 create mode 100644 Source/cmNinjaNormalTargetGenerator.cxx
 create mode 100644 Source/cmNinjaNormalTargetGenerator.h
 create mode 100644 Source/cmNinjaTargetGenerator.cxx
 create mode 100644 Source/cmNinjaTargetGenerator.h
 create mode 100644 Source/cmNinjaTypes.h
 create mode 100644 Source/cmNinjaUtilityTargetGenerator.cxx
 create mode 100644 Source/cmNinjaUtilityTargetGenerator.h

diff --git a/Modules/CMakeNinjaFindMake.cmake b/Modules/CMakeNinjaFindMake.cmake
new file mode 100644
index 0000000..f15c3e0
--- /dev/null
+++ b/Modules/CMakeNinjaFindMake.cmake
@@ -0,0 +1,17 @@
+
+#=============================================================================
+# Copyright 2011 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+FIND_PROGRAM(CMAKE_MAKE_PROGRAM ninja
+  DOC "Program used to build from build.ninja files.")
+MARK_AS_ADVANCED(CMAKE_MAKE_PROGRAM)
diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake
index 8d6f5df..bdcaf9d 100644
--- a/Modules/Compiler/GNU.cmake
+++ b/Modules/Compiler/GNU.cmake
@@ -24,6 +24,15 @@ macro(__compiler_gnu lang)
   set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
 
+  # Older versions of gcc (< 4.5) contain a bug causing them to report a missing
+  # header file as a warning if depfiles are enabled, causing check_header_file
+  # tests to always succeed.  Work around this by disabling dependency tracking
+  # in try_compile mode.
+  GET_PROPERTY(_IN_TC GLOBAL PROPERTY IN_TRY_COMPILE)
+  if(NOT _IN_TC OR CMAKE_FORCE_DEPFILES)
+    set(CMAKE_DEPFILE_FLAGS_${lang} "-MMD -MF <DEPFILE>")
+  endif()
+
   # Initial configuration flags.
   set(CMAKE_${lang}_FLAGS_INIT "")
   set(CMAKE_${lang}_FLAGS_DEBUG_INIT "-g")
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index a37771b..d8c5b9a 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -833,6 +833,12 @@ function(ExternalProject_Add_StepTargets name)
   foreach(step ${steps})
     add_custom_target(${name}-${step}
       DEPENDS ${stamp_dir}${cfgdir}/${name}-${step})
+
+    # Depend on other external projects (target-level).
+    get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
+    foreach(arg IN LISTS deps)
+      add_dependencies(${name}-${step} ${arg})
+    endforeach()
   endforeach()
 endfunction(ExternalProject_Add_StepTargets)
 
@@ -1450,9 +1456,18 @@ function(ExternalProject_Add name)
   # depends on the 'done' mark so that it rebuilds when this project
   # rebuilds.  It is important that 'done' is not the output of any
   # custom command so that CMake does not propagate build rules to
-  # other external project targets.
+  # other external project targets, which may cause problems during
+  # parallel builds.  However, the Ninja generator needs to see the entire
+  # dependency graph, and can cope with custom commands belonging to
+  # multiple targets, so we add the 'done' mark as an output for Ninja only.
+  set(complete_outputs ${cmf_dir}${cfgdir}/${name}-complete)
+  if(${CMAKE_GENERATOR} MATCHES "Ninja")
+    set(complete_outputs
+        ${complete_outputs} ${stamp_dir}${cfgdir}/${name}-done)
+  endif()
+
   add_custom_command(
-    OUTPUT ${cmf_dir}${cfgdir}/${name}-complete
+    OUTPUT ${complete_outputs}
     COMMENT "Completed '${name}'"
     COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir}
     COMMAND ${CMAKE_COMMAND} -E touch ${cmf_dir}${cfgdir}/${name}-complete
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index ba41d98..95725ba 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -346,6 +346,24 @@ IF (WIN32)
   ENDIF(NOT UNIX)
 ENDIF (WIN32)
 
+# Ninja only works on UNIX.
+IF(UNIX)
+  SET(SRCS ${SRCS}
+    cmGlobalNinjaGenerator.cxx
+    cmGlobalNinjaGenerator.h
+    cmNinjaTypes.h
+    cmLocalNinjaGenerator.cxx
+    cmLocalNinjaGenerator.h
+    cmNinjaTargetGenerator.cxx
+    cmNinjaTargetGenerator.h
+    cmNinjaNormalTargetGenerator.cxx
+    cmNinjaNormalTargetGenerator.h
+    cmNinjaUtilityTargetGenerator.cxx
+    cmNinjaUtilityTargetGenerator.h
+    )
+  ADD_DEFINITIONS(-DCMAKE_USE_NINJA)
+ENDIF(UNIX)
+
 # create a library used by the command line and the GUI
 ADD_LIBRARY(CMakeLib ${SRCS})
 TARGET_LINK_LIBRARIES(CMakeLib cmsys
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
new file mode 100644
index 0000000..2579c3c
--- /dev/null
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -0,0 +1,772 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmGeneratedFileStream.h"
+#include "cmVersion.h"
+
+const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
+const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja";
+const char* cmGlobalNinjaGenerator::INDENT = "  ";
+
+void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count)
+{
+  for(int i = 0; i < count; ++i)
+    os << cmGlobalNinjaGenerator::INDENT;
+}
+
+void cmGlobalNinjaGenerator::WriteDivider(std::ostream& os)
+{
+  os
+    << "# ======================================"
+    << "=======================================\n";
+}
+
+void cmGlobalNinjaGenerator::WriteComment(std::ostream& os,
+                                          const std::string& comment)
+{
+  if (comment.empty())
+    return;
+
+  std::string replace = comment;
+  std::string::size_type lpos = 0;
+  std::string::size_type rpos;
+  while((rpos = replace.find('\n', lpos)) != std::string::npos)
+    {
+    os << "# " << replace.substr(lpos, rpos - lpos) << "\n";
+    lpos = rpos + 1;
+    }
+  os << "# " << replace.substr(lpos) << "\n";
+}
+
+static bool IsIdentChar(char c)
+{
+  return
+    ('a' <= c && c <= 'z') ||
+    ('+' <= c && c <= '9') ||  // +,-./ and numbers
+    ('A' <= c && c <= 'Z') ||
+    (c == '_') || (c == '$') || (c == '\\');
+}
+
+std::string cmGlobalNinjaGenerator::EncodeIdent(const std::string &ident,
+                                                std::ostream &vars) {
+  if (std::find_if(ident.begin(), ident.end(),
+                   std::not1(std::ptr_fun(IsIdentChar))) != ident.end()) {
+    static unsigned VarNum = 0;
+    std::ostringstream names;
+    names << "ident" << VarNum++;
+    vars << names.str() << " = " << ident << "\n";
+    return "$" + names.str();
+  } else {
+    return ident;
+  }
+}
+
+std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string &lit)
+{
+  std::string result = lit;
+  cmSystemTools::ReplaceString(result, "$", "$$");
+  return result;
+}
+
+void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
+                                        const std::string& comment,
+                                        const std::string& rule,
+                                        const cmNinjaDeps& outputs,
+                                        const cmNinjaDeps& explicitDeps,
+                                        const cmNinjaDeps& implicitDeps,
+                                        const cmNinjaDeps& orderOnlyDeps,
+                                        const cmNinjaVars& variables)
+{
+  // Make sure there is a rule.
+  if(rule.empty())
+    {
+    cmSystemTools::Error("No rule for WriteBuildStatement! called "
+                         "with comment: ",
+                         comment.c_str());
+    return;
+    }
+
+  // Make sure there is at least one output file.
+  if(outputs.empty())
+    {
+    cmSystemTools::Error("No output files for WriteBuildStatement! called "
+                         "with comment: ",
+                         comment.c_str());
+    return;
+    }
+
+  cmGlobalNinjaGenerator::WriteComment(os, comment);
+
+  std::ostringstream builds;
+
+  // TODO: Better formatting for when there are multiple input/output files.
+
+  // Write outputs files.
+  builds << "build";
+  for(cmNinjaDeps::const_iterator i = outputs.begin();
+      i != outputs.end();
+      ++i)
+    builds << " " << EncodeIdent(*i, os);
+  builds << ":";
+
+  // Write the rule.
+  builds << " " << rule;
+
+  // Write explicit dependencies.
+  for(cmNinjaDeps::const_iterator i = explicitDeps.begin();
+      i != explicitDeps.end();
+      ++i)
+    builds  << " " << EncodeIdent(*i, os);
+
+  // Write implicit dependencies.
+  if(!implicitDeps.empty())
+    {
+    builds << " |";
+    for(cmNinjaDeps::const_iterator i = implicitDeps.begin();
+        i != implicitDeps.end();
+        ++i)
+      builds  << " " << EncodeIdent(*i, os);
+    }
+
+  // Write order-only dependencies.
+  if(!orderOnlyDeps.empty())
+    {
+    builds << " ||";
+    for(cmNinjaDeps::const_iterator i = orderOnlyDeps.begin();
+        i != orderOnlyDeps.end();
+        ++i)
+      builds  << " " << EncodeIdent(*i, os);
+    }
+
+  builds << "\n";
+
+  os << builds.str();
+
+  // Write the variables bound to this build statement.
+  for(cmNinjaVars::const_iterator i = variables.begin();
+      i != variables.end();
+      ++i)
+    cmGlobalNinjaGenerator::WriteVariable(os, i->first, i->second, "", 1);
+}
+
+void cmGlobalNinjaGenerator::WritePhonyBuild(std::ostream& os,
+                                             const std::string& comment,
+                                             const cmNinjaDeps& outputs,
+                                             const cmNinjaDeps& explicitDeps,
+                                             const cmNinjaDeps& implicitDeps,
+                                             const cmNinjaDeps& orderOnlyDeps,
+                                             const cmNinjaVars& variables)
+{
+  cmGlobalNinjaGenerator::WriteBuild(os,
+                                     comment,
+                                     "phony",
+                                     outputs,
+                                     explicitDeps,
+                                     implicitDeps,
+                                     orderOnlyDeps,
+                                     variables);
+}
+
+void cmGlobalNinjaGenerator::AddCustomCommandRule()
+{
+  this->AddRule("CUSTOM_COMMAND",
+                "$COMMAND",
+                "$DESC",
+                "Rule for running custom commands.",
+                /*depfile*/ "",
+                /*restat*/ true);
+}
+
+void
+cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command,
+                                                const std::string& description,
+                                                const std::string& comment,
+                                                const cmNinjaDeps& outputs,
+                                                const cmNinjaDeps& deps,
+                                              const cmNinjaDeps& orderOnlyDeps)
+{
+  this->AddCustomCommandRule();
+
+  cmNinjaVars vars;
+  vars["COMMAND"] = command;
+  vars["DESC"] = EncodeLiteral(description);
+
+  cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream,
+                                     comment,
+                                     "CUSTOM_COMMAND",
+                                     outputs,
+                                     deps,
+                                     cmNinjaDeps(),
+                                     orderOnlyDeps,
+                                     vars);
+}
+
+void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
+                                       const std::string& name,
+                                       const std::string& command,
+                                       const std::string& description,
+                                       const std::string& comment,
+                                       const std::string& depfile,
+                                       bool restat,
+                                       bool generator)
+{
+  // Make sure the rule has a name.
+  if(name.empty())
+    {
+    cmSystemTools::Error("No name given for WriteRuleStatement! called "
+                         "with comment: ",
+                         comment.c_str());
+    return;
+    }
+
+  // Make sure a command is given.
+  if(command.empty())
+    {
+    cmSystemTools::Error("No command given for WriteRuleStatement! called "
+                         "with comment: ",
+                         comment.c_str());
+    return;
+    }
+
+  cmGlobalNinjaGenerator::WriteComment(os, comment);
+
+  // Write the rule.
+  os << "rule " << name << "\n";
+
+  // Write the depfile if any.
+  if(!depfile.empty())
+    {
+    cmGlobalNinjaGenerator::Indent(os, 1);
+    os << "depfile = " << depfile << "\n";
+    }
+
+  // Write the command.
+  cmGlobalNinjaGenerator::Indent(os, 1);
+  os << "command = " << command << "\n";
+
+  // Write the description if any.
+  if(!description.empty())
+    {
+    cmGlobalNinjaGenerator::Indent(os, 1);
+    os << "description = " << description << "\n";
+    }
+
+  if(restat)
+    {
+    cmGlobalNinjaGenerator::Indent(os, 1);
+    os << "restat = 1\n";
+    }
+
+  if(generator)
+    {
+    cmGlobalNinjaGenerator::Indent(os, 1);
+    os << "generator = 1\n";
+    }
+}
+
+void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
+                                           const std::string& name,
+                                           const std::string& value,
+                                           const std::string& comment,
+                                           int indent)
+{
+  // Make sure we have a name.
+  if(name.empty())
+    {
+    cmSystemTools::Error("No name given for WriteVariable! called "
+                         "with comment: ",
+                         comment.c_str());
+    return;
+    }
+
+  // Do not add a variable if the value is empty.
+  std::string val = cmSystemTools::TrimWhitespace(value);
+  if(val.empty())
+    {
+    return;
+    }
+
+  cmGlobalNinjaGenerator::WriteComment(os, comment);
+  cmGlobalNinjaGenerator::Indent(os, indent);
+  os << name << " = " << val << "\n";
+}
+
+void cmGlobalNinjaGenerator::WriteInclude(std::ostream& os,
+                                          const std::string& filename,
+                                          const std::string& comment)
+{
+  cmGlobalNinjaGenerator::WriteComment(os, comment);
+  os << "include " << filename << "\n";
+}
+
+void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
+                                          const cmNinjaDeps& targets,
+                                          const std::string& comment)
+{
+  cmGlobalNinjaGenerator::WriteComment(os, comment);
+  os << "default";
+  for(cmNinjaDeps::const_iterator i = targets.begin(); i != targets.end(); ++i)
+    os << " " << *i;
+  os << "\n";
+}
+
+
+cmGlobalNinjaGenerator::cmGlobalNinjaGenerator()
+  : cmGlobalGenerator()
+  , BuildFileStream(0)
+  , RulesFileStream(0)
+  , Rules()
+  , AllDependencies()
+{
+  // // Ninja is not ported to non-Unix OS yet.
+  // this->ForceUnixPaths = true;
+  this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
+}
+
+//----------------------------------------------------------------------------
+// Virtual public methods.
+
+cmLocalGenerator* cmGlobalNinjaGenerator::CreateLocalGenerator()
+{
+  cmLocalGenerator* lg = new cmLocalNinjaGenerator;
+  lg->SetGlobalGenerator(this);
+  return lg;
+}
+
+void cmGlobalNinjaGenerator
+::GetDocumentation(cmDocumentationEntry& entry) const
+{
+  entry.Name = this->GetName();
+  entry.Brief = "Generates build.ninja files (experimental).";
+  entry.Full =
+    "A build.ninja file is generated into the build tree. Recent "
+    "versions of the ninja program can build the project through the "
+    "\"all\" target.  An \"install\" target is also provided.";
+}
+
+// Implemented in all cmGlobaleGenerator sub-classes.
+// Used in:
+//   Source/cmLocalGenerator.cxx
+//   Source/cmake.cxx
+void cmGlobalNinjaGenerator::Generate()
+{
+  this->OpenBuildFileStream();
+  this->OpenRulesFileStream();
+
+  this->cmGlobalGenerator::Generate();
+
+  this->WriteAssumedSourceDependencies(*this->BuildFileStream);
+  this->WriteTargetAliases(*this->BuildFileStream);
+  this->WriteBuiltinTargets(*this->BuildFileStream);
+
+  this->CloseRulesFileStream();
+  this->CloseBuildFileStream();
+}
+
+// Implemented in all cmGlobaleGenerator sub-classes.
+// Used in:
+//   Source/cmMakefile.cxx:
+void cmGlobalNinjaGenerator
+::EnableLanguage(std::vector<std::string>const& languages,
+                 cmMakefile *mf,
+                 bool optional)
+{
+  this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
+  std::string path;
+  for(std::vector<std::string>::const_iterator l = languages.begin();
+      l != languages.end(); ++l)
+    {
+    if(*l == "NONE")
+      {
+      continue;
+      }
+    if(*l == "Fortran")
+      {
+      std::string message = "The \"";
+      message += this->GetName();
+      message += "\" generator does not support the language \"";
+      message += *l;
+      message += "\" yet.";
+      cmSystemTools::Error(message.c_str());
+      }
+    this->ResolveLanguageCompiler(*l, mf, optional);
+    }
+}
+
+// Implemented by:
+//   cmGlobalUnixMakefileGenerator3
+//   cmGlobalVisualStudio10Generator
+//   cmGlobalVisualStudio6Generator
+//   cmGlobalVisualStudio7Generator
+//   cmGlobalXCodeGenerator
+// Called by:
+//   cmGlobalGenerator::Build()
+std::string cmGlobalNinjaGenerator
+::GenerateBuildCommand(const char* makeProgram,
+                       const char* projectName,
+                       const char* additionalOptions,
+                       const char* targetName,
+                       const char* config,
+                       bool ignoreErrors,
+                       bool fast)
+{
+  // Project name and config are not used yet.
+  (void)projectName;
+  (void)config;
+  // Ninja does not have -i equivalent option yet.
+  (void)ignoreErrors;
+  // We do not handle fast build yet.
+  (void)fast;
+
+  std::string makeCommand =
+    cmSystemTools::ConvertToUnixOutputPath(makeProgram);
+
+  if(additionalOptions)
+    {
+    makeCommand += " ";
+    makeCommand += additionalOptions;
+    }
+  if(targetName)
+    {
+    if(strcmp(targetName, "clean") == 0)
+      {
+      makeCommand += " -t clean";
+      }
+    else
+      {
+      makeCommand += " ";
+      makeCommand += targetName;
+      }
+    }
+
+  return makeCommand;
+}
+
+//----------------------------------------------------------------------------
+// Non-virtual public methods.
+
+void cmGlobalNinjaGenerator::AddRule(const std::string& name,
+                                     const std::string& command,
+                                     const std::string& description,
+                                     const std::string& comment,
+                                     const std::string& depfile,
+                                     bool restat,
+                                     bool generator)
+{
+  // Do not add the same rule twice.
+  if (this->HasRule(name))
+    return;
+
+  this->Rules.insert(name);
+  cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream,
+                                    name,
+                                    command,
+                                    description,
+                                    comment,
+                                    depfile,
+                                    restat,
+                                    generator);
+}
+
+bool cmGlobalNinjaGenerator::HasRule(const std::string &name)
+{
+  RulesSetType::const_iterator rule = this->Rules.find(name);
+  return (rule != this->Rules.end());
+}
+
+//----------------------------------------------------------------------------
+// Private methods
+
+void cmGlobalNinjaGenerator::OpenBuildFileStream()
+{
+  // Compute Ninja's build file path.
+  std::string buildFilePath =
+    this->GetCMakeInstance()->GetHomeOutputDirectory();
+  buildFilePath += "/";
+  buildFilePath += cmGlobalNinjaGenerator::NINJA_BUILD_FILE;
+
+  // Get a stream where to generate things.
+  if (!this->BuildFileStream)
+    {
+    this->BuildFileStream = new cmGeneratedFileStream(buildFilePath.c_str());
+    if (!this->BuildFileStream)
+      {
+      // An error message is generated by the constructor if it cannot
+      // open the file.
+      return;
+      }
+    }
+
+  // Write the do not edit header.
+  this->WriteDisclaimer(*this->BuildFileStream);
+
+  // Write a comment about this file.
+  *this->BuildFileStream
+    << "# This file contains all the build statements describing the\n"
+    << "# compilation DAG.\n\n"
+    ;
+}
+
+void cmGlobalNinjaGenerator::CloseBuildFileStream()
+{
+  if (this->BuildFileStream)
+    {
+    delete this->BuildFileStream;
+    this->BuildFileStream = 0;
+    }
+  else
+    {
+    cmSystemTools::Error("Build file stream was not open.");
+   }
+}
+
+void cmGlobalNinjaGenerator::OpenRulesFileStream()
+{
+  // Compute Ninja's build file path.
+  std::string rulesFilePath =
+    this->GetCMakeInstance()->GetHomeOutputDirectory();
+  rulesFilePath += "/";
+  rulesFilePath += cmGlobalNinjaGenerator::NINJA_RULES_FILE;
+
+  // Get a stream where to generate things.
+  if (!this->RulesFileStream)
+    {
+    this->RulesFileStream = new cmGeneratedFileStream(rulesFilePath.c_str());
+    if (!this->RulesFileStream)
+      {
+      // An error message is generated by the constructor if it cannot
+      // open the file.
+      return;
+      }
+    }
+
+  // Write the do not edit header.
+  this->WriteDisclaimer(*this->RulesFileStream);
+
+  // Write comment about this file.
+  *this->RulesFileStream
+    << "# This file contains all the rules used to get the outputs files\n"
+    << "# built from the input files.\n"
+    << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
+    ;
+}
+
+void cmGlobalNinjaGenerator::CloseRulesFileStream()
+{
+  if (this->RulesFileStream)
+    {
+    delete this->RulesFileStream;
+    this->RulesFileStream = 0;
+    }
+  else
+    {
+    cmSystemTools::Error("Rules file stream was not open.");
+   }
+}
+
+void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
+{
+  os
+    << "# CMAKE generated file: DO NOT EDIT!\n"
+    << "# Generated by \"" << this->GetName() << "\""
+    << " Generator, CMake Version "
+    << cmVersion::GetMajorVersion() << "."
+    << cmVersion::GetMinorVersion() << "\n\n";
+}
+
+void cmGlobalNinjaGenerator::AddDependencyToAll(cmTarget* target)
+{
+  this->AppendTargetOutputs(target, this->AllDependencies);
+}
+
+void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies(std::ostream& os)
+{
+  for (std::map<std::string, std::set<std::string> >::iterator
+       i = this->AssumedSourceDependencies.begin();
+       i != this->AssumedSourceDependencies.end(); ++i) {
+    WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
+                            "Assume dependencies for generated source file.",
+                            cmNinjaDeps(1, i->first),
+                            cmNinjaDeps(i->second.begin(), i->second.end()));
+  }
+}
+
+void
+cmGlobalNinjaGenerator
+::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs)
+{
+  std::string name, dir;
+  const char* configName =
+    target->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE");
+
+  switch (target->GetType()) {
+  case cmTarget::EXECUTABLE:
+  case cmTarget::SHARED_LIBRARY:
+  case cmTarget::STATIC_LIBRARY:
+  case cmTarget::MODULE_LIBRARY:
+    name = target->GetFullName(configName);
+    dir = target->GetDirectory(configName);
+    break;
+
+  case cmTarget::UTILITY:
+    dir = target->GetMakefile()->GetStartOutputDirectory();
+  case cmTarget::GLOBAL_TARGET:
+    // dir is always "" for GLOBAL_TARGETs so that we use the target in HOME
+    name = target->GetName();
+    break;
+
+  default:
+    return;
+  }
+
+  std::string path =
+    static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0])
+      ->ConvertToNinjaPath(dir.c_str());
+  if (path.empty() || path == ".")
+    outputs.push_back(name);
+  else {
+    path += "/";
+    path += name;
+    outputs.push_back(path);
+  }
+}
+
+void
+cmGlobalNinjaGenerator
+::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs)
+{
+  if (target->GetType() == cmTarget::GLOBAL_TARGET) {
+    // Global targets only depend on other utilities, which may not appear in
+    // the TargetDepends set (e.g. "all").
+    std::set<cmStdString> const& utils = target->GetUtilities();
+    outputs.insert(outputs.end(), utils.begin(), utils.end());
+  } else {
+    cmTargetDependSet const& targetDeps =
+      this->GetTargetDirectDepends(*target);
+    for (cmTargetDependSet::const_iterator i = targetDeps.begin();
+         i != targetDeps.end(); ++i) {
+      this->AppendTargetOutputs(*i, outputs);
+    }
+  }
+}
+
+void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
+                                            cmTarget* target) {
+  cmNinjaDeps outputs;
+  this->AppendTargetOutputs(target, outputs);
+  // Mark the target's outputs as ambiguous to ensure that no other target uses
+  // the output as an alias.
+  for (cmNinjaDeps::iterator i = outputs.begin(); i != outputs.end(); ++i)
+    TargetAliases[*i] = 0;
+
+  // Insert the alias into the map.  If the alias was already present in the
+  // map and referred to another target, mark it as ambiguous.
+  std::pair<TargetAliasMap::iterator, bool> newAlias =
+    TargetAliases.insert(make_pair(alias, target));
+  if (newAlias.second && newAlias.first->second != target)
+    newAlias.first->second = 0;
+}
+
+void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
+{
+  cmGlobalNinjaGenerator::WriteDivider(os);
+  os << "# Target aliases.\n\n";
+
+  for (TargetAliasMap::iterator i = TargetAliases.begin();
+       i != TargetAliases.end(); ++i) {
+    // Don't write ambiguous aliases.
+    if (!i->second)
+      continue;
+
+    cmNinjaDeps deps;
+    this->AppendTargetOutputs(i->second, deps);
+
+    cmGlobalNinjaGenerator::WritePhonyBuild(os,
+                                            "",
+                                            cmNinjaDeps(1, i->first),
+                                            deps);
+  }
+}
+
+void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
+{
+  // Write headers.
+  cmGlobalNinjaGenerator::WriteDivider(os);
+  os << "# Built-in targets\n\n";
+
+  this->WriteTargetAll(os);
+  this->WriteTargetRebuildManifest(os);
+}
+
+void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
+{
+  cmNinjaDeps outputs;
+  outputs.push_back("all");
+
+  cmGlobalNinjaGenerator::WritePhonyBuild(os,
+                                          "The main all target.",
+                                          outputs,
+                                          this->AllDependencies);
+
+  cmGlobalNinjaGenerator::WriteDefault(os,
+                                       outputs,
+                                       "Make the all target the default.");
+}
+
+void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
+{
+  cmMakefile* mfRoot = this->LocalGenerators[0]->GetMakefile();
+
+  std::ostringstream cmd;
+  cmd << mfRoot->GetRequiredDefinition("CMAKE_COMMAND")
+      << " -H" << mfRoot->GetHomeDirectory()
+      << " -B" << mfRoot->GetHomeOutputDirectory();
+  WriteRule(*this->RulesFileStream,
+            "RERUN_CMAKE",
+            cmd.str(),
+            "Re-running CMake...",
+            "Rule for re-running cmake.",
+            /*depfile=*/ "",
+            /*restat=*/ false,
+            /*generator=*/ true);
+
+  cmNinjaDeps implicitDeps;
+  for (std::vector<cmLocalGenerator *>::const_iterator i =
+       this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) {
+    const std::vector<std::string>& lf = (*i)->GetMakefile()->GetListFiles();
+    implicitDeps.insert(implicitDeps.end(), lf.begin(), lf.end());
+  }
+  std::sort(implicitDeps.begin(), implicitDeps.end());
+  implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
+                     implicitDeps.end());
+  implicitDeps.push_back("CMakeCache.txt");
+
+  WriteBuild(os,
+             "Re-run CMake if any of its inputs changed.",
+             "RERUN_CMAKE",
+             /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE),
+             /*explicitDeps=*/ cmNinjaDeps(),
+             implicitDeps,
+             /*orderOnlyDeps=*/ cmNinjaDeps(),
+             /*variables=*/ cmNinjaVars());
+
+  WritePhonyBuild(os,
+                  "A missing CMake input file is not an error.",
+                  implicitDeps,
+                  cmNinjaDeps(),
+                  cmNinjaDeps(),
+                  cmNinjaDeps(),
+                  cmNinjaVars());
+}
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
new file mode 100644
index 0000000..171d14b
--- /dev/null
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -0,0 +1,329 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmGlobalNinjaGenerator_h
+#  define cmGlobalNinjaGenerator_h
+
+#  include "cmGlobalGenerator.h"
+#  include "cmNinjaTypes.h"
+
+class cmLocalGenerator;
+class cmGeneratedFileStream;
+
+/**
+ * \class cmGlobalNinjaGenerator
+ * \brief Write a build.ninja file.
+ *
+ * The main differences between this generator and the UnixMakefile
+ * generator family are:
+ * - We don't care about VERBOSE variable or RULE_MESSAGES property since
+ *   it is handle by Ninja's -v option.
+ * - We don't care about computing any progress status since Ninja manages
+ *   it itself.
+ * - We don't care about generating a clean target since Ninja already have
+ *   a clean tool.
+ * - We generate one build.ninja and one rules.ninja per project.
+ * - We try to minimize the number of generated rules: one per target and
+ *   language.
+ * - We use Ninja special variable $in and $out to produce nice output.
+ * - We extensively use Ninja variable overloading system to minimize the
+ *   number of generated rules.
+ */
+class cmGlobalNinjaGenerator : public cmGlobalGenerator
+{
+public:
+  /// The default name of Ninja's build file. Typically: build.ninja.
+  static const char* NINJA_BUILD_FILE;
+
+  /// The default name of Ninja's rules file. Typically: rules.ninja.
+  /// It is included in the main build.ninja file.
+  static const char* NINJA_RULES_FILE;
+
+  /// The indentation string used when generating Ninja's build file.
+  static const char* INDENT;
+
+  /// Write @a count times INDENT level to output stream @a os.
+  static void Indent(std::ostream& os, int count);
+
+  /// Write a divider in the given output stream @a os.
+  static void WriteDivider(std::ostream& os);
+
+  static std::string EncodeIdent(const std::string &ident, std::ostream &vars);
+  static std::string EncodeLiteral(const std::string &lit);
+
+  /**
+   * Write the given @a comment to the output stream @a os. It
+   * handles new line character properly.
+   */
+  static void WriteComment(std::ostream& os, const std::string& comment);
+
+  /**
+   * Write a build statement to @a os with the @a comment using
+   * the @a rule the list of @a outputs files and inputs.
+   * It also writes the variables bound to this build statement.
+   * @warning no escaping of any kind is done here.
+   */
+  static void WriteBuild(std::ostream& os,
+                         const std::string& comment,
+                         const std::string& rule,
+                         const cmNinjaDeps& outputs,
+                         const cmNinjaDeps& explicitDeps,
+                         const cmNinjaDeps& implicitDeps,
+                         const cmNinjaDeps& orderOnlyDeps,
+                         const cmNinjaVars& variables);
+
+  /**
+   * Helper to write a build statement with the special 'phony' rule.
+   */
+  static void WritePhonyBuild(std::ostream& os,
+                              const std::string& comment,
+                              const cmNinjaDeps& outputs,
+                              const cmNinjaDeps& explicitDeps,
+                              const cmNinjaDeps& implicitDeps = cmNinjaDeps(),
+                              const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(),
+                              const cmNinjaVars& variables = cmNinjaVars());
+
+  void WriteCustomCommandBuild(const std::string& command,
+                               const std::string& description,
+                               const std::string& comment,
+                               const cmNinjaDeps& outputs,
+                               const cmNinjaDeps& deps = cmNinjaDeps(),
+                             const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
+
+  /**
+   * Write a rule statement named @a name to @a os with the @a comment,
+   * the mandatory @a command, the @a depfile and the @a description.
+   * It also writes the variables bound to this rule statement.
+   * @warning no escaping of any kind is done here.
+   */
+  static void WriteRule(std::ostream& os,
+                        const std::string& name,
+                        const std::string& command,
+                        const std::string& description,
+                        const std::string& comment = "",
+                        const std::string& depfile = "",
+                        bool restat = false,
+                        bool generator = false);
+
+  /**
+   * Write a variable named @a name to @a os with value @a value and an
+   * optional @a comment. An @a indent level can be specified.
+   * @warning no escaping of any kind is done here.
+   */
+  static void WriteVariable(std::ostream& os,
+                            const std::string& name,
+                            const std::string& value,
+                            const std::string& comment = "",
+                            int indent = 0);
+
+  /**
+   * Write an include statement including @a filename with an optional
+   * @a comment to the @a os stream.
+   */
+  static void WriteInclude(std::ostream& os,
+                           const std::string& filename,
+                           const std::string& comment = "");
+
+  /**
+   * Write a default target statement specifying @a targets as
+   * the default targets.
+   */
+  static void WriteDefault(std::ostream& os,
+                           const cmNinjaDeps& targets,
+                           const std::string& comment = "");
+
+public:
+  /// Default constructor.
+  cmGlobalNinjaGenerator();
+
+  /// Convenience method for creating an instance of this class.
+  static cmGlobalGenerator* New() {
+    return new cmGlobalNinjaGenerator; }
+
+  /// Destructor.
+  virtual ~cmGlobalNinjaGenerator() { }
+
+  /// Overloaded methods. @see cmGlobalGenerator::CreateLocalGenerator()
+  virtual cmLocalGenerator* CreateLocalGenerator();
+
+  /// Overloaded methods. @see cmGlobalGenerator::GetName().
+  virtual const char* GetName() const {
+    return cmGlobalNinjaGenerator::GetActualName(); }
+
+  /// @return the name of this generator.
+  static const char* GetActualName() { return "Ninja"; }
+
+  /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
+  virtual void GetDocumentation(cmDocumentationEntry& entry) const;
+
+  /// Overloaded methods. @see cmGlobalGenerator::Generate()
+  virtual void Generate();
+
+  /// Overloaded methods. @see cmGlobalGenerator::EnableLanguage()
+  virtual void EnableLanguage(std::vector<std::string>const& languages,
+                              cmMakefile* mf,
+                              bool optional);
+
+  /// Overloaded methods. @see cmGlobalGenerator::GenerateBuildCommand()
+  virtual std::string GenerateBuildCommand(const char* makeProgram,
+                                           const char* projectName,
+                                           const char* additionalOptions,
+                                           const char* targetName,
+                                           const char* config,
+                                           bool ignoreErrors,
+                                           bool fast);
+
+  // Setup target names
+  virtual const char* GetAllTargetName()           const { return "all"; }
+  virtual const char* GetInstallTargetName()       const { return "install"; }
+  virtual const char* GetInstallLocalTargetName()  const {
+    return "install/local";
+  }
+  virtual const char* GetInstallStripTargetName()  const {
+    return "install/strip";
+  }
+  virtual const char* GetTestTargetName()          const { return "test"; }
+  virtual const char* GetPackageTargetName()       const { return "package"; }
+  virtual const char* GetPackageSourceTargetName() const {
+    return "package_source";
+  }
+  virtual const char* GetEditCacheTargetName()     const {
+    return "edit_cache";
+  }
+  virtual const char* GetRebuildCacheTargetName()  const {
+    return "rebuild_cache";
+  }
+  virtual const char* GetCleanTargetName()         const { return "clean"; }
+
+public:
+  cmGeneratedFileStream* GetBuildFileStream() const
+  { return this->BuildFileStream; }
+
+  cmGeneratedFileStream* GetRulesFileStream() const
+  { return this->RulesFileStream; }
+
+  /**
+   * Add a rule to the generated build system.
+   * Call WriteRule() behind the scene but perform some check before like:
+   * - Do not add twice the same rule.
+   */
+  void AddRule(const std::string& name,
+               const std::string& command,
+               const std::string& description,
+               const std::string& comment = "",
+               const std::string& depfile = "",
+               bool restat = false,
+               bool generator = false);
+
+  bool HasRule(const std::string& name);
+
+  void AddCustomCommandRule();
+
+protected:
+
+  /// Overloaded methods.
+  /// @see cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
+  virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; }
+
+private:
+  // In order to access the AddDependencyToAll() functions and co.
+  friend class cmLocalNinjaGenerator;
+
+  // In order to access the SeenCustomCommand() function.
+  friend class cmNinjaTargetGenerator;
+  friend class cmNinjaNormalTargetGenerator;
+  friend class cmNinjaUtilityTargetGenerator;
+
+private:
+  void OpenBuildFileStream();
+  void CloseBuildFileStream();
+
+  void OpenRulesFileStream();
+  void CloseRulesFileStream();
+
+  /// Write the common disclaimer text at the top of each build file.
+  void WriteDisclaimer(std::ostream& os);
+
+  void AddDependencyToAll(cmTarget* target);
+
+  void WriteAssumedSourceDependencies(std::ostream& os);
+
+  void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs);
+  void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs);
+
+  void AddTargetAlias(const std::string& alias, cmTarget* target);
+  void WriteTargetAliases(std::ostream& os);
+
+  void WriteBuiltinTargets(std::ostream& os);
+  void WriteTargetAll(std::ostream& os);
+  void WriteTargetRebuildManifest(std::ostream& os);
+
+  /// Called when we have seen the given custom command.  Returns true
+  /// if we has seen it before.
+  bool SeenCustomCommand(cmCustomCommand *cc) {
+    return !this->CustomCommands.insert(cc).second;
+  }
+
+  /// Called when we have seen the given custom command output.
+  void SeenCustomCommandOutput(const std::string &output) {
+    this->CustomCommandOutputs.insert(output);
+    // We don't need the assumed dependencies anymore, because we have
+    // an output.
+    this->AssumedSourceDependencies.erase(output);
+  }
+
+  bool HasCustomCommandOutput(const std::string &output) {
+    return this->CustomCommandOutputs.find(output) !=
+           this->CustomCommandOutputs.end();
+  }
+
+  void AddAssumedSourceDependencies(const std::string &source,
+                                    const cmNinjaDeps &deps) {
+    std::set<std::string> &ASD = this->AssumedSourceDependencies[source];
+    // Because we may see the same source file multiple times (same source
+    // specified in multiple targets), compute the union of any assumed
+    // dependencies.
+    ASD.insert(deps.begin(), deps.end());
+  }
+
+private:
+  /// The file containing the build statement. (the relation ship of the
+  /// compilation DAG).
+  cmGeneratedFileStream* BuildFileStream;
+  /// The file containing the rule statements. (The action attached to each
+  /// edge of the compilation DAG).
+  cmGeneratedFileStream* RulesFileStream;
+
+  /// The type used to store the set of rules added to the generated build
+  /// system.
+  typedef std::set<std::string> RulesSetType;
+
+  /// The set of rules added to the generated build system.
+  RulesSetType Rules;
+
+  /// The set of dependencies to add to the "all" target.
+  cmNinjaDeps AllDependencies;
+
+  /// The set of custom commands we have seen.
+  std::set<cmCustomCommand *> CustomCommands;
+
+  /// The set of custom command outputs we have seen.
+  std::set<std::string> CustomCommandOutputs;
+
+  /// The mapping from source file to assumed dependencies.
+  std::map<std::string, std::set<std::string> > AssumedSourceDependencies;
+
+  typedef std::map<std::string, cmTarget*> TargetAliasMap;
+  TargetAliasMap TargetAliases;
+};
+
+#endif // ! cmGlobalNinjaGenerator_h
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
new file mode 100644
index 0000000..6ae5032
--- /dev/null
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -0,0 +1,413 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmLocalNinjaGenerator.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmMakefile.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmNinjaTargetGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmSourceFile.h"
+#include "cmComputeLinkInformation.h"
+#include "cmake.h"
+
+#include <assert.h>
+
+cmLocalNinjaGenerator::cmLocalNinjaGenerator()
+  : cmLocalGenerator()
+  , ConfigName("")
+  , HomeRelativeOutputPath("")
+{
+  this->IsMakefileGenerator = true;
+}
+
+//----------------------------------------------------------------------------
+// Virtual public methods.
+
+cmLocalNinjaGenerator::~cmLocalNinjaGenerator()
+{
+}
+
+void cmLocalNinjaGenerator::Generate()
+{
+  this->SetConfigName();
+
+  this->WriteProcessedMakefile(this->GetBuildFileStream());
+  this->WriteProcessedMakefile(this->GetRulesFileStream());
+
+  this->WriteBuildFileTop();
+
+  cmTargets& targets = this->GetMakefile()->GetTargets();
+  for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
+    {
+    cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(&t->second);
+    if(tg)
+      {
+      tg->Generate();
+      // Add the target to "all" if required.
+      if (!this->GetGlobalNinjaGenerator()->IsExcluded(
+            this->GetGlobalNinjaGenerator()->LocalGenerators[0],
+            t->second))
+        this->GetGlobalNinjaGenerator()->AddDependencyToAll(&t->second);
+      delete tg;
+      }
+    }
+
+  this->WriteCustomCommandBuildStatements();
+}
+
+// Implemented in:
+//   cmLocalUnixMakefileGenerator3.
+// Used in:
+//   Source/cmMakefile.cxx
+//   Source/cmGlobalGenerator.cxx
+void cmLocalNinjaGenerator::Configure()
+{
+  // Compute the path to use when referencing the current output
+  // directory from the top output directory.
+  this->HomeRelativeOutputPath =
+    this->Convert(this->Makefile->GetStartOutputDirectory(), HOME_OUTPUT);
+  if(this->HomeRelativeOutputPath == ".")
+    {
+    this->HomeRelativeOutputPath = "";
+    }
+  this->cmLocalGenerator::Configure();
+
+}
+
+// TODO: Picked up from cmLocalUnixMakefileGenerator3.  Refactor it.
+std::string cmLocalNinjaGenerator
+::GetTargetDirectory(cmTarget const& target) const
+{
+  std::string dir = cmake::GetCMakeFilesDirectoryPostSlash();
+  dir += target.GetName();
+#if defined(__VMS)
+  dir += "_dir";
+#else
+  dir += ".dir";
+#endif
+  return dir;
+}
+
+//----------------------------------------------------------------------------
+// Non-virtual public methods.
+
+const cmGlobalNinjaGenerator*
+cmLocalNinjaGenerator::GetGlobalNinjaGenerator() const
+{
+  return
+    static_cast<const cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
+}
+
+cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
+{
+  return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
+}
+
+// TODO: Picked up from cmLocalUnixMakefileGenerator3.  Refactor it.
+std::string
+cmLocalNinjaGenerator
+::GetObjectFileName(const cmTarget& target,
+                    const cmSourceFile& source)
+{
+  // Make sure we never hit this old case.
+  if(source.GetProperty("MACOSX_PACKAGE_LOCATION"))
+    {
+    std::string msg = "MACOSX_PACKAGE_LOCATION set on source file: ";
+    msg += source.GetFullPath();
+    this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
+                                      msg.c_str());
+    }
+
+  // Start with the target directory.
+  std::string obj = this->GetTargetDirectory(target);
+  obj += "/";
+
+  // Get the object file name without the target directory.
+  std::string dir_max;
+  dir_max += this->Makefile->GetCurrentOutputDirectory();
+  dir_max += "/";
+  dir_max += obj;
+  std::string objectName =
+    this->GetObjectFileNameWithoutTarget(source, dir_max, 0);
+  // Append the object name to the target directory.
+  obj += objectName;
+  return obj;
+}
+
+//----------------------------------------------------------------------------
+// Virtual protected methods.
+
+std::string
+cmLocalNinjaGenerator::ConvertToLinkReference(std::string const& lib)
+{
+  return this->Convert(lib.c_str(), HOME_OUTPUT, SHELL);
+}
+
+std::string
+cmLocalNinjaGenerator::ConvertToIncludeReference(std::string const& path)
+{
+  return this->Convert(path.c_str(), HOME_OUTPUT, SHELL);
+}
+
+//----------------------------------------------------------------------------
+// Private methods.
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetBuildFileStream() const
+{
+  return *this->GetGlobalNinjaGenerator()->GetBuildFileStream();
+}
+
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetRulesFileStream() const
+{
+  return *this->GetGlobalNinjaGenerator()->GetRulesFileStream();
+}
+
+const cmake* cmLocalNinjaGenerator::GetCMakeInstance() const
+{
+  return this->GetGlobalGenerator()->GetCMakeInstance();
+}
+
+cmake* cmLocalNinjaGenerator::GetCMakeInstance()
+{
+  return this->GetGlobalGenerator()->GetCMakeInstance();
+}
+
+bool cmLocalNinjaGenerator::isRootMakefile() const
+{
+  return (strcmp(this->Makefile->GetCurrentDirectory(),
+                 this->GetCMakeInstance()->GetHomeDirectory()) == 0);
+}
+
+void cmLocalNinjaGenerator::WriteBuildFileTop()
+{
+  // We do that only once for the top CMakeLists.txt file.
+  if(!this->isRootMakefile())
+    return;
+
+  // For the build file.
+  this->WriteProjectHeader(this->GetBuildFileStream());
+  this->WriteNinjaFilesInclusion(this->GetBuildFileStream());
+
+  // For the rule file.
+  this->WriteProjectHeader(this->GetRulesFileStream());
+}
+
+void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os)
+{
+  cmGlobalNinjaGenerator::WriteDivider(os);
+  os
+    << "# Project: " << this->GetMakefile()->GetProjectName() << std::endl
+    << "# Configuration: " << this->ConfigName << std::endl
+    ;
+  cmGlobalNinjaGenerator::WriteDivider(os);
+}
+
+void cmLocalNinjaGenerator::WriteNinjaFilesInclusion(std::ostream& os)
+{
+  cmGlobalNinjaGenerator::WriteDivider(os);
+  os
+    << "# Include auxiliary files.\n"
+    << "\n"
+    ;
+  cmGlobalNinjaGenerator::WriteInclude(os,
+                                      cmGlobalNinjaGenerator::NINJA_RULES_FILE,
+                                       "Include rules file.");
+  os << "\n";
+}
+
+void cmLocalNinjaGenerator::SetConfigName()
+{
+  // Store the configuration name that will be generated.
+  if(const char* config =
+       this->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE"))
+    {
+    // Use the build type given by the user.
+    this->ConfigName = config;
+    }
+  else
+    {
+    // No configuration type given.
+    this->ConfigName = "";
+    }
+}
+
+void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os)
+{
+  cmGlobalNinjaGenerator::WriteDivider(os);
+  os
+    << "# Write statements declared in CMakeLists.txt:" << std::endl
+    << "# " << this->Makefile->GetCurrentListFile() << std::endl
+    ;
+  if(this->isRootMakefile())
+    os << "# Which is the root file." << std::endl;
+  cmGlobalNinjaGenerator::WriteDivider(os);
+  os << std::endl;
+}
+
+std::string cmLocalNinjaGenerator::ConvertToNinjaPath(const char *path)
+{
+  return this->Convert(path,
+                       cmLocalGenerator::HOME_OUTPUT,
+                       cmLocalGenerator::MAKEFILE);
+}
+
+void
+cmLocalNinjaGenerator
+::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs)
+{
+  this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs);
+}
+
+void
+cmLocalNinjaGenerator
+::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs)
+{
+  this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs);
+}
+
+void cmLocalNinjaGenerator::AppendCustomCommandDeps(const cmCustomCommand *cc,
+                                                    cmNinjaDeps &ninjaDeps)
+{
+  const std::vector<std::string> &deps = cc->GetDepends();
+  for (std::vector<std::string>::const_iterator i = deps.begin();
+       i != deps.end(); ++i) {
+    std::string dep;
+    if (this->GetRealDependency(i->c_str(), this->GetConfigName(), dep))
+      ninjaDeps.push_back(ConvertToNinjaPath(dep.c_str()));
+  }
+}
+
+std::string cmLocalNinjaGenerator::BuildCommandLine(
+                                    const std::vector<std::string> &cmdLines)
+{
+  // If we have no commands but we need to build a command anyway, use ":".
+  // This happens when building a POST_BUILD value for link targets that
+  // don't use POST_BUILD.
+  if (cmdLines.empty())
+    return ":";
+
+  // TODO: This will work only on Unix platforms. I don't
+  // want to use a link.txt file because I will lose the benefit of the
+  // $in variables. A discussion about dealing with multiple commands in
+  // a rule is started here:
+  // http://groups.google.com/group/ninja-build/browse_thread/thread/d515f23a78986008
+  std::ostringstream cmd;
+  for (std::vector<std::string>::const_iterator li = cmdLines.begin();
+       li != cmdLines.end(); ++li) {
+    if (li != cmdLines.begin())
+      cmd << " && ";
+    cmd << *li;
+  }
+  return cmd.str();
+}
+
+void cmLocalNinjaGenerator::AppendCustomCommandLines(const cmCustomCommand *cc,
+                                            std::vector<std::string> &cmdLines)
+{
+  cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this->Makefile);
+  if (ccg.GetNumberOfCommands() > 0) {
+    std::ostringstream cdCmd;
+    cdCmd << "cd ";
+    if (const char* wd = cc->GetWorkingDirectory())
+      cdCmd << wd;
+    else
+      cdCmd << this->GetMakefile()->GetStartOutputDirectory();
+    cmdLines.push_back(cdCmd.str());
+  }
+  for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) {
+    cmdLines.push_back(ccg.GetCommand(i));
+    std::string& cmd = cmdLines.back();
+    ccg.AppendArguments(i, cmd);
+  }
+}
+
+void
+cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(cmCustomCommand *cc,
+                                            const cmNinjaDeps& orderOnlyDeps)
+{
+  if (this->GetGlobalNinjaGenerator()->SeenCustomCommand(cc))
+    return;
+
+  const std::vector<std::string> &outputs = cc->GetOutputs();
+  cmNinjaDeps ninjaOutputs(outputs.size()), ninjaDeps;
+
+  std::transform(outputs.begin(), outputs.end(),
+                 ninjaOutputs.begin(), MapToNinjaPath());
+  this->AppendCustomCommandDeps(cc, ninjaDeps);
+
+  for (cmNinjaDeps::iterator i = ninjaOutputs.begin(); i != ninjaOutputs.end();
+       ++i)
+    this->GetGlobalNinjaGenerator()->SeenCustomCommandOutput(*i);
+
+  std::vector<std::string> cmdLines;
+  this->AppendCustomCommandLines(cc, cmdLines);
+
+  if (cmdLines.empty()) {
+    cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
+                                            "Phony custom command for " +
+                                              ninjaOutputs[0],
+                                            ninjaOutputs,
+                                            ninjaDeps,
+                                            cmNinjaDeps(),
+                                            orderOnlyDeps,
+                                            cmNinjaVars());
+  } else {
+    this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild(
+      this->BuildCommandLine(cmdLines),
+      this->ConstructComment(*cc),
+      "Custom command for " + ninjaOutputs[0],
+      ninjaOutputs,
+      ninjaDeps,
+      orderOnlyDeps);
+  }
+}
+
+void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand* cc,
+                                                   cmTarget* target)
+{
+  this->CustomCommandTargets[cc].insert(target);
+}
+
+void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements()
+{
+  for (CustomCommandTargetMap::iterator i = this->CustomCommandTargets.begin();
+       i != this->CustomCommandTargets.end(); ++i) {
+    // A custom command may appear on multiple targets.  However, some build
+    // systems exist where the target dependencies on some of the targets are
+    // overspecified, leading to a dependency cycle.  If we assume all target
+    // dependencies are a superset of the true target dependencies for this
+    // custom command, we can take the set intersection of all target
+    // dependencies to obtain a correct dependency list.
+    //
+    // FIXME: This won't work in certain obscure scenarios involving indirect
+    // dependencies.
+    std::set<cmTarget*>::iterator j = i->second.begin();
+    assert(j != i->second.end());
+    std::vector<std::string> ccTargetDeps;
+    this->AppendTargetDepends(*j, ccTargetDeps);
+    std::sort(ccTargetDeps.begin(), ccTargetDeps.end());
+    ++j;
+
+    for (; j != i->second.end(); ++j) {
+      std::vector<std::string> jDeps, depsIntersection;
+      this->AppendTargetDepends(*j, jDeps);
+      std::sort(jDeps.begin(), jDeps.end());
+      std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(),
+                            jDeps.begin(), jDeps.end(),
+                            std::back_inserter(depsIntersection));
+      ccTargetDeps = depsIntersection;
+    }
+
+    this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps);
+  }
+}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
new file mode 100644
index 0000000..218eee1
--- /dev/null
+++ b/Source/cmLocalNinjaGenerator.h
@@ -0,0 +1,134 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmLocalNinjaGenerator_h
+#  define cmLocalNinjaGenerator_h
+
+#  include "cmLocalGenerator.h"
+#  include "cmNinjaTypes.h"
+
+class cmGlobalNinjaGenerator;
+class cmGeneratedFileStream;
+class cmake;
+
+/**
+ * \class cmLocalNinjaGenerator
+ * \brief Write a local build.ninja file.
+ *
+ * cmLocalNinjaGenerator produces a local build.ninja file from its
+ * member Makefile.
+ */
+class cmLocalNinjaGenerator : public cmLocalGenerator
+{
+public:
+  /// Default constructor.
+  cmLocalNinjaGenerator();
+
+  /// Destructor.
+  virtual ~cmLocalNinjaGenerator();
+
+  /// Overloaded methods. @see cmLocalGenerator::Generate()
+  virtual void Generate();
+
+  /// Overloaded methods. @see cmLocalGenerator::Configure()
+  virtual void Configure();
+
+  /// Overloaded methods. @see cmLocalGenerator::GetTargetDirectory()
+  virtual std::string GetTargetDirectory(cmTarget const& target) const;
+
+public:
+  const cmGlobalNinjaGenerator* GetGlobalNinjaGenerator() const;
+  cmGlobalNinjaGenerator* GetGlobalNinjaGenerator();
+
+  /**
+   * Shortcut to get the cmake instance throw the global generator.
+   * @return an instance of the cmake object.
+   */
+  const cmake* GetCMakeInstance() const;
+  cmake* GetCMakeInstance();
+
+  const char* GetConfigName() const
+  { return this->ConfigName.c_str(); }
+
+  std::string GetObjectFileName(const cmTarget& target,
+                                const cmSourceFile& source);
+
+  /// @return whether we are processing the top CMakeLists.txt file.
+  bool isRootMakefile() const;
+
+  /// @returns the relative path between the HomeOutputDirectory and this
+  /// local generators StartOutputDirectory.
+  std::string GetHomeRelativeOutputPath() const
+  { return this->HomeRelativeOutputPath; }
+
+protected:
+  virtual std::string ConvertToLinkReference(std::string const& lib);
+  virtual std::string ConvertToIncludeReference(std::string const& path);
+
+private:
+  friend class cmGlobalNinjaGenerator;
+
+  // In order to access to protected member of the local generator.
+  friend class cmNinjaTargetGenerator;
+  friend class cmNinjaNormalTargetGenerator;
+  friend class cmNinjaUtilityTargetGenerator;
+
+private:
+  cmGeneratedFileStream& GetBuildFileStream() const;
+  cmGeneratedFileStream& GetRulesFileStream() const;
+
+  void WriteBuildFileTop();
+  void WriteProjectHeader(std::ostream& os);
+  void WriteNinjaFilesInclusion(std::ostream& os);
+  void WriteProcessedMakefile(std::ostream& os);
+
+  void SetConfigName();
+
+  std::string ConvertToNinjaPath(const char *path);
+
+  struct map_to_ninja_path {
+    cmLocalNinjaGenerator *LocalGenerator;
+    map_to_ninja_path(cmLocalNinjaGenerator *LocalGenerator)
+      : LocalGenerator(LocalGenerator) {}
+    std::string operator()(const std::string &path) {
+      return LocalGenerator->ConvertToNinjaPath(path.c_str());
+    }
+  };
+  map_to_ninja_path MapToNinjaPath() {
+    return map_to_ninja_path(this);
+  }
+
+  void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs);
+  void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs);
+
+  void AppendCustomCommandDeps(const cmCustomCommand *cc,
+                               cmNinjaDeps &ninjaDeps);
+  std::string BuildCommandLine(const std::vector<std::string> &cmdLines);
+  void AppendCustomCommandLines(const cmCustomCommand *cc,
+                                std::vector<std::string> &cmdLines);
+  void WriteCustomCommandRule(); 
+  void WriteCustomCommandBuildStatement(cmCustomCommand *cc,
+                                        const cmNinjaDeps& orderOnlyDeps);
+
+  void AddCustomCommandTarget(cmCustomCommand* cc, cmTarget* target);
+  void WriteCustomCommandBuildStatements();
+
+private:
+  std::string ConfigName;
+  std::string HomeRelativeOutputPath;
+
+  typedef std::map<cmCustomCommand*, std::set<cmTarget*> >
+    CustomCommandTargetMap;
+  CustomCommandTargetMap CustomCommandTargets;
+};
+
+#endif // ! cmLocalNinjaGenerator_h
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
new file mode 100644
index 0000000..bdd4f3d
--- /dev/null
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -0,0 +1,402 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmNinjaNormalTargetGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmSourceFile.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+
+#include <assert.h>
+
+cmNinjaNormalTargetGenerator::
+cmNinjaNormalTargetGenerator(cmTarget* target)
+  : cmNinjaTargetGenerator(target)
+  , TargetNameOut()
+  , TargetNameSO()
+  , TargetNameReal()
+  , TargetNameImport()
+  , TargetNamePDB()
+  , TargetLinkLanguage(target->GetLinkerLanguage(this->GetConfigName()))
+{
+  if (target->GetType() == cmTarget::EXECUTABLE)
+    target->GetExecutableNames(this->TargetNameOut,
+                               this->TargetNameReal,
+                               this->TargetNameImport,
+                               this->TargetNamePDB,
+                               GetLocalGenerator()->GetConfigName());
+  else
+    target->GetLibraryNames(this->TargetNameOut,
+                            this->TargetNameSO,
+                            this->TargetNameReal,
+                            this->TargetNameImport,
+                            this->TargetNamePDB,
+                            GetLocalGenerator()->GetConfigName());
+}
+
+cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
+{
+}
+
+void cmNinjaNormalTargetGenerator::Generate()
+{
+  if (!this->TargetLinkLanguage) {
+    cmSystemTools::Error("CMake can not determine linker language for target:",
+                         this->GetTarget()->GetName());
+    return;
+  }
+
+  // Write the rules for each language.
+  this->WriteLanguagesRules();
+
+  // Write the build statements
+  this->WriteObjectBuildStatements();
+
+  this->WriteLinkRule();
+  this->WriteLinkStatement();
+
+  this->GetBuildFileStream() << "\n";
+  this->GetRulesFileStream() << "\n";
+}
+
+void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
+{
+  cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
+  this->GetRulesFileStream()
+    << "# Rules for each languages for "
+    << cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
+    << " target "
+    << this->GetTargetName()
+    << "\n\n";
+
+  std::set<cmStdString> languages;
+  this->GetTarget()->GetLanguages(languages);
+  for(std::set<cmStdString>::const_iterator l = languages.begin();
+      l != languages.end();
+      ++l)
+    this->WriteLanguageRules(*l);
+}
+
+const char *cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
+{
+  switch (this->GetTarget()->GetType()) {
+    case cmTarget::STATIC_LIBRARY:
+      return "static library";
+    case cmTarget::SHARED_LIBRARY:
+      return "shared library";
+    case cmTarget::MODULE_LIBRARY:
+      return "shared module";
+    case cmTarget::EXECUTABLE:
+      return "executable";
+    default:
+      return 0;
+  }
+}
+
+std::string
+cmNinjaNormalTargetGenerator
+::LanguageLinkerRule() const
+{
+  return std::string(this->TargetLinkLanguage)
+    + "_"
+    + cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
+    + "_LINKER";
+}
+
+void
+cmNinjaNormalTargetGenerator
+::WriteLinkRule()
+{
+  std::string ruleName = this->LanguageLinkerRule();
+
+  if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
+    cmLocalGenerator::RuleVariables vars;
+    vars.RuleLauncher = "RULE_LAUNCH_LINK";
+    vars.CMTarget = this->GetTarget();
+    vars.Language = this->TargetLinkLanguage;
+    vars.Objects = "$in";
+    std::string objdir = cmake::GetCMakeFilesDirectoryPostSlash();
+    objdir += this->GetTargetName();
+    objdir += ".dir";
+    objdir = this->GetLocalGenerator()->Convert(objdir.c_str(),
+                                                cmLocalGenerator::START_OUTPUT,
+                                                cmLocalGenerator::SHELL);
+    vars.ObjectDir = objdir.c_str();
+    vars.Target = "$out";
+    vars.TargetSOName = "$SONAME";
+
+    // Setup the target version.
+    std::string targetVersionMajor;
+    std::string targetVersionMinor;
+    {
+    cmOStringStream majorStream;
+    cmOStringStream minorStream;
+    int major;
+    int minor;
+    this->GetTarget()->GetTargetVersion(major, minor);
+    majorStream << major;
+    minorStream << minor;
+    targetVersionMajor = majorStream.str();
+    targetVersionMinor = minorStream.str();
+    }
+    vars.TargetVersionMajor = targetVersionMajor.c_str();
+    vars.TargetVersionMinor = targetVersionMinor.c_str();
+
+    vars.LinkLibraries = "$LINK_LIBRARIES";
+    vars.Flags = "$FLAGS";
+    vars.LinkFlags = "$LINK_FLAGS";
+
+    std::string langFlags;
+    this->GetLocalGenerator()->AddLanguageFlags(langFlags,
+                                                this->TargetLinkLanguage,
+                                                this->GetConfigName());
+    langFlags += "$ARCHITECTURE_FLAGS";
+    vars.LanguageCompileFlags = langFlags.c_str();
+
+    // Rule for linking library.
+    std::vector<std::string> linkCmds = this->ComputeLinkCmd();
+    for(std::vector<std::string>::iterator i = linkCmds.begin();
+        i != linkCmds.end();
+        ++i)
+      {
+      this->GetLocalGenerator()->ExpandRuleVariables(*i, vars);
+      }
+    linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
+    linkCmds.push_back("$POST_BUILD");
+    std::string linkCmd =
+      this->GetLocalGenerator()->BuildCommandLine(linkCmds);
+
+    // Write the linker rule.
+    std::ostringstream comment;
+    comment << "Rule for linking " << this->TargetLinkLanguage << " "
+            << this->GetVisibleTypeName() << ".";
+    std::ostringstream description;
+    description << "Linking " << this->TargetLinkLanguage << " "
+                << this->GetVisibleTypeName() << " $out";
+    this->GetGlobalGenerator()->AddRule(ruleName,
+                                        linkCmd,
+                                        description.str(),
+                                        comment.str());
+  }
+
+  if (this->TargetNameOut != this->TargetNameReal) {
+    std::string cmakeCommand =
+      this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND");
+    if (this->GetTarget()->GetType() == cmTarget::EXECUTABLE)
+      this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_EXECUTABLE",
+                                          cmakeCommand +
+                                          " -E cmake_symlink_executable"
+                                          " $in $out && $POST_BUILD",
+                                          "Creating executable symlink $out",
+                                      "Rule for creating executable symlink.");
+    else
+      this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_LIBRARY",
+                                          cmakeCommand +
+                                          " -E cmake_symlink_library"
+                                          " $in $SONAME $out && $POST_BUILD",
+                                          "Creating library symlink $out",
+                                         "Rule for creating library symlink.");
+  }
+}
+
+std::vector<std::string>
+cmNinjaNormalTargetGenerator
+::ComputeLinkCmd()
+{
+  cmTarget::TargetType targetType = this->GetTarget()->GetType();
+  switch (targetType) {
+    case cmTarget::STATIC_LIBRARY: {
+      // Check if you have a non archive way to create the static library.
+      {
+      std::string linkCmdVar = "CMAKE_";
+      linkCmdVar += this->TargetLinkLanguage;
+      linkCmdVar += "_CREATE_STATIC_LIBRARY";
+      if (const char *linkCmd =
+            this->GetMakefile()->GetDefinition(linkCmdVar.c_str()))
+        {
+        return std::vector<std::string>(1, linkCmd);
+        }
+      }
+
+      // We have archive link commands set. First, delete the existing archive.
+      std::vector<std::string> linkCmds;
+      linkCmds.push_back("rm -f $out");
+
+      // TODO: Use ARCHIVE_APPEND for archives over a certain size. 
+      {
+      std::string linkCmdVar = "CMAKE_";
+      linkCmdVar += this->TargetLinkLanguage;
+      linkCmdVar += "_ARCHIVE_CREATE";
+      const char *linkCmd =
+        this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
+      linkCmds.push_back(linkCmd);
+      }
+      {
+      std::string linkCmdVar = "CMAKE_";
+      linkCmdVar += this->TargetLinkLanguage;
+      linkCmdVar += "_ARCHIVE_FINISH";
+      const char *linkCmd =
+        this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
+      linkCmds.push_back(linkCmd);
+      }
+      return linkCmds;
+    }
+    case cmTarget::SHARED_LIBRARY:
+    case cmTarget::MODULE_LIBRARY:
+    case cmTarget::EXECUTABLE: {
+      std::string linkCmdVar = "CMAKE_";
+      linkCmdVar += this->TargetLinkLanguage;
+      switch (targetType) {
+      case cmTarget::SHARED_LIBRARY:
+        linkCmdVar += "_CREATE_SHARED_LIBRARY";
+        break;
+      case cmTarget::MODULE_LIBRARY:
+        linkCmdVar += "_CREATE_SHARED_MODULE";
+        break;
+      case cmTarget::EXECUTABLE:
+        linkCmdVar += "_LINK_EXECUTABLE";
+        break;
+      default:
+        assert(0 && "Unexpected target type");
+      }
+      const char *linkCmd =
+        this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
+      return std::vector<std::string>(1, linkCmd);
+    }
+    default:
+      assert(0 && "Unexpected target type");
+  }
+}
+
+void cmNinjaNormalTargetGenerator::WriteLinkStatement()
+{
+  // Write comments.
+  cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
+  this->GetBuildFileStream()
+    << "# Link build statements for "
+    << cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
+    << " target "
+    << this->GetTargetName()
+    << "\n\n";
+
+  cmNinjaDeps emptyDeps;
+  cmNinjaVars vars;
+
+  std::string targetOutput = this->GetTargetFilePath(this->TargetNameOut);
+  std::string targetOutputReal = this->GetTargetFilePath(this->TargetNameReal);
+
+  // Compute the comment.
+  std::ostringstream comment;
+  comment << "Link the " << this->GetVisibleTypeName() << " "
+          << targetOutputReal;
+
+  // Compute outputs.
+  cmNinjaDeps outputs;
+  outputs.push_back(targetOutputReal);
+
+  // Compute specific libraries to link with.
+  cmNinjaDeps explicitDeps = this->GetObjects(),
+              implicitDeps = this->ComputeLinkDeps();
+
+  this->GetLocalGenerator()->GetTargetFlags(vars["LINK_LIBRARIES"],
+                                            vars["FLAGS"],
+                                            vars["LINK_FLAGS"],
+                                            *this->GetTarget());
+
+  // Compute specific link flags.
+  this->GetLocalGenerator()->AddArchitectureFlags(vars["ARCHITECTURE_FLAGS"],
+                                                  this->GetTarget(),
+                                                  this->TargetLinkLanguage,
+                                                  this->GetConfigName());
+  vars["SONAME"] = this->TargetNameSO;
+
+  std::vector<cmCustomCommand> *cmdLists[3] = {
+    &this->GetTarget()->GetPreBuildCommands(),
+    &this->GetTarget()->GetPreLinkCommands(),
+    &this->GetTarget()->GetPostBuildCommands()
+  };
+
+  std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
+  std::vector<std::string> *cmdLineLists[3] = {
+    &preLinkCmdLines,
+    &preLinkCmdLines,
+    &postBuildCmdLines
+  };
+
+  for (unsigned i = 0; i != 3; ++i) {
+    for (std::vector<cmCustomCommand>::const_iterator
+         ci = cmdLists[i]->begin();
+         ci != cmdLists[i]->end(); ++ci) {
+      this->GetLocalGenerator()->AppendCustomCommandLines(&*ci,
+                                                          *cmdLineLists[i]);
+    }
+  }
+
+  // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for
+  // the link commands.
+  if (!preLinkCmdLines.empty())
+    preLinkCmdLines.push_back(std::string("cd ") +
+                              this->GetMakefile()->GetHomeOutputDirectory());
+
+  vars["PRE_LINK"] =
+    this->GetLocalGenerator()->BuildCommandLine(preLinkCmdLines);
+  std::string postBuildCmdLine =
+    this->GetLocalGenerator()->BuildCommandLine(postBuildCmdLines);
+
+  cmNinjaVars symlinkVars;
+  if (targetOutput == targetOutputReal) {
+    vars["POST_BUILD"] = postBuildCmdLine;
+  } else {
+    vars["POST_BUILD"] = ":";
+    symlinkVars["POST_BUILD"] = postBuildCmdLine;
+  }
+
+  // Write the build statement for this target.
+  cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
+                                     comment.str(),
+                                     this->LanguageLinkerRule(),
+                                     outputs,
+                                     explicitDeps,
+                                     implicitDeps,
+                                     emptyDeps,
+                                     vars);
+
+  if (targetOutput != targetOutputReal) {
+    if (this->GetTarget()->GetType() == cmTarget::EXECUTABLE) {
+      cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
+                                  "Create executable symlink " + targetOutput,
+                                         "CMAKE_SYMLINK_EXECUTABLE",
+                                         cmNinjaDeps(1, targetOutput),
+                                         cmNinjaDeps(1, targetOutputReal),
+                                         emptyDeps,
+                                         emptyDeps,
+                                         symlinkVars);
+    } else {
+      symlinkVars["SONAME"] = this->GetTargetFilePath(this->TargetNameSO);
+      cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
+                                      "Create library symlink " + targetOutput,
+                                         "CMAKE_SYMLINK_LIBRARY",
+                                         cmNinjaDeps(1, targetOutput),
+                                         cmNinjaDeps(1, targetOutputReal),
+                                         emptyDeps,
+                                         emptyDeps,
+                                         symlinkVars);
+    }
+  }
+
+  // Add aliases for the file name and the target name.
+  this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut,
+                                             this->GetTarget());
+  this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
+                                             this->GetTarget());
+}
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
new file mode 100644
index 0000000..99f5a13
--- /dev/null
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -0,0 +1,47 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmNinjaNormalTargetGenerator_h
+#  define cmNinjaNormalTargetGenerator_h
+
+#  include "cmNinjaTargetGenerator.h"
+#  include "cmNinjaTypes.h"
+
+class cmSourceFile;
+
+class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator
+{
+public:
+  cmNinjaNormalTargetGenerator(cmTarget* target);
+  ~cmNinjaNormalTargetGenerator();
+
+  void Generate();
+
+private:
+  std::string LanguageLinkerRule() const;
+  const char* GetVisibleTypeName() const;
+  void WriteLanguagesRules();
+  void WriteLinkRule();
+  void WriteLinkStatement();
+  std::vector<std::string> ComputeLinkCmd();
+
+private:
+  // Target name info.
+  std::string TargetNameOut;
+  std::string TargetNameSO;
+  std::string TargetNameReal;
+  std::string TargetNameImport;
+  std::string TargetNamePDB;
+  const char *TargetLinkLanguage;
+};
+
+#endif // ! cmNinjaNormalTargetGenerator_h
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
new file mode 100644
index 0000000..e48ac12
--- /dev/null
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -0,0 +1,445 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmNinjaTargetGenerator.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmNinjaNormalTargetGenerator.h"
+#include "cmNinjaUtilityTargetGenerator.h"
+#include "cmSystemTools.h"
+#include "cmMakefile.h"
+#include "cmComputeLinkInformation.h"
+#include "cmSourceFile.h"
+#include "cmCustomCommandGenerator.h"
+
+#include <algorithm>
+
+cmNinjaTargetGenerator *
+cmNinjaTargetGenerator::New(cmTarget* target)
+{
+  switch (target->GetType())
+    {
+      case cmTarget::EXECUTABLE:
+      case cmTarget::SHARED_LIBRARY:
+      case cmTarget::STATIC_LIBRARY:
+      case cmTarget::MODULE_LIBRARY:
+        return new cmNinjaNormalTargetGenerator(target);
+
+      case cmTarget::UTILITY:
+        return new cmNinjaUtilityTargetGenerator(target);;
+
+      case cmTarget::GLOBAL_TARGET: {
+        // We only want to process global targets that live in the home
+        // (i.e. top-level) directory.  CMake creates copies of these targets
+        // in every directory, which we don't need.
+        cmMakefile *mf = target->GetMakefile();
+        if (strcmp(mf->GetStartDirectory(), mf->GetHomeDirectory()) == 0)
+          return new cmNinjaUtilityTargetGenerator(target);
+        // else fallthrough
+      }
+
+      default:
+        return 0;
+    }
+}
+
+cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmTarget* target)
+  : Target(target),
+    Makefile(target->GetMakefile()),
+    LocalGenerator(
+      static_cast<cmLocalNinjaGenerator*>(Makefile->GetLocalGenerator())),
+    Objects()
+{
+}
+
+cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
+{
+}
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
+{
+  return *this->GetGlobalGenerator()->GetBuildFileStream();
+}
+
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const
+{
+  return *this->GetGlobalGenerator()->GetRulesFileStream();
+}
+
+cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const
+{
+  return this->LocalGenerator->GetGlobalNinjaGenerator();
+}
+
+const char* cmNinjaTargetGenerator::GetConfigName() const
+{
+  return this->LocalGenerator->ConfigName.c_str();
+}
+
+// TODO: Picked up from cmMakefileTargetGenerator.  Refactor it.
+const char* cmNinjaTargetGenerator::GetFeature(const char* feature)
+{
+  return this->Target->GetFeature(feature, this->GetConfigName());
+}
+
+// TODO: Picked up from cmMakefileTargetGenerator.  Refactor it.
+bool cmNinjaTargetGenerator::GetFeatureAsBool(const char* feature)
+{
+  return cmSystemTools::IsOn(this->GetFeature(feature));
+}
+
+// TODO: Picked up from cmMakefileTargetGenerator.  Refactor it.
+void cmNinjaTargetGenerator::AddFeatureFlags(std::string& flags,
+                                             const char* lang)
+{
+  // Add language-specific flags.
+  this->LocalGenerator->AddLanguageFlags(flags, lang, this->GetConfigName());
+
+  if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION"))
+    {
+    this->LocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
+    }
+}
+
+// TODO: Most of the code is picked up from
+// void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink),
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
+// Refactor it.
+std::string
+cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source,
+                                              const std::string& language)
+{
+  std::string flags;
+
+  this->AddFeatureFlags(flags, language.c_str());
+
+  this->GetLocalGenerator()->AddArchitectureFlags(flags,
+                                                  this->GetTarget(),
+                                                  language.c_str(),
+                                                  this->GetConfigName());
+
+  // TODO: Fortran support.
+  // // Fortran-specific flags computed for this target.
+  // if(*l == "Fortran")
+  //   {
+  //   this->AddFortranFlags(flags);
+  //   }
+
+  // Add shared-library flags if needed.
+  {
+  bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) ||
+                 (this->Target->GetType() == cmTarget::MODULE_LIBRARY));
+  this->GetLocalGenerator()->AddSharedFlags(flags, language.c_str(), shared);
+  }
+
+  // TODO: Handle response file.
+  // Add include directory flags.
+  {
+  std::string includeFlags =
+    this->LocalGenerator->GetIncludeFlags(language.c_str(), false);
+  this->LocalGenerator->AppendFlags(flags, includeFlags.c_str());
+  }
+
+  // Append old-style preprocessor definition flags.
+  this->LocalGenerator->AppendFlags(flags, this->Makefile->GetDefineFlags());
+
+  // Add target-specific and source-specific flags.
+  this->LocalGenerator->AppendFlags(flags,
+                                   this->Target->GetProperty("COMPILE_FLAGS"));
+  this->LocalGenerator->AppendFlags(flags,
+                                    source->GetProperty("COMPILE_FLAGS"));
+
+  // TODO: Handle Apple frameworks.
+
+  return flags;
+}
+
+// TODO: Refactor with
+// void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
+std::string
+cmNinjaTargetGenerator::
+ComputeDefines(cmSourceFile *source, const std::string& language)
+{
+  std::string defines;
+
+  // Add the export symbol definition for shared library objects.
+  if(const char* exportMacro = this->Target->GetExportMacro())
+    {
+    this->LocalGenerator->AppendDefines(defines, exportMacro,
+                                        language.c_str());
+    }
+
+  // Add preprocessor definitions for this target and configuration.
+  this->LocalGenerator->AppendDefines
+    (defines,
+     this->Makefile->GetProperty("COMPILE_DEFINITIONS"),
+     language.c_str());
+  this->LocalGenerator->AppendDefines
+    (defines,
+     this->Target->GetProperty("COMPILE_DEFINITIONS"),
+     language.c_str());
+  this->LocalGenerator->AppendDefines
+    (defines,
+     source->GetProperty("COMPILE_DEFINITIONS"),
+     language.c_str());
+  {
+  std::string defPropName = "COMPILE_DEFINITIONS_";
+  defPropName += cmSystemTools::UpperCase(this->GetConfigName());
+  this->LocalGenerator->AppendDefines
+    (defines,
+     this->Makefile->GetProperty(defPropName.c_str()),
+     language.c_str());
+  this->LocalGenerator->AppendDefines
+    (defines,
+     this->Target->GetProperty(defPropName.c_str()),
+     language.c_str());
+  this->LocalGenerator->AppendDefines
+    (defines,
+     source->GetProperty(defPropName.c_str()),
+     language.c_str());
+  }
+
+  return defines;
+}
+
+std::string cmNinjaTargetGenerator::ConvertToNinjaPath(const char *path) const
+{
+  return this->LocalGenerator->Convert(path,
+                                       cmLocalGenerator::HOME_OUTPUT,
+                                       cmLocalGenerator::MAKEFILE);
+}
+
+cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const
+{
+  // Static libraries never depend on other targets for linking.
+  if (this->Target->GetType() == cmTarget::STATIC_LIBRARY)
+    return cmNinjaDeps();
+
+  cmComputeLinkInformation* cli =
+    this->Target->GetLinkInformation(this->GetConfigName());
+  if(!cli)
+    return cmNinjaDeps();
+
+  const std::vector<std::string> &deps = cli->GetDepends();
+  cmNinjaDeps result(deps.size());
+  std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath());
+  return result;
+}
+
+std::string
+cmNinjaTargetGenerator
+::GetSourceFilePath(cmSourceFile* source) const
+{
+  return ConvertToNinjaPath(source->GetFullPath().c_str());
+}
+
+std::string
+cmNinjaTargetGenerator
+::GetObjectFilePath(cmSourceFile* source) const
+{
+  std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+  if(!path.empty())
+    path += "/";
+  path += this->LocalGenerator->GetObjectFileName(*this->Target, *source);
+  return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
+{
+  std::string dir = this->Target->GetDirectory(this->GetConfigName());
+  return ConvertToNinjaPath(dir.c_str());
+}
+
+std::string
+cmNinjaTargetGenerator
+::GetTargetFilePath(const std::string& name) const
+{
+  std::string path = this->GetTargetOutputDir();
+  if (path.empty() || path == ".")
+    return name;
+  path += "/";
+  path += name;
+  return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetName() const
+{
+  return this->Target->GetName();
+}
+
+void
+cmNinjaTargetGenerator
+::WriteLanguageRules(const std::string& language)
+{
+  this->GetRulesFileStream()
+    << "# Rules for language " << language << "\n\n";
+  this->WriteCompileRule(language);
+  this->GetRulesFileStream() << "\n";
+}
+
+void
+cmNinjaTargetGenerator
+::WriteCompileRule(const std::string& language)
+{
+  cmLocalGenerator::RuleVariables vars;
+  vars.RuleLauncher = "RULE_LAUNCH_COMPILE";
+  vars.CMTarget = this->GetTarget();
+  std::string lang = language;
+  vars.Language = lang.c_str();
+  vars.Source = "$in";
+  vars.Object = "$out";
+  std::string flags = "$FLAGS";
+  vars.Defines = "$DEFINES";
+
+  std::string depfile;
+  std::string depfileFlagsName = "CMAKE_DEPFILE_FLAGS_" + language;
+  const char *depfileFlags =
+    this->GetMakefile()->GetDefinition(depfileFlagsName.c_str());
+  if (depfileFlags) {
+    std::string depfileFlagsStr = depfileFlags;
+    depfile = "$out.d";
+    cmSystemTools::ReplaceString(depfileFlagsStr, "<DEPFILE>",
+                                 depfile.c_str());
+    flags += " " + depfileFlagsStr;
+  }
+  vars.Flags = flags.c_str();
+
+  // Rule for compiling object file.
+  std::string compileCmdVar = "CMAKE_";
+  compileCmdVar += language;
+  compileCmdVar += "_COMPILE_OBJECT";
+  std::string compileCmd =
+    this->GetMakefile()->GetRequiredDefinition(compileCmdVar.c_str());
+
+  this->GetLocalGenerator()->ExpandRuleVariables(compileCmd, vars);
+
+  // Write the rule for compiling file of the given language.
+  std::ostringstream comment;
+  comment << "Rule for compiling " << language << " files.";
+  std::ostringstream description;
+  description << "Building " << language << " object $out";
+  this->GetGlobalGenerator()->AddRule(this->LanguageCompilerRule(language),
+                                      compileCmd,
+                                      description.str(),
+                                      comment.str(),
+                                      depfile);
+}
+
+void
+cmNinjaTargetGenerator
+::WriteObjectBuildStatements()
+{
+  // Write comments.
+  cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
+  this->GetBuildFileStream()
+    << "# Object build statements for "
+    << cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
+    << " target "
+    << this->GetTargetName()
+    << "\n\n";
+
+  // For each source files of this target.
+  for(std::vector<cmSourceFile*>::const_iterator i =
+        this->GetTarget()->GetSourceFiles().begin();
+      i != this->GetTarget()->GetSourceFiles().end();
+      ++i)
+    this->WriteObjectBuildStatement(*i);
+
+  this->GetBuildFileStream() << "\n";
+}
+
+void
+cmNinjaTargetGenerator
+::WriteObjectBuildStatement(cmSourceFile* source)
+{
+  if (cmCustomCommand *cc = source->GetCustomCommand())
+    this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget());
+
+  cmNinjaDeps emptyDeps;
+
+  std::string comment;
+  const char* language = source->GetLanguage();
+  // If we cannot get the language this is probably a non-source file provided
+  // in the list (typically an header file).
+  if (!language) {
+    if (source->GetPropertyAsBool("EXTERNAL_OBJECT"))
+      this->Objects.push_back(this->GetSourceFilePath(source));
+    return;
+  }
+
+  if (source->GetPropertyAsBool("HEADER_FILE_ONLY"))
+    return;
+
+  std::string rule = this->LanguageCompilerRule(language);
+
+  cmNinjaDeps outputs;
+  std::string objectFileName = this->GetObjectFilePath(source);
+  outputs.push_back(objectFileName);
+  // Add this object to the list of object files.
+  this->Objects.push_back(objectFileName);
+
+  cmNinjaDeps explicitDeps;
+  std::string sourceFileName = this->GetSourceFilePath(source);
+  explicitDeps.push_back(sourceFileName);
+
+  // Ensure that the target dependencies are built before any source file in
+  // the target, using order-only dependencies.
+  cmNinjaDeps orderOnlyDeps;
+  this->GetLocalGenerator()->AppendTargetDepends(this->Target, orderOnlyDeps);
+
+  if(const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) {
+    std::vector<std::string> depList;
+    cmSystemTools::ExpandListArgument(objectDeps, depList);
+    std::transform(depList.begin(), depList.end(),
+                   std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+  }
+
+  // Add order-only dependency on any header file with a custom command.
+  {
+    const std::vector<cmSourceFile*>& sources =
+      this->GetTarget()->GetSourceFiles();
+    for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+        si != sources.end(); ++si) {
+      if (!(*si)->GetLanguage()) {
+        if (cmCustomCommand* cc = (*si)->GetCustomCommand()) {
+          const std::vector<std::string>& ccoutputs = cc->GetOutputs();
+          std::transform(ccoutputs.begin(), ccoutputs.end(),
+                         std::back_inserter(orderOnlyDeps), MapToNinjaPath());
+        }
+      }
+    }
+  }
+
+  // If the source file is GENERATED and does not have a custom command
+  // (either attached to this source file or another one), assume that one of
+  // the target dependencies, OBJECT_DEPENDS or header file custom commands
+  // will rebuild the file.
+  if (source->GetPropertyAsBool("GENERATED") && !source->GetCustomCommand() &&
+      !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) {
+    this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName,
+                                                             orderOnlyDeps);
+  }
+  
+  cmNinjaVars vars;
+  vars["FLAGS"] = this->ComputeFlagsForObject(source, language);
+  vars["DEFINES"] = this->ComputeDefines(source, language);
+
+  cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
+                                     comment,
+                                     rule,
+                                     outputs,
+                                     explicitDeps,
+                                     emptyDeps,
+                                     orderOnlyDeps,
+                                     vars);
+}
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
new file mode 100644
index 0000000..cf47abf
--- /dev/null
+++ b/Source/cmNinjaTargetGenerator.h
@@ -0,0 +1,115 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmNinjaTargetGenerator_h
+#define cmNinjaTargetGenerator_h
+
+#include "cmStandardIncludes.h"
+#include "cmNinjaTypes.h"
+#include "cmLocalNinjaGenerator.h"
+
+class cmTarget;
+class cmGlobalNinjaGenerator;
+class cmGeneratedFileStream;
+class cmMakefile;
+class cmSourceFile;
+class cmCustomCommand;
+
+class cmNinjaTargetGenerator
+{
+public:
+  /// Create a cmNinjaTargetGenerator according to the @a target's type.
+  static cmNinjaTargetGenerator* New(cmTarget* target);
+
+  /// Build a NinjaTargetGenerator.
+  cmNinjaTargetGenerator(cmTarget* target);
+
+  /// Destructor.
+  virtual ~cmNinjaTargetGenerator();
+
+  virtual void Generate() = 0;
+
+  std::string GetTargetName() const;
+
+protected:
+  cmGeneratedFileStream& GetBuildFileStream() const;
+  cmGeneratedFileStream& GetRulesFileStream() const;
+
+  cmTarget* GetTarget() const
+  { return this->Target; }
+
+  cmLocalNinjaGenerator* GetLocalGenerator() const
+  { return this->LocalGenerator; }
+
+  cmGlobalNinjaGenerator* GetGlobalGenerator() const;
+
+  cmMakefile* GetMakefile() const
+  { return this->Makefile; }
+
+  const char* GetConfigName() const;
+
+  std::string LanguageCompilerRule(const std::string& lang) const
+  { return lang + "_COMPILER"; }
+
+  const char* GetFeature(const char* feature);
+  bool GetFeatureAsBool(const char* feature);
+  void AddFeatureFlags(std::string& flags, const char* lang);
+
+  /**
+   * Compute the flags for compilation of object files for a given @a language.
+   * @note Generally it is the value of the variable whose name is computed
+   *       by LanguageFlagsVarName().
+   */
+  std::string ComputeFlagsForObject(cmSourceFile *source,
+                                    const std::string& language);
+
+  std::string ComputeDefines(cmSourceFile *source,
+                             const std::string& language);
+
+  std::string ConvertToNinjaPath(const char *path) const;
+  cmLocalNinjaGenerator::map_to_ninja_path MapToNinjaPath() const {
+    return this->GetLocalGenerator()->MapToNinjaPath();
+  }
+
+  /// @return the list of link dependency for the given target @a target.
+  cmNinjaDeps ComputeLinkDeps() const;
+
+  /// @return the source file path for the given @a source.
+  std::string GetSourceFilePath(cmSourceFile* source) const;
+
+  /// @return the object file path for the given @a source.
+  std::string GetObjectFilePath(cmSourceFile* source) const;
+
+  /// @return the file path where the target named @a name is generated.
+  std::string GetTargetFilePath(const std::string& name) const;
+
+  /// @return the output path for the target.
+  virtual std::string GetTargetOutputDir() const;
+
+  void WriteLanguageRules(const std::string& language);
+  void WriteCompileRule(const std::string& language);
+  void WriteObjectBuildStatements();
+  void WriteObjectBuildStatement(cmSourceFile* source);
+  void WriteCustomCommandBuildStatement(cmCustomCommand *cc);
+
+  cmNinjaDeps GetObjects() const
+  { return this->Objects; }
+
+private:
+  cmTarget* Target;
+  cmMakefile* Makefile;
+  cmLocalNinjaGenerator* LocalGenerator;
+  /// List of object files for this target.
+  cmNinjaDeps Objects;
+};
+
+#endif // ! cmNinjaTargetGenerator_h
diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h
new file mode 100644
index 0000000..29ef153
--- /dev/null
+++ b/Source/cmNinjaTypes.h
@@ -0,0 +1,19 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmNinjaTypes_h
+#  define cmNinjaTypes_h
+
+typedef std::vector<std::string> cmNinjaDeps;
+typedef std::map<std::string, std::string> cmNinjaVars;
+
+#endif // ! cmGlobalNinjaGenerator_h
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
new file mode 100644
index 0000000..0a15834
--- /dev/null
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -0,0 +1,99 @@
+#include "cmNinjaUtilityTargetGenerator.h"
+#include "cmCustomCommand.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmTarget.h"
+
+cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(cmTarget *target)
+  : cmNinjaTargetGenerator(target) {}
+
+cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() {}
+
+void cmNinjaUtilityTargetGenerator::Generate()
+{
+  std::vector<std::string> commands;
+  cmNinjaDeps deps, outputs;
+
+  const std::vector<cmCustomCommand> *cmdLists[2] = {
+    &this->GetTarget()->GetPreBuildCommands(),
+    &this->GetTarget()->GetPostBuildCommands()
+  };
+
+  for (unsigned i = 0; i != 2; ++i) {
+    for (std::vector<cmCustomCommand>::const_iterator
+         ci = cmdLists[i]->begin(); ci != cmdLists[i]->end(); ++ci) {
+      this->GetLocalGenerator()->AppendCustomCommandDeps(&*ci, deps);
+      this->GetLocalGenerator()->AppendCustomCommandLines(&*ci, commands);
+    }
+  }
+
+  const std::vector<cmSourceFile*>& sources =
+    this->GetTarget()->GetSourceFiles();
+  for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
+      source != sources.end(); ++source)
+    {
+    if(cmCustomCommand* cc = (*source)->GetCustomCommand())
+      {
+      this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget());
+
+      // Depend on all custom command outputs.
+      const std::vector<std::string>& outputs = cc->GetOutputs();
+      std::transform(outputs.begin(), outputs.end(),
+                     std::back_inserter(deps), MapToNinjaPath());
+      }
+    }
+
+  this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
+  this->GetLocalGenerator()->AppendTargetDepends(this->GetTarget(), deps);
+
+  if (commands.empty()) {
+    cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
+                                            "Utility command for "
+                                            + this->GetTargetName(),
+                                            outputs,
+                                            deps);
+  } else {
+    std::string command =
+      this->GetLocalGenerator()->BuildCommandLine(commands);
+    const char *echoStr = this->GetTarget()->GetProperty("EchoString");
+    std::string desc;
+    if (echoStr)
+      desc = echoStr;
+    else
+      desc = "Running utility command for " + this->GetTargetName();
+
+    // TODO: fix problematic global targets.  For now, search and replace the
+    // makefile vars.
+    cmSystemTools::ReplaceString(command, "$(CMAKE_SOURCE_DIR)",
+                         this->GetTarget()->GetMakefile()->GetHomeDirectory());
+    cmSystemTools::ReplaceString(command, "$(CMAKE_BINARY_DIR)",
+                   this->GetTarget()->GetMakefile()->GetHomeOutputDirectory());
+    cmSystemTools::ReplaceString(command, "$(ARGS)", "");
+
+    if (command.find('$') != std::string::npos)
+      return;
+
+    std::string utilCommandName = cmake::GetCMakeFilesDirectoryPostSlash();
+    utilCommandName += this->GetTargetName() + ".util";
+
+    this->GetGlobalGenerator()->WriteCustomCommandBuild(
+      command,
+      desc,
+      "Utility command for " + this->GetTargetName(),
+      cmNinjaDeps(1, utilCommandName),
+      deps);
+
+    cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
+                                            "",
+                                            outputs,
+                                            cmNinjaDeps(1, utilCommandName),
+                                            cmNinjaDeps(),
+                                            cmNinjaDeps(),
+                                            cmNinjaVars());
+  }
+
+  this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
+                                             this->GetTarget());
+}
diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h
new file mode 100644
index 0000000..8b82ce4
--- /dev/null
+++ b/Source/cmNinjaUtilityTargetGenerator.h
@@ -0,0 +1,30 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <peter at pcc.me.uk>
+  Copyright 2011 Nicolas Despres <nicolas.despres at gmail.com>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmNinjaUtilityTargetGenerator_h
+#  define cmNinjaUtilityTargetGenerator_h
+
+#  include "cmNinjaTargetGenerator.h"
+#  include "cmNinjaTypes.h"
+
+class cmSourceFile;
+
+class cmNinjaUtilityTargetGenerator : public cmNinjaTargetGenerator
+{
+public:
+  cmNinjaUtilityTargetGenerator(cmTarget* target);
+  ~cmNinjaUtilityTargetGenerator();
+
+  void Generate();
+};
+
+#endif // ! cmNinjaUtilityTargetGenerator_h
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index d691f46..1d793d7 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -84,6 +84,10 @@
 #endif
 #include "cmGlobalUnixMakefileGenerator3.h"
 
+#ifdef CMAKE_USE_NINJA
+#  include "cmGlobalNinjaGenerator.h"
+#endif
+
 #if defined(CMAKE_HAVE_VS_GENERATORS)
 #include "cmCallVisualStudioMacro.h"
 #endif
@@ -2614,6 +2618,10 @@ void cmake::AddDefaultGenerators()
 #endif
   this->Generators[cmGlobalUnixMakefileGenerator3::GetActualName()] =
     &cmGlobalUnixMakefileGenerator3::New;
+#ifdef CMAKE_USE_NINJA
+  this->Generators[cmGlobalNinjaGenerator::GetActualName()] =
+    &cmGlobalNinjaGenerator::New;
+#endif
 #ifdef CMAKE_USE_XCODE
   this->Generators[cmGlobalXCodeGenerator::GetActualName()] =
     &cmGlobalXCodeGenerator::New;
diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt
index 31392b5..aa32d67 100644
--- a/Tests/BuildDepends/CMakeLists.txt
+++ b/Tests/BuildDepends/CMakeLists.txt
@@ -40,6 +40,8 @@ if("${CMAKE_GENERATOR}" MATCHES "Make")
 endif()
 list(APPEND _cmake_options "-DTEST_LINK_DEPENDS=${TEST_LINK_DEPENDS}")
 
+list(APPEND _cmake_options "-DCMAKE_FORCE_DEPFILES=1")
+
 file(MAKE_DIRECTORY ${BuildDepends_BINARY_DIR}/Project)
 message("Creating Project/foo.cxx")
 write_file(${BuildDepends_BINARY_DIR}/Project/foo.cxx 
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 21d1196..4670526 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -325,6 +325,15 @@ IF(BUILD_TESTING)
       --build-target car
       --test-command car
       )
+
+    IF(${CMAKE_TEST_GENERATOR} MATCHES "Ninja")
+      # The Ninja generator does not create a recursive build system.  Start
+      # from the root directory.
+      SET(SubProject_SUBDIR)
+    ELSE()
+      SET(SubProject_SUBDIR "/foo")
+    ENDIF()
+
     # For stage 2, do not run cmake again.
     # Then build the foo sub project which should build
     # the bar library which should be referenced because
@@ -332,13 +341,14 @@ IF(BUILD_TESTING)
     # directly in the foo sub project
     ADD_TEST(SubProject-Stage2  ${CMAKE_CTEST_COMMAND}
       --build-and-test
-      "${CMake_SOURCE_DIR}/Tests/SubProject/foo"
-      "${CMake_BINARY_DIR}/Tests/SubProject/foo"
+      "${CMake_SOURCE_DIR}/Tests/SubProject${SubProject_SUBDIR}"
+      "${CMake_BINARY_DIR}/Tests/SubProject${SubProject_SUBDIR}"
       --build-generator ${CMAKE_TEST_GENERATOR}
       --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
       --build-nocmake
       --build-project foo
       --build-target foo
+      --build-exe-dir "${CMake_BINARY_DIR}/Tests/SubProject/foo"
       --test-command foo
       )
     SET_TESTS_PROPERTIES ( SubProject-Stage2 PROPERTIES DEPENDS SubProject)
diff --git a/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt b/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt
index c7cc090..c362e79 100644
--- a/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt
+++ b/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt
@@ -24,6 +24,12 @@ IF ("${PROJECT_SOURCE_DIR}" STREQUAL "${ANOTHER_PROJ_SOURCE_DIR}")
     MATH(EXPR MAXPATH "${MAXPATH} - 46")
   ENDIF()
 
+  # Ninja imposes a maximum path component count of 30.  Permit more
+  # path components in the source path.
+  IF(${CMAKE_GENERATOR} MATCHES "Ninja")
+    MATH(EXPR MAXPATH "${MAXPATH} - 44")
+  ENDIF()
+
   # MAXPATH less 25 for last /and/deeper/simple.cxx part and small safety
   MATH(EXPR MAXPATH "${MAXPATH} - 25")
   STRING(LENGTH "${DEEPDIR}" DEEPDIR_LEN)
-- 
1.7.5.3




More information about the cmake-developers mailing list