GN: toolchain threading cleanup Remove the thread-unsafe toolchain pointer on the otherwise-threadsafe Settings object. I replaced it with the toolchain label, and moved the is_default flag from the toolchain to the Settings object. This required that I pass the toolchain around in a few more places, but also simplifies some other cases. I removed the toolchain prefix from Ninja rules for the default toolchain since that's not necessary any more for GYP compat. This fixes an annoying double-free in the toolchain manager. I think my current refactor will clean this up in a later phase. R=scottmg@chromium.org Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=232657 Review URL: https://codereview.chromium.org/51693002 Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 132715e1e82b1f69fc5a67d3acedb24c12d02e2a
diff --git a/tools/gn/config.cc b/tools/gn/config.cc index 850d596..5b89e2b 100644 --- a/tools/gn/config.cc +++ b/tools/gn/config.cc
@@ -10,7 +10,8 @@ #include "tools/gn/item_tree.h" #include "tools/gn/scheduler.h" -Config::Config(const Label& label) : Item(label) { +Config::Config(const Settings* settings, const Label& label) + : Item(settings, label) { } Config::~Config() { @@ -38,7 +39,7 @@ ItemNode* node = tree->GetExistingNodeLocked(label); Config* config = NULL; if (!node) { - config = new Config(label); + config = new Config(settings, label); node = new ItemNode(config); node->set_originally_referenced_from_here(specified_from_here); tree->AddNodeLocked(node);
diff --git a/tools/gn/config.h b/tools/gn/config.h index 0ee9b7b..e5a1df6 100644 --- a/tools/gn/config.h +++ b/tools/gn/config.h
@@ -17,7 +17,7 @@ // Represents a named config in the dependency graph. class Config : public Item { public: - Config(const Label& label); + Config(const Settings* settings, const Label& label); virtual ~Config(); virtual Config* AsConfig() OVERRIDE;
diff --git a/tools/gn/function_exec_script.cc b/tools/gn/function_exec_script.cc index bf55165..b382575 100644 --- a/tools/gn/function_exec_script.cc +++ b/tools/gn/function_exec_script.cc
@@ -301,7 +301,7 @@ } ScopedTrace trace(TraceItem::TRACE_SCRIPT_EXECUTE, script_source.value()); - trace.SetToolchain(settings->toolchain()->label()); + trace.SetToolchain(settings->toolchain_label()); // Add all dependencies of this script, including the script itself, to the // build deps.
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc index 933d55e..dde0306 100644 --- a/tools/gn/function_toolchain.cc +++ b/tools/gn/function_toolchain.cc
@@ -102,7 +102,7 @@ // This object will actually be copied into the one owned by the toolchain // manager, but that has to be done in the lock. - Toolchain toolchain(label); + Toolchain toolchain(scope->settings(), label); Scope block_scope(scope); block_scope.SetProperty(&kToolchainPropertyKey, &toolchain);
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc index acc8fe9..0e27297 100644 --- a/tools/gn/functions.cc +++ b/tools/gn/functions.cc
@@ -134,7 +134,7 @@ } const Label& ToolchainLabelForScope(const Scope* scope) { - return scope->settings()->toolchain()->label(); + return scope->settings()->toolchain_label(); } Label MakeLabelForScope(const Scope* scope,
diff --git a/tools/gn/gyp_helper.cc b/tools/gn/gyp_helper.cc index f69ed8f..fb669af 100644 --- a/tools/gn/gyp_helper.cc +++ b/tools/gn/gyp_helper.cc
@@ -45,10 +45,10 @@ } std::string GypHelper::GetNameForTarget(const Target* target) const { - const Toolchain* toolchain = target->settings()->toolchain(); - if (toolchain->is_default()) + if (target->settings()->is_default()) return target->label().name(); // Default toolchain has no suffix. - return target->label().name() + "_" + toolchain->label().name(); + return target->label().name() + "_" + + target->settings()->toolchain_label().name(); } std::string GypHelper::GetFullRefForTarget(const Target* target) const {
diff --git a/tools/gn/input_conversion.cc b/tools/gn/input_conversion.cc index 19a8047..c40bdba 100644 --- a/tools/gn/input_conversion.cc +++ b/tools/gn/input_conversion.cc
@@ -117,9 +117,7 @@ } BuildSettings build_settings; - Label empty_label; - Toolchain toolchain(empty_label); - Settings settings(&build_settings, &toolchain, std::string()); + Settings settings(&build_settings, std::string()); Scope scope(&settings); Err nested_err;
diff --git a/tools/gn/item.cc b/tools/gn/item.cc index 747183c..fa16975 100644 --- a/tools/gn/item.cc +++ b/tools/gn/item.cc
@@ -6,7 +6,9 @@ #include "base/logging.h" -Item::Item(const Label& label) : label_(label) { +Item::Item(const Settings* settings, const Label& label) + : settings_(settings), + label_(label) { } Item::~Item() {
diff --git a/tools/gn/item.h b/tools/gn/item.h index 2538c50..69115bd 100644 --- a/tools/gn/item.h +++ b/tools/gn/item.h
@@ -11,6 +11,7 @@ class Config; class ItemNode; +class Settings; class Target; class Toolchain; @@ -18,9 +19,11 @@ // graph. class Item { public: - Item(const Label& label); + Item(const Settings* settings, const Label& label); virtual ~Item(); + const Settings* settings() const { return settings_; } + // This is guaranteed to never change after construction so this can be // accessed from any thread with no locking once the item is constructed. const Label& label() const { return label_; } @@ -49,6 +52,7 @@ virtual void OnResolved() {} private: + const Settings* settings_; Label label_; ItemNode* item_node_;
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc index 3a1d620..c404006 100644 --- a/tools/gn/ninja_binary_target_writer.cc +++ b/tools/gn/ninja_binary_target_writer.cc
@@ -86,8 +86,9 @@ } // namespace NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, + const Toolchain* toolchain, std::ostream& out) - : NinjaTargetWriter(target, out), + : NinjaTargetWriter(target, toolchain, out), tool_type_(GetToolTypeForTarget(target)){ } @@ -145,7 +146,6 @@ const Target::FileList& sources = target_->sources(); object_files->reserve(sources.size()); - const Toolchain* toolchain = GetToolchain(); std::string implicit_deps = GetSourcesImplicitDeps(); for (size_t i = 0; i < sources.size(); i++) { @@ -156,7 +156,7 @@ if (input_file_type == SOURCE_UNKNOWN) continue; // Skip unknown file types. std::string command = - helper_.GetRuleForSourceType(settings_, toolchain, input_file_type); + helper_.GetRuleForSourceType(settings_, input_file_type); if (command.empty()) continue; // Skip files not needing compilation. @@ -265,8 +265,7 @@ RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags, flag_options, out_); - const Toolchain* toolchain = GetToolchain(); - const Toolchain::Tool& tool = toolchain->GetTool(tool_type_); + const Toolchain::Tool& tool = toolchain_->GetTool(tool_type_); // Followed by library search paths that have been recursively pushed // through the dependency tree. @@ -306,7 +305,7 @@ path_output_.WriteFile(out_, external_output_file); } out_ << ": " - << helper_.GetRulePrefix(GetToolchain()) + << helper_.GetRulePrefix(target_->settings()) << Toolchain::ToolTypeToName(tool_type_); std::set<OutputFile> extra_object_files; @@ -346,7 +345,7 @@ out_ << "build "; path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); out_ << ": " - << helper_.GetRulePrefix(target_->settings()->toolchain()) + << helper_.GetRulePrefix(target_->settings()) << "stamp"; std::set<OutputFile> extra_object_files;
diff --git a/tools/gn/ninja_binary_target_writer.h b/tools/gn/ninja_binary_target_writer.h index 8c57ffb..c188335 100644 --- a/tools/gn/ninja_binary_target_writer.h +++ b/tools/gn/ninja_binary_target_writer.h
@@ -13,7 +13,9 @@ // library, or a static library). class NinjaBinaryTargetWriter : public NinjaTargetWriter { public: - NinjaBinaryTargetWriter(const Target* target, std::ostream& out); + NinjaBinaryTargetWriter(const Target* target, + const Toolchain* toolchain, + std::ostream& out); virtual ~NinjaBinaryTargetWriter(); virtual void Run() OVERRIDE;
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc index a7de4a1..96a7448 100644 --- a/tools/gn/ninja_binary_target_writer_unittest.cc +++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -22,7 +22,7 @@ // Source set itself. { std::ostringstream out; - NinjaBinaryTargetWriter writer(&target, out); + NinjaBinaryTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); // TODO(brettw) I think we'll need to worry about backslashes here @@ -36,10 +36,10 @@ "cflags_objc =\n" "cflags_objcc =\n" "\n" - "build obj/foo/bar.input1.obj: tc_cxx ../../foo/input1.cc\n" - "build obj/foo/bar.input2.obj: tc_cxx ../../foo/input2.cc\n" + "build obj/foo/bar.input1.obj: cxx ../../foo/input1.cc\n" + "build obj/foo/bar.input2.obj: cxx ../../foo/input2.cc\n" "\n" - "build obj/foo/bar.stamp: tc_stamp obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n"; + "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n"; std::string out_str = out.str(); #if defined(OS_WIN) std::replace(out_str.begin(), out_str.end(), '\\', '/'); @@ -55,7 +55,7 @@ { std::ostringstream out; - NinjaBinaryTargetWriter writer(&shlib_target, out); + NinjaBinaryTargetWriter writer(&shlib_target, setup.toolchain(), out); writer.Run(); // TODO(brettw) I think we'll need to worry about backslashes here @@ -73,7 +73,7 @@ "manifests = obj/foo/shlib.intermediate.manifest\n" "ldflags = /MANIFEST /ManifestFile:obj/foo/shlib.intermediate.manifest\n" "libs =\n" - "build shlib.dll shlib.dll.lib: tc_solink obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n" + "build shlib.dll shlib.dll.lib: solink obj/foo/bar.input1.obj obj/foo/bar.input2.obj\n" " soname = shlib.dll\n" " lib = shlib.dll\n" " dll = shlib.dll\n"
diff --git a/tools/gn/ninja_copy_target_writer.cc b/tools/gn/ninja_copy_target_writer.cc index 5de249f..89b3e3f 100644 --- a/tools/gn/ninja_copy_target_writer.cc +++ b/tools/gn/ninja_copy_target_writer.cc
@@ -9,8 +9,9 @@ #include "tools/gn/string_utils.h" NinjaCopyTargetWriter::NinjaCopyTargetWriter(const Target* target, + const Toolchain* toolchain, std::ostream& out) - : NinjaTargetWriter(target, out) { + : NinjaTargetWriter(target, toolchain, out) { } NinjaCopyTargetWriter::~NinjaCopyTargetWriter() { @@ -22,8 +23,7 @@ std::vector<OutputFile> output_files; - std::string rule_prefix = - helper_.GetRulePrefix(target_->settings()->toolchain()); + std::string rule_prefix = helper_.GetRulePrefix(target_->settings()); for (size_t i = 0; i < target_->sources().size(); i++) { const SourceFile& input_file = target_->sources()[i];
diff --git a/tools/gn/ninja_copy_target_writer.h b/tools/gn/ninja_copy_target_writer.h index 99bbaff..cadbc38 100644 --- a/tools/gn/ninja_copy_target_writer.h +++ b/tools/gn/ninja_copy_target_writer.h
@@ -11,7 +11,9 @@ // Writes a .ninja file for a copy target type. class NinjaCopyTargetWriter : public NinjaTargetWriter { public: - NinjaCopyTargetWriter(const Target* target, std::ostream& out); + NinjaCopyTargetWriter(const Target* target, + const Toolchain* toolchain, + std::ostream& out); virtual ~NinjaCopyTargetWriter(); virtual void Run() OVERRIDE;
diff --git a/tools/gn/ninja_copy_target_writer_unittest.cc b/tools/gn/ninja_copy_target_writer_unittest.cc index c31cbd2..5642d9d 100644 --- a/tools/gn/ninja_copy_target_writer_unittest.cc +++ b/tools/gn/ninja_copy_target_writer_unittest.cc
@@ -27,14 +27,14 @@ setup.settings()->set_target_os(Settings::LINUX); std::ostringstream out; - NinjaCopyTargetWriter writer(&target, out); + NinjaCopyTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); const char expected_linux[] = - "build input1.out: tc_copy ../../foo/input1.txt\n" - "build input2.out: tc_copy ../../foo/input2.txt\n" + "build input1.out: copy ../../foo/input1.txt\n" + "build input2.out: copy ../../foo/input2.txt\n" "\n" - "build obj/foo/bar.stamp: tc_stamp input1.out input2.out\n"; + "build obj/foo/bar.stamp: stamp input1.out input2.out\n"; std::string out_str = out.str(); #if defined(OS_WIN) std::replace(out_str.begin(), out_str.end(), '\\', '/'); @@ -47,16 +47,16 @@ setup.settings()->set_target_os(Settings::WIN); std::ostringstream out; - NinjaCopyTargetWriter writer(&target, out); + NinjaCopyTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); // TODO(brettw) I think we'll need to worry about backslashes here // depending if we're on actual Windows or Linux pretending to be Windows. const char expected_win[] = - "build input1.out: tc_copy ../../foo/input1.txt\n" - "build input2.out: tc_copy ../../foo/input2.txt\n" + "build input1.out: copy ../../foo/input1.txt\n" + "build input2.out: copy ../../foo/input2.txt\n" "\n" - "build obj/foo/bar.stamp: tc_stamp input1.out input2.out\n"; + "build obj/foo/bar.stamp: stamp input1.out input2.out\n"; std::string out_str = out.str(); #if defined(OS_WIN) std::replace(out_str.begin(), out_str.end(), '\\', '/');
diff --git a/tools/gn/ninja_group_target_writer.cc b/tools/gn/ninja_group_target_writer.cc index 606f916..d29f917 100644 --- a/tools/gn/ninja_group_target_writer.cc +++ b/tools/gn/ninja_group_target_writer.cc
@@ -8,8 +8,9 @@ #include "tools/gn/string_utils.h" NinjaGroupTargetWriter::NinjaGroupTargetWriter(const Target* target, + const Toolchain* toolchain, std::ostream& out) - : NinjaTargetWriter(target, out) { + : NinjaTargetWriter(target, toolchain, out) { } NinjaGroupTargetWriter::~NinjaGroupTargetWriter() { @@ -21,7 +22,7 @@ out_ << std::endl << "build "; path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); out_ << ": " - << helper_.GetRulePrefix(target_->settings()->toolchain()) + << helper_.GetRulePrefix(target_->settings()) << "stamp"; const LabelTargetVector& deps = target_->deps();
diff --git a/tools/gn/ninja_group_target_writer.h b/tools/gn/ninja_group_target_writer.h index 31625f8..862b920 100644 --- a/tools/gn/ninja_group_target_writer.h +++ b/tools/gn/ninja_group_target_writer.h
@@ -11,7 +11,9 @@ // Writes a .ninja file for a group target type. class NinjaGroupTargetWriter : public NinjaTargetWriter { public: - NinjaGroupTargetWriter(const Target* target, std::ostream& out); + NinjaGroupTargetWriter(const Target* target, + const Toolchain* toolchain, + std::ostream& out); virtual ~NinjaGroupTargetWriter(); virtual void Run() OVERRIDE;
diff --git a/tools/gn/ninja_helper.cc b/tools/gn/ninja_helper.cc index d90b698..e872c24 100644 --- a/tools/gn/ninja_helper.cc +++ b/tools/gn/ninja_helper.cc
@@ -189,23 +189,20 @@ return ret; } -std::string NinjaHelper::GetRulePrefix(const Toolchain* toolchain) const { - // This code doesn't prefix the default toolchain commands. This is disabled - // so we can coexist with GYP's commands (which aren't prefixed). If we don't - // need to coexist with GYP anymore, we can uncomment this to make things a - // bit prettier. - //if (toolchain->is_default()) - // return std::string(); // Default toolchain has no prefix. - return toolchain->label().name() + "_"; +std::string NinjaHelper::GetRulePrefix(const Settings* settings) const { + // Don't prefix the default toolchain so it looks prettier, prefix everything + // else. + if (settings->is_default()) + return std::string(); // Default toolchain has no prefix. + return settings->toolchain_label().name() + "_"; } std::string NinjaHelper::GetRuleForSourceType(const Settings* settings, - const Toolchain* toolchain, SourceFileType type) const { // This function may be hot since it will be called for every source file // in the tree. We could cache the results to avoid making a string for // every invocation. - std::string prefix = GetRulePrefix(toolchain); + std::string prefix = GetRulePrefix(settings); if (type == SOURCE_C) return prefix + "cc";
diff --git a/tools/gn/ninja_helper.h b/tools/gn/ninja_helper.h index bef2fcd..84a2c89 100644 --- a/tools/gn/ninja_helper.h +++ b/tools/gn/ninja_helper.h
@@ -52,12 +52,11 @@ // Returns the prefix for rules on the given toolchain. We need this to // disambiguate a given rule for each toolchain. - std::string GetRulePrefix(const Toolchain* toolchain) const; + std::string GetRulePrefix(const Settings* settings) const; // Returns the name of the rule name for the given toolchain and file/target // type. Returns the empty string for source files with no command. std::string GetRuleForSourceType(const Settings* settings, - const Toolchain* toolchain, SourceFileType type) const; // Returns the relative directory in either slashes or the system separator
diff --git a/tools/gn/ninja_helper_unittest.cc b/tools/gn/ninja_helper_unittest.cc index 6e3b25c..81f3669 100644 --- a/tools/gn/ninja_helper_unittest.cc +++ b/tools/gn/ninja_helper_unittest.cc
@@ -17,9 +17,10 @@ public: HelperSetterUpper() : build_settings(), - toolchain(Label(SourceDir("//"), "tc")), - settings(&build_settings, &toolchain, std::string()), + settings(&build_settings, std::string()), + toolchain(&settings, Label(SourceDir("//"), "tc")), target(&settings, Label(SourceDir("//tools/gn/"), "name")) { + settings.set_toolchain_label(toolchain.label()); settings.set_target_os(Settings::WIN); // Output going to "out/Debug". @@ -30,8 +31,8 @@ } BuildSettings build_settings; - Toolchain toolchain; Settings settings; + Toolchain toolchain; Target target; };
diff --git a/tools/gn/ninja_script_target_writer.cc b/tools/gn/ninja_script_target_writer.cc index 1b8358c..e8cdef4 100644 --- a/tools/gn/ninja_script_target_writer.cc +++ b/tools/gn/ninja_script_target_writer.cc
@@ -11,8 +11,9 @@ #include "tools/gn/target.h" NinjaScriptTargetWriter::NinjaScriptTargetWriter(const Target* target, + const Toolchain* toolchain, std::ostream& out) - : NinjaTargetWriter(target, out), + : NinjaTargetWriter(target, toolchain, out), path_output_no_escaping_( target->settings()->build_settings()->build_dir(), ESCAPE_NONE, false) { @@ -152,7 +153,7 @@ out_ << "build "; path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_)); out_ << ": " - << helper_.GetRulePrefix(target_->settings()->toolchain()) + << helper_.GetRulePrefix(target_->settings()) << "stamp"; for (size_t i = 0; i < output_files.size(); i++) { out_ << " ";
diff --git a/tools/gn/ninja_script_target_writer.h b/tools/gn/ninja_script_target_writer.h index e84d618..9c51a6a 100644 --- a/tools/gn/ninja_script_target_writer.h +++ b/tools/gn/ninja_script_target_writer.h
@@ -17,7 +17,9 @@ // Writes a .ninja file for a custom script target type. class NinjaScriptTargetWriter : public NinjaTargetWriter { public: - NinjaScriptTargetWriter(const Target* target, std::ostream& out); + NinjaScriptTargetWriter(const Target* target, + const Toolchain* toolchain, + std::ostream& out); virtual ~NinjaScriptTargetWriter(); virtual void Run() OVERRIDE;
diff --git a/tools/gn/ninja_script_target_writer_unittest.cc b/tools/gn/ninja_script_target_writer_unittest.cc index 1394717..f2c8a93 100644 --- a/tools/gn/ninja_script_target_writer_unittest.cc +++ b/tools/gn/ninja_script_target_writer_unittest.cc
@@ -21,7 +21,7 @@ SourceFile("//out/Debug/gen/{{source_name_part}}.cc")); std::ostringstream out; - NinjaScriptTargetWriter writer(&target, out); + NinjaScriptTargetWriter writer(&target, setup.toolchain(), out); FileTemplate output_template = writer.GetOutputTemplate(); @@ -42,7 +42,7 @@ Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); std::ostringstream out; - NinjaScriptTargetWriter writer(&target, out); + NinjaScriptTargetWriter writer(&target, setup.toolchain(), out); std::vector<std::string> args; args.push_back("-i"); @@ -88,7 +88,7 @@ "/usr/bin/python"))); std::ostringstream out; - NinjaScriptTargetWriter writer(&target, out); + NinjaScriptTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); const char expected_linux[] = @@ -107,7 +107,7 @@ " source = ../../foo/input2.txt\n" " source_name_part = input2\n" "\n" - "build obj/foo/bar.stamp: tc_stamp input1.out input2.out\n"; + "build obj/foo/bar.stamp: stamp input1.out input2.out\n"; std::string out_str = out.str(); #if defined(OS_WIN) @@ -125,7 +125,7 @@ setup.settings()->set_target_os(Settings::WIN); std::ostringstream out; - NinjaScriptTargetWriter writer(&target, out); + NinjaScriptTargetWriter writer(&target, setup.toolchain(), out); writer.Run(); // TODO(brettw) I think we'll need to worry about backslashes here @@ -151,7 +151,7 @@ " source = ../../foo/input2.txt\n" " source_name_part = input2\n" "\n" - "build obj/foo/bar.stamp: tc_stamp input1.out input2.out\n"; + "build obj/foo/bar.stamp: stamp input1.out input2.out\n"; std::string out_str = out.str(); #if defined(OS_WIN) std::replace(out_str.begin(), out_str.end(), '\\', '/');
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc index d73c873..bdc0472 100644 --- a/tools/gn/ninja_target_writer.cc +++ b/tools/gn/ninja_target_writer.cc
@@ -19,9 +19,12 @@ #include "tools/gn/target.h" #include "tools/gn/trace.h" -NinjaTargetWriter::NinjaTargetWriter(const Target* target, std::ostream& out) +NinjaTargetWriter::NinjaTargetWriter(const Target* target, + const Toolchain* toolchain, + std::ostream& out) : settings_(target->settings()), target_(target), + toolchain_(toolchain), out_(out), path_output_(settings_->build_settings()->build_dir(), ESCAPE_NINJA, true), @@ -45,7 +48,7 @@ ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, target->label().GetUserVisibleName(false)); - trace.SetToolchain(settings->toolchain()->label()); + trace.SetToolchain(settings->toolchain_label()); base::FilePath ninja_file(settings->build_settings()->GetFullPath( helper.GetNinjaFileForTarget(target).GetSourceFile( @@ -54,6 +57,10 @@ if (g_scheduler->verbose_logging()) g_scheduler->Log("Writing", FilePathToUTF8(ninja_file)); + const Toolchain* tc = settings->build_settings()->toolchain_manager() + .GetToolchainDefinitionUnlocked(settings->toolchain_label()); + CHECK(tc); + file_util::CreateDirectory(ninja_file.DirName()); // It's rediculously faster to write to a string and then write that to @@ -62,19 +69,19 @@ // Call out to the correct sub-type of writer. if (target->output_type() == Target::COPY_FILES) { - NinjaCopyTargetWriter writer(target, file); + NinjaCopyTargetWriter writer(target, tc, file); writer.Run(); } else if (target->output_type() == Target::CUSTOM) { - NinjaScriptTargetWriter writer(target, file); + NinjaScriptTargetWriter writer(target, tc, file); writer.Run(); } else if (target->output_type() == Target::GROUP) { - NinjaGroupTargetWriter writer(target, file); + NinjaGroupTargetWriter writer(target, tc, file); writer.Run(); } else if (target->output_type() == Target::EXECUTABLE || target->output_type() == Target::STATIC_LIBRARY || target->output_type() == Target::SHARED_LIBRARY || target->output_type() == Target::SOURCE_SET) { - NinjaBinaryTargetWriter writer(target, file); + NinjaBinaryTargetWriter writer(target, tc, file); writer.Run(); } else { CHECK(0); @@ -85,10 +92,6 @@ static_cast<int>(contents.size())); } -const Toolchain* NinjaTargetWriter::GetToolchain() const { - return target_->settings()->toolchain(); -} - std::string NinjaTargetWriter::GetSourcesImplicitDeps() const { std::ostringstream ret; ret << " |";
diff --git a/tools/gn/ninja_target_writer.h b/tools/gn/ninja_target_writer.h index c9c72a7..e1c3bf8 100644 --- a/tools/gn/ninja_target_writer.h +++ b/tools/gn/ninja_target_writer.h
@@ -19,7 +19,9 @@ // generated by the NinjaBuildWriter. class NinjaTargetWriter { public: - NinjaTargetWriter(const Target* target, std::ostream& out); + NinjaTargetWriter(const Target* target, + const Toolchain* toolchain, + std::ostream& out); virtual ~NinjaTargetWriter(); static void RunAndWriteFile(const Target* target); @@ -27,9 +29,6 @@ virtual void Run() = 0; protected: - // Returns the toolchain associated with the target. - const Toolchain* GetToolchain() const; - // Returns the string to be appended to source rules that encodes the // order-only dependencies for the current target. This will include the // "|" character so can just be appended to the source rules. If there are no @@ -41,6 +40,7 @@ const Settings* settings_; // Non-owning. const Target* target_; // Non-owning. + const Toolchain* toolchain_; // Non-owning. std::ostream& out_; PathOutput path_output_;
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc index 310caba..5f33e69 100644 --- a/tools/gn/ninja_toolchain_writer.cc +++ b/tools/gn/ninja_toolchain_writer.cc
@@ -13,6 +13,7 @@ #include "tools/gn/settings.h" #include "tools/gn/target.h" #include "tools/gn/toolchain.h" +#include "tools/gn/toolchain_manager.h" #include "tools/gn/trace.h" NinjaToolchainWriter::NinjaToolchainWriter( @@ -62,11 +63,14 @@ } void NinjaToolchainWriter::WriteRules() { - const Toolchain* tc = settings_->toolchain(); + const Toolchain* tc = settings_->build_settings()->toolchain_manager() + .GetToolchainDefinitionUnlocked(settings_->toolchain_label()); + CHECK(tc); + std::string indent(" "); NinjaHelper helper(settings_->build_settings()); - std::string rule_prefix = helper.GetRulePrefix(tc); + std::string rule_prefix = helper.GetRulePrefix(settings_); for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) { Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
diff --git a/tools/gn/scope_per_file_provider.cc b/tools/gn/scope_per_file_provider.cc index 525aab6..1f4bc25 100644 --- a/tools/gn/scope_per_file_provider.cc +++ b/tools/gn/scope_per_file_provider.cc
@@ -43,7 +43,7 @@ const Value* ScopePerFileProvider::GetCurrentToolchain() { if (!current_toolchain_) { current_toolchain_.reset(new Value(NULL, - scope_->settings()->toolchain()->label().GetUserVisibleName(false))); + scope_->settings()->toolchain_label().GetUserVisibleName(false))); } return current_toolchain_.get(); }
diff --git a/tools/gn/scope_per_file_provider_unittest.cc b/tools/gn/scope_per_file_provider_unittest.cc index 1137d3b..776a0aa 100644 --- a/tools/gn/scope_per_file_provider_unittest.cc +++ b/tools/gn/scope_per_file_provider_unittest.cc
@@ -6,34 +6,26 @@ #include "tools/gn/build_settings.h" #include "tools/gn/scope_per_file_provider.h" #include "tools/gn/settings.h" +#include "tools/gn/test_with_scope.h" #include "tools/gn/toolchain.h" #include "tools/gn/variables.h" TEST(ScopePerFileProvider, Expected) { - Err err; - - BuildSettings build_settings; - build_settings.toolchain_manager().SetDefaultToolchainUnlocked( - Label(SourceDir("//toolchain/"), "default", SourceDir(), ""), - LocationRange(), &err); - EXPECT_FALSE(err.has_error()); - - build_settings.SetBuildDir(SourceDir("//out/Debug/")); + TestWithScope test; // Prevent horrible wrapping of calls below. #define GPV(val) provider.GetProgrammaticValue(val)->string_value() // Test the default toolchain. { - Toolchain toolchain(Label(SourceDir("//toolchain/"), "tc")); - Settings settings(&build_settings, &toolchain, std::string()); - - Scope scope(&settings); + Scope scope(test.settings()); scope.set_source_dir(SourceDir("//source/")); ScopePerFileProvider provider(&scope); - EXPECT_EQ("//toolchain:tc", GPV(variables::kCurrentToolchain)); - EXPECT_EQ("//toolchain:default", GPV(variables::kDefaultToolchain)); + EXPECT_EQ("//toolchain:default", GPV(variables::kCurrentToolchain)); + // TODO(brettw) this test harness does not set up the Toolchain manager + // which is the source of this value, so we can't test this yet. + //EXPECT_EQ("//toolchain:default", GPV(variables::kDefaultToolchain)); EXPECT_EQ("//out/Debug", GPV(variables::kRootBuildDir)); EXPECT_EQ("//out/Debug/gen", GPV(variables::kRootGenDir)); EXPECT_EQ("//out/Debug", GPV(variables::kRootOutDir)); @@ -43,13 +35,17 @@ // Test some with an alternate toolchain. { - Toolchain toolchain(Label(SourceDir("//toolchain/"), "tc")); - Settings settings(&build_settings, &toolchain, "tc"); + Settings settings(test.build_settings(), "tc"); + Toolchain toolchain(&settings, Label(SourceDir("//toolchain/"), "tc")); + settings.set_toolchain_label(toolchain.label()); Scope scope(&settings); scope.set_source_dir(SourceDir("//source/")); ScopePerFileProvider provider(&scope); + EXPECT_EQ("//toolchain:tc", GPV(variables::kCurrentToolchain)); + // See above. + //EXPECT_EQ("//toolchain:default", GPV(variables::kDefaultToolchain)); EXPECT_EQ("//out/Debug", GPV(variables::kRootBuildDir)); EXPECT_EQ("//out/Debug/tc/gen", GPV(variables::kRootGenDir)); EXPECT_EQ("//out/Debug/tc", GPV(variables::kRootOutDir));
diff --git a/tools/gn/settings.cc b/tools/gn/settings.cc index bfab85d..b8de976 100644 --- a/tools/gn/settings.cc +++ b/tools/gn/settings.cc
@@ -9,10 +9,9 @@ #include "tools/gn/filesystem_utils.h" Settings::Settings(const BuildSettings* build_settings, - const Toolchain* toolchain, const std::string& output_subdir_name) : build_settings_(build_settings), - toolchain_(toolchain), + is_default_(false), import_manager_(), base_config_(this), greedy_target_generation_(false) {
diff --git a/tools/gn/settings.h b/tools/gn/settings.h index 1305c58..df6a3d6 100644 --- a/tools/gn/settings.h +++ b/tools/gn/settings.h
@@ -38,18 +38,17 @@ // toolchain's outputs. It should have no slashes in it. The default // toolchain should use an empty string. Settings(const BuildSettings* build_settings, - const Toolchain* toolchain, const std::string& output_subdir_name); ~Settings(); const BuildSettings* build_settings() const { return build_settings_; } - // Danger: this must only be used for getting the toolchain label until the - // toolchain has been resolved. Otherwise, it will be modified on an - // arbitrary thread when the toolchain invocation is found. Generally, you - // will only read this from the target generation where we know everything - // has been resolved and won't change. - const Toolchain* toolchain() const { return toolchain_; } + const Label& toolchain_label() const { return toolchain_label_; } + void set_toolchain_label(const Label& l) { toolchain_label_ = l; } + + // Indicates if this corresponds to the default toolchain. + bool is_default() const { return is_default_; } + void set_is_default(bool id) { is_default_ = id; } bool IsMac() const { return target_os_ == MAC; } bool IsLinux() const { return target_os_ == LINUX; } @@ -94,7 +93,8 @@ private: const BuildSettings* build_settings_; - const Toolchain* toolchain_; + Label toolchain_label_; + bool is_default_; TargetOS target_os_;
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc index 8bce9b5..47a243a 100644 --- a/tools/gn/setup.cc +++ b/tools/gn/setup.cc
@@ -202,9 +202,9 @@ Setup::Setup() : CommonSetup(), - empty_toolchain_(Label()), - empty_settings_(&empty_build_settings_, &empty_toolchain_, std::string()), + empty_settings_(&empty_build_settings_, std::string()), dotfile_scope_(&empty_settings_) { + empty_settings_.set_toolchain_label(Label()); } Setup::~Setup() {
diff --git a/tools/gn/setup.h b/tools/gn/setup.h index c2b3d82..8b6d714 100644 --- a/tools/gn/setup.h +++ b/tools/gn/setup.h
@@ -91,7 +91,6 @@ // These empty settings and toolchain are used to interpret the command line // and dot file. BuildSettings empty_build_settings_; - Toolchain empty_toolchain_; Settings empty_settings_; Scope dotfile_scope_;
diff --git a/tools/gn/target.cc b/tools/gn/target.cc index 291d579..28dcf91 100644 --- a/tools/gn/target.cc +++ b/tools/gn/target.cc
@@ -57,8 +57,7 @@ } // namespace Target::Target(const Settings* settings, const Label& label) - : Item(label), - settings_(settings), + : Item(settings, label), output_type_(UNKNOWN), hard_dep_(false), external_(false), @@ -155,9 +154,9 @@ } // Mark as resolved. - if (!settings_->build_settings()->target_resolved_callback().is_null()) { + if (!settings()->build_settings()->target_resolved_callback().is_null()) { g_scheduler->ScheduleWork(base::Bind(&TargetResolvedThunk, - settings_->build_settings()->target_resolved_callback(), + settings()->build_settings()->target_resolved_callback(), this)); } }
diff --git a/tools/gn/target.h b/tools/gn/target.h index d5c1af3..13b278c 100644 --- a/tools/gn/target.h +++ b/tools/gn/target.h
@@ -58,8 +58,6 @@ bool HasBeenGenerated() const; void SetGenerated(const Token* token); - const Settings* settings() const { return settings_; } - OutputType output_type() const { return output_type_; } void set_output_type(OutputType t) { output_type_ = t; } @@ -149,7 +147,6 @@ // dependencies have been resolved. void PullDependentTargetInfo(std::set<const Config*>* unique_configs); - const Settings* settings_; OutputType output_type_; std::string output_name_;
diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc index ea1700f..ef213b5 100644 --- a/tools/gn/target_unittest.cc +++ b/tools/gn/target_unittest.cc
@@ -15,16 +15,17 @@ public: TargetTest() : build_settings_(), - toolchain_(Label(SourceDir("//tc/"), "tc")), - settings_(&build_settings_, &toolchain_, std::string()) { + settings_(&build_settings_, std::string()), + toolchain_(&settings_, Label(SourceDir("//tc/"), "tc")) { + settings_.set_toolchain_label(toolchain_.label()); } virtual ~TargetTest() { } protected: BuildSettings build_settings_; - Toolchain toolchain_; Settings settings_; + Toolchain toolchain_; }; } // namespace @@ -122,15 +123,15 @@ b.deps().push_back(LabelTargetPair(&c)); // Normal non-inherited config. - Config config(Label(SourceDir("//foo/"), "config")); + Config config(&settings_, Label(SourceDir("//foo/"), "config")); c.configs().push_back(LabelConfigPair(&config)); // All dependent config. - Config all(Label(SourceDir("//foo/"), "all")); + Config all(&settings_, Label(SourceDir("//foo/"), "all")); c.all_dependent_configs().push_back(LabelConfigPair(&all)); // Direct dependent config. - Config direct(Label(SourceDir("//foo/"), "direct")); + Config direct(&settings_, Label(SourceDir("//foo/"), "direct")); c.direct_dependent_configs().push_back(LabelConfigPair(&direct)); c.OnResolved();
diff --git a/tools/gn/test_with_scope.cc b/tools/gn/test_with_scope.cc index e83c99c..e149e92 100644 --- a/tools/gn/test_with_scope.cc +++ b/tools/gn/test_with_scope.cc
@@ -6,9 +6,13 @@ TestWithScope::TestWithScope() : build_settings_(), - toolchain_(Label(SourceDir("//toolchain/"), "tc")), - settings_(&build_settings_, &toolchain_, std::string()), + settings_(&build_settings_, std::string()), + toolchain_(&settings_, Label(SourceDir("//toolchain/"), "default")), scope_(&settings_) { + build_settings_.SetBuildDir(SourceDir("//out/Debug/")); + + settings_.set_toolchain_label(toolchain_.label()); + settings_.set_is_default(true); } TestWithScope::~TestWithScope() {
diff --git a/tools/gn/test_with_scope.h b/tools/gn/test_with_scope.h index 7d512c4..df2c93e 100644 --- a/tools/gn/test_with_scope.h +++ b/tools/gn/test_with_scope.h
@@ -20,12 +20,13 @@ BuildSettings* build_settings() { return &build_settings_; } Settings* settings() { return &settings_; } + Toolchain* toolchain() { return &toolchain_; } Scope* scope() { return &scope_; } private: BuildSettings build_settings_; - Toolchain toolchain_; Settings settings_; + Toolchain toolchain_; Scope scope_; DISALLOW_COPY_AND_ASSIGN(TestWithScope);
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc index 887fba2..eee458a 100644 --- a/tools/gn/toolchain.cc +++ b/tools/gn/toolchain.cc
@@ -25,7 +25,8 @@ Toolchain::Tool::~Tool() { } -Toolchain::Toolchain(const Label& label) : Item(label), is_default_(false) { +Toolchain::Toolchain(const Settings* settings, const Label& label) + : Item(settings, label) { } Toolchain::~Toolchain() {
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h index 106f2f4..210c2c0 100644 --- a/tools/gn/toolchain.h +++ b/tools/gn/toolchain.h
@@ -70,7 +70,7 @@ std::string rspfile_content; }; - Toolchain(const Label& label); + Toolchain(const Settings* settings, const Label& label); virtual ~Toolchain(); // Item overrides. @@ -87,9 +87,6 @@ const std::string& environment() const { return environment_; } void set_environment(const std::string& env) { environment_ = env; } - bool is_default() const { return is_default_; } - void set_is_default(bool id) { is_default_ = id; } - // Specifies build argument overrides that will be set on the base scope. It // will be as if these arguments were passed in on the command line. This // allows a toolchain to override the OS type of the default toolchain or @@ -100,7 +97,6 @@ private: Tool tools_[TYPE_NUMTYPES]; - bool is_default_; Scope::KeyValueMap args_; std::string environment_;
diff --git a/tools/gn/toolchain_manager.cc b/tools/gn/toolchain_manager.cc index affdec9..4edf212 100644 --- a/tools/gn/toolchain_manager.cc +++ b/tools/gn/toolchain_manager.cc
@@ -78,11 +78,17 @@ const Label& toolchain_name, const std::string& output_subdir_name) : state(TOOLCHAIN_NOT_LOADED), - toolchain(toolchain_name), + settings(build_settings, output_subdir_name), + toolchain(new Toolchain(&settings, toolchain_name)), toolchain_set(false), - settings(build_settings, &toolchain, output_subdir_name), toolchain_file_loaded(false), item_node(NULL) { + settings.set_toolchain_label(toolchain_name); + } + + ~Info() { + if (!item_node) // See toolchain definition for more. + delete toolchain; } // Makes sure that an ItemNode is created for the toolchain, which lets @@ -95,17 +101,13 @@ void EnsureItemNode() { if (!item_node) { ItemTree& tree = settings.build_settings()->item_tree(); - item_node = new ItemNode(&toolchain); + item_node = new ItemNode(toolchain); tree.AddNodeLocked(item_node); } } ToolchainState state; - Toolchain toolchain; - bool toolchain_set; - LocationRange toolchain_definition_location; - // The first place in the build that we saw a reference for this toolchain. // This allows us to report errors if it can't be loaded and blame some // reasonable place of the code. This will be empty for the default toolchain. @@ -118,6 +120,13 @@ // is only ever read or written inside the lock. Settings settings; + // When we create an item node, this pointer will be owned by that node + // so it's lifetime is managed by the dependency graph. Before we've created + // the ItemNode, this class has to takre responsibility for this pointer. + Toolchain* toolchain; + bool toolchain_set; + LocationRange toolchain_definition_location; + // Set when the file corresponding to the toolchain definition is loaded. // This will normally be set right after "toolchain_set". However, if the // toolchain definition is missing, the file might be marked loaded but the @@ -202,7 +211,7 @@ // Since we don't allow defining a toolchain more than once, we know that // once it's set it won't be mutated, so we can safely return this pointer // for reading outside the lock. - return &found->second->toolchain; + return found->second->toolchain; } bool ToolchainManager::SetDefaultToolchainUnlocked( @@ -261,13 +270,10 @@ } // The labels should match or else we're setting the wrong one! - CHECK(info->toolchain.label() == tc.label()); + CHECK(info->toolchain->label() == tc.label()); - // Save the toolchain. We can just overwrite our definition, but we need to - // be careful to preserve the is_default flag. - bool is_default = info->toolchain.is_default(); - info->toolchain = tc; - info->toolchain.set_is_default(is_default); + // Save the toolchain. We can just overwrite our definition. + *info->toolchain = tc; if (info->toolchain_set) { *err = Err(defined_from, "Duplicate toolchain definition."); @@ -423,8 +429,9 @@ // to set the label, but we can assign the toolchain to a new one. Loading // the build config can not change the toolchain, so we won't be overwriting // anything useful. - info->toolchain = Toolchain(default_toolchain_); - info->toolchain.set_is_default(true); + *info->toolchain = Toolchain(&info->settings, default_toolchain_); + info->settings.set_is_default(true); + info->settings.set_toolchain_label(default_toolchain_); info->EnsureItemNode(); // The default toolchain is loaded in greedy mode so all targets we @@ -486,8 +493,8 @@ Scope* base_config = info->settings.base_config(); base_config->set_source_dir(SourceDir("//")); - info->settings.build_settings()->build_args().SetupRootScope(base_config, - info->settings.toolchain()->args()); + info->settings.build_settings()->build_args().SetupRootScope( + base_config, info->toolchain->args()); base_config->SetProcessingBuildConfig(); if (is_default) @@ -495,7 +502,7 @@ ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, info->settings.build_settings()->build_config_file().value()); - trace.SetToolchain(info->settings.toolchain()->label()); + trace.SetToolchain(info->settings.toolchain_label()); const BlockNode* root_block = root->AsBlock(); Err err; @@ -540,7 +547,7 @@ if (root && !g_scheduler->is_failed()) { if (g_scheduler->verbose_logging()) { g_scheduler->Log("Running", file_name.value() + " with toolchain " + - info->toolchain.label().GetUserVisibleName(false)); + info->toolchain->label().GetUserVisibleName(false)); } Scope our_scope(info->settings.base_config()); @@ -548,7 +555,7 @@ our_scope.set_source_dir(file_name.GetDir()); ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, file_name.value()); - trace.SetToolchain(info->settings.toolchain()->label()); + trace.SetToolchain(info->settings.toolchain_label()); Err err; root->Execute(&our_scope, &err);