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