Add support for user defined "pool" to GN. Allow user to define pool of limited size to limit the number of concurrent tasks that are executed for a given set of tools. The pool object directly correspond to a ninja pool and can be shared by multiple targets. Design document: https://docs.google.com/document/d/1b598i4WmeFOe3_iRBrjPKSXdcR5R32UPtgxqKmoY2-M/view BUG=612786 Review-Url: https://codereview.chromium.org/2006923004 Cr-Original-Commit-Position: refs/heads/master@{#397917} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 40451c5093a4108bf65d3aae30bea2ab014f4b94
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn index 2dfcf7f..e136127 100644 --- a/tools/gn/BUILD.gn +++ b/tools/gn/BUILD.gn
@@ -146,6 +146,8 @@ "path_output.h", "pattern.cc", "pattern.h", + "pool.cc", + "pool.h", "qt_creator_writer.cc", "qt_creator_writer.h", "runtime_deps.cc",
diff --git a/tools/gn/builder.cc b/tools/gn/builder.cc index 22b4c47..036d390 100644 --- a/tools/gn/builder.cc +++ b/tools/gn/builder.cc
@@ -11,6 +11,7 @@ #include "tools/gn/deps_iterator.h" #include "tools/gn/err.h" #include "tools/gn/loader.h" +#include "tools/gn/pool.h" #include "tools/gn/scheduler.h" #include "tools/gn/settings.h" #include "tools/gn/target.h" @@ -263,6 +264,19 @@ if (!AddDeps(record, toolchain->deps(), err)) return false; + for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) { + Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i); + Tool* tool = toolchain->GetTool(tool_type); + if (!tool || tool->pool().label.is_null()) + continue; + + BuilderRecord* dep_record = GetOrCreateRecordOfType( + tool->pool().label, tool->pool().origin, BuilderRecord::ITEM_POOL, err); + if (!dep_record) + return false; + record->AddDep(dep_record); + } + // The default toolchain gets generated by default. Also propogate the // generate flag if it depends on items in a non-default toolchain. if (record->should_generate() || @@ -429,6 +443,8 @@ Toolchain* toolchain = record->item()->AsToolchain(); if (!ResolveDeps(&toolchain->deps(), err)) return false; + if (!ResolvePools(toolchain, err)) + return false; } record->set_resolved(true); @@ -497,6 +513,29 @@ return true; } +bool Builder::ResolvePools(Toolchain* toolchain, Err* err) { + for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) { + Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i); + Tool* tool = toolchain->GetTool(tool_type); + if (!tool || tool->pool().label.is_null()) + continue; + + BuilderRecord* record = + GetResolvedRecordOfType(tool->pool().label, toolchain->defined_from(), + BuilderRecord::ITEM_POOL, err); + if (!record) { + *err = Err(tool->pool().origin, "Pool for tool not defined.", + "I was hoping to find a pool " + + tool->pool().label.GetUserVisibleName(false)); + return false; + } + + tool->set_pool(LabelPtrPair<Pool>(record->item()->AsPool())); + } + + return true; +} + std::string Builder::CheckForCircularDependencies( const std::vector<const BuilderRecord*>& bad_records) const { std::vector<const BuilderRecord*> cycle;
diff --git a/tools/gn/builder.h b/tools/gn/builder.h index 0445976..0c2fe70 100644 --- a/tools/gn/builder.h +++ b/tools/gn/builder.h
@@ -119,6 +119,7 @@ bool ResolveDeps(LabelTargetVector* deps, Err* err); bool ResolveConfigs(UniqueVector<LabelConfigPair>* configs, Err* err); bool ResolveToolchain(Target* target, Err* err); + bool ResolvePools(Toolchain* toolchain, Err* err); // Given a list of unresolved records, tries to find any circular // dependencies and returns the string describing the problem. If no circular
diff --git a/tools/gn/builder_record.cc b/tools/gn/builder_record.cc index 842dbc4..107e441 100644 --- a/tools/gn/builder_record.cc +++ b/tools/gn/builder_record.cc
@@ -26,6 +26,8 @@ return "config"; case ITEM_TOOLCHAIN: return "toolchain"; + case ITEM_POOL: + return "pool"; case ITEM_UNKNOWN: default: return "unknown"; @@ -41,6 +43,8 @@ return !!item->AsConfig(); case ITEM_TOOLCHAIN: return !!item->AsToolchain(); + case ITEM_POOL: + return !!item->AsPool(); case ITEM_UNKNOWN: default: return false; @@ -55,6 +59,8 @@ return ITEM_CONFIG; if (item->AsToolchain()) return ITEM_TOOLCHAIN; + if (item->AsPool()) + return ITEM_POOL; NOTREACHED(); return ITEM_UNKNOWN;
diff --git a/tools/gn/builder_record.h b/tools/gn/builder_record.h index a767c9b..7643b47 100644 --- a/tools/gn/builder_record.h +++ b/tools/gn/builder_record.h
@@ -35,7 +35,8 @@ ITEM_UNKNOWN, ITEM_TARGET, ITEM_CONFIG, - ITEM_TOOLCHAIN + ITEM_TOOLCHAIN, + ITEM_POOL }; BuilderRecord(ItemType type, const Label& label);
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md index 59c54dc..c5b36cf 100644 --- a/tools/gn/docs/reference.md +++ b/tools/gn/docs/reference.md
@@ -2143,6 +2143,47 @@ ``` +## **pool**: Defines a pool object. + +``` + Pool objects can be applied to a tool to limit the parallelism of the + build. This object has a single property "depth" corresponding to + the number of tasks that may run simultaneously. + + As the file containing the pool definition may be executed in the + of more than one toolchain it is recommended to specify an explicit + toolchain when definining and referencing a pool. + + A pool is referenced by its label just like a target. + +``` + +### **Variables** + +``` + depth* + * = required + +``` + +### **Example** + +``` + if (current_toolchain == default_toolchain) { + pool("link_pool") { + depth = 1 + } + } + + toolchain("toolchain") { + tool("link") { + command = "..." + pool = ":link_pool($default_toolchain)") + } + } + + +``` ## **print**: Prints to the console. ``` @@ -2913,6 +2954,14 @@ "{{output_dir}}/{{target_output_name}}.lib", ] + pool [label, optional] + + Label of the pool to use for the tool. Pools are used to limit + the number of tasks that can execute concurrently during the + build. + + See also "gn help pool". + link_output [string with substitutions] depend_output [string with substitutions] runtime_link_output [string with substitutions]
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc index aaa9b7e..210cc2c 100644 --- a/tools/gn/function_toolchain.cc +++ b/tools/gn/function_toolchain.cc
@@ -8,6 +8,8 @@ #include "tools/gn/err.h" #include "tools/gn/functions.h" +#include "tools/gn/label.h" +#include "tools/gn/label_ptr.h" #include "tools/gn/parse_tree.h" #include "tools/gn/scheduler.h" #include "tools/gn/scope.h" @@ -57,6 +59,31 @@ return true; } +// Reads the given label from the scope (if present) and puts the result into +// dest. If the value is not a label, sets the error and returns false. +bool ReadLabel(Scope* scope, + const char* var, + Tool* tool, + const ParseNode* origin, + const Label& current_toolchain, + void (Tool::*set)(const LabelPtrPair<Pool>&), + Err* err) { + const Value* v = scope->GetValue(var, true); + if (!v) + return true; // Not present is fine. + + Label label = + Label::Resolve(scope->GetSourceDir(), current_toolchain, *v, err); + if (err->has_error()) + return false; + + LabelPtrPair<Pool> pair(label); + pair.origin = origin; + + (tool->*set)(pair); + return true; +} + // Calls the given validate function on each type in the list. On failure, // sets the error, blame the value, and return false. bool ValidateSubstitutionList(const std::vector<SubstitutionType>& list, @@ -518,6 +545,14 @@ " \"{{output_dir}}/{{target_output_name}}.lib\",\n" " ]\n" "\n" + " pool [label, optional]\n" + "\n" + " Label of the pool to use for the tool. Pools are used to limit\n" + " the number of tasks that can execute concurrently during the\n" + " build.\n" + "\n" + " See also \"gn help pool\".\n" + "\n" " link_output [string with substitutions]\n" " depend_output [string with substitutions]\n" " runtime_link_output [string with substitutions]\n" @@ -908,7 +943,9 @@ !ReadPattern(&block_scope, "rspfile", subst_validator, tool.get(), &Tool::set_rspfile, err) || !ReadPattern(&block_scope, "rspfile_content", subst_validator, tool.get(), - &Tool::set_rspfile_content, err)) { + &Tool::set_rspfile_content, err) || + !ReadLabel(&block_scope, "pool", tool.get(), function, toolchain->label(), + &Tool::set_pool, err)) { return Value(); }
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc index af413d6..24bc2c9 100644 --- a/tools/gn/functions.cc +++ b/tools/gn/functions.cc
@@ -15,6 +15,7 @@ #include "tools/gn/err.h" #include "tools/gn/input_file.h" #include "tools/gn/parse_tree.h" +#include "tools/gn/pool.h" #include "tools/gn/scheduler.h" #include "tools/gn/scope.h" #include "tools/gn/settings.h" @@ -678,6 +679,94 @@ return Value(); } +// pool ------------------------------------------------------------------------ + +const char kPool[] = "pool"; +const char kPool_HelpShort[] = + "pool: Defines a pool object."; +const char kPool_Help[] = + "pool: Defines a pool object.\n" + "\n" + " Pool objects can be applied to a tool to limit the parallelism of the\n" + " build. This object has a single property \"depth\" corresponding to\n" + " the number of tasks that may run simultaneously.\n" + "\n" + " As the file containing the pool definition may be executed in the\n" + " of more than one toolchain it is recommended to specify an explicit\n" + " toolchain when definining and referencing a pool.\n" + "\n" + " A pool is referenced by its label just like a target.\n" + "\n" + "Variables\n" + "\n" + " depth*\n" + " * = required\n" + "\n" + "Example\n" + "\n" + " if (current_toolchain == default_toolchain) {\n" + " pool(\"link_pool\") {\n" + " depth = 1\n" + " }\n" + " }\n" + "\n" + " toolchain(\"toolchain\") {\n" + " tool(\"link\") {\n" + " command = \"...\"\n" + " pool = \":link_pool($default_toolchain)\")\n" + " }\n" + " }\n"; + +const char kDepth[] = "depth"; + +Value RunPool(const FunctionCallNode* function, + const std::vector<Value>& args, + Scope* scope, + Err* err) { + NonNestableBlock non_nestable(scope, function, "pool"); + if (!non_nestable.Enter(err)) + return Value(); + + if (!EnsureSingleStringArg(function, args, err) || + !EnsureNotProcessingImport(function, scope, err)) + return Value(); + + Label label(MakeLabelForScope(scope, function, args[0].string_value())); + + if (g_scheduler->verbose_logging()) + g_scheduler->Log("Defining pool", label.GetUserVisibleName(true)); + + // Get the pool depth. It is an error to define a pool without a depth, + // so check first for the presence of the value. + const Value* depth = scope->GetValue(kDepth, true); + if (!depth) { + *err = Err(function, "Can't define a pool without depth."); + return Value(); + } + + if (!depth->VerifyTypeIs(Value::INTEGER, err)) + return Value(); + + if (depth->int_value() < 0) { + *err = Err(function, "depth must be positive or nul."); + return Value(); + } + + // Create the new pool. + std::unique_ptr<Pool> pool(new Pool(scope->settings(), label)); + pool->set_depth(depth->int_value()); + + // Save the generated item. + Scope::ItemVector* collector = scope->GetItemCollector(); + if (!collector) { + *err = Err(function, "Can't define a pool in this context."); + return Value(); + } + collector->push_back(pool.release()); + + return Value(); +} + // print ----------------------------------------------------------------------- const char kPrint[] = "print"; @@ -826,6 +915,7 @@ INSERT_FUNCTION(GetPathInfo, false) INSERT_FUNCTION(GetTargetOutputs, false) INSERT_FUNCTION(Import, false) + INSERT_FUNCTION(Pool, false) INSERT_FUNCTION(Print, false) INSERT_FUNCTION(ProcessFileTemplate, false) INSERT_FUNCTION(ReadFile, false)
diff --git a/tools/gn/functions.h b/tools/gn/functions.h index 3ce945e..aadc966 100644 --- a/tools/gn/functions.h +++ b/tools/gn/functions.h
@@ -222,6 +222,14 @@ BlockNode* block, Err* err); +extern const char kPool[]; +extern const char kPool_HelpShort[]; +extern const char kPool_Help[]; +Value RunPool(const FunctionCallNode* function, + const std::vector<Value>& args, + Scope* block_scope, + Err* err); + extern const char kPrint[]; extern const char kPrint_HelpShort[]; extern const char kPrint_Help[];
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp index 8428948..352a332 100644 --- a/tools/gn/gn.gyp +++ b/tools/gn/gn.gyp
@@ -146,6 +146,8 @@ 'path_output.h', 'pattern.cc', 'pattern.h', + 'pool.cc', + 'pool.h', 'qt_creator_writer.cc', 'qt_creator_writer.h', 'runtime_deps.cc',
diff --git a/tools/gn/item.cc b/tools/gn/item.cc index b0efd64..4fb65d1 100644 --- a/tools/gn/item.cc +++ b/tools/gn/item.cc
@@ -20,6 +20,12 @@ const Config* Item::AsConfig() const { return nullptr; } +Pool* Item::AsPool() { + return nullptr; +} +const Pool* Item::AsPool() const { + return nullptr; +} Target* Item::AsTarget() { return nullptr; } @@ -40,6 +46,8 @@ return "target"; if (AsToolchain()) return "toolchain"; + if (AsPool()) + return "pool"; NOTREACHED(); return "this thing that I have no idea what it is"; }
diff --git a/tools/gn/item.h b/tools/gn/item.h index 069c3ed..3ec482a 100644 --- a/tools/gn/item.h +++ b/tools/gn/item.h
@@ -12,6 +12,7 @@ class Config; class ParseNode; +class Pool; class Settings; class Target; class Toolchain; @@ -38,6 +39,8 @@ // Manual RTTI. virtual Config* AsConfig(); virtual const Config* AsConfig() const; + virtual Pool* AsPool(); + virtual const Pool* AsPool() const; virtual Target* AsTarget(); virtual const Target* AsTarget() const; virtual Toolchain* AsToolchain();
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc index 2cbb245..627edb2 100644 --- a/tools/gn/ninja_build_writer.cc +++ b/tools/gn/ninja_build_writer.cc
@@ -23,6 +23,7 @@ #include "tools/gn/filesystem_utils.h" #include "tools/gn/input_file_manager.h" #include "tools/gn/ninja_utils.h" +#include "tools/gn/pool.h" #include "tools/gn/scheduler.h" #include "tools/gn/switches.h" #include "tools/gn/target.h" @@ -129,24 +130,26 @@ const std::vector<const Settings*>& all_settings, const Toolchain* default_toolchain, const std::vector<const Target*>& default_toolchain_targets, + const std::vector<const Pool*>& all_pools, std::ostream& out, std::ostream& dep_out) : build_settings_(build_settings), all_settings_(all_settings), default_toolchain_(default_toolchain), default_toolchain_targets_(default_toolchain_targets), + all_pools_(all_pools), out_(out), dep_out_(dep_out), path_output_(build_settings->build_dir(), - build_settings->root_path_utf8(), ESCAPE_NINJA) { -} + build_settings->root_path_utf8(), + ESCAPE_NINJA) {} NinjaBuildWriter::~NinjaBuildWriter() { } bool NinjaBuildWriter::Run(Err* err) { WriteNinjaRules(); - WriteLinkPool(); + WriteAllPools(); WriteSubninjas(); return WritePhonyAndAllRules(err); } @@ -157,13 +160,14 @@ const std::vector<const Settings*>& all_settings, const Toolchain* default_toolchain, const std::vector<const Target*>& default_toolchain_targets, + const std::vector<const Pool*>& all_pools, Err* err) { ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja"); std::stringstream file; std::stringstream depfile; NinjaBuildWriter gen(build_settings, all_settings, default_toolchain, - default_toolchain_targets, file, depfile); + default_toolchain_targets, all_pools, file, depfile); if (!gen.Run(err)) return false; @@ -224,10 +228,17 @@ out_ << std::endl; } -void NinjaBuildWriter::WriteLinkPool() { +void NinjaBuildWriter::WriteAllPools() { out_ << "pool link_pool\n" << " depth = " << default_toolchain_->concurrent_links() << std::endl << std::endl; + + for (const Pool* pool : all_pools_) { + std::string pool_name = pool->GetNinjaName(default_toolchain_->label()); + out_ << "pool " << pool_name << std::endl + << " depth = " << pool->depth() << std::endl + << std::endl; + } } void NinjaBuildWriter::WriteSubninjas() {
diff --git a/tools/gn/ninja_build_writer.h b/tools/gn/ninja_build_writer.h index e94f93d..358ecc6 100644 --- a/tools/gn/ninja_build_writer.h +++ b/tools/gn/ninja_build_writer.h
@@ -14,6 +14,7 @@ class BuildSettings; class Err; +class Pool; class Settings; class Target; class Toolchain; @@ -28,12 +29,14 @@ const std::vector<const Settings*>& all_settings, const Toolchain* default_toolchain, const std::vector<const Target*>& default_toolchain_targets, + const std::vector<const Pool*>& all_pools, Err* err); NinjaBuildWriter(const BuildSettings* settings, const std::vector<const Settings*>& all_settings, const Toolchain* default_toolchain, const std::vector<const Target*>& default_toolchain_targets, + const std::vector<const Pool*>& all_pools, std::ostream& out, std::ostream& dep_out); ~NinjaBuildWriter(); @@ -42,7 +45,7 @@ private: void WriteNinjaRules(); - void WriteLinkPool(); + void WriteAllPools(); void WriteSubninjas(); bool WritePhonyAndAllRules(Err* err); @@ -52,6 +55,7 @@ std::vector<const Settings*> all_settings_; const Toolchain* default_toolchain_; std::vector<const Target*> default_toolchain_targets_; + std::vector<const Pool*> all_pools_; std::ostream& out_; std::ostream& dep_out_; PathOutput path_output_;
diff --git a/tools/gn/ninja_build_writer_unittest.cc b/tools/gn/ninja_build_writer_unittest.cc index 48d7302..955eb1c 100644 --- a/tools/gn/ninja_build_writer_unittest.cc +++ b/tools/gn/ninja_build_writer_unittest.cc
@@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "tools/gn/ninja_build_writer.h" +#include "tools/gn/pool.h" #include "tools/gn/scheduler.h" #include "tools/gn/target.h" #include "tools/gn/test_with_scope.h" @@ -31,12 +32,19 @@ target_bar.SetToolchain(setup.toolchain()); ASSERT_TRUE(target_bar.OnResolved(&err)); + Pool swiming_pool(setup.settings(), + Label(SourceDir("//swiming/"), "pool", + SourceDir("//other/"), "toolchain")); + swiming_pool.set_depth(42); + std::ostringstream ninja_out; std::ostringstream depfile_out; std::vector<const Settings*> all_settings = {setup.settings()}; std::vector<const Target*> targets = {&target_foo, &target_bar}; + std::vector<const Pool*> all_pools = {&swiming_pool}; NinjaBuildWriter writer(setup.build_settings(), all_settings, - setup.toolchain(), targets, ninja_out, depfile_out); + setup.toolchain(), targets, all_pools, ninja_out, + depfile_out); ASSERT_TRUE(writer.Run(&err)); const char expected_rule_gn[] = "rule gn\n"; @@ -48,6 +56,9 @@ const char expected_link_pool[] = "pool link_pool\n" " depth = 0\n" + "\n" + "pool other_toolchain_swiming_pool\n" + " depth = 42\n" "\n"; const char expected_toolchain[] = "subninja toolchain.ninja\n" @@ -102,8 +113,10 @@ std::ostringstream depfile_out; std::vector<const Settings*> all_settings = { setup.settings() }; std::vector<const Target*> targets = { &target_foo, &target_bar }; + std::vector<const Pool*> all_pools; NinjaBuildWriter writer(setup.build_settings(), all_settings, - setup.toolchain(), targets, ninja_out, depfile_out); + setup.toolchain(), targets, all_pools, ninja_out, + depfile_out); ASSERT_FALSE(writer.Run(&err)); const char expected_help_test[] =
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc index e7459eb..1deff58 100644 --- a/tools/gn/ninja_toolchain_writer.cc +++ b/tools/gn/ninja_toolchain_writer.cc
@@ -11,6 +11,7 @@ #include "tools/gn/build_settings.h" #include "tools/gn/filesystem_utils.h" #include "tools/gn/ninja_utils.h" +#include "tools/gn/pool.h" #include "tools/gn/settings.h" #include "tools/gn/substitution_writer.h" #include "tools/gn/target.h" @@ -113,6 +114,10 @@ type == Toolchain::TYPE_SOLINK_MODULE || type == Toolchain::TYPE_LINK) { out_ << kIndent << "pool = link_pool\n"; + } else if (tool->pool().ptr) { + std::string pool_name = + tool->pool().ptr->GetNinjaName(settings_->default_toolchain_label()); + out_ << kIndent << "pool = " << pool_name << std::endl; } if (tool->restat())
diff --git a/tools/gn/ninja_writer.cc b/tools/gn/ninja_writer.cc index 154f017..7d26f48 100644 --- a/tools/gn/ninja_writer.cc +++ b/tools/gn/ninja_writer.cc
@@ -29,9 +29,11 @@ std::vector<const Settings*> all_settings; std::vector<const Target*> default_targets; - if (!writer.WriteToolchains(&all_settings, &default_targets, err)) + std::vector<const Pool*> all_pools; + if (!writer.WriteToolchains(&all_settings, &default_targets, &all_pools, err)) return false; - return writer.WriteRootBuildfiles(all_settings, default_targets, err); + return writer.WriteRootBuildfiles(all_settings, default_targets, all_pools, + err); } // static @@ -42,11 +44,14 @@ Err* err) { NinjaWriter writer(build_settings, builder); std::vector<const Target*> default_targets; - return writer.WriteToolchains(all_settings, &default_targets, err); + std::vector<const Pool*> all_pools; + return writer.WriteToolchains(all_settings, &default_targets, &all_pools, + err); } bool NinjaWriter::WriteToolchains(std::vector<const Settings*>* all_settings, std::vector<const Target*>* default_targets, + std::vector<const Pool*>* all_pools, Err* err) { // Categorize all targets by toolchain. typedef std::map<Label, std::vector<const Target*> > CategorizedMap; @@ -79,6 +84,7 @@ // Write out the toolchain buildfiles, and also accumulate the set of // all settings and find the list of targets in the default toolchain. + UniqueVector<const Pool*> pools; for (const auto& i : categorized) { const Settings* settings = builder_->loader()->GetToolchainSettings(i.first); @@ -91,8 +97,16 @@ "Couldn't open toolchain buildfile(s) for writing").PrintToStdout(); return false; } + + for (int j = Toolchain::TYPE_NONE + 1; j < Toolchain::TYPE_NUMTYPES; j++) { + Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(j); + const Tool* tool = toolchain->GetTool(tool_type); + if (tool && tool->pool().ptr) + pools.push_back(tool->pool().ptr); + } } + *all_pools = pools.vector(); *default_targets = categorized[default_label]; return true; } @@ -100,6 +114,7 @@ bool NinjaWriter::WriteRootBuildfiles( const std::vector<const Settings*>& all_settings, const std::vector<const Target*>& default_targets, + const std::vector<const Pool*>& all_pools, Err* err) { // All Settings objects should have the same default toolchain, and there // should always be at least one settings object in the build. @@ -110,5 +125,5 @@ // Write the root buildfile. return NinjaBuildWriter::RunAndWriteFile(build_settings_, all_settings, default_toolchain, default_targets, - err); + all_pools, err); }
diff --git a/tools/gn/ninja_writer.h b/tools/gn/ninja_writer.h index fa4a433..ea8fc47 100644 --- a/tools/gn/ninja_writer.h +++ b/tools/gn/ninja_writer.h
@@ -14,6 +14,7 @@ class Builder; class BuildSettings; class Err; +class Pool; class Settings; class Target; @@ -36,12 +37,13 @@ NinjaWriter(const BuildSettings* build_settings, Builder* builder); ~NinjaWriter(); - bool WriteToolchains( - std::vector<const Settings*>* all_settings, - std::vector<const Target*>* default_targets, - Err* err); + bool WriteToolchains(std::vector<const Settings*>* all_settings, + std::vector<const Target*>* default_targets, + std::vector<const Pool*>* all_pools, + Err* err); bool WriteRootBuildfiles(const std::vector<const Settings*>& all_settings, const std::vector<const Target*>& default_targets, + const std::vector<const Pool*>& all_pools, Err* err); const BuildSettings* build_settings_;
diff --git a/tools/gn/pool.cc b/tools/gn/pool.cc new file mode 100644 index 0000000..e4fc206 --- /dev/null +++ b/tools/gn/pool.cc
@@ -0,0 +1,48 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/gn/pool.h" + +#include <sstream> + +#include "base/logging.h" + +Pool::Pool(const Settings* settings, const Label& label) + : Item(settings, label) {} + +Pool::~Pool() {} + +Pool* Pool::AsPool() { + return this; +} + +const Pool* Pool::AsPool() const { + return this; +} + +std::string Pool::GetNinjaName(const Label& default_toolchain) const { + bool include_toolchain = label().toolchain_dir() != default_toolchain.dir() || + label().toolchain_name() != default_toolchain.name(); + return GetNinjaName(include_toolchain); +} + +std::string Pool::GetNinjaName(bool include_toolchain) const { + std::ostringstream buffer; + if (include_toolchain) { + DCHECK(label().toolchain_dir().is_source_absolute()); + std::string toolchain_dir = label().toolchain_dir().value(); + for (std::string::size_type i = 2; i < toolchain_dir.size(); ++i) { + buffer << (toolchain_dir[i] == '/' ? '_' : toolchain_dir[i]); + } + buffer << label().toolchain_name() << "_"; + } + + DCHECK(label().dir().is_source_absolute()); + std::string label_dir = label().dir().value(); + for (std::string::size_type i = 2; i < label_dir.size(); ++i) { + buffer << (label_dir[i] == '/' ? '_' : label_dir[i]); + } + buffer << label().name(); + return buffer.str(); +}
diff --git a/tools/gn/pool.h b/tools/gn/pool.h new file mode 100644 index 0000000..d719364 --- /dev/null +++ b/tools/gn/pool.h
@@ -0,0 +1,41 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TOOLS_GN_POOL_H_ +#define TOOLS_GN_POOL_H_ + +#include <string> + +#include "tools/gn/item.h" + +// Represents a named pool in the dependency graph. +// +// A pool is used to limit the parallelism of task invocation in the +// generated ninja build. Pools are referenced by toolchains. +class Pool : public Item { + public: + Pool(const Settings* settings, const Label& label); + ~Pool() override; + + Pool(const Pool&) = delete; + Pool& operator=(const Pool&) = delete; + + // Item implementation. + Pool* AsPool() override; + const Pool* AsPool() const override; + + // The pool depth (number of task to run simultaneously). + int64_t depth() const { return depth_; } + void set_depth(int64_t depth) { depth_ = depth; } + + // The pool name in generated ninja files. + std::string GetNinjaName(const Label& default_toolchain) const; + + private: + std::string GetNinjaName(bool include_toolchain) const; + + int64_t depth_ = 0; +}; + +#endif // TOOLS_GN_POOL_H_
diff --git a/tools/gn/tool.h b/tools/gn/tool.h index f6727ed..96ff7c0 100644 --- a/tools/gn/tool.h +++ b/tools/gn/tool.h
@@ -9,9 +9,13 @@ #include "base/logging.h" #include "base/macros.h" +#include "tools/gn/label.h" +#include "tools/gn/label_ptr.h" #include "tools/gn/substitution_list.h" #include "tools/gn/substitution_pattern.h" +class Pool; + class Tool { public: enum DepsFormat { @@ -173,6 +177,9 @@ rspfile_content_ = content; } + const LabelPtrPair<Pool>& pool() const { return pool_; } + void set_pool(const LabelPtrPair<Pool>& pool) { pool_ = pool; } + // Other functions ---------------------------------------------------------- // Called when the toolchain is saving this tool, after everything is filled @@ -191,6 +198,8 @@ return substitution_bits_; } + bool OnResolved(Err* err); + private: SubstitutionPattern command_; std::string default_output_extension_; @@ -209,6 +218,7 @@ bool restat_; SubstitutionPattern rspfile_; SubstitutionPattern rspfile_content_; + LabelPtrPair<Pool> pool_; bool complete_;
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc index 14d2bfd..03c9c59 100644 --- a/tools/gn/toolchain.cc +++ b/tools/gn/toolchain.cc
@@ -86,6 +86,11 @@ } } +Tool* Toolchain::GetTool(ToolType type) { + DCHECK(type != TYPE_NONE); + return tools_[static_cast<size_t>(type)].get(); +} + const Tool* Toolchain::GetTool(ToolType type) const { DCHECK(type != TYPE_NONE); return tools_[static_cast<size_t>(type)].get();
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h index 0c20726..76858de 100644 --- a/tools/gn/toolchain.h +++ b/tools/gn/toolchain.h
@@ -78,6 +78,7 @@ static std::string ToolTypeToName(ToolType type); // Returns null if the tool hasn't been defined. + Tool* GetTool(ToolType type); const Tool* GetTool(ToolType type) const; // Set a tool. When all tools are configured, you should call