[WIP] GN generator
diff --git a/Modules/CMakeGNFindMake.cmake b/Modules/CMakeGNFindMake.cmake
new file mode 100644
index 0000000..9772a10
--- /dev/null
+++ b/Modules/CMakeGNFindMake.cmake
@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+find_program(CMAKE_MAKE_PROGRAM
+  NAMES gn
+  DOC "Program used to build from BUILD.gn files.")
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 59920f8..ab543a6 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -738,9 +738,15 @@
 
 # Ninja support
 set(SRCS ${SRCS}
+  cmGlobalGNGenerator.cxx
+  cmGlobalGNGenerator.h
   cmGlobalNinjaGenerator.cxx
   cmGlobalNinjaGenerator.h
+  cmGNTargetGenerator.cxx
+  cmGNTargetGenerator.h
   cmNinjaTypes.h
+  cmLocalGNGenerator.cxx
+  cmLocalGNGenerator.h
   cmLocalNinjaGenerator.cxx
   cmLocalNinjaGenerator.h
   cmNinjaTargetGenerator.cxx
diff --git a/Source/cmGNTargetGenerator.cxx b/Source/cmGNTargetGenerator.cxx
new file mode 100644
index 0000000..7885d49
--- /dev/null
+++ b/Source/cmGNTargetGenerator.cxx
@@ -0,0 +1,158 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmGNTargetGenerator.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmLinkLineComputer.h"
+#include "cmLocalGNGenerator.h"
+#include "cmMakefile.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+
+#include <iostream>
+
+cmGNTargetGenerator::cmGNTargetGenerator(cmGeneratorTarget* target)
+  : cmCommonTargetGenerator(target)
+  , LocalGenerator(
+      static_cast<cmLocalGNGenerator*>(target->GetLocalGenerator()))
+{
+  this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
+}
+
+cmGNTargetGenerator::~cmGNTargetGenerator()
+{
+}
+
+cmGeneratedFileStream& cmGNTargetGenerator::GetBuildFileStream() const
+{
+  return *this->GetGlobalGenerator()->GetBuildFileStream();
+}
+
+cmGlobalGNGenerator* cmGNTargetGenerator::GetGlobalGenerator() const
+{
+  return this->LocalGenerator->GetGlobalGNGenerator();
+}
+
+void cmGNTargetGenerator::Generate()
+{
+  std::string type;
+  switch (this->GeneratorTarget->GetType()) {
+    case cmStateEnums::OBJECT_LIBRARY:
+      type = "source_set";
+      break;
+    case cmStateEnums::STATIC_LIBRARY:
+      type = "static_library";
+      break;
+    case cmStateEnums::SHARED_LIBRARY:
+      type = "shared_library";
+      break;
+    case cmStateEnums::EXECUTABLE:
+      type = "executable";
+      break;
+    case cmStateEnums::MODULE_LIBRARY:
+      type = "loadable_module";
+      break;
+    case cmStateEnums::INTERFACE_LIBRARY:
+      type = "config";
+      break;
+    case cmStateEnums::UTILITY:
+      type = "group";
+      break;
+    // GLOBAL_TARGET
+    // UNKNOWN_LIBRARY
+    default:
+      type = "group";
+      break;
+  }
+
+  std::vector<std::string> sources;
+  std::map<std::string, std::string> variables;
+
+  std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+
+  std::vector<cmSourceFile const*> cmSources;
+  this->GeneratorTarget->GetObjectSources(cmSources, config);
+  for (std::vector<cmSourceFile const*>::const_iterator i = cmSources.begin();
+       i != cmSources.end(); ++i) {
+    std::string sourcePath = this->LocalGenerator->ConvertToRelativePath(
+      this->LocalGenerator->GetState()->GetBinaryDirectory(), (*i)->GetFullPath());;
+    sources.push_back(sourcePath);
+  }
+
+  std::vector<std::string> deps;
+  std::vector<std::string> depends;
+  this->LocalGenerator->AppendTargetDepends(this->GeneratorTarget, depends);
+  for (std::vector<std::string>::const_iterator i = depends.begin();
+       i != depends.end(); ++i) {
+    deps.push_back(":" + *i);
+  }
+
+  // Flags
+  
+  const std::string& linkLanguage =
+    this->GetGeneratorTarget()->GetLinkerLanguage(config);
+  
+  std::string createRule = this->GeneratorTarget->GetCreateRuleVariable(
+    this->TargetLinkLanguage, this->GetConfigName());
+  //bool useWatcomQuote = this->Makefile->IsOn(createRule + "_USE_WATCOM_QUOTE");
+
+  CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+    this->GetGlobalGenerator()->CreateLinkLineComputer(
+      this->LocalGenerator,
+      this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+  //linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+
+  std::string cflags1;
+  this->LocalGenerator->AddLanguageFlags(cflags1, linkLanguage, config);
+  std::cout << "[" << this->GetGeneratorTarget()->GetName() << "] language cflags:" << cflags1 << "\n";
+
+  std::vector<std::string> flags;
+  std::string s = this->GetFlags(linkLanguage);
+  if (!s.empty())
+    flags = cmSystemTools::tokenize(s, " ");
+  std::cout << "[" << this->GetGeneratorTarget()->GetName() << "] flags:" << s << "\n";
+
+  std::vector<std::string> defines;
+  this->GeneratorTarget->GetCompileDefinitions(defines, this->ConfigName, linkLanguage);
+
+  std::vector<std::string> includes;
+  s = this->GetIncludes(linkLanguage);
+  if (!s.empty())
+    includes = cmSystemTools::tokenize(s, " ");
+
+  std::string libs, cflags, ldflags, frameworkPath, linkPath;
+  this->LocalGenerator->GetTargetFlags(
+    linkLineComputer.get(), this->ConfigName, libs, cflags, ldflags,
+    frameworkPath, linkPath, this->GeneratorTarget);
+  std::cout << "[" << this->GetGeneratorTarget()->GetName() << "] target cflags:" << cflags << "\n";
+  std::cout << "[" << this->GetGeneratorTarget()->GetName() << "] target ldflags:" << ldflags << "\n";
+  std::cout << "[" << this->GetGeneratorTarget()->GetName() << "] target link:" << linkPath << "\n";
+
+  this->GetGlobalGenerator()->WriteTarget(
+    this->GetBuildFileStream(), "", type, this->GetGeneratorTarget()->GetName(),
+    "", flags, defines, includes, sources, deps, variables);
+
+  this->GetBuildFileStream() << "\n";
+}
+
+void cmGNTargetGenerator::AddIncludeFlags(std::string& languageFlags,
+                                          std::string const& language)
+{
+#if 0
+  std::vector<std::string> includes;
+  this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+                                              language, this->GetConfigName());
+  // Add include directory flags.
+  std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
+    includes, this->GeneratorTarget, language,
+    language == "RC", // full include paths for RC needed by cmcldeps
+    false, this->GetConfigName());
+  if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
+    std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
+  }
+
+  this->LocalGenerator->AppendFlags(languageFlags, includeFlags);
+#endif
+}
diff --git a/Source/cmGNTargetGenerator.h b/Source/cmGNTargetGenerator.h
new file mode 100644
index 0000000..3028d63
--- /dev/null
+++ b/Source/cmGNTargetGenerator.h
@@ -0,0 +1,58 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmGNTargetGenerator_h
+#define cmGNTargetGenerator_h
+
+#include <cmConfigure.h>
+
+#include "cmCommonTargetGenerator.h"
+#include "cmGlobalGNGenerator.h"
+
+class cmGeneratedFileStream;
+class cmGeneratorTarget;
+class cmLocalGNGenerator;
+class cmMakefile;
+
+class cmGNTargetGenerator : public cmCommonTargetGenerator
+{
+public:
+  cmGNTargetGenerator(cmGeneratorTarget* target);
+
+  ~cmGNTargetGenerator() CM_OVERRIDE;
+
+  void Generate();
+
+protected:
+  cmGeneratedFileStream& GetBuildFileStream() const;
+
+  cmGeneratorTarget* GetGeneratorTarget() const
+  {
+    return this->GeneratorTarget;
+  }
+
+  cmLocalGNGenerator* GetLocalGenerator() const
+  {
+    return this->LocalGenerator;
+  }
+
+  cmGlobalGNGenerator* GetGlobalGenerator() const;
+
+  cmMakefile* GetMakefile() const { return this->Makefile; }
+
+  std::string ConvertToNinjaPath(const std::string& path) const
+  {
+    return this->GetGlobalGenerator()->ConvertToGNPath(path);
+  }
+
+  void AddIncludeFlags(std::string& flags,
+                       std::string const& lang) CM_OVERRIDE;
+
+  std::string ComputeDefines(cmSourceFile const* source,
+                             const std::string& language);
+
+private:
+  cmLocalGNGenerator* LocalGenerator;
+  std::string TargetLinkLanguage;
+};
+
+#endif // ! cmGNTargetGenerator_h
diff --git a/Source/cmGlobalGNGenerator.cxx b/Source/cmGlobalGNGenerator.cxx
new file mode 100644
index 0000000..7fe7127
--- /dev/null
+++ b/Source/cmGlobalGNGenerator.cxx
@@ -0,0 +1,477 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmGlobalGNGenerator.h"
+
+#include "cmDocumentationEntry.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmLocalGenerator.h"
+#include "cmLocalGNGenerator.h"
+#include "cmMakefile.h"
+#include "cmState.h"
+#include "cmVersion.h"
+
+class cmake;
+
+const char* cmGlobalGNGenerator::GN_BUILD_FILE = "BUILD.gn";
+const char* cmGlobalGNGenerator::INDENT = "  ";
+
+#if 0
+namespace {
+class cmGNWriter
+{
+public:
+  cmGNWriter(std::ostream& output, std::size_t level = 0);
+
+private:
+  std::ostream& Output;
+  std::size_t Level;
+};
+
+cmGNWriter::cmGNWriter(std::ostream& output, std::size_t level = 0)
+  : Output(output)
+  , Level(level)
+{
+}
+
+void cmGNWriter::StartScope(std::string const& name)
+{
+  Output << type + "(\"" + name + "\")";
+  Output << "{";
+}
+
+};
+#endif
+
+void cmGlobalGNGenerator::Indent(std::ostream& os, int count)
+{
+  for (int i = 0; i < count; ++i) {
+    os << cmGlobalGNGenerator::INDENT;
+  }
+}
+
+void cmGlobalGNGenerator::WriteComment(std::ostream& os,
+                                       const std::string& comment)
+{
+  if (comment.empty()) {
+    return;
+  }
+
+  std::string::size_type lpos = 0;
+  std::string::size_type rpos;
+  while ((rpos = comment.find('\n', lpos)) != std::string::npos) {
+    os << "# " << comment.substr(lpos, rpos - lpos) << "\n";
+    lpos = rpos + 1;
+  }
+  os << "# " << comment.substr(lpos) << "\n";
+}
+
+void cmGlobalGNGenerator::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;
+  }
+
+  cmGlobalGNGenerator::WriteComment(os, comment);
+  cmGlobalGNGenerator::Indent(os, indent);
+  os << name << " = " << val << "\n";
+}
+
+void cmGlobalGNGenerator::WriteVariable(std::ostream& os,
+                                        const std::string& name,
+                                        const std::vector<std::string>& values,
+                                        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 there are no values.
+  if (values.empty()) {
+    return;
+  }
+
+  cmGlobalGNGenerator::WriteComment(os, comment);
+  cmGlobalGNGenerator::Indent(os, indent);
+  os << name << " = [\n";
+  for (std::vector<std::string>::const_iterator i = values.begin();
+       i != values.end(); ++i) {
+    std::string val = cmSystemTools::TrimWhitespace(*i);
+    cmGlobalGNGenerator::Indent(os, indent + 1);
+    os << "\"" << val << "\",\n";
+  }
+  cmGlobalGNGenerator::Indent(os, indent);
+  os << "]\n";
+}
+
+void cmGlobalGNGenerator::WriteFunction(std::ostream& os,
+                                        const std::string& name,
+                                        const std::vector<std::string>& args,
+                                        const std::string& comment,
+                                        int indent)
+{
+  // Make sure we have a name.
+  if (name.empty()) {
+    cmSystemTools::Error("No name given for WriteFunction! called "
+                         "with comment: ",
+                         comment.c_str());
+    return;
+  }
+
+  // Do not add a variable if there are no values.
+  //if (values.empty()) {
+  //  return;
+  //}
+
+  cmGlobalGNGenerator::WriteComment(os, comment);
+  cmGlobalGNGenerator::Indent(os, indent);
+  os << name << "(";
+  for (std::vector<std::string>::const_iterator i = args.begin();
+       i != args.end(); ++i) {
+    std::string val = cmSystemTools::TrimWhitespace(*i);
+    os << "\"" << val << "\"";
+    if (i + 1 == args.end())
+      os << ",";
+  }
+  os << ")\n";
+}
+
+void cmGlobalGNGenerator::WriteTarget(
+  std::ostream& os, const std::string& comment, const std::string& type,
+  const std::string& name, const std::string& output_name,
+  const std::vector<std::string>& flags,
+  const std::vector<std::string>& defines,
+  const std::vector<std::string>& includes,
+  const std::vector<std::string>& sources,
+  const std::vector<std::string>& deps,
+  const std::map<std::string, std::string>& variables,
+  int cmdLineLimit)
+{
+  cmGlobalGNGenerator::WriteComment(os, comment);
+
+  std::string id = type + "(\"" + name + "\")";
+
+  std::ostringstream variable_assignments;
+  cmGlobalGNGenerator::WriteVariable(variable_assignments, "cflags", flags, "", 1);
+  cmGlobalGNGenerator::WriteVariable(variable_assignments, "defines", defines, "", 1);
+  cmGlobalGNGenerator::WriteVariable(variable_assignments, "include_dirs", includes, "", 1);
+  cmGlobalGNGenerator::WriteVariable(variable_assignments, "sources", sources, "", 1);
+  cmGlobalGNGenerator::WriteVariable(variable_assignments, "deps", deps, "", 1);
+
+  for (std::map<std::string, std::string>::const_iterator i = variables.begin();
+       i != variables.end(); ++i) {
+    cmGlobalGNGenerator::WriteVariable(variable_assignments, i->first,
+                                       i->second, "", 1);
+  }
+  std::string assignments = variable_assignments.str();
+
+  os << id << " {\n" << assignments << "}\n";
+}
+
+cmGlobalGNGenerator::cmGlobalGNGenerator(cmake* cm)
+  : cmGlobalCommonGenerator(cm)
+  , BuildFileStream(CM_NULLPTR)
+{
+  this->FindMakeProgramFile = "CMakeGNFindMake.cmake";
+}
+
+cmGlobalGNGenerator::~cmGlobalGNGenerator()
+{
+}
+
+static void WriteDotGN(std::ostream& os)
+{
+  cmGlobalGNGenerator::WriteVariable(os, "buildconfig", "\"//build/BUILDCONFIG.gn\"");
+}
+
+static void WriteBuildConfig(std::ostream& os)
+{
+  os << "set_default_toolchain(\"//build:host\")";
+}
+
+static void WriteToolchainBuild(std::ostream& os)
+{
+  os << "toolchain(\"host\") {\n";
+  cmGlobalGNGenerator::WriteVariable(os, "cc", "\"cc\"", "", 1);
+  cmGlobalGNGenerator::WriteVariable(os, "cxx", "\"c++\"", "", 1);
+  cmGlobalGNGenerator::WriteVariable(os, "ar", "\"ar\"", "", 1);
+  cmGlobalGNGenerator::WriteVariable(os, "ld", "cxx", "", 1);
+  os << "  tool(\"cc\") {\n";
+  cmGlobalGNGenerator::WriteVariable(os, "depfile", "\"{{output}}.d\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "command", "\"$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "depsformat", "\"gcc\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "description", "\"CC {{output}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "outputs", std::vector<std::string>{
+      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+    }, "", 2);
+  os << "  }\n";
+  os << "  tool(\"cxx\") {\n";
+  cmGlobalGNGenerator::WriteVariable(os, "depfile", "\"{{output}}.d\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "command", "\"$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "depsformat", "\"gcc\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "description", "\"CXX {{output}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "outputs", std::vector<std::string>{
+      "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+    }, "", 2);
+  os << "  }\n";
+  os << "  tool(\"alink\") {\n";
+  cmGlobalGNGenerator::WriteVariable(os, "rspfile", "\"{{output}}.rsp\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "command", "\"rm -f {{output}} && $ar {{arflags}} rcsD {{output}} @\\\"$rspfile\\\"\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "description", "\"AR {{output}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "rspfile_content", "\"{{inputs}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "outputs", std::vector<std::string>{
+      "{{output_dir}}/{{target_output_name}}{{output_extension}}",
+    }, "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "default_output_dir", "\"{{root_out_dir}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "default_output_extension", "\".a\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "output_prefix", "\"lib\"", "", 2);
+  os << "  }\n";
+  os << "  tool(\"solink\") {\n";
+  cmGlobalGNGenerator::WriteVariable(os, "outname", "\"{{target_output_name}}{{output_extension}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "outfile", "\"{{output_dir}}/$outname\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "rspfile", "\"$outfile.rsp\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "command", "\"$ld -shared {{ldflags}} -o \\\"$outfile\\\" -Wl,-soname=\\\"$outname\\\" @\\\"$rspfile\\\"\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "description", "\"SOLINK $outfile\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "rspfile_content", "\"-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "outputs", std::vector<std::string>{
+      "{{output_dir}}/{{target_output_name}}{{output_extension}}",
+    }, "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "default_output_dir", "\"{{root_out_dir}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "default_output_extension", "\".so\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "output_prefix", "\"lib\"", "", 2);
+  os << "  }\n";
+  os << "  tool(\"link\") {\n";
+  cmGlobalGNGenerator::WriteVariable(os, "outfile", "\"{{output_dir}}/{{target_output_name}}{{output_extension}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "rspfile", "\"$outfile.rsp\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "command", "\"$ld {{ldflags}} -o $outfile -Wl,--start-group @\\\"$rspfile\\\" {{solibs}} -Wl,--end-group {{libs}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "description", "\"LINK $outfile\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "default_output_dir", "\"{{root_out_dir}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "rspfile_content", "\"{{inputs}}\"", "", 2);
+  cmGlobalGNGenerator::WriteVariable(os, "outputs", std::vector<std::string>{
+      "{{output_dir}}/{{target_output_name}}{{output_extension}}",
+    }, "", 2);
+  os << "  }\n";
+  os << "}\n";
+}
+
+// Implemented by:
+//   cmGlobalUnixMakefileGenerator3
+//   cmGlobalGhsMultiGenerator
+//   cmGlobalVisualStudio10Generator
+//   cmGlobalVisualStudio7Generator
+//   cmGlobalXCodeGenerator
+// Called by:
+//   cmGlobalGenerator::Build()
+void cmGlobalGNGenerator::GenerateBuildCommand(
+  std::vector<std::string>& makeCommand, const std::string& makeProgram,
+  const std::string& /*projectName*/, const std::string& projectDir,
+  const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
+  bool verbose, std::vector<std::string> const& makeOptions)
+{
+  makeCommand.push_back(this->SelectMakeProgram(makeProgram));
+
+  //if (verbose) {
+  //  makeCommand.push_back("-v");
+  //}
+
+  if (!projectDir.empty()) {
+    cmGeneratedFileStream *dot = new cmGeneratedFileStream(
+      (projectDir + "/.gn").c_str(), false, this->GetMakefileEncoding());
+    WriteDotGN(*dot);
+    delete dot;
+    cmGeneratedFileStream *buildconfig = new cmGeneratedFileStream(
+      (projectDir + "/build/BUILDCONFIG.gn").c_str(), false, this->GetMakefileEncoding());
+    WriteBuildConfig(*buildconfig);
+    delete buildconfig;
+    cmGeneratedFileStream *toolchain = new cmGeneratedFileStream(
+      (projectDir + "/build/BUILD.gn").c_str(), false, this->GetMakefileEncoding());
+    WriteToolchainBuild(*toolchain);
+    delete toolchain;
+  }
+
+  makeCommand.insert(makeCommand.end(), makeOptions.begin(),
+                     makeOptions.end());
+  if (!targetName.empty()) {
+    if (targetName == "clean") {
+      makeCommand.push_back("-t");
+      makeCommand.push_back("clean");
+    } else {
+      makeCommand.push_back("gen");
+      makeCommand.push_back(targetName);
+    }
+  }
+}
+
+// Non-virtual public methods
+
+std::string cmGlobalGNGenerator::ConvertToGNPath(
+  const std::string& path) const
+{
+  cmLocalGNGenerator* gn =
+    static_cast<cmLocalGNGenerator*>(this->LocalGenerators[0]);
+  return gn->ConvertToRelativePath(
+    this->LocalGenerators[0]->GetState()->GetBinaryDirectory(), path);
+  /*return this->NinjaOutputPath(convPath);*/
+}
+
+void cmGlobalGNGenerator::AppendTargetDepends(
+  cmGeneratorTarget const* target, std::vector<std::string>& outputs)
+{
+  if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
+    // These depend only on other CMake-provided targets, e.g. "all".
+    std::set<std::string> const& utils = target->GetUtilities();
+    for (std::set<std::string>::const_iterator i = utils.begin();
+         i != utils.end(); ++i) {
+      std::string d =
+        target->GetLocalGenerator()->GetCurrentBinaryDirectory() +
+        std::string("/") + *i;
+      outputs.push_back(this->ConvertToGNPath(d));
+    }
+  } else {
+    std::vector<std::string> outs;
+    std::string config =
+        target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+
+    cmTargetDependSet const& targetDeps = this->GetTargetDirectDepends(target);
+    for (cmTargetDependSet::const_iterator i = targetDeps.begin();
+         i != targetDeps.end(); ++i) {
+      if ((*i)->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+        continue;
+      }
+      /*outs.push_back(this->ConvertToGNPath(
+        (*i)->GetFullPath(config, false, false)));*/
+      outs.push_back(this->ConvertToGNPath((*i)->GetName()));
+    }
+    std::sort(outs.begin(), outs.end());
+    outputs.insert(outputs.end(), outs.begin(), outs.end());
+  }
+}
+
+// Virtual public methods.
+
+cmLocalGenerator* cmGlobalGNGenerator::CreateLocalGenerator(cmMakefile* mf)
+{
+  return new cmLocalGNGenerator(this, mf);
+}
+
+codecvt::Encoding cmGlobalGNGenerator::GetMakefileEncoding() const
+{
+  return codecvt::None;
+}
+
+void cmGlobalGNGenerator::GetDocumentation(cmDocumentationEntry& entry)
+{
+  entry.Name = cmGlobalGNGenerator::GetActualName();
+  entry.Brief = "Generates BUILD.gn files.";
+}
+
+void cmGlobalGNGenerator::Generate()
+{
+  this->OpenBuildFileStream();
+
+  this->cmGlobalGenerator::Generate();
+
+  this->CloseBuildFileStream();
+}
+
+// Private methods
+
+void cmGlobalGNGenerator::OpenBuildFileStream()
+{
+  // Compute GN's build file path.
+  std::string buildFilePath =
+    this->GetCMakeInstance()->GetHomeOutputDirectory();
+  buildFilePath += "/";
+  buildFilePath += cmGlobalGNGenerator::GN_BUILD_FILE;
+
+  // Get a stream where to generate things.
+  if (!this->BuildFileStream) {
+    this->BuildFileStream = new cmGeneratedFileStream(
+      buildFilePath.c_str(), false, this->GetMakefileEncoding());
+    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);
+}
+
+void cmGlobalGNGenerator::CloseBuildFileStream()
+{
+  if (this->BuildFileStream) {
+    delete this->BuildFileStream;
+    this->BuildFileStream = CM_NULLPTR;
+  } else {
+    cmSystemTools::Error("Build file stream was not open.");
+  }
+}
+
+// Private virtual overrides
+
+void cmGlobalGNGenerator::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";
+}
+
+#if 0
+void cmGlobalNinjaGenerator::AppendTargetOutputs(
+  cmGeneratorTarget const* target, cmNinjaDeps& outputs)
+{
+  std::string configName =
+    target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+
+  // for frameworks, we want the real name, not smple name
+  // frameworks always appear versioned, and the build.ninja
+  // will always attempt to manage symbolic links instead
+  // of letting cmOSXBundleGenerator do it.
+  bool realname = target->IsFrameworkOnApple();
+
+  switch (target->GetType()) {
+    case cmStateEnums::EXECUTABLE:
+    case cmStateEnums::SHARED_LIBRARY:
+    case cmStateEnums::STATIC_LIBRARY:
+    case cmStateEnums::MODULE_LIBRARY: {
+      outputs.push_back(this->ConvertToNinjaPath(
+        target->GetFullPath(configName, false, realname)));
+      break;
+    }
+    case cmStateEnums::OBJECT_LIBRARY:
+    case cmStateEnums::GLOBAL_TARGET:
+    case cmStateEnums::UTILITY: {
+      std::string path =
+        target->GetLocalGenerator()->GetCurrentBinaryDirectory() +
+        std::string("/") + target->GetName();
+      outputs.push_back(this->ConvertToNinjaPath(path));
+      break;
+    }
+
+    default:
+      return;
+  }
+}
+#endif
diff --git a/Source/cmGlobalGNGenerator.h b/Source/cmGlobalGNGenerator.h
new file mode 100644
index 0000000..45ddb8b
--- /dev/null
+++ b/Source/cmGlobalGNGenerator.h
@@ -0,0 +1,155 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmGlobalGNGenerator_h
+#define cmGlobalGNGenerator_h
+
+#include <cmConfigure.h>
+
+#include "cmGlobalCommonGenerator.h"
+#include "cmGlobalGenerator.h"
+#include "cmGlobalGeneratorFactory.h"
+
+#include <map>
+#include <vector>
+
+class cmGeneratedFileStream;
+class cmake;
+
+/** \class cmGlobalCommonGenerator
+ * \brief Common infrastructure for Makefile and Ninja global generators.
+ */
+class cmGlobalGNGenerator : public cmGlobalCommonGenerator
+{
+public:
+  /// The default name of Ninja's build file. Typically: build.ninja.
+  static const char* GN_BUILD_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);
+
+  /**
+   * Utilized by the generator factory to determine if this generator
+   * supports toolsets.
+   */
+  static bool SupportsToolset() { return false; }
+
+  /**
+   * Utilized by the generator factory to determine if this generator
+   * supports platforms.
+   */
+  static bool SupportsPlatform() { return false; }
+
+  /**
+   * 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 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 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::vector<std::string>& values,
+                            const std::string& comment = "", int indent = 0);
+
+  /**
+   * 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.
+   */
+  void WriteTarget(std::ostream& os, const std::string& comment,
+                   const std::string& type, const std::string& name,
+                   const std::string& output_name,
+                   const std::vector<std::string>& flags,
+                   const std::vector<std::string>& defines,
+                   const std::vector<std::string>& includes,
+                   const std::vector<std::string>& sources,
+                   const std::vector<std::string>& deps,
+                   const std::map<std::string, std::string>& variables,
+                   /*const std::vector<std::string>& outputs,
+                   const std::vector<std::string>& cflags,
+                   const std::vector<std::string>& implicitOuts,
+                   const std::vector<std::string>& explicitDeps,
+                   const std::vector<std::string>& implicitDeps,
+                   const std::vector<std::string>& orderOnlyDeps,
+                   const std::map<std::string, std::string>& variables,*/
+                   int cmdLineLimit = 0);
+
+  void WriteFunction(std::ostream& os,
+                     const std::string& name,
+                     const std::vector<std::string>& args,
+                     const std::string& comment,
+                     int indent);
+
+public:
+  cmGlobalGNGenerator(cmake* cm);
+
+  static cmGlobalGeneratorFactory* NewFactory()
+  {
+    return new cmGlobalGeneratorSimpleFactory<cmGlobalGNGenerator>();
+  }
+
+  ~cmGlobalGNGenerator() CM_OVERRIDE;
+
+  cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) CM_OVERRIDE;
+
+  std::string GetName() const CM_OVERRIDE
+  {
+    return cmGlobalGNGenerator::GetActualName();
+  }
+
+  static std::string GetActualName() { return "GN"; }
+
+  /** Get encoding used by generator for ninja files */
+  codecvt::Encoding GetMakefileEncoding() const CM_OVERRIDE;
+
+  static void GetDocumentation(cmDocumentationEntry& entry);
+
+  void GenerateBuildCommand(std::vector<std::string>& makeCommand,
+                            const std::string& makeProgram,
+                            const std::string& projectName,
+                            const std::string& projectDir,
+                            const std::string& targetName,
+                            const std::string& config, bool fast, bool verbose,
+                            std::vector<std::string> const& makeOptions =
+                              std::vector<std::string>()) CM_OVERRIDE;
+
+  cmGeneratedFileStream* GetBuildFileStream() const
+  {
+    return this->BuildFileStream;
+  }
+
+  std::string ConvertToGNPath(const std::string& path) const;
+
+  void AppendTargetDepends(
+    cmGeneratorTarget const* target, std::vector<std::string>& outputs);
+
+protected:
+  void Generate() CM_OVERRIDE;
+
+private:
+  void OpenBuildFileStream();
+  void CloseBuildFileStream();
+
+  /// Write the common disclaimer text at the top of each build file.
+  void WriteDisclaimer(std::ostream& os);
+
+  cmGeneratedFileStream* BuildFileStream;
+};
+
+#endif
diff --git a/Source/cmLocalGNGenerator.cxx b/Source/cmLocalGNGenerator.cxx
new file mode 100644
index 0000000..7a37207
--- /dev/null
+++ b/Source/cmLocalGNGenerator.cxx
@@ -0,0 +1,79 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmLocalGNGenerator.h"
+
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmGlobalGNGenerator.h"
+#include "cmGNTargetGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmState.h"
+
+cmLocalGNGenerator::cmLocalGNGenerator(cmGlobalGenerator* gg,
+                                       cmMakefile* mf)
+  : cmLocalCommonGenerator(gg, mf, mf->GetState()->GetBinaryDirectory())
+{
+}
+
+cmLocalGNGenerator::~cmLocalGNGenerator()
+{
+}
+
+// Virtual public methods
+
+void cmLocalGNGenerator::ComputeObjectFilenames(
+  std::map<cmSourceFile const*, std::string>& mapping,
+  cmGeneratorTarget const* gt)
+{
+  for (std::map<cmSourceFile const*, std::string>::iterator si =
+         mapping.begin();
+       si != mapping.end(); ++si) {
+    cmSourceFile const* sf = si->first;
+    si->second =
+      this->GetObjectFileNameWithoutTarget(*sf, gt->ObjectDirectory);
+  }
+}
+
+void cmLocalGNGenerator::Generate()
+{
+  // Compute the path to use when referencing the current output
+  // directory from the top output directory.
+  this->HomeRelativeOutputPath = this->ConvertToRelativePath(
+    this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory());
+  if (this->HomeRelativeOutputPath == ".") {
+    this->HomeRelativeOutputPath = "";
+  }
+
+  std::vector<cmGeneratorTarget*> targets = this->GetGeneratorTargets();
+  for (std::vector<cmGeneratorTarget*>::iterator t = targets.begin();
+       t != targets.end(); ++t) {
+    if ((*t)->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+      continue;
+    }
+    cmGNTargetGenerator tg(*t);
+    tg.Generate();
+  }
+}
+
+// Non-virtual public methods.
+
+const cmGlobalGNGenerator* cmLocalGNGenerator::GetGlobalGNGenerator()
+  const
+{
+  return static_cast<const cmGlobalGNGenerator*>(
+    this->GetGlobalGenerator());
+}
+
+cmGlobalGNGenerator* cmLocalGNGenerator::GetGlobalGNGenerator()
+{
+  return static_cast<cmGlobalGNGenerator*>(this->GetGlobalGenerator());
+}
+
+void cmLocalGNGenerator::AppendTargetDepends(
+  cmGeneratorTarget* target, std::vector<std::string>& outputs)
+{
+  this->GetGlobalGNGenerator()->AppendTargetDepends(target, outputs);
+}
diff --git a/Source/cmLocalGNGenerator.h b/Source/cmLocalGNGenerator.h
new file mode 100644
index 0000000..b54aa7d
--- /dev/null
+++ b/Source/cmLocalGNGenerator.h
@@ -0,0 +1,43 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmLocalGNGenerator_h
+#define cmLocalGNGenerator_h
+
+#include <cmConfigure.h>
+
+#include <string>
+
+#include "cmLocalCommonGenerator.h"
+
+class cmGeneratorTarget;
+class cmGlobalGenerator;
+class cmGlobalGNGenerator;
+class cmMakefile;
+
+/** \class cmLocalCommonGenerator
+ * \brief Common infrastructure for Makefile and Ninja local generators.
+ */
+class cmLocalGNGenerator : public cmLocalCommonGenerator
+{
+public:
+  cmLocalGNGenerator(cmGlobalGenerator* gg, cmMakefile* mf);
+
+  ~cmLocalGNGenerator() CM_OVERRIDE;
+
+  void Generate() CM_OVERRIDE;
+
+  const cmGlobalGNGenerator* GetGlobalGNGenerator() const;
+  cmGlobalGNGenerator* GetGlobalGNGenerator();
+
+  void AppendTargetDepends(cmGeneratorTarget* target,
+                           std::vector<std::string>& outputs);
+
+  void ComputeObjectFilenames(
+    std::map<cmSourceFile const*, std::string>& mapping,
+    cmGeneratorTarget const* gt = CM_NULLPTR) CM_OVERRIDE;
+
+private:
+  std::string HomeRelativeOutputPath;
+};
+
+#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 4363c12..9863312 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -83,6 +83,8 @@
 #endif
 #include "cmExtraCodeLiteGenerator.h"
 
+#include "cmGlobalGNGenerator.h"
+
 #if !defined(CMAKE_BOOT_MINGW)
 #include "cmExtraCodeBlocksGenerator.h"
 #endif
@@ -1685,6 +1687,7 @@
 #if defined(CMAKE_BUILD_WITH_CMAKE)
   this->Generators.push_back(cmGlobalNinjaGenerator::NewFactory());
 #endif
+  this->Generators.push_back(cmGlobalGNGenerator::NewFactory());
 #if defined(CMAKE_USE_WMAKE)
   this->Generators.push_back(cmGlobalWatcomWMakeGenerator::NewFactory());
 #endif