gn: Make generation of main build.ninja file deterministic.
Follow-up to https://codereview.chromium.org/1494883002/ which either missed
the main build.ninja file, or build.ninja file writing has since gotten
nondetermistic again.
Fixes three cases of nondeterminism in build.ninja:
* Order of pools
* Order of subninjas for each toolchain
* Order of phony targets in build.ninja
BUG=662750,565075
Review-Url: https://codereview.chromium.org/2485523002
Cr-Original-Commit-Position: refs/heads/master@{#430416}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 8c2865318628b91312ea2bfa065590e3dc4f920a
diff --git a/tools/gn/builder.h b/tools/gn/builder.h
index c8b54c9..573d8ed 100644
--- a/tools/gn/builder.h
+++ b/tools/gn/builder.h
@@ -5,8 +5,9 @@
#ifndef TOOLS_GN_BUILDER_H_
#define TOOLS_GN_BUILDER_H_
+#include <map>
+
#include "base/callback.h"
-#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "tools/gn/builder_record.h"
#include "tools/gn/label.h"
@@ -130,7 +131,7 @@
Loader* loader_;
// Owning pointers.
- typedef base::hash_map<Label, BuilderRecord*> RecordMap;
+ typedef std::map<Label, BuilderRecord*> RecordMap;
RecordMap records_;
ResolvedGeneratedCallback resolved_and_generated_callback_;
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index a0dd8ce..a805bb9 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -134,7 +134,8 @@
NinjaBuildWriter::NinjaBuildWriter(
const BuildSettings* build_settings,
- const std::map<const Settings*, const Toolchain*>& used_toolchains,
+ const std::unordered_map<const Settings*, const Toolchain*>&
+ used_toolchains,
const Toolchain* default_toolchain,
const std::vector<const Target*>& default_toolchain_targets,
std::ostream& out,
@@ -167,7 +168,7 @@
ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja");
std::vector<const Target*> all_targets = builder.GetAllResolvedTargets();
- std::map<const Settings*, const Toolchain*> used_toolchains;
+ std::unordered_map<const Settings*, const Toolchain*> used_toolchains;
// Find the default toolchain info.
Label default_toolchain_label = builder.loader()->GetDefaultToolchain();
@@ -260,7 +261,7 @@
void NinjaBuildWriter::WriteAllPools() {
// Compute the pools referenced by all tools of all used toolchains.
- std::set<const Pool*> used_pools;
+ std::unordered_set<const Pool*> used_pools;
for (const auto& pair : used_toolchains_) {
for (int j = Toolchain::TYPE_NONE + 1; j < Toolchain::TYPE_NUMTYPES; j++) {
Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(j);
@@ -270,16 +271,38 @@
}
}
- for (const Pool* pool : used_pools) {
- std::string pool_name = pool->GetNinjaName(default_toolchain_->label());
- out_ << "pool " << pool_name << std::endl
+ // Write pools sorted by their name, to make output deterministic.
+ std::vector<const Pool*> sorted_pools(used_pools.begin(), used_pools.end());
+ auto pool_name = [this](const Pool* pool) {
+ return pool->GetNinjaName(default_toolchain_->label());
+ };
+ std::sort(sorted_pools.begin(), sorted_pools.end(),
+ [&pool_name](const Pool* a, const Pool* b) {
+ return pool_name(a) < pool_name(b);
+ });
+ for (const Pool* pool : sorted_pools) {
+ out_ << "pool " << pool_name(pool) << std::endl
<< " depth = " << pool->depth() << std::endl
<< std::endl;
}
}
void NinjaBuildWriter::WriteSubninjas() {
- for (const auto& pair : used_toolchains_) {
+ // Write toolchains sorted by their name, to make output deterministic.
+ std::vector<std::pair<const Settings*, const Toolchain*>> sorted_settings(
+ used_toolchains_.begin(), used_toolchains_.end());
+ std::sort(sorted_settings.begin(), sorted_settings.end(),
+ [this](const std::pair<const Settings*, const Toolchain*>& a,
+ const std::pair<const Settings*, const Toolchain*>& b) {
+ // Always put the default toolchain first.
+ if (b.second == default_toolchain_)
+ return false;
+ if (a.second == default_toolchain_)
+ return true;
+ return GetNinjaFileForToolchain(a.first) <
+ GetNinjaFileForToolchain(b.first);
+ });
+ for (const auto& pair : sorted_settings) {
out_ << "subninja ";
path_output_.WriteFile(out_, GetNinjaFileForToolchain(pair.first));
out_ << std::endl;
diff --git a/tools/gn/ninja_build_writer.h b/tools/gn/ninja_build_writer.h
index cf72852..530ac71 100644
--- a/tools/gn/ninja_build_writer.h
+++ b/tools/gn/ninja_build_writer.h
@@ -25,13 +25,13 @@
// build itself.
class NinjaBuildWriter {
public:
- NinjaBuildWriter(
- const BuildSettings* settings,
- const std::map<const Settings*, const Toolchain*>& used_toolchains,
- const Toolchain* default_toolchain,
- const std::vector<const Target*>& default_toolchain_targets,
- std::ostream& out,
- std::ostream& dep_out);
+ NinjaBuildWriter(const BuildSettings* settings,
+ const std::unordered_map<const Settings*, const Toolchain*>&
+ used_toolchains,
+ const Toolchain* default_toolchain,
+ const std::vector<const Target*>& default_toolchain_targets,
+ std::ostream& out,
+ std::ostream& dep_out);
~NinjaBuildWriter();
// The design of this class is that this static factory function takes the
@@ -57,7 +57,7 @@
const BuildSettings* build_settings_;
- const std::map<const Settings*, const Toolchain*>& used_toolchains_;
+ const std::unordered_map<const Settings*, const Toolchain*>& used_toolchains_;
const Toolchain* default_toolchain_;
const std::vector<const Target*>& default_toolchain_targets_;
diff --git a/tools/gn/ninja_build_writer_unittest.cc b/tools/gn/ninja_build_writer_unittest.cc
index 9fee37a..9885231 100644
--- a/tools/gn/ninja_build_writer_unittest.cc
+++ b/tools/gn/ninja_build_writer_unittest.cc
@@ -48,7 +48,7 @@
Settings other_settings(setup.build_settings(), "toolchain/");
other_settings.set_toolchain_label(other_toolchain_label);
- std::map<const Settings*, const Toolchain*> used_toolchains;
+ std::unordered_map<const Settings*, const Toolchain*> used_toolchains;
used_toolchains[setup.settings()] = setup.toolchain();
used_toolchains[&other_settings] = &other_toolchain;
@@ -117,7 +117,7 @@
target_bar.SetToolchain(setup.toolchain());
ASSERT_TRUE(target_bar.OnResolved(&err));
- std::map<const Settings*, const Toolchain*> used_toolchains;
+ std::unordered_map<const Settings*, const Toolchain*> used_toolchains;
used_toolchains[setup.settings()] = setup.toolchain();
std::vector<const Target*> targets = { &target_foo, &target_bar };
std::ostringstream ninja_out;