[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