Revert "Write to ninja files via a standard API" This reverts commit 8e99cccde6c2b7e4e9a2076baf68b45d40f15613. Reason for revert: Speculative rollback Failure Link: https://ci.chromium.org/ui/p/chromium/builders/try/ios-simulator/2976370/overview Original change's description: > Write to ninja files via a standard API > > This paves the way to have multiple targets in a single ninja file, > which in turn should allow us to shard targets without degrading build > performance. > > Benchmarking reveals a statistically insignificant impact on > performance, and `siso dump` (crrev.com/c/8275910) reveals that the build graph > is identical to before. > > Change-Id: I188fd8b075bb2f5cec9ff253c9220ae26a6a6964 > Reviewed-on: https://gn-review.googlesource.com/c/gn/+/25740 > Reviewed-by: Takuto Ikuta <tikuta@google.com> > Commit-Queue: Matt Stark <msta@google.com> TBR=tikuta@google.com,gn-scoped@luci-project-accounts.iam.gserviceaccount.com,msta@google.com No-Presubmit: true No-Tree-Checks: true No-Try: true Change-Id: Ia10bceec638142f3c2be2f2e7c613d84da5f8d35 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/26121 Reviewed-by: Takuto Ikuta <tikuta@google.com> Reviewed-by: Matt Stark <msta@google.com> Commit-Queue: Matt Stark <msta@google.com>
diff --git a/build/gen.py b/build/gen.py index 428c713..e4e377e 100755 --- a/build/gen.py +++ b/build/gen.py
@@ -861,7 +861,6 @@ 'src/gn/ninja_c_binary_target_writer.cc', 'src/gn/ninja_copy_target_writer.cc', 'src/gn/ninja_create_bundle_target_writer.cc', - 'src/gn/ninja_file.cc', 'src/gn/ninja_generated_file_target_writer.cc', 'src/gn/ninja_group_target_writer.cc', 'src/gn/ninja_module_writer_util.cc',
diff --git a/integration_tests/simple/goldens/obj/hello.ninja b/integration_tests/simple/goldens/obj/hello.ninja index 9ad97cf..b5f77f8 100644 --- a/integration_tests/simple/goldens/obj/hello.ninja +++ b/integration_tests/simple/goldens/obj/hello.ninja
@@ -4,7 +4,6 @@ target_out_dir = obj target_output_name = hello - build obj/hello.hello.o: cxx ../hello.cc source_file_part = hello.cc source_name_part = hello
diff --git a/integration_tests/simple/goldens/obj/hello_shared.ninja b/integration_tests/simple/goldens/obj/hello_shared.ninja index 21ddb24..998ee5e 100644 --- a/integration_tests/simple/goldens/obj/hello_shared.ninja +++ b/integration_tests/simple/goldens/obj/hello_shared.ninja
@@ -4,7 +4,6 @@ target_out_dir = obj target_output_name = libhello_shared - build obj/libhello_shared.hello_shared.o: cxx ../hello_shared.cc source_file_part = hello_shared.cc source_name_part = hello_shared
diff --git a/integration_tests/simple/goldens/obj/hello_static.ninja b/integration_tests/simple/goldens/obj/hello_static.ninja index c2821dd..c554743 100644 --- a/integration_tests/simple/goldens/obj/hello_static.ninja +++ b/integration_tests/simple/goldens/obj/hello_static.ninja
@@ -4,7 +4,6 @@ target_out_dir = obj target_output_name = libhello_static - build obj/libhello_static.hello_static.o: cxx ../hello_static.cc source_file_part = hello_static.cc source_name_part = hello_static
diff --git a/src/gn/ninja_action_target_writer.cc b/src/gn/ninja_action_target_writer.cc index b5490d3..0d01d07 100644 --- a/src/gn/ninja_action_target_writer.cc +++ b/src/gn/ninja_action_target_writer.cc
@@ -26,7 +26,7 @@ NinjaActionTargetWriter::~NinjaActionTargetWriter() = default; -void NinjaActionTargetWriter::GenerateRules() { +void NinjaActionTargetWriter::Run() { std::string custom_rule_name = WriteRuleDefinition(); // Collect our deps to pass as additional "hard dependencies" for input deps. @@ -78,6 +78,7 @@ std::vector<OutputFile> input_deps = stamp_deps.implicit; input_deps.insert(input_deps.end(), stamp_deps.order_only.begin(), stamp_deps.order_only.end()); + out_ << std::endl; // Collects all output files for writing below. std::vector<OutputFile> output_files; @@ -91,33 +92,47 @@ // Write a rule that invokes the script once with the outputs as outputs, // and the data as inputs. It does not depend on the sources. + out_ << "build"; SubstitutionWriter::GetListAsOutputFiles( settings_, target_->action_values().outputs(), &output_files); + WriteOutputs(output_files); - NinjaBuildEdge edge{ - .rule = custom_rule_name, - .outputs = output_files, - .implicit_inputs = input_deps, - .order_only_inputs = order_only_deps, - }; - AddValidationInputs(edge); - - WriteNinjaVariablesForAction(edge.edge_vars); - - if (target_->action_values().has_depfile()) - WriteDepfile(SourceFile(), edge.edge_vars); - - if (target_->pool().ptr) { - edge.edge_vars.emplace_back("pool", - target_->pool().ptr->GetNinjaName( - settings_->default_toolchain_label())); + out_ << ": " << custom_rule_name; + if (!input_deps.empty()) { + // As in WriteSourceRules, we want to force this target to rebuild any + // time any of its dependencies change. + out_ << " |"; + path_output_.WriteFiles(out_, input_deps); + } + if (!order_only_deps.empty()) { + // Write any order-only deps out for actions just like they are for + // binaries. + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); } - AddEdge(std::move(edge)); + WriteValidations(); + out_ << std::endl; + + if (target_->action_values().has_depfile()) { + WriteDepfile(SourceFile()); + } + + WriteNinjaVariablesForAction(); + + if (target_->pool().ptr) { + out_ << " pool = "; + out_ << target_->pool().ptr->GetNinjaName( + settings_->default_toolchain_label()); + out_ << std::endl; + } } + out_ << std::endl; // Write the phony, which doesn't need to depend on the data deps because they // have been added as order-only deps of the action output itself. + // + // TODO(thakis): If the action has just a single output, make things depend std::vector<OutputFile> stamp_file_order_only_deps; WriteStampOrPhonyForTarget(output_files, stamp_file_order_only_deps); } @@ -137,8 +152,7 @@ EscapeOptions args_escape_options; args_escape_options.mode = ESCAPE_NINJA_COMMAND; - std::ostringstream rule_out; - rule_out << "rule " << custom_rule_name << std::endl; + out_ << "rule " << custom_rule_name << std::endl; if (target_->action_values().uses_rsp_file()) { // Needs a response file. The unique_name part is for action_foreach so @@ -149,17 +163,17 @@ if (!target_->sources().empty()) rspfile += ".$unique_name"; rspfile += ".rsp"; - rule_out << " rspfile = " << rspfile << std::endl; + out_ << " rspfile = " << rspfile << std::endl; // Response file contents. - rule_out << " rspfile_content ="; + out_ << " rspfile_content ="; for (const auto& arg : target_->action_values().rsp_file_contents().list()) { - rule_out << " "; + out_ << " "; SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, - rule_out); + out_); } - rule_out << std::endl; + out_ << std::endl; } // The command line requires shell escaping to properly handle filenames @@ -168,33 +182,29 @@ settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND); - rule_out << " command = "; - command_output.WriteFile(rule_out, - settings_->build_settings()->python_path()); - rule_out << " "; - command_output.WriteFile(rule_out, target_->action_values().script()); + out_ << " command = "; + command_output.WriteFile(out_, settings_->build_settings()->python_path()); + out_ << " "; + command_output.WriteFile(out_, target_->action_values().script()); for (const auto& arg : args.list()) { - rule_out << " "; - SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, - rule_out); + out_ << " "; + SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, out_); } - rule_out << std::endl; + out_ << std::endl; auto mnemonic = target_->action_values().mnemonic(); if (mnemonic.empty()) mnemonic = "ACTION"; - rule_out << " description = " << mnemonic << " " << target_label - << std::endl; - rule_out << " restat = 1" << std::endl; + out_ << " description = " << mnemonic << " " << target_label << std::endl; + out_ << " restat = 1" << std::endl; const Tool* tool = target_->toolchain()->GetTool(GeneralTool::kGeneralToolAction); if (tool && tool->pool().ptr) { - rule_out << " pool = "; - rule_out << tool->pool().ptr->GetNinjaName( + out_ << " pool = "; + out_ << tool->pool().ptr->GetNinjaName( settings_->default_toolchain_label()); - rule_out << std::endl; + out_ << std::endl; } - target_group_.custom_rules.push_back(rule_out.str()); return custom_rule_name; } @@ -211,32 +221,31 @@ const Target::FileList& sources = target_->sources(); for (size_t i = 0; i < sources.size(); i++) { - std::vector<OutputFile> cur_outputs; - SubstitutionWriter::ApplyListToSourceAsOutputFile( - target_, settings_, target_->action_values().outputs(), sources[i], - &cur_outputs); - output_files->insert(output_files->end(), cur_outputs.begin(), - cur_outputs.end()); + out_ << "build"; + WriteOutputFilesForBuildLine(sources[i], output_files); - // Using "|" for the dependencies forces all implicit dependencies to be - // fully up to date before running the action, and will re-run this - // action if any input dependencies change. This is important because - // this action may consume the outputs of previous steps. - // Write any order-only deps out for actions just like they are written - // out for binaries. - NinjaBuildEdge edge{ - .rule = custom_rule_name, - .outputs = std::move(cur_outputs), - .explicit_inputs = {OutputFile(settings_->build_settings(), - sources[i])}, - .implicit_inputs = input_deps, - .order_only_inputs = order_only_deps, - }; - AddValidationInputs(edge); + out_ << ": " << custom_rule_name << " "; + path_output_.WriteFile(out_, sources[i]); + if (!input_deps.empty()) { + // Using "|" for the dependencies forces all implicit dependencies to be + // fully up to date before running the action, and will re-run this + // action if any input dependencies change. This is important because + // this action may consume the outputs of previous steps. + out_ << " |"; + path_output_.WriteFiles(out_, input_deps); + } + if (!order_only_deps.empty()) { + // Write any order-only deps out for actions just like they are written + // out for binaries. + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + WriteValidations(); + out_ << std::endl; // Response files require a unique name be defined. if (target_->action_values().uses_rsp_file()) - edge.edge_vars.emplace_back("unique_name", std::to_string(i)); + out_ << " unique_name = " << i << std::endl; // The required types is the union of the args and response file. This // might theoretically duplicate a definition if the same substitution is @@ -246,48 +255,60 @@ SubstitutionWriter::WriteNinjaVariablesForSource( target_, settings_, sources[i], target_->action_values().args().required_types(), args_escape_options, - edge.edge_vars); + out_); SubstitutionWriter::WriteNinjaVariablesForSource( target_, settings_, sources[i], target_->action_values().rsp_file_contents().required_types(), - args_escape_options, edge.edge_vars); - WriteNinjaVariablesForAction(edge.edge_vars); + args_escape_options, out_); + WriteNinjaVariablesForAction(); - if (target_->action_values().has_depfile()) - WriteDepfile(sources[i], edge.edge_vars); - - if (target_->pool().ptr) { - edge.edge_vars.emplace_back("pool", - target_->pool().ptr->GetNinjaName( - settings_->default_toolchain_label())); + if (target_->action_values().has_depfile()) { + WriteDepfile(sources[i]); } - - AddEdge(std::move(edge)); + if (target_->pool().ptr) { + out_ << " pool = "; + out_ << target_->pool().ptr->GetNinjaName( + settings_->default_toolchain_label()); + out_ << std::endl; + } } } -void NinjaActionTargetWriter::WriteDepfile( +void NinjaActionTargetWriter::WriteOutputFilesForBuildLine( const SourceFile& source, - std::vector<NinjaVariable>& edge_vars) { - std::ostringstream ss; + std::vector<OutputFile>* output_files) { + size_t first_output_index = output_files->size(); + + SubstitutionWriter::ApplyListToSourceAsOutputFile( + target_, settings_, target_->action_values().outputs(), source, + output_files); + + for (size_t i = first_output_index; i < output_files->size(); i++) { + out_ << " "; + WriteOutput((*output_files)[i]); + } +} + +void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) { + out_ << " depfile = "; path_output_.WriteFile( - ss, SubstitutionWriter::ApplyPatternToSourceAsOutputFile( - target_, settings_, target_->action_values().depfile(), source)); - edge_vars.emplace_back("depfile", ss.str()); + out_, + SubstitutionWriter::ApplyPatternToSourceAsOutputFile( + target_, settings_, target_->action_values().depfile(), source)); + out_ << std::endl; // Using "deps = gcc" allows Ninja to read and store the depfile content in // its internal database which improves performance, especially for large // depfiles. The use of this feature with depfiles that contain multiple // outputs require Ninja version 1.9.0 or newer. if (settings_->build_settings()->ninja_required_version() >= Version{1, 9, 0}) { - edge_vars.emplace_back("deps", "gcc"); + out_ << " deps = gcc" << std::endl; } } -void NinjaActionTargetWriter::WriteNinjaVariablesForAction( - std::vector<NinjaVariable>& edge_vars) { +void NinjaActionTargetWriter::WriteNinjaVariablesForAction() { SubstitutionBits subst; target_->action_values().args().FillRequiredTypes(&subst); - WriteRustCompilerVars(subst, /*always_write=*/false, edge_vars); - WriteCCompilerVars(subst, /*respect_source_used=*/false, edge_vars); + WriteRustCompilerVars(subst, /*indent=*/true, /*always_write=*/false); + WriteCCompilerVars(subst, /*indent=*/true, /*respect_source_types=*/false); }
diff --git a/src/gn/ninja_action_target_writer.h b/src/gn/ninja_action_target_writer.h index 930a6df..eff087b 100644 --- a/src/gn/ninja_action_target_writer.h +++ b/src/gn/ninja_action_target_writer.h
@@ -18,9 +18,13 @@ NinjaActionTargetWriter(const Target* target, std::ostream& out); ~NinjaActionTargetWriter() override; - void GenerateRules() override; + void Run() override; private: + FRIEND_TEST_ALL_PREFIXES(NinjaActionTargetWriter, + WriteOutputFilesForBuildLine); + FRIEND_TEST_ALL_PREFIXES(NinjaActionTargetWriter, + WriteOutputFilesForBuildLineWithDepfile); FRIEND_TEST_ALL_PREFIXES(NinjaActionTargetWriter, WriteArgsSubstitutions); // Writes the Ninja rule for invoking the script. @@ -39,12 +43,17 @@ const std::vector<OutputFile>& order_only_deps, std::vector<OutputFile>* output_files); - void WriteDepfile(const SourceFile& source, - std::vector<NinjaVariable>& edge_vars); + // Writes the output files generated by the output template for the given + // source file. This will start with a space and will not include a newline. + // Appends the output files to the given vector. + void WriteOutputFilesForBuildLine(const SourceFile& source, + std::vector<OutputFile>* output_files); + + void WriteDepfile(const SourceFile& source); // Writes variables that we make available to all actions, irrespective // of whether they're associated with a specific source file. - void WriteNinjaVariablesForAction(std::vector<NinjaVariable>& edge_vars); + void WriteNinjaVariablesForAction(); // Path output writer that doesn't do any escaping or quoting. It does, // however, convert slashes. Used for
diff --git a/src/gn/ninja_action_target_writer_unittest.cc b/src/gn/ninja_action_target_writer_unittest.cc index cd3b0e7..e855582 100644 --- a/src/gn/ninja_action_target_writer_unittest.cc +++ b/src/gn/ninja_action_target_writer_unittest.cc
@@ -14,6 +14,29 @@ #include "util/build_config.h" #include "util/test/test.h" +TEST(NinjaActionTargetWriter, WriteOutputFilesForBuildLine) { + Err err; + TestWithScope setup; + + Target target(setup.settings(), Label(SourceDir("//foo/"), "bar")); + target.set_output_type(Target::ACTION_FOREACH); + target.action_values().outputs() = + SubstitutionList::MakeForTest("//out/Debug/gen/a b{{source_name_part}}.h", + "//out/Debug/gen/{{source_name_part}}.cc"); + + target.SetToolchain(setup.toolchain()); + ASSERT_TRUE(target.OnResolved(&err)); + + std::ostringstream out; + NinjaActionTargetWriter writer(&target, out); + + SourceFile source("//foo/bar.in"); + std::vector<OutputFile> output_files; + writer.WriteOutputFilesForBuildLine(source, &output_files); + + EXPECT_EQ(" gen/a$ bbar.h gen/bar.cc", out.str()); +} + // Tests an action with no sources. TEST(NinjaActionTargetWriter, ActionNoSources) { Err err; @@ -43,7 +66,6 @@ description = ACTION //foo++:bar() restat = 1 - build foo.out: __foo___bar___rule | ../../foo++/script.py ../../foo++/included.txt build phony/foo++/bar: phony foo.out @@ -88,7 +110,6 @@ description = ACTION //foo:bar() restat = 1 - build foo.out: __foo_bar___rule | ../../foo/script.py ../../foo/included.txt pool = console @@ -130,7 +151,6 @@ " description = ACTION //foo:bar()\n" " restat = 1\n" "\n" - "\n" "build foo.out: __foo_bar___rule | ../../foo/script.py " "../../foo/included.txt ../../foo/source.txt\n" "\n" @@ -188,7 +208,6 @@ " description = ACTION //foo:bar()\n" " restat = 1\n" "\n" - "\n" "build foo.out: __foo_bar___rule | ../../foo/script.py " "../../foo/included.txt ../../foo/source.txt phony/foo/dep || " "phony/foo/datadep\n" @@ -265,8 +284,6 @@ #endif " description = ACTION //foo:bar()\n" " restat = 1\n" - "\n" - "\n" "build phony/foo/bar.inputdeps: phony ../../foo/script.py " "../../foo/included.txt phony/foo/dep\n" "\n" @@ -274,7 +291,6 @@ "phony/foo/bar.inputdeps || phony/foo/bundle_data_dep " "phony/foo/datadep\n" " source_name_part = input1\n" - "\n" "build input2.out: __foo_bar___rule ../../foo/input2.txt | " "phony/foo/bar.inputdeps || phony/foo/bundle_data_dep " "phony/foo/datadep\n" @@ -335,8 +351,6 @@ #endif " description = ACTION //foo:bar()\n" " restat = 1\n" - "\n" - "\n" "build phony/foo/bar.inputdeps: phony ../../foo/script.py " "../../foo/included.txt\n" "\n" @@ -345,7 +359,6 @@ " source_name_part = input1\n" " depfile = gen/input1.d\n" " deps = gcc\n" - "\n" "build input2.out: __foo_bar___rule ../../foo/input2.txt" " | phony/foo/bar.inputdeps\n" " source_name_part = input2\n" @@ -397,7 +410,6 @@ " description = ACTION //foo:bar()\n" " restat = 1\n" "\n" - "\n" "build input1.out: __foo_bar___rule ../../foo/input1.txt" " | ../../foo/script.py\n" // Necessary for the rspfile defined in the rule. @@ -452,7 +464,6 @@ " description = ACTION //foo:bar()\n" " restat = 1\n" "\n" - "\n" "build input1.out: __foo_bar___rule ../../foo/input1.txt" " | ../../foo/script.py\n" // Substitution for the args. @@ -499,7 +510,6 @@ " description = ACTION //foo:foo()\n" " restat = 1\n" "\n" - "\n" "build foo.out: __foo_foo___rule | ../../foo/script.py" " ../../foo/input1.txt phony/foo/dep\n" "\n" @@ -529,7 +539,6 @@ " description = ACTION //bar:bar()\n" " restat = 1\n" "\n" - "\n" // Do not have obj/foo/dep.stamp as dependency. "build bar.out: __bar_bar___rule | ../../bar/script.py" " ../../bar/input1.txt phony/foo/foo\n" @@ -586,7 +595,6 @@ " description = ACTION //foo:foo()\n" " restat = 1\n" "\n" - "\n" "build foo.out: __foo_foo___rule | ../../foo/script.py" " ../../foo/input1.txt\n" " rustenv = my_rustenv\n" @@ -639,7 +647,6 @@ R"( description = ACTION //foo:bar() restat = 1 - build foo.out: __foo_bar___rule | ../../foo/my$ script.py ../../foo/input$ file.txt build phony/foo/bar: phony foo.out @@ -684,7 +691,6 @@ " description = ACTION //foo:bar()\n" " restat = 1\n" "\n" - "\n" "build foo.out: __foo_bar___rule | ../../foo/script.py |@ phony/foo/val\n" "\n" "build phony/foo/bar: phony foo.out |@ phony/foo/val\n";
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc index 3e465bc..8c8d2a0 100644 --- a/src/gn/ninja_binary_target_writer.cc +++ b/src/gn/ninja_binary_target_writer.cc
@@ -99,17 +99,19 @@ NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() = default; -void NinjaBinaryTargetWriter::GenerateRules() { +void NinjaBinaryTargetWriter::Run() { if (target_->source_types_used().RustSourceUsed()) { NinjaRustBinaryTargetWriter writer(target_, out_); writer.SetResolvedTargetData(GetResolvedTargetData()); - target_group_ = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs_); + writer.Run(); return; } NinjaCBinaryTargetWriter writer(target_, out_); writer.SetResolvedTargetData(GetResolvedTargetData()); - target_group_ = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs_); + writer.Run(); } void NinjaBinaryTargetWriter::WritePublicModuleMap(std::ostream& out, @@ -158,7 +160,7 @@ std::vector<OutputFile> NinjaBinaryTargetWriter::WriteInputsStampOrPhonyAndGetDep( - size_t num_output_uses) { + size_t num_output_uses) const { CHECK(target_->toolchain()) << "Toolchain not set on target " << target_->label().GetUserVisibleName(true); @@ -181,7 +183,7 @@ std::vector<OutputFile> outs; for (const SourceFile* source : inputs) - outs.emplace_back(settings_->build_settings(), *source); + outs.push_back(OutputFile(settings_->build_settings(), *source)); // If there are multiple inputs, but the phony target would be referenced only // once, don't write it but depend on the inputs directly. @@ -205,13 +207,17 @@ GeneralTool::kGeneralToolStamp; } - AddEdge(NinjaBuildEdge{ - .rule = tool, - .outputs = {stamp_or_phony}, - .explicit_inputs = outs, - .is_target_output = false, - }); + out_ << "build "; + WriteOutput(stamp_or_phony); + out_ << ": " << tool; + // File inputs. + for (const auto* input : inputs) { + out_ << " "; + path_output_.WriteFile(out_, *input); + } + + out_ << std::endl; return {stamp_or_phony}; } @@ -366,44 +372,46 @@ void NinjaBinaryTargetWriter::WriteCompilerBuildLine( const std::vector<SourceFile>& sources, - std::vector<OutputFile> extra_deps, - std::vector<OutputFile> order_only_deps, + const std::vector<OutputFile>& extra_deps, + const std::vector<OutputFile>& order_only_deps, const Tool* tool, - std::vector<OutputFile> outputs, + const std::vector<OutputFile>& outputs, bool can_write_source_info, bool restat_output_allowed) { - if (auto phony = tool->inputs_phony_or_file(rule_prefix_, - *settings_->build_settings())) { - extra_deps.push_back(*phony); + out_ << "build"; + WriteOutputs(outputs); + + out_ << ": " << rule_prefix_ << tool->name(); + path_output_.WriteFiles(out_, sources); + + if (!extra_deps.empty() || !tool->inputs().empty()) { + out_ << " |"; + path_output_.WriteFiles(out_, extra_deps); + if (auto phony = tool->inputs_phony_or_file(rule_prefix_, + *settings_->build_settings())) { + out_ << " "; + path_output_.WriteFile(out_, *phony); + } } - NinjaBuildEdge edge{ - .rule = rule_prefix_ + tool->name(), - .outputs = std::move(outputs), - .explicit_inputs = ToOutputFiles(sources), - .implicit_inputs = std::move(extra_deps), - .order_only_inputs = std::move(order_only_deps), - }; - AddValidationInputs(edge); + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + WriteValidations(); + out_ << std::endl; if (!sources.empty() && can_write_source_info) { - edge.edge_vars.emplace_back("source_file_part", sources[0].GetName()); - edge.edge_vars.emplace_back( - "source_name_part", - std::string(FindFilenameNoExtension(&sources[0].value()))); + out_ << " " << "source_file_part = " << sources[0].GetName(); + out_ << std::endl; + out_ << " " << "source_name_part = " + << FindFilenameNoExtension(&sources[0].value()); + out_ << std::endl; } if (restat_output_allowed) { - edge.edge_vars.emplace_back("restat", "1"); + out_ << " restat = 1" << std::endl; } - - if (target_->pool().ptr) { - edge.edge_vars.emplace_back("pool", - target_->pool().ptr->GetNinjaName( - settings_->default_toolchain_label())); - } - - AddEdge(std::move(edge)); } void NinjaBinaryTargetWriter::WriteCustomLinkerFlags(std::ostream& out, @@ -459,7 +467,7 @@ WriteLibrarySearchPath(out, tool); if (optional_def_file) { - out << " /DEF:"; + out_ << " /DEF:"; path_output_.WriteFile(out, *optional_def_file); } }
diff --git a/src/gn/ninja_binary_target_writer.h b/src/gn/ninja_binary_target_writer.h index 93774a6..99b2b72 100644 --- a/src/gn/ninja_binary_target_writer.h +++ b/src/gn/ninja_binary_target_writer.h
@@ -20,7 +20,7 @@ NinjaBinaryTargetWriter(const Target* target, std::ostream& out); ~NinjaBinaryTargetWriter() override; - void GenerateRules() override; + void Run() override; void WritePublicModuleMap(std::ostream& out, const SourceDir& out_dir); void WritePrivateModuleMap(std::ostream& out, const SourceDir& out_dir); @@ -42,7 +42,7 @@ // If there are no implicit dependencies and no extra target dependencies // are passed in, this returns an empty vector. std::vector<OutputFile> WriteInputsStampOrPhonyAndGetDep( - size_t num_phony_uses); + size_t num_phony_uses) const; // Gets all target dependencies and classifies them, as well as accumulates // object files from source sets we need to link. @@ -60,10 +60,10 @@ ClassifiedDeps* classified_deps) const; void WriteCompilerBuildLine(const std::vector<SourceFile>& sources, - std::vector<OutputFile> extra_deps, - std::vector<OutputFile> order_only_deps, + const std::vector<OutputFile>& extra_deps, + const std::vector<OutputFile>& order_only_deps, const Tool* tool, - std::vector<OutputFile> outputs, + const std::vector<OutputFile>& outputs, bool can_write_source_info = true, bool restat_output_allowed = false);
diff --git a/src/gn/ninja_binary_target_writer_unittest.cc b/src/gn/ninja_binary_target_writer_unittest.cc index 1c34ff0..d8e12bc 100644 --- a/src/gn/ninja_binary_target_writer_unittest.cc +++ b/src/gn/ninja_binary_target_writer_unittest.cc
@@ -42,18 +42,15 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc\n" " source_file_part = input2.cc\n" " source_name_part = input2\n" "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.input1.o " "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -146,14 +143,12 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.source1.o: cxx ../../foo/source1.cc | " "../../foo/input1 ../../foo/input2\n" " source_file_part = source1.cc\n" " source_name_part = source1\n" "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.source1.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -185,15 +180,12 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build phony/foo/bar.inputs: phony " "../../foo/input1 ../../foo/input2\n" - "\n" "build obj/foo/bar.source1.o: cxx ../../foo/source1.cc | " "phony/foo/bar.inputs\n" " source_file_part = source1.cc\n" " source_name_part = source1\n" - "\n" "build obj/foo/bar.source2.o: cxx ../../foo/source2.cc | " "phony/foo/bar.inputs\n" " source_file_part = source2.cc\n" @@ -201,7 +193,6 @@ "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.source1.o " "obj/foo/bar.source2.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -249,14 +240,12 @@ "target_out_dir = obj/foo\n" "target_output_name = b\n" "\n" - "\n" "build obj/foo/b.source1.o: cxx ../../foo/source1.cc | " "phony/foo/a.public_inputs || phony/foo/a\n" " source_file_part = source1.cc\n" " source_name_part = source1\n" "\n" "build phony/foo/b.linkdeps: phony obj/foo/b.source1.o || phony/foo/a\n" - "\n" "build phony/foo/b: phony phony/foo/b.linkdeps\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str);
diff --git a/src/gn/ninja_bundle_data_target_writer.cc b/src/gn/ninja_bundle_data_target_writer.cc index 01373b1..d6c2e56 100644 --- a/src/gn/ninja_bundle_data_target_writer.cc +++ b/src/gn/ninja_bundle_data_target_writer.cc
@@ -14,7 +14,7 @@ NinjaBundleDataTargetWriter::~NinjaBundleDataTargetWriter() = default; -void NinjaBundleDataTargetWriter::GenerateRules() { +void NinjaBundleDataTargetWriter::Run() { std::vector<OutputFile> output_files; for (const SourceFile& source_file : target_->sources()) { output_files.push_back(
diff --git a/src/gn/ninja_bundle_data_target_writer.h b/src/gn/ninja_bundle_data_target_writer.h index be87dd8..720c593 100644 --- a/src/gn/ninja_bundle_data_target_writer.h +++ b/src/gn/ninja_bundle_data_target_writer.h
@@ -13,7 +13,7 @@ NinjaBundleDataTargetWriter(const Target* target, std::ostream& out); ~NinjaBundleDataTargetWriter() override; - void GenerateRules() override; + void Run() override; private: NinjaBundleDataTargetWriter(const NinjaBundleDataTargetWriter&) = delete;
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc index 155d0de..a56f587 100644 --- a/src/gn/ninja_c_binary_target_writer.cc +++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -11,12 +11,15 @@ #include <set> #include <sstream> +#include "base/strings/string_util.h" #include "gn/builtin_tool.h" #include "gn/c_substitution_type.h" #include "gn/config_values_extractors.h" +#include "gn/deps_iterator.h" #include "gn/err.h" #include "gn/escape.h" #include "gn/filesystem_utils.h" +#include "gn/general_tool.h" #include "gn/ninja_module_writer_util.h" #include "gn/ninja_target_command_util.h" #include "gn/ninja_utils.h" @@ -60,7 +63,7 @@ NinjaCBinaryTargetWriter::~NinjaCBinaryTargetWriter() = default; -void NinjaCBinaryTargetWriter::GenerateRules() { +void NinjaCBinaryTargetWriter::Run() { std::set<ClangModuleDep> module_dep_info = GetModuleDepsInformation(target_, resolved()); @@ -173,7 +176,8 @@ const std::set<ClangModuleDep>& module_dep_info) { const SubstitutionBits& subst = target_->toolchain()->substitution_bits(); - WriteCCompilerVars(subst, /*respect_source_used=*/true); + WriteCCompilerVars(subst, /*indent=*/false, + /*respect_source_types_used=*/true); WriteModuleNameSubstitution(); @@ -194,12 +198,11 @@ void NinjaCBinaryTargetWriter::WriteModuleNameSubstitution() { if (target_->toolchain()->substitution_bits().used.count( &CSubstitutionModuleName)) { + out_ << CSubstitutionModuleName.ninja_name << " = "; EscapeOptions options; options.mode = ESCAPE_NINJA; - std::ostringstream val; - EscapeStringToStream(val, target_->module_name(), options); - target_group_.target_vars.emplace_back(CSubstitutionModuleName.ninja_name, - val.str()); + EscapeStringToStream(out_, target_->module_name(), options); + out_ << std::endl; } } @@ -208,11 +211,15 @@ const std::set<ClangModuleDep>& module_dep_info, bool include_self) { if (target_->toolchain()->substitution_bits().used.count(substitution)) { - std::ostringstream val; + EscapeOptions options; + options.mode = ESCAPE_NINJA_COMMAND; + + out_ << substitution->ninja_name << " ="; for (const auto& module_dep : module_dep_info) { - module_dep.Write(val, path_output_, include_self); + module_dep.Write(out_, path_output_, include_self); } - target_group_.target_vars.emplace_back(substitution->ninja_name, val.str()); + + out_ << std::endl; } } @@ -305,7 +312,7 @@ // This build line needs a custom language-specific flags value. Rule-specific // variables are just indented underneath the rule line. - std::ostringstream flag_val; + out_ << " " << flag_type->ninja_name << " ="; // Each substitution flag is overwritten in the target rule to replace the // implicitly generated -include flag with the -x <header lang> flag required @@ -314,26 +321,27 @@ if (tool_name == CTool::kCToolCc) { RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, target_, &ConfigValues::cflags_c, opts, - flag_val); + out_); } else if (tool_name == CTool::kCToolCxx) { RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, target_, &ConfigValues::cflags_cc, - opts, flag_val); + opts, out_); } else if (tool_name == CTool::kCToolObjC) { RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, target_, &ConfigValues::cflags_objc, - opts, flag_val); + opts, out_); } else if (tool_name == CTool::kCToolObjCxx) { RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, target_, &ConfigValues::cflags_objcc, - opts, flag_val); + opts, out_); } // Append the command to specify the language of the .gch file. - flag_val << " -x " << GetPCHLangForToolType(tool_name); + out_ << " -x " << GetPCHLangForToolType(tool_name); - target_group_.edges.back().edge_vars.emplace_back(flag_type->ninja_name, - flag_val.str()); + // Write two blank lines to help separate the PCH build lines from the + // regular source build lines. + out_ << std::endl << std::endl; } void NinjaCBinaryTargetWriter::WriteWindowsPCHCommand( @@ -360,15 +368,16 @@ // This build line needs a custom language-specific flags value. Rule-specific // variables are just indented underneath the rule line. - std::ostringstream flag_val; + out_ << " " << flag_type->ninja_name << " ="; // Append the command to generate the .pch file. // This adds the value to the existing flag instead of overwriting it. - flag_val << " ${" << flag_type->ninja_name << "} /Yc" - << target_->config_values().precompiled_header(); + out_ << " ${" << flag_type->ninja_name << "}"; + out_ << " /Yc" << target_->config_values().precompiled_header(); - target_group_.edges.back().edge_vars.emplace_back(flag_type->ninja_name, - flag_val.str()); + // Write two blank lines to help separate the PCH build lines from the + // regular source build lines. + out_ << std::endl << std::endl; } void NinjaCBinaryTargetWriter::WriteSources( @@ -466,6 +475,7 @@ WriteCompilerBuildLine({source}, deps, order_only_deps, tool, tool_outputs); + WritePool(out_); } // It's theoretically possible for a compiler to produce more than one @@ -482,6 +492,8 @@ extra_files->push_back(tool_outputs[i]); } } + + out_ << std::endl; } void NinjaCBinaryTargetWriter::WriteSwiftSources( @@ -517,6 +529,8 @@ swift_order_only_deps.vector(), tool, *output_files, /*can_write_source_info=*/false, /*restat_output_allowed=*/true); + + out_ << std::endl; } void NinjaCBinaryTargetWriter::WriteSourceSetStamp( @@ -555,53 +569,53 @@ path.append(".linkdeps"); link_phony = OutputFile(std::move(path)); - NinjaBuildEdge link_edge{ - .rule = BuiltinTool::kBuiltinToolPhony, - .outputs = {link_phony}, - .explicit_inputs = link_files, - .order_only_inputs = order_only_deps, - .is_target_output = false, - }; - AddEdge(std::move(link_edge)); + out_ << "build "; + path_output_.WriteFile(out_, link_phony); + out_ << ": " << BuiltinTool::kBuiltinToolPhony; + path_output_.WriteFiles(out_, link_files); + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + out_ << std::endl; // 2. Default phony target containing all files (including additional // outputs). Depend on the .link target to avoid duplicating object files. - NinjaBuildEdge default_edge{ - .rule = BuiltinTool::kBuiltinToolPhony, - .outputs = {target_->dependency_output()}, - .explicit_inputs = {link_phony}, - .is_target_output = false, - }; + out_ << "build "; + path_output_.WriteFile(out_, target_->dependency_output()); + out_ << ": " << BuiltinTool::kBuiltinToolPhony; + out_ << " "; + path_output_.WriteFile(out_, link_phony); // Collect non-object files (additional outputs) to add here. + std::vector<OutputFile> non_object_files; for (const auto& file : object_files) { if (!file.AsSourceFile(build_settings).IsObjectType()) { - default_edge.explicit_inputs.push_back(file); + non_object_files.push_back(file); } } - AddEdge(std::move(default_edge)); + path_output_.WriteFiles(out_, non_object_files); + out_ << std::endl; } void NinjaCBinaryTargetWriter::WriteLinkerStuff( - std::vector<OutputFile> object_files, + const std::vector<OutputFile>& object_files, const std::vector<SourceFile>& other_files, const std::vector<OutputFile>& input_deps) { std::vector<OutputFile> output_files; SubstitutionWriter::ApplyListToLinkerAsOutputFile( target_, tool_, tool_->outputs(), &output_files); - NinjaBuildEdge edge{ - .rule = rule_prefix_ + tool_->name(), - .outputs = std::move(output_files), - }; + out_ << "build"; + WriteOutputs(output_files); + + out_ << ": " << rule_prefix_ << tool_->name(); ClassifiedDeps classified_deps = GetClassifiedDeps(); // Object files. - edge.explicit_inputs = std::move(object_files); - edge.explicit_inputs.insert(edge.explicit_inputs.end(), - classified_deps.extra_object_files.begin(), - classified_deps.extra_object_files.end()); + path_output_.WriteFiles(out_, object_files); + path_output_.WriteFiles(out_, classified_deps.extra_object_files); // Dependencies. std::vector<OutputFile> implicit_deps; @@ -624,7 +638,8 @@ solibs.push_back(cur->link_output_file()); } else { // Normal case, just link to this target. - edge.explicit_inputs.push_back(cur->link_output_file()); + out_ << " "; + path_output_.WriteFile(out_, cur->link_output_file()); } } @@ -697,7 +712,11 @@ } } - edge.implicit_inputs = std::move(implicit_deps); + // Append implicit dependencies collected above. + if (!implicit_deps.empty()) { + out_ << " |"; + path_output_.WriteFiles(out_, implicit_deps); + } // Append data dependencies as order-only dependencies. // @@ -712,77 +731,87 @@ // on the sources, there is already an implicit order-only dependency. // However, it's extra work to separate these out and there's no disadvantage // to listing them again. - edge.order_only_inputs = - GetOrderOnlyDepsFromNonLinkableDeps(classified_deps.non_linkable_deps); + WriteOrderOnlyDependencies(classified_deps.non_linkable_deps); - AddValidationInputs(edge); + WriteValidations(); + + // End of the link "build" line. + out_ << std::endl; // The remaining things go in the inner scope of the link line. if (target_->output_type() == Target::EXECUTABLE || target_->output_type() == Target::SHARED_LIBRARY || target_->output_type() == Target::LOADABLE_MODULE) { - { - std::ostringstream ss; - WriteLinkerFlags(ss, tool_, optional_def_file); - edge.edge_vars.emplace_back("ldflags", ss.str()); - } - { - std::ostringstream ss; - WriteLibs(ss, tool_); - edge.edge_vars.emplace_back("libs", ss.str()); - } - { - std::ostringstream ss; - WriteFrameworks(ss, tool_); - edge.edge_vars.emplace_back("frameworks", ss.str()); - } - { - std::ostringstream ss; - WriteSwiftModules(ss, tool_, swiftmodules); - edge.edge_vars.emplace_back("swiftmodules", ss.str()); - } + out_ << " ldflags ="; + WriteLinkerFlags(out_, tool_, optional_def_file); + out_ << std::endl; + out_ << " libs ="; + WriteLibs(out_, tool_); + out_ << std::endl; + out_ << " frameworks ="; + WriteFrameworks(out_, tool_); + out_ << std::endl; + out_ << " swiftmodules ="; + WriteSwiftModules(out_, tool_, swiftmodules); + out_ << std::endl; } else if (target_->output_type() == Target::STATIC_LIBRARY) { - std::ostringstream ss; + out_ << " arflags ="; RecursiveTargetConfigStringsToStream(kRecursiveWriterKeepDuplicates, target_, &ConfigValues::arflags, - GetFlagOptions(), ss); - edge.edge_vars.emplace_back("arflags", ss.str()); + GetFlagOptions(), out_); + out_ << std::endl; } + WriteOutputSubstitutions(); + WriteLibsList("solibs", solibs); + WriteLibsList("rlibs", transitive_rustlibs); + WritePool(out_); +} +void NinjaCBinaryTargetWriter::WriteOutputSubstitutions() { const std::string output_extension = SubstitutionWriter::GetLinkerSubstitution(target_, tool_, &SubstitutionOutputExtension); - edge.edge_vars.emplace_back("output_extension", output_extension); + out_ << " output_extension ="; + if (!output_extension.empty()) { + out_ << " " << output_extension; + } + out_ << std::endl; const std::string output_dir = SubstitutionWriter::GetLinkerSubstitution( target_, tool_, &SubstitutionOutputDir); - edge.edge_vars.emplace_back("output_dir", output_dir); - - if (!solibs.empty()) { - std::ostringstream ss; - PathOutput output(path_output_.current_dir(), - settings_->build_settings()->root_path_utf8(), - ESCAPE_NINJA_COMMAND); - output.WriteFiles(ss, solibs); - edge.edge_vars.emplace_back("solibs", ss.str()); + out_ << " output_dir ="; + if (!output_dir.empty()) { + out_ << " " << output_dir; } + out_ << std::endl; +} - if (!transitive_rustlibs.empty()) { - std::ostringstream ss; - PathOutput output(path_output_.current_dir(), - settings_->build_settings()->root_path_utf8(), - ESCAPE_NINJA_COMMAND); - output.WriteFiles(ss, transitive_rustlibs); - edge.edge_vars.emplace_back("rlibs", ss.str()); +void NinjaCBinaryTargetWriter::WriteLibsList( + const std::string& label, + const std::vector<OutputFile>& libs) { + if (libs.empty()) + return; + + out_ << " " << label << " ="; + PathOutput output(path_output_.current_dir(), + settings_->build_settings()->root_path_utf8(), + ESCAPE_NINJA_COMMAND); + output.WriteFiles(out_, libs); + out_ << std::endl; +} + +void NinjaCBinaryTargetWriter::WriteOrderOnlyDependencies( + const UniqueVector<const Target*>& non_linkable_deps) { + std::vector<OutputFile> outputs_to_write = + GetOrderOnlyDepsFromNonLinkableDeps(non_linkable_deps); + + if (!outputs_to_write.empty()) { + out_ << " ||"; + for (const auto& output : outputs_to_write) { + out_ << " "; + path_output_.WriteFile(out_, output); + } } - - if (target_->pool().ptr) { - edge.edge_vars.emplace_back("pool", - target_->pool().ptr->GetNinjaName( - settings_->default_toolchain_label())); - } - - AddEdge(std::move(edge)); } bool NinjaCBinaryTargetWriter::CheckForDuplicateObjectFiles(
diff --git a/src/gn/ninja_c_binary_target_writer.h b/src/gn/ninja_c_binary_target_writer.h index 7ba7840..3353a1b 100644 --- a/src/gn/ninja_c_binary_target_writer.h +++ b/src/gn/ninja_c_binary_target_writer.h
@@ -20,7 +20,7 @@ NinjaCBinaryTargetWriter(const Target* target, std::ostream& out); ~NinjaCBinaryTargetWriter() override; - void GenerateRules() override; + void Run() override; private: using OutputFileSet = std::set<OutputFile>; @@ -92,9 +92,20 @@ // Writes the stamp line for a source set. These are not linked. void WriteSourceSetStamp(const std::vector<OutputFile>& object_files); - void WriteLinkerStuff(std::vector<OutputFile> object_files, + void WriteLinkerStuff(const std::vector<OutputFile>& object_files, const std::vector<SourceFile>& other_files, const std::vector<OutputFile>& input_deps); + void WriteOutputSubstitutions(); + void WriteLibsList(const std::string& label, + const std::vector<OutputFile>& libs); + + // Writes the implicit dependencies for the link or stamp line. This is + // the "||" and everything following it on the ninja line. + // + // The order-only dependencies are the non-linkable deps passed in as an + // argument, plus the data file dependencies in the target. + void WriteOrderOnlyDependencies( + const UniqueVector<const Target*>& non_linkable_deps); // Checks for duplicates in the given list of output files. If any duplicates // are found, throws an error and return false.
diff --git a/src/gn/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc index 3d051ee..34a473f 100644 --- a/src/gn/ninja_c_binary_target_writer_unittest.cc +++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -60,18 +60,15 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc\n" " source_file_part = input2.cc\n" " source_name_part = input2\n" "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.input1.o " "obj/foo/bar.input2.o ../../foo/input3.o ../../foo/input4.obj\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -218,14 +215,12 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.input1.o obj/foo/input1.dwo: cxx " "../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.input1.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps obj/foo/input1.dwo\n"; EXPECT_EQ(expected, out.str()); @@ -274,14 +269,12 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.input1.o obj/foo/input1.dwo: cxx " "../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.input1.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps obj/foo/input1.dwo\n"; EXPECT_EQ(expected, out.str()); @@ -344,17 +337,14 @@ "target_out_dir = obj/foo\n" "target_output_name = b\n" "\n" - "\n" "build obj/foo/b.b.o obj/foo/b.dwo: cxx ../../foo/b.cc\n" " source_file_part = b.cc\n" " source_name_part = b\n" - "\n" "build obj/foo/b.b2.o obj/foo/b2.dwo: cxx ../../foo/b2.cc\n" " source_file_part = b2.cc\n" " source_name_part = b2\n" "\n" "build phony/foo/b.linkdeps: phony obj/foo/b.b.o obj/foo/b.b2.o\n" - "\n" "build phony/foo/b: phony phony/foo/b.linkdeps obj/foo/b.dwo " "obj/foo/b2.dwo\n"; @@ -377,7 +367,6 @@ "target_out_dir = obj/foo\n" "target_output_name = liba\n" "\n" - "\n" "build obj/foo/liba.a.o: cxx ../../foo/a.cc\n" " source_file_part = a.cc\n" " source_name_part = a\n" @@ -470,7 +459,6 @@ "target_out_dir = obj/foo\n" "target_output_name = libf\n" "\n" - "\n" "build obj/foo/libf.f.o obj/foo/f.dwo: cxx ../../foo/f.cc\n" " source_file_part = f.cc\n" " source_name_part = f\n" @@ -532,7 +520,6 @@ "target_out_dir = obj/foo\n" "target_output_name = libbar\n" "\n" - "\n" "build obj/foo/libbar.input1.o: cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" @@ -582,7 +569,6 @@ "target_out_dir = obj/foo\n" "target_output_name = libbar\n" "\n" - "\n" "build obj/foo/libbar.input1.o: cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" @@ -615,7 +601,6 @@ "target_out_dir = obj/foo\n" "target_output_name = libbar\n" "\n" - "\n" "build obj/foo/libbar.input1.o: cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" @@ -667,7 +652,6 @@ "target_out_dir = obj/foo\n" "target_output_name = libbar\n" "\n" - "\n" "build obj/foo/libbar.input1.o: cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" @@ -729,7 +713,6 @@ "target_out_dir = obj/foo\n" "target_output_name = main\n" "\n" - "\n" "build obj/foo/main.main.o: cxx ../../foo/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -786,12 +769,10 @@ "target_out_dir = obj/foo\n" "target_output_name = libshlib\n" "\n" - "\n" "build obj/foo/libshlib.input1.o: cxx ../../foo/input1.cc" " || phony/foo/action\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build obj/foo/libshlib.input2.o: cxx ../../foo/input2.cc" " || phony/foo/action\n" " source_file_part = input2.cc\n" @@ -856,7 +837,6 @@ "target_out_dir = obj/foo\n" "target_output_name = gen_obj\n" "\n" - "\n" "build obj/BUILD_DIR/gen_obj.generated.o: cxx generated.cc" " || phony/foo/generate\n" " source_file_part = generated.cc\n" @@ -867,7 +847,6 @@ // The order-only dependency here is strictly unnecessary since the // sources list this as an order-only dep. " || phony/foo/generate\n" - "\n" "build phony/foo/gen_obj: phony phony/foo/gen_obj.linkdeps\n"; std::string obj_str = obj_out.str(); @@ -939,7 +918,6 @@ "target_out_dir = obj/foo\n" "target_output_name = final_target\n" "\n" - "\n" "build obj/foo/final_target.main.o: cxx ../../foo/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -1102,11 +1080,9 @@ "target_out_dir = obj/foo\n" "target_output_name = shlib\n" "\n" - "\n" "build obj/foo/shlib.input1.o: cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build obj/foo/shlib.input2.o: cxx ../../foo/input2.cc\n" " source_file_part = input2.cc\n" " source_name_part = input2\n" @@ -1163,14 +1139,12 @@ "target_out_dir = obj/foo\n" "target_output_name = inter\n" "\n" - "\n" "build obj/foo/inter.inter.o: cxx ../../foo/inter.cc\n" " source_file_part = inter.cc\n" " source_name_part = inter\n" "\n" "build phony/foo/inter.linkdeps: phony obj/foo/inter.inter.o || " "./data_target\n" - "\n" "build phony/foo/inter: phony phony/foo/inter.linkdeps\n"; EXPECT_EQ(inter_expected, inter_out.str()); @@ -1202,7 +1176,6 @@ "target_out_dir = obj/foo\n" "target_output_name = exe\n" "\n" - "\n" "build obj/foo/exe.final.o: cxx ../../foo/final.cc\n" " source_file_part = final.cc\n" " source_name_part = final\n" @@ -1245,7 +1218,6 @@ "target_out_dir = obj/foo\n" "target_output_name = libbar\n" "\n" - "\n" "build obj/foo/libbar.sources.o: cxx ../../foo/sources.cc\n" " source_file_part = sources.cc\n" " source_name_part = sources\n" @@ -1286,7 +1258,6 @@ "target_out_dir = obj/foo\n" "target_output_name = libbar\n" "\n" - "\n" "build obj/foo/libbar.sources.o: cxx ../../foo/sources.cc\n" " source_file_part = sources.cc\n" " source_name_part = sources\n" @@ -1325,7 +1296,6 @@ "target_out_dir = obj/foo\n" "target_output_name = exe\n" "\n" - "\n" "build obj/foo/exe.final.o: cxx ../../foo/final.cc\n" " source_file_part = final.cc\n" " source_name_part = final\n" @@ -1404,12 +1374,10 @@ "cflags_cc =\n" "target_output_name = no_pch_target\n" "\n" - "\n" "build withpch/obj/foo/no_pch_target.input1.o: " "withpch_cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build withpch/obj/foo/no_pch_target.input2.o: " "withpch_cc ../../foo/input2.c\n" " source_file_part = input2.c\n" @@ -1418,7 +1386,6 @@ "build withpch/phony/foo/no_pch_target.linkdeps: " "phony withpch/obj/foo/no_pch_target.input1.o " "withpch/obj/foo/no_pch_target.input2.o\n" - "\n" "build withpch/phony/foo/no_pch_target: " "phony withpch/phony/foo/no_pch_target.linkdeps\n"; EXPECT_EQ(no_pch_expected, out.str()); @@ -1454,7 +1421,6 @@ "/Yubuild/precompile.h\n" "target_output_name = pch_target\n" "\n" - "\n" // Compile the precompiled source files with /Yc. "build withpch/obj/build/pch_target.precompile.c.o: " "withpch_cc ../../build/precompile.cc\n" @@ -1474,7 +1440,6 @@ "withpch/obj/build/pch_target.precompile.cc.o\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build withpch/obj/foo/pch_target.input2.o: " "withpch_cc ../../foo/input2.c | " // Explicit dependency on the PCH build step. @@ -1488,7 +1453,6 @@ // The precompiled object files were added to the outputs. "withpch/obj/build/pch_target.precompile.c.o " "withpch/obj/build/pch_target.precompile.cc.o\n" - "\n" "build withpch/phony/foo/pch_target: phony " "withpch/phony/foo/pch_target.linkdeps\n"; EXPECT_EQ(pch_win_expected, out.str()); @@ -1560,12 +1524,10 @@ "cflags_cc =\n" "target_output_name = no_pch_target\n" "\n" - "\n" "build withpch/obj/foo/no_pch_target.input1.o: " "withpch_cxx ../../foo/input1.cc\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build withpch/obj/foo/no_pch_target.input2.o: " "withpch_cc ../../foo/input2.c\n" " source_file_part = input2.c\n" @@ -1574,7 +1536,6 @@ "build withpch/phony/foo/no_pch_target.linkdeps: " "phony withpch/obj/foo/no_pch_target.input1.o " "withpch/obj/foo/no_pch_target.input2.o\n" - "\n" "build withpch/phony/foo/no_pch_target: " "phony withpch/phony/foo/no_pch_target.linkdeps\n"; EXPECT_EQ(no_pch_expected, out.str()); @@ -1608,7 +1569,6 @@ "cflags_cc = -include withpch/obj/build/pch_target.precompile.h-cc\n" "target_output_name = pch_target\n" "\n" - "\n" // Compile the precompiled sources with -x <lang>. "build withpch/obj/build/pch_target.precompile.h-c.gch: " "withpch_cc ../../build/precompile.h\n" @@ -1628,7 +1588,6 @@ "withpch/obj/build/pch_target.precompile.h-cc.gch\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build withpch/obj/foo/pch_target.input2.o: " "withpch_cc ../../foo/input2.c | " // Explicit dependency on the PCH build step. @@ -1639,7 +1598,6 @@ "build withpch/phony/foo/pch_target.linkdeps: " "phony withpch/obj/foo/pch_target.input1.o " "withpch/obj/foo/pch_target.input2.o\n" - "\n" "build withpch/phony/foo/pch_target: " "phony withpch/phony/foo/pch_target.linkdeps\n"; EXPECT_EQ(pch_gcc_expected, out.str()); @@ -1701,12 +1659,10 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc" " | ../../foo/input.data\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc" " | ../../foo/input.data\n" " source_file_part = input2.cc\n" @@ -1714,7 +1670,6 @@ "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.input1.o " "obj/foo/bar.input2.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; EXPECT_EQ(expected, out.str()); @@ -1780,15 +1735,12 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build phony/foo/bar.inputs: phony" " ../../foo/input1.data ../../foo/input2.data\n" - "\n" "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc" " | phony/foo/bar.inputs\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc" " | phony/foo/bar.inputs\n" " source_file_part = input2.cc\n" @@ -1796,7 +1748,6 @@ "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.input1.o " "obj/foo/bar.input2.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; EXPECT_EQ(expected, out.str()); @@ -1840,15 +1791,12 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build phony/foo/bar.inputs: phony" " ../../foo/input1.data ../../foo/input2.data ../../foo/input3.data\n" - "\n" "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc" " | phony/foo/bar.inputs\n" " source_file_part = input1.cc\n" " source_name_part = input1\n" - "\n" "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc" " | phony/foo/bar.inputs\n" " source_file_part = input2.cc\n" @@ -1856,7 +1804,6 @@ "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.input1.o " "obj/foo/bar.input2.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; EXPECT_EQ(expected, out.str()); @@ -1902,7 +1849,6 @@ "target_out_dir = obj/bar\n" "target_output_name = bar\n" "\n" - "\n" "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n" " source_file_part = bar.cc\n" " source_name_part = bar\n" @@ -2080,7 +2026,6 @@ "target_out_dir = obj/exe\n" "target_output_name = exe\n" "\n" - "\n" "build obj/exe/exe.main.o: cxx ../../exe/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -2249,7 +2194,6 @@ "target_out_dir = obj/exe\n" "target_output_name = exe\n" "\n" - "\n" "build obj/exe/exe.main.o: cxx ../../exe/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -2327,7 +2271,6 @@ "target_out_dir = obj/bar\n" "target_output_name = bar\n" "\n" - "\n" "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n" " source_file_part = bar.cc\n" " source_name_part = bar\n" @@ -2431,7 +2374,6 @@ "target_out_dir = obj/exe\n" "target_output_name = binary\n" "\n" - "\n" "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -2528,7 +2470,6 @@ "target_out_dir = obj/exe\n" "target_output_name = binary\n" "\n" - "\n" "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -2627,7 +2568,6 @@ "target_out_dir = obj/exe\n" "target_output_name = binary\n" "\n" - "\n" "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -2738,7 +2678,6 @@ "target_out_dir = obj/exe\n" "target_output_name = binary\n" "\n" - "\n" "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n" " source_file_part = main.cc\n" " source_name_part = main\n" @@ -2787,12 +2726,10 @@ "target_out_dir = obj/foo\n" "target_output_name = libbar\n" "\n" - "\n" "build obj/foo/libbar.bar.o: cxx ../../foo/bar.cc | " "obj/foo/libbar.bar.pcm\n" " source_file_part = bar.cc\n" " source_name_part = bar\n" - "\n" "build obj/foo/libbar.bar.pcm: cxx_module ../../foo/bar.modulemap\n" " source_file_part = bar.modulemap\n" " source_name_part = bar\n" @@ -2834,18 +2771,15 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.bar.o: cxx ../../foo/bar.cc | " "obj/foo/bar.bar.pcm\n" " source_file_part = bar.cc\n" " source_name_part = bar\n" - "\n" "build obj/foo/bar.bar.pcm: cxx_module ../../foo/bar.modulemap\n" " source_file_part = bar.modulemap\n" " source_name_part = bar\n" "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.bar.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps obj/foo/bar.bar.pcm\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -2882,13 +2816,11 @@ "target_out_dir = obj/foo\n" "target_output_name = foo\n" "\n" - "\n" "build gen/foo/foo.h obj/foo/Foo.swiftmodule obj/foo/file1.o " "obj/foo/file2.o: swift ../../foo/file1.swift ../../foo/file2.swift\n" " restat = 1\n" "\n" "build phony/foo/foo.linkdeps: phony obj/foo/file1.o obj/foo/file2.o\n" - "\n" "build phony/foo/foo: phony phony/foo/foo.linkdeps gen/foo/foo.h " "obj/foo/Foo.swiftmodule\n"; @@ -2922,14 +2854,12 @@ "target_out_dir = obj/bar\n" "target_output_name = bar\n" "\n" - "\n" "build gen/bar/bar.h obj/bar/Bar.swiftmodule obj/bar/bar.o: swift " "../../bar/bar.swift || phony/foo/foo\n" " restat = 1\n" "\n" "build phony/bar/bar.linkdeps: phony obj/bar/bar.o || " "phony/foo/foo.linkdeps\n" - "\n" "build phony/bar/bar: phony phony/bar/bar.linkdeps gen/bar/bar.h " "obj/bar/Bar.swiftmodule\n"; @@ -2971,14 +2901,12 @@ "target_out_dir = obj/bar\n" "target_output_name = bar\n" "\n" - "\n" "build gen/bar/bar.h obj/bar/Bar.swiftmodule obj/bar/bar.o: swift " "../../bar/bar.swift || phony/bar/group phony/foo/foo\n" " restat = 1\n" "\n" "build phony/bar/bar.linkdeps: phony obj/bar/bar.o || " "phony/foo/foo.linkdeps\n" - "\n" "build phony/bar/bar: phony phony/bar/bar.linkdeps gen/bar/bar.h " "obj/bar/Bar.swiftmodule\n"; @@ -3111,11 +3039,9 @@ target_out_dir = obj/blah target_output_name = liba - build obj/blah/liba.a.pcm: cxx_module ../../blah/a.modulemap source_file_part = a.modulemap source_name_part = a - build obj/blah/liba.a.o: cxx ../../blah/a.cc | obj/blah/liba.a.pcm source_file_part = a.cc source_name_part = a @@ -3162,11 +3088,9 @@ target_out_dir = obj/stuff target_output_name = libb - build obj/stuff/libb.b.pcm: cxx_module ../../stuff/b.modulemap | obj/blah/liba.a.pcm source_file_part = b.modulemap source_name_part = b - build obj/stuff/libb.b.o: cxx ../../stuff/b.cc | obj/stuff/libb.b.pcm obj/blah/liba.a.pcm source_file_part = b.cc source_name_part = b @@ -3211,7 +3135,6 @@ target_out_dir = obj/things target_output_name = libc - build obj/stuff/libc.c.pcm: cxx_module ../../stuff/c.modulemap | obj/stuff/libb.b.pcm obj/blah/liba.a.pcm source_file_part = c.modulemap source_name_part = c @@ -3254,11 +3177,9 @@ target_out_dir = obj/zap target_output_name = c - build obj/zap/c.x.o: cxx ../../zap/x.cc | obj/stuff/libb.b.pcm obj/blah/liba.a.pcm source_file_part = x.cc source_name_part = x - build obj/zap/c.y.o: cxx ../../zap/y.cc | obj/stuff/libb.b.pcm obj/blah/liba.a.pcm source_file_part = y.cc source_name_part = y @@ -3314,7 +3235,6 @@ target_out_dir = obj/launchpad target_output_name = main - build obj/launchpad/main.main.o: cxx ../../launchpad/main.cc source_file_part = main.cc source_name_part = main @@ -3366,7 +3286,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.source.o: cxx ../../foo/source.cc\n" " source_file_part = source.cc\n" " source_name_part = source\n" @@ -3431,7 +3350,6 @@ "root_out_dir = .\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.source.o: cxx ../../foo/source.cc | " "../../bin/clang++\n" " source_file_part = source.cc\n" @@ -3525,13 +3443,11 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build obj/foo/bar.source1.o: cxx ../../foo/source1.cc\n" " source_file_part = source1.cc\n" " source_name_part = source1\n" "\n" "build phony/foo/bar.linkdeps: phony obj/foo/bar.source1.o\n" - "\n" "build phony/foo/bar: phony phony/foo/bar.linkdeps\n"; writer.Run(); std::string ninja_str = ninja_out.str(); @@ -3674,13 +3590,11 @@ "target_out_dir = obj/foo\n" "target_output_name = root\n" "\n" - "\n" "build obj/foo/root.root.o: cxx ../../foo/root.cc\n" " source_file_part = root.cc\n" " source_name_part = root\n" "\n" "build phony/foo/root.linkdeps: phony obj/foo/root.root.o\n" - "\n" "build phony/foo/root: phony phony/foo/root.linkdeps\n"; EXPECT_EQ(expected_root_ninja, root_ninja_str); @@ -3750,14 +3664,12 @@ "target_out_dir = obj/foo\n" "target_output_name = a\n" "\n" - "\n" "build obj/foo/a.a.o: cxx ../../foo/a.cc\n" " source_file_part = a.cc\n" " source_name_part = a\n" "\n" "build phony/foo/a.linkdeps: phony obj/foo/a.a.o" " || phony/foo/b.linkdeps\n" - "\n" "build phony/foo/a: phony phony/foo/a.linkdeps\n"; EXPECT_EQ(expected, out.str());
diff --git a/src/gn/ninja_copy_target_writer.cc b/src/gn/ninja_copy_target_writer.cc index 3c26e78..16fca06 100644 --- a/src/gn/ninja_copy_target_writer.cc +++ b/src/gn/ninja_copy_target_writer.cc
@@ -4,6 +4,7 @@ #include "gn/ninja_copy_target_writer.h" +#include "base/strings/string_util.h" #include "gn/general_tool.h" #include "gn/ninja_utils.h" #include "gn/output_file.h" @@ -20,7 +21,7 @@ NinjaCopyTargetWriter::~NinjaCopyTargetWriter() = default; -void NinjaCopyTargetWriter::GenerateRules() { +void NinjaCopyTargetWriter::Run() { const Tool* copy_tool = target_->toolchain()->GetTool(GeneralTool::kGeneralToolCopy); if (!copy_tool) { @@ -54,6 +55,7 @@ std::vector<OutputFile> output_files; WriteCopyRules(&output_files); + out_ << std::endl; WriteStampOrPhonyForTarget(output_files, std::vector<OutputFile>()); } @@ -113,15 +115,20 @@ target_, target_->settings(), output_subst, input_file); output_files->push_back(output_file); - NinjaBuildEdge edge{ - .rule = tool_name, - .outputs = {output_file}, - .explicit_inputs = {OutputFile(settings_->build_settings(), - input_file)}, - .implicit_inputs = implicit_deps, - .order_only_inputs = order_only_deps, - }; - AddValidationInputs(edge); - AddEdge(std::move(edge)); + out_ << "build "; + WriteOutput(std::move(output_file)); + + out_ << ": " << tool_name << " "; + path_output_.WriteFile(out_, input_file); + if (!implicit_deps.empty()) { + out_ << " |"; + path_output_.WriteFiles(out_, implicit_deps); + } + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + WriteValidations(); + out_ << std::endl; } }
diff --git a/src/gn/ninja_copy_target_writer.h b/src/gn/ninja_copy_target_writer.h index 1016f2c..95d50b4 100644 --- a/src/gn/ninja_copy_target_writer.h +++ b/src/gn/ninja_copy_target_writer.h
@@ -13,7 +13,7 @@ NinjaCopyTargetWriter(const Target* target, std::ostream& out); ~NinjaCopyTargetWriter() override; - void GenerateRules() override; + void Run() override; private: // Writes the rules top copy the file(s), putting the computed output file
diff --git a/src/gn/ninja_copy_target_writer_unittest.cc b/src/gn/ninja_copy_target_writer_unittest.cc index 0199b50..6fc5e43 100644 --- a/src/gn/ninja_copy_target_writer_unittest.cc +++ b/src/gn/ninja_copy_target_writer_unittest.cc
@@ -34,7 +34,6 @@ const char expected_linux[] = "build input1.out: copy ../../foo/input1.txt\n" - "\n" "build input2.out: copy ../../foo/input2.txt\n" "\n" "build phony/foo/bar: phony input1.out input2.out\n"; @@ -211,9 +210,7 @@ const char expected_linux[] = "build phony/foo/bar.inputdeps: phony || phony/foo/action1 " "phony/foo/action2\n" - "\n" "build action1.copy: copy action1.out | phony/foo/bar.inputdeps\n" - "\n" "build action2.copy: copy action2.out | phony/foo/bar.inputdeps\n" "\n" "build phony/foo/bar: phony action1.copy action2.copy\n";
diff --git a/src/gn/ninja_create_bundle_target_writer.cc b/src/gn/ninja_create_bundle_target_writer.cc index bf45ad4..c91d41c 100644 --- a/src/gn/ninja_create_bundle_target_writer.cc +++ b/src/gn/ninja_create_bundle_target_writer.cc
@@ -74,7 +74,7 @@ NinjaCreateBundleTargetWriter::~NinjaCreateBundleTargetWriter() = default; -void NinjaCreateBundleTargetWriter::GenerateRules() { +void NinjaCreateBundleTargetWriter::Run() { if (!EnsureAllToolsAvailable(target_)) return; @@ -109,13 +109,14 @@ // Write a phony target for the outer bundle directory. This allows other // targets to treat the entire bundle as a single unit, even though it is // a directory, so that it can be depended upon as a discrete build edge. - AddEdge(NinjaBuildEdge{ - .rule = BuiltinTool::kBuiltinToolPhony, - .outputs = {OutputFile( - settings_->build_settings(), - target_->bundle_data().GetBundleRootDirOutput(settings_))}, - .explicit_inputs = {target_->dependency_output()}, - }); + out_ << "build "; + + WriteOutput( + OutputFile(settings_->build_settings(), + target_->bundle_data().GetBundleRootDirOutput(settings_))); + out_ << ": " << BuiltinTool::kBuiltinToolPhony << " "; + out_ << target_->dependency_output().value(); + out_ << std::endl; } std::string NinjaCreateBundleTargetWriter::WritePostProcessingRuleDefinition() { @@ -127,28 +128,24 @@ base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name); custom_rule_name.append("_post_processing_rule"); - std::ostringstream rule_out; - rule_out << "rule " << custom_rule_name << std::endl; - rule_out << " command = "; - path_output_.WriteFile(rule_out, settings_->build_settings()->python_path()); - rule_out << " "; - path_output_.WriteFile(rule_out, - target_->bundle_data().post_processing_script()); + out_ << "rule " << custom_rule_name << std::endl; + out_ << " command = "; + path_output_.WriteFile(out_, settings_->build_settings()->python_path()); + out_ << " "; + path_output_.WriteFile(out_, target_->bundle_data().post_processing_script()); const SubstitutionList& args = target_->bundle_data().post_processing_args(); EscapeOptions args_escape_options; args_escape_options.mode = ESCAPE_NINJA_COMMAND; for (const auto& arg : args.list()) { - rule_out << " "; - SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, - rule_out); + out_ << " "; + SubstitutionWriter::WriteWithNinjaVariables(arg, args_escape_options, out_); } - rule_out << std::endl; - rule_out << " description = POST PROCESSING " << target_label << std::endl; - rule_out << " restat = 1" << std::endl; - - target_group_.custom_rules.push_back(rule_out.str()); + out_ << std::endl; + out_ << " description = POST PROCESSING " << target_label << std::endl; + out_ << " restat = 1" << std::endl; + out_ << std::endl; WritePostProcessingManifestFile(); return custom_rule_name; @@ -211,15 +208,22 @@ /*err=*/nullptr); output_files->push_back(expanded_output_file); - AddEdge(NinjaBuildEdge{ - .rule = GetNinjaRulePrefixForToolchain(settings_) + - GeneralTool::kGeneralToolCopyBundleData, - .outputs = {expanded_output_file}, - .explicit_inputs = {OutputFile(settings_->build_settings(), - source_file)}, - .implicit_inputs = implicit_deps, - .order_only_inputs = order_only_deps, - }); + out_ << "build "; + WriteOutput(std::move(expanded_output_file)); + out_ << ": " << GetNinjaRulePrefixForToolchain(settings_) + << GeneralTool::kGeneralToolCopyBundleData << " "; + path_output_.WriteFile(out_, source_file); + + if (!implicit_deps.empty()) { + out_ << " |"; + path_output_.WriteFiles(out_, implicit_deps); + } + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + + out_ << std::endl; } } @@ -253,68 +257,80 @@ if (target_->bundle_data().assets_catalog_sources().empty()) { DCHECK(!target_->bundle_data().partial_info_plist().is_null()); - AddEdge(NinjaBuildEdge{ - .rule = GetNinjaRulePrefixForToolchain(settings_) + - GeneralTool::kGeneralToolStamp, - .outputs = {partial_info_plist}, - .implicit_inputs = implicit_deps, - .order_only_inputs = order_only_deps, - }); + out_ << "build "; + WriteOutput(partial_info_plist); + out_ << ": " << GetNinjaRulePrefixForToolchain(settings_) + << GeneralTool::kGeneralToolStamp; + if (!implicit_deps.empty()) { + out_ << " |"; + path_output_.WriteFiles(out_, implicit_deps); + } + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + out_ << std::endl; return; } OutputFile input_dep = WriteCompileAssetsCatalogInputDepsStampOrPhony( target_->bundle_data().assets_catalog_deps()); + DCHECK(!input_dep.value().empty()); - std::vector<OutputFile> implicit_outputs; + out_ << "build "; + WriteOutput(std::move(compiled_catalog)); if (partial_info_plist != OutputFile()) { // If "partial_info_plist" is non-empty, then add it to list of implicit // outputs of the asset catalog compilation, so that target can use it // without getting the ninja error "'foo', needed by 'bar', missing and // no known rule to make it". - implicit_outputs.push_back(partial_info_plist); + out_ << " | "; + WriteOutput(partial_info_plist); } - std::vector<OutputFile> implicit_inputs; - implicit_inputs.push_back(input_dep); - implicit_inputs.insert(implicit_inputs.end(), implicit_deps.begin(), - implicit_deps.end()); + out_ << ": " << GetNinjaRulePrefixForToolchain(settings_) + << GeneralTool::kGeneralToolCompileXCAssets; - std::vector<NinjaVariable> edge_vars; - edge_vars.emplace_back("product_type", target_->bundle_data().product_type()); + SourceFileSet asset_catalog_bundles; + for (const auto& source : target_->bundle_data().assets_catalog_sources()) { + out_ << " "; + path_output_.WriteFile(out_, source); + asset_catalog_bundles.insert(source); + } + + out_ << " | "; + path_output_.WriteFile(out_, input_dep); + path_output_.WriteFiles(out_, implicit_deps); + + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + + out_ << std::endl; + + out_ << " product_type = " << target_->bundle_data().product_type() + << std::endl; if (partial_info_plist != OutputFile()) { - std::ostringstream ss; - path_output_.WriteFile(ss, partial_info_plist); - edge_vars.emplace_back("partial_info_plist", ss.str()); + out_ << " partial_info_plist = "; + path_output_.WriteFile(out_, partial_info_plist); + out_ << std::endl; } const std::vector<SubstitutionPattern>& flags = target_->bundle_data().xcasset_compiler_flags().list(); if (!flags.empty()) { - std::ostringstream ss; + out_ << " " << SubstitutionXcassetsCompilerFlags.ninja_name << " ="; EscapeOptions args_escape_options; args_escape_options.mode = ESCAPE_NINJA_COMMAND; for (const auto& flag : flags) { - ss << " "; + out_ << " "; SubstitutionWriter::WriteWithNinjaVariables(flag, args_escape_options, - ss); + out_); } - edge_vars.emplace_back(SubstitutionXcassetsCompilerFlags.ninja_name, - ss.str()); + out_ << std::endl; } - - AddEdge(NinjaBuildEdge{ - .rule = GetNinjaRulePrefixForToolchain(settings_) + - GeneralTool::kGeneralToolCompileXCAssets, - .outputs = {compiled_catalog}, - .implicit_outputs = std::move(implicit_outputs), - .explicit_inputs = - ToOutputFiles(target_->bundle_data().assets_catalog_sources()), - .implicit_inputs = std::move(implicit_inputs), - .order_only_inputs = order_only_deps, - .edge_vars = std::move(edge_vars), - }); } OutputFile @@ -342,18 +358,17 @@ GeneralTool::kGeneralToolStamp; } - std::vector<OutputFile> explicit_inputs; + out_ << "build "; + WriteOutput(xcassets_input_stamp_or_phony); + out_ << ": " << tool; + for (const Target* target : dependencies) { if (target->has_dependency_output()) { - explicit_inputs.push_back(target->dependency_output()); + out_ << " "; + path_output_.WriteFile(out_, target->dependency_output()); } } - - AddEdge(NinjaBuildEdge{ - .rule = tool, - .outputs = {xcassets_input_stamp_or_phony}, - .explicit_inputs = std::move(explicit_inputs), - }); + out_ << std::endl; return xcassets_input_stamp_or_phony; } @@ -370,21 +385,22 @@ output_files); DCHECK(!post_processing_input_stamp_file.value().empty()); + out_ << "build"; std::vector<OutputFile> post_processing_output_files; SubstitutionWriter::GetListAsOutputFiles( settings_, target_->bundle_data().post_processing_outputs(), &post_processing_output_files); + WriteOutputs(post_processing_output_files); // Since the post-processing step depends on all the files from the bundle, // the create_bundle stamp can just depends on the output of the signature // script (dependencies are transitive). - *output_files = post_processing_output_files; + *output_files = std::move(post_processing_output_files); - AddEdge(NinjaBuildEdge{ - .rule = post_processing_rule_name, - .outputs = std::move(post_processing_output_files), - .implicit_inputs = {post_processing_input_stamp_file}, - }); + out_ << ": " << post_processing_rule_name; + out_ << " | "; + path_output_.WriteFile(out_, post_processing_input_stamp_file); + out_ << std::endl; } OutputFile @@ -428,12 +444,22 @@ GeneralTool::kGeneralToolStamp; } - AddEdge(NinjaBuildEdge{ - .rule = tool, - .outputs = {stamp_or_phony}, - .explicit_inputs = ToOutputFiles(post_processing_input_files), - .implicit_inputs = implicit_deps, - .order_only_inputs = order_only_deps, - }); + out_ << "build "; + WriteOutput(stamp_or_phony); + out_ << ": " << tool; + + for (const SourceFile& source : post_processing_input_files) { + out_ << " "; + path_output_.WriteFile(out_, source); + } + if (!implicit_deps.empty()) { + out_ << " |"; + path_output_.WriteFiles(out_, implicit_deps); + } + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + out_ << std::endl; return stamp_or_phony; }
diff --git a/src/gn/ninja_create_bundle_target_writer.h b/src/gn/ninja_create_bundle_target_writer.h index 6c4d746..7d603a0 100644 --- a/src/gn/ninja_create_bundle_target_writer.h +++ b/src/gn/ninja_create_bundle_target_writer.h
@@ -15,7 +15,7 @@ NinjaCreateBundleTargetWriter(const Target* target, std::ostream& out); ~NinjaCreateBundleTargetWriter() override; - void GenerateRules() override; + void Run() override; private: // Writes the Ninja rule for invoking the post-processing script.
diff --git a/src/gn/ninja_create_bundle_target_writer_unittest.cc b/src/gn/ninja_create_bundle_target_writer_unittest.cc index d0b9d02..2d23969 100644 --- a/src/gn/ninja_create_bundle_target_writer_unittest.cc +++ b/src/gn/ninja_create_bundle_target_writer_unittest.cc
@@ -77,17 +77,13 @@ const char expected[] = "build phony/baz/bar.inputdeps: phony || phony/foo/bar " "phony/foo/data\n" - "\n" "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data " "../../foo/input1.txt | phony/baz/bar.inputdeps\n" - "\n" "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data " "../../foo/input2.txt | phony/baz/bar.inputdeps\n" - "\n" "build phony/baz/bar: phony " "bar.bundle/Contents/Resources/input1.txt " "bar.bundle/Contents/Resources/input2.txt\n" - "\n" "build bar.bundle: phony phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -129,17 +125,13 @@ const char expected[] = "build phony/baz/bar.inputdeps: phony || phony/foo/bar " "phony/foo/data\n" - "\n" "build gen/bar.bundle/Contents/Resources/input1.txt: copy_bundle_data " "../../foo/input1.txt | phony/baz/bar.inputdeps\n" - "\n" "build gen/bar.bundle/Contents/Resources/input2.txt: copy_bundle_data " "../../foo/input2.txt | phony/baz/bar.inputdeps\n" - "\n" "build phony/baz/bar: phony " "gen/bar.bundle/Contents/Resources/input1.txt " "gen/bar.bundle/Contents/Resources/input2.txt\n" - "\n" "build gen/bar.bundle: phony phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -172,10 +164,8 @@ const char expected[] = "build baz/bar/bar_partial_info.plist: stamp || phony/foo/bar\n" - "\n" "build phony/baz/bar: phony " "baz/bar/bar_partial_info.plist || phony/foo/bar\n" - "\n" "build bar.bundle: phony phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -239,15 +229,12 @@ const char expected[] = "build phony/baz/bar.inputdeps: phony || phony/foo/bar " "phony/foo/data\n" - "\n" "build bar.bundle/Contents/Resources/Assets.car: compile_xcassets " "../../foo/Foo.xcassets | phony/foo/data phony/baz/bar.inputdeps\n" " product_type = com.apple.product-type\n" " xcasset_compiler_flags = --app-icon foo\n" - "\n" "build phony/baz/bar: phony " "bar.bundle/Contents/Resources/Assets.car\n" - "\n" "build bar.bundle: phony phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -283,7 +270,6 @@ const char expected[] = "build phony/baz/bar: phony || phony/foo/action\n" - "\n" "build bar.bundle: phony phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -406,20 +392,15 @@ "build phony/baz/bar.inputdeps: phony || phony/biz/assets " "phony/foo/assets phony/foo/bar phony/foo/data " "phony/qux/info_plist phony/quz/assets\n" - "\n" "build bar.bundle/Contents/Info.plist: copy_bundle_data " "../../qux/qux-Info.plist | phony/baz/bar.inputdeps\n" - "\n" "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data " "../../foo/input1.txt | phony/baz/bar.inputdeps\n" - "\n" "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data " "../../foo/input2.txt | phony/baz/bar.inputdeps\n" - "\n" "build phony/baz/bar.xcassets.inputdeps: phony " "phony/foo/assets " "phony/quz/assets phony/biz/assets\n" - "\n" "build bar.bundle/Contents/Resources/Assets.car | " "baz/bar/bar_partial_info.plist: compile_xcassets " "../../foo/Foo.xcassets ../../quz/Quz.xcassets " @@ -427,14 +408,12 @@ "phony/baz/bar.inputdeps\n" " product_type = com.apple.product-type\n" " partial_info_plist = baz/bar/bar_partial_info.plist\n" - "\n" "build phony/baz/bar: phony " "bar.bundle/Contents/Info.plist " "bar.bundle/Contents/Resources/input1.txt " "bar.bundle/Contents/Resources/input2.txt " "bar.bundle/Contents/Resources/Assets.car " "baz/bar/bar_partial_info.plist\n" - "\n" "build bar.bundle: phony phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -492,36 +471,29 @@ writer.Run(); const char expected[] = + "build phony/baz/bar.inputdeps: phony || ./quz phony/foo/bar " + "phony/foo/data\n" "rule __baz_bar___toolchain_default__post_processing_rule\n" " command = ../../build/codesign.py -b=quz bar.bundle\n" " description = POST PROCESSING //baz:bar(//toolchain:default)\n" " restat = 1\n" "\n" - "\n" - "build phony/baz/bar.inputdeps: phony || ./quz phony/foo/bar " - "phony/foo/data\n" - "\n" "build bar.bundle/Contents/Resources/input1.txt: copy_bundle_data " "../../foo/input1.txt | phony/baz/bar.inputdeps\n" - "\n" "build bar.bundle/Contents/Resources/input2.txt: copy_bundle_data " "../../foo/input2.txt | phony/baz/bar.inputdeps\n" - "\n" "build phony/baz/bar.postprocessing.inputdeps: phony " "../../build/codesign.py " "quz " "bar.bundle/Contents/Resources/input1.txt " "bar.bundle/Contents/Resources/input2.txt | " "phony/baz/bar.inputdeps\n" - "\n" "build bar.bundle/Contents/quz bar.bundle/_CodeSignature/CodeResources: " "__baz_bar___toolchain_default__post_processing_rule " "| phony/baz/bar.postprocessing.inputdeps\n" - "\n" "build phony/baz/bar: phony " "bar.bundle/Contents/quz " "bar.bundle/_CodeSignature/CodeResources ./quz\n" - "\n" "build bar.bundle: phony phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); @@ -582,39 +554,32 @@ writer.Run(); const char expected[] = + "build toolchain/phony/baz/bar.inputdeps: phony || ./quz " + "toolchain/phony/foo/bar " + "toolchain/phony/foo/data\n" "rule __baz_bar___toolchain_default__post_processing_rule\n" " command = ../../build/codesign.py -b=quz bar.bundle\n" " description = POST PROCESSING //baz:bar(//toolchain:default)\n" " restat = 1\n" "\n" - "\n" - "build toolchain/phony/baz/bar.inputdeps: phony || ./quz " - "toolchain/phony/foo/bar " - "toolchain/phony/foo/data\n" - "\n" "build bar.bundle/Contents/Resources/input1.txt: " "toolchain_copy_bundle_data " "../../foo/input1.txt | toolchain/phony/baz/bar.inputdeps\n" - "\n" "build bar.bundle/Contents/Resources/input2.txt: " "toolchain_copy_bundle_data " "../../foo/input2.txt | toolchain/phony/baz/bar.inputdeps\n" - "\n" "build toolchain/phony/baz/bar.postprocessing.inputdeps: phony " "../../build/codesign.py " "quz " "bar.bundle/Contents/Resources/input1.txt " "bar.bundle/Contents/Resources/input2.txt | " "toolchain/phony/baz/bar.inputdeps\n" - "\n" "build bar.bundle/Contents/quz bar.bundle/_CodeSignature/CodeResources: " "__baz_bar___toolchain_default__post_processing_rule " "| toolchain/phony/baz/bar.postprocessing.inputdeps\n" - "\n" "build toolchain/phony/baz/bar: phony " "bar.bundle/Contents/quz " "bar.bundle/_CodeSignature/CodeResources ./quz\n" - "\n" "build bar.bundle: phony toolchain/phony/baz/bar\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str);
diff --git a/src/gn/ninja_file.cc b/src/gn/ninja_file.cc deleted file mode 100644 index cacb7f6..0000000 --- a/src/gn/ninja_file.cc +++ /dev/null
@@ -1,127 +0,0 @@ -// Copyright 2026 The GN 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 "gn/ninja_file.h" - -#include <ostream> -#include <string> - -#include "base/logging.h" -#include "gn/escape.h" -#include "gn/string_output_buffer.h" - -namespace { - -void WriteOutputFile(std::ostream& out, const OutputFile& file) { - EscapeOptions opts; - opts.mode = ESCAPE_NINJA; - out << " "; - EscapeStringToStream(out, file.value(), opts); -} - -void WriteVariable(std::ostream& out, - std::string_view name, - const std::string& value, - bool indent = false) { - if (indent) - out << " "; - out << name << " ="; - if (!value.empty()) { - if (!value.starts_with(' ')) - out << " "; - out << value; - } - out << '\n'; -} - -void WriteRules(std::ostream& out, const std::vector<std::string>& rules) { - if (!rules.empty()) { - for (const auto& rule : rules) { - out << rule << '\n'; - } - out << '\n'; - } -} - -} // namespace - -void NinjaFile::AddTargetGroup(NinjaTargetGroup group) { - targets.push_back(std::move(group)); -} - -void NinjaFile::Hoist() { - if (targets.empty()) - return; - - if (targets.size() == 1) { - file_vars = std::move(targets.front().target_vars); - targets.front().target_vars.clear(); - return; - } - - CHECK(false) << "Multiple targets per ninja file not yet implemented"; -} - -void NinjaFile::Serialize(std::ostream& out) { - Hoist(); - - for (const auto& var : file_vars) { - WriteVariable(out, var.name, var.value, /*indent=*/false); - } - if (!file_vars.empty()) - out << "\n\n"; - - WriteRules(out, custom_rules); - - for (size_t i = 0; i < targets.size(); ++i) { - if (i > 0) - out << "\n\n"; - const auto& target = targets[i]; - WriteRules(out, target.custom_rules); - for (size_t e = 0; e < target.edges.size(); ++e) { - if (e > 0) - out << "\n"; - const auto& edge = target.edges[e]; - out << "build"; - for (const auto& output : edge.outputs) - WriteOutputFile(out, output); - if (!edge.implicit_outputs.empty()) { - out << " |"; - for (const auto& out_file : edge.implicit_outputs) - WriteOutputFile(out, out_file); - } - out << ": " << edge.rule; - for (const auto& input : edge.explicit_inputs) - WriteOutputFile(out, input); - if (!edge.implicit_inputs.empty()) { - out << " |"; - for (const auto& in_file : edge.implicit_inputs) - WriteOutputFile(out, in_file); - } - if (!edge.order_only_inputs.empty()) { - out << " ||"; - for (const auto& in_file : edge.order_only_inputs) - WriteOutputFile(out, in_file); - } - if (!edge.validation_inputs.empty()) { - out << " |@"; - for (const auto& in_file : edge.validation_inputs) - WriteOutputFile(out, in_file); - } - out << "\n"; - - for (const auto& var : target.target_vars) { - WriteVariable(out, var.name, var.value, /*indent=*/true); - } - for (const auto& var : edge.edge_vars) { - WriteVariable(out, var.name, var.value, /*indent=*/true); - } - } - } -} - -void NinjaFile::Serialize(StringOutputBuffer& out) { - std::ostream os(&out); - Serialize(os); -}
diff --git a/src/gn/ninja_file.h b/src/gn/ninja_file.h deleted file mode 100644 index c2b3de9..0000000 --- a/src/gn/ninja_file.h +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright 2026 The GN 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_NINJA_FILE_H_ -#define TOOLS_GN_NINJA_FILE_H_ - -#include <iosfwd> -#include <string> -#include <string_view> -#include <vector> - -#include "gn/output_file.h" - -class StringOutputBuffer; -class Target; - -// A single variable assignment in Ninja syntax (e.g. cflags = -fPIC). -struct NinjaVariable { - std::string_view name; - std::string value; - - bool operator==(const NinjaVariable& other) const = default; -}; - -// Represents a single 'build <outputs>: <rule> <inputs>' edge. -struct NinjaBuildEdge { - std::string rule; - std::vector<OutputFile> outputs; - std::vector<OutputFile> implicit_outputs = {}; - - std::vector<OutputFile> explicit_inputs = {}; - std::vector<OutputFile> implicit_inputs = {}; - std::vector<OutputFile> order_only_inputs = {}; - std::vector<OutputFile> validation_inputs = {}; - - // Variables specific to this edge (e.g. source_file_part, source_name_part). - std::vector<NinjaVariable> edge_vars = {}; - - // Whether the outputs of this edge are target outputs for - // --ide=ninja_outputs. Intermediate input dependency stamps/phonies are not - // target outputs. See https://gn.issues.chromium.org/448860851. - bool is_target_output = true; -}; - -// Represents a group of build edges and shared variables for a target. -struct NinjaTargetGroup { - const Target* target = nullptr; - - // Custom rule definitions specific to this target (e.g. for action targets). - std::vector<std::string> custom_rules; - - // Variables shared across all edges in this target (e.g. cflags, defines, - // target_out_dir). - std::vector<NinjaVariable> target_vars; - - // Compilation, link, or action build edges for this target. - std::vector<NinjaBuildEdge> edges; -}; - -// Represents a complete Ninja build file. -class NinjaFile { - public: - // Top-level / hoisted variables. - std::vector<NinjaVariable> file_vars; - - // Custom rule definitions. - std::vector<std::string> custom_rules; - - // Target groups contained in this file. - std::vector<NinjaTargetGroup> targets; - - // Adds a target group to this file. - void AddTargetGroup(NinjaTargetGroup group); - - // Serializes the Ninja AST to an output stream or StringOutputBuffer. - void Serialize(std::ostream& out); - void Serialize(StringOutputBuffer& out); - - private: - // Hoists identical target variables across all targets into file_vars. - void Hoist(); -}; - -#endif // TOOLS_GN_NINJA_FILE_H_
diff --git a/src/gn/ninja_generated_file_target_writer.cc b/src/gn/ninja_generated_file_target_writer.cc index 9fd07f2..6de8207 100644 --- a/src/gn/ninja_generated_file_target_writer.cc +++ b/src/gn/ninja_generated_file_target_writer.cc
@@ -20,7 +20,7 @@ NinjaGeneratedFileTargetWriter::~NinjaGeneratedFileTargetWriter() = default; -void NinjaGeneratedFileTargetWriter::GenerateRules() { +void NinjaGeneratedFileTargetWriter::Run() { // Write the file. GenerateFile();
diff --git a/src/gn/ninja_generated_file_target_writer.h b/src/gn/ninja_generated_file_target_writer.h index dc18fe2..3103388 100644 --- a/src/gn/ninja_generated_file_target_writer.h +++ b/src/gn/ninja_generated_file_target_writer.h
@@ -13,7 +13,7 @@ NinjaGeneratedFileTargetWriter(const Target* target, std::ostream& out); ~NinjaGeneratedFileTargetWriter() override; - void GenerateRules() override; + void Run() override; private: void GenerateFile();
diff --git a/src/gn/ninja_group_target_writer.cc b/src/gn/ninja_group_target_writer.cc index c936a12..7db1a3a 100644 --- a/src/gn/ninja_group_target_writer.cc +++ b/src/gn/ninja_group_target_writer.cc
@@ -16,7 +16,7 @@ NinjaGroupTargetWriter::~NinjaGroupTargetWriter() = default; -void NinjaGroupTargetWriter::GenerateRules() { +void NinjaGroupTargetWriter::Run() { // A group rule just generates a phony target with dependencies on each of // the deps and data_deps in the group. std::vector<OutputFile> output_files;
diff --git a/src/gn/ninja_group_target_writer.h b/src/gn/ninja_group_target_writer.h index 663cc45..7a3f211 100644 --- a/src/gn/ninja_group_target_writer.h +++ b/src/gn/ninja_group_target_writer.h
@@ -13,7 +13,7 @@ NinjaGroupTargetWriter(const Target* target, std::ostream& out); ~NinjaGroupTargetWriter() override; - void GenerateRules() override; + void Run() override; private: NinjaGroupTargetWriter(const NinjaGroupTargetWriter&) = delete;
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc index d0651bf..a8bea8f 100644 --- a/src/gn/ninja_rust_binary_target_writer.cc +++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -27,21 +27,21 @@ return opts; } -void WriteVar(std::string_view name, +void WriteVar(const char* name, const std::string& value, EscapeOptions opts, - std::vector<NinjaVariable>& target_vars) { - std::ostringstream ss; - EscapeStringToStream(ss, value, opts); - target_vars.emplace_back(name, ss.str()); + std::ostream& out) { + out << name << " = "; + EscapeStringToStream(out, value, opts); + out << std::endl; } void WriteCrateVars(const Target* target, const Tool* tool, EscapeOptions opts, - std::vector<NinjaVariable>& target_vars) { + std::ostream& out) { WriteVar(kRustSubstitutionCrateName.ninja_name, - target->rust_values().crate_name(), opts, target_vars); + target->rust_values().crate_name(), opts, out); std::string crate_type; switch (target->rust_values().crate_type()) { @@ -86,17 +86,16 @@ default: NOTREACHED(); } - WriteVar(kRustSubstitutionCrateType.ninja_name, crate_type, opts, - target_vars); + WriteVar(kRustSubstitutionCrateType.ninja_name, crate_type, opts, out); WriteVar(SubstitutionOutputExtension.ninja_name, SubstitutionWriter::GetLinkerSubstitution( target, tool, &SubstitutionOutputExtension), - opts, target_vars); + opts, out); WriteVar(SubstitutionOutputDir.ninja_name, SubstitutionWriter::GetLinkerSubstitution(target, tool, &SubstitutionOutputDir), - opts, target_vars); + opts, out); } } // namespace @@ -110,7 +109,7 @@ // TODO(juliehockett): add inherited library support? and IsLinkable support? // for c-cross-compat -void NinjaRustBinaryTargetWriter::GenerateRules() { +void NinjaRustBinaryTargetWriter::Run() { DCHECK(target_->output_type() != Target::SOURCE_SET); size_t num_output_uses = target_->sources().size(); @@ -291,15 +290,16 @@ WriteExternsAndDeps(extern_deps, transitive_crates, rustdeps, nonrustdeps, swiftmodules); WriteSourcesAndInputs(); + WritePool(out_); } void NinjaRustBinaryTargetWriter::WriteCompilerVars() { const SubstitutionBits& subst = target_->toolchain()->substitution_bits(); EscapeOptions opts = GetFlagOptions(); - WriteCrateVars(target_, tool_, opts, target_group_.target_vars); + WriteCrateVars(target_, tool_, opts, out_); - WriteRustCompilerVars(subst, /*always_write=*/true); + WriteRustCompilerVars(subst, /*indent=*/false, /*always_write=*/true); WriteSharedVars(subst); } @@ -312,25 +312,25 @@ // because it is handled sufficiently by crate_root and the generation // of depfiles by rustc. But for those which do... for (const auto& source : target_->sources()) { - deps->emplace_back(settings_->build_settings(), source); + deps->push_back(OutputFile(settings_->build_settings(), source)); } for (const auto& data : target_->config_values().inputs()) { - deps->emplace_back(settings_->build_settings(), data); + deps->push_back(OutputFile(settings_->build_settings(), data)); } } void NinjaRustBinaryTargetWriter::WriteSourcesAndInputs() { - std::ostringstream val; + out_ << " sources ="; for (const auto& source : target_->sources()) { - val << " "; - path_output_.WriteFile(val, + out_ << " "; + path_output_.WriteFile(out_, OutputFile(settings_->build_settings(), source)); } for (const auto& data : target_->config_values().inputs()) { - val << " "; - path_output_.WriteFile(val, OutputFile(settings_->build_settings(), data)); + out_ << " "; + path_output_.WriteFile(out_, OutputFile(settings_->build_settings(), data)); } - target_group_.edges.back().edge_vars.emplace_back("sources", val.str()); + out_ << std::endl; } void NinjaRustBinaryTargetWriter::WriteExternsAndDeps( @@ -339,25 +339,24 @@ const std::vector<OutputFile>& rustdeps, const std::vector<OutputFile>& nonrustdeps, const std::vector<OutputFile>& swiftmodules) { - std::ostringstream externs_val; // Writes a external LibFile which comes from user-specified externs, and may // be either a string or a SourceFile. - auto write_extern_lib_file = [this, &externs_val](std::string_view crate_name, - LibFile lib_file) { - externs_val << " --extern "; - externs_val << crate_name; - externs_val << "="; + auto write_extern_lib_file = [this](std::string_view crate_name, + LibFile lib_file) { + out_ << " --extern "; + out_ << crate_name; + out_ << "="; if (lib_file.is_source_file()) { - path_output_.WriteFile(externs_val, lib_file.source_file()); + path_output_.WriteFile(out_, lib_file.source_file()); } else { EscapeOptions escape_opts_command; escape_opts_command.mode = ESCAPE_NINJA_COMMAND; - EscapeStringToStream(externs_val, lib_file.value(), escape_opts_command); + EscapeStringToStream(out_, lib_file.value(), escape_opts_command); } }; // Writes an external OutputFile which comes from a dependency of the current // target. - auto write_extern_target = [this, &externs_val](const Target& dep) { + auto write_extern_target = [this](const Target& dep) { std::string_view crate_name; const auto& aliased_deps = target_->rust_values().aliased_deps(); if (auto it = aliased_deps.find(dep.label()); it != aliased_deps.end()) { @@ -366,12 +365,15 @@ crate_name = dep.rust_values().crate_name(); } - externs_val << " --extern "; - externs_val << crate_name; - externs_val << "="; - path_output_.WriteFile(externs_val, dep.dependency_output_file()); + out_ << " --extern "; + out_ << crate_name; + out_ << "="; + path_output_.WriteFile(out_, dep.dependency_output_file()); }; + // Write accessible crates with `--extern` to add them to the extern prelude. + out_ << " externs ="; + // Tracking to avoid emitted the same lib twice. We track it instead of // pre-emptively constructing a UniqueVector since we would have to also store // the crate name, and in the future the public-ness. @@ -416,14 +418,13 @@ } } - target_group_.edges.back().edge_vars.emplace_back("externs", - externs_val.str()); + out_ << std::endl; + out_ << " rustdeps ="; - std::ostringstream rustdeps_val; for (const SourceDir& dir : private_extern_dirs) { // TODO: switch to using `--extern priv:name` after stabilization. - rustdeps_val << " -Ldependency="; - path_output_.WriteDir(rustdeps_val, dir, PathOutput::DIR_NO_LAST_SLASH); + out_ << " -Ldependency="; + path_output_.WriteDir(out_, dir, PathOutput::DIR_NO_LAST_SLASH); } // If rustc will invoke a linker, then pass linker arguments to include those @@ -433,30 +434,27 @@ // that allows dynamic linking, as rustc may have previously put it into // static-only mode. if (nonrustdeps.size() > 0) { - rustdeps_val << " " << tool_->dynamic_link_switch(); + out_ << " " << tool_->dynamic_link_switch(); } for (const auto& nonrustdep : nonrustdeps) { - rustdeps_val << " -Clink-arg="; - path_output_.WriteFile(rustdeps_val, nonrustdep); + out_ << " -Clink-arg="; + path_output_.WriteFile(out_, nonrustdep); } // Library search paths are required to find system libraries named in #[link] // directives, which will not be specified in non-Rust native dependencies. - WriteLibrarySearchPath(rustdeps_val, tool_); + WriteLibrarySearchPath(out_, tool_); // If rustc will invoke a linker, all libraries need the passed through to the // linker. - WriteLibs(rustdeps_val, tool_); - WriteFrameworks(rustdeps_val, tool_); - WriteSwiftModules(rustdeps_val, tool_, swiftmodules); + WriteLibs(out_, tool_); + WriteFrameworks(out_, tool_); + WriteSwiftModules(out_, tool_, swiftmodules); - target_group_.edges.back().edge_vars.emplace_back("rustdeps", - rustdeps_val.str()); - - std::ostringstream ldflags_val; + out_ << std::endl; + out_ << " ldflags ="; // If rustc will invoke a linker, linker flags need to be forwarded through to // the linker. - WriteCustomLinkerFlags(ldflags_val, tool_); + WriteCustomLinkerFlags(out_, tool_); - target_group_.edges.back().edge_vars.emplace_back("ldflags", - ldflags_val.str()); + out_ << std::endl; }
diff --git a/src/gn/ninja_rust_binary_target_writer.h b/src/gn/ninja_rust_binary_target_writer.h index 0b08b0d..83e1203 100644 --- a/src/gn/ninja_rust_binary_target_writer.h +++ b/src/gn/ninja_rust_binary_target_writer.h
@@ -17,7 +17,7 @@ NinjaRustBinaryTargetWriter(const Target* target, std::ostream& out); ~NinjaRustBinaryTargetWriter() override; - void GenerateRules() override; + void Run() override; private: struct ExternCrate {
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc index 201e1e7..3f20c5a 100644 --- a/src/gn/ninja_rust_binary_target_writer_unittest.cc +++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -56,8 +56,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -65,7 +65,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/input3.rs " "../../foo/main.rs\n" " source_file_part = main.rs\n" @@ -113,7 +112,7 @@ "crate_name = privatecrate\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -121,7 +120,6 @@ "target_out_dir = obj/baz\n" "target_output_name = libprivatelib\n" "\n" - "\n" "build obj/baz/libprivatelib.rlib: rust_rlib ../../baz/lib.rs | " "../../baz/privatelib.rs ../../baz/lib.rs\n" " source_file_part = lib.rs\n" @@ -156,7 +154,7 @@ "crate_name = farcrate\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -164,7 +162,6 @@ "target_out_dir = obj/far\n" "target_output_name = libfarlib\n" "\n" - "\n" "build obj/far/libfarlib.rlib: rust_rlib ../../far/lib.rs | " "../../far/farlib.rs ../../far/lib.rs\n" " source_file_part = lib.rs\n" @@ -199,7 +196,7 @@ "crate_name = publiccrate\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -207,7 +204,6 @@ "target_out_dir = obj/bar\n" "target_output_name = libpubliclib\n" "\n" - "\n" "build obj/bar/libpubliclib.rlib: rust_rlib ../../bar/lib.rs | " "../../bar/publiclib.rs ../../bar/lib.rs obj/far/libfarlib.rlib\n" " source_file_part = lib.rs\n" @@ -255,8 +251,8 @@ const char expected[] = "crate_name = main_crate\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -264,7 +260,6 @@ "target_out_dir = obj/main\n" "target_output_name = main\n" "\n" - "\n" "build ./main_crate: rust_bin ../../main/main.rs | " "../../main/source.rs ../../main/main.rs obj/foo/libdirect.rlib " "obj/bar/libpubliclib.rlib obj/far/libfarlib.rlib " @@ -310,7 +305,7 @@ "crate_name = private_inside\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -318,7 +313,6 @@ "target_out_dir = obj/faz\n" "target_output_name = libprivate_inside\n" "\n" - "\n" "build obj/faz/libprivate_inside.rlib: rust_rlib ../../faz/lib.rs | " "../../faz/private_inside.rs ../../faz/lib.rs\n" " source_file_part = lib.rs\n" @@ -352,7 +346,7 @@ "crate_name = inside\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -360,7 +354,6 @@ "target_out_dir = obj/baz\n" "target_output_name = libinside\n" "\n" - "\n" "build obj/baz/libinside.rlib: rust_rlib ../../baz/lib.rs | " "../../baz/inside.rs ../../baz/lib.rs\n" " source_file_part = lib.rs\n" @@ -397,7 +390,7 @@ "crate_name = mylib\n" "crate_type = dylib\n" "output_extension = .so\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -405,7 +398,6 @@ "target_out_dir = obj/bar\n" "target_output_name = libmylib\n" "\n" - "\n" "build obj/bar/libmylib.so: rust_dylib ../../bar/lib.rs | " "../../bar/mylib.rs ../../bar/lib.rs " "obj/baz/libinside.rlib obj/faz/libprivate_inside.rlib\n" @@ -470,8 +462,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -479,7 +471,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs obj/foo/libdirect.so obj/bar/libmylib.so " "obj/baz/libinside.rlib\n" @@ -524,7 +515,7 @@ "crate_name = mymacro\n" "crate_type = proc-macro\n" "output_extension = .so\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -532,7 +523,6 @@ "target_out_dir = obj/bar\n" "target_output_name = libmymacro\n" "\n" - "\n" "build obj/bar/libmymacro.so: rust_macro ../../bar/lib.rs | " "../../bar/mylib.rs ../../bar/lib.rs\n" " source_file_part = lib.rs\n" @@ -585,7 +575,7 @@ "crate_name = mylib\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -593,7 +583,6 @@ "target_out_dir = obj/bar\n" "target_output_name = libmylib\n" "\n" - "\n" "build obj/bar/libmylib.rlib: rust_rlib ../../bar/lib.rs | " "../../bar/mylib.rs ../../bar/lib.rs obj/bar/libmymacro.so || " "obj/bar/libmymacro.so\n" @@ -628,8 +617,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -637,7 +626,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | " "../../foo/source.rs ../../foo/main.rs " "obj/bar/libmylib.rlib obj/bar/libmymacro.so\n" @@ -714,8 +702,8 @@ const char expected[] = "crate_name = f_crate\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -723,7 +711,6 @@ "target_out_dir = obj/foo\n" "target_output_name = f\n" "\n" - "\n" "build ./f_crate: rust_bin ../../foo/main.rs | ../../foo/main.rs " "obj/foo/b.b.o || phony/foo/b.linkdeps\n" " source_file_part = main.rs\n" @@ -805,8 +792,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -814,7 +801,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs obj/bar/libdirect.rlib obj/baz/libmylib.rlib " "obj/faz/libtransitive.rlib\n" @@ -909,8 +895,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -918,7 +904,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs obj/baz/sourceset.csourceset.o " "obj/bar/libmylib.rlib " @@ -957,8 +942,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -966,7 +951,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs obj/foo/libstatic.a\n" " source_file_part = main.rs\n" @@ -1000,7 +984,7 @@ "crate_name = baz\n" "crate_type = staticlib\n" "output_extension = .a\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1008,7 +992,6 @@ "target_out_dir = obj/baz\n" "target_output_name = libbaz\n" "\n" - "\n" "build obj/baz/libbaz.a: rust_staticlib ../../baz/lib.rs | " "../../baz/lib.rs " "obj/foo/libstatic.a\n" @@ -1172,8 +1155,8 @@ const char expected[] = "crate_name = exe\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1181,7 +1164,6 @@ "target_out_dir = obj/exe\n" "target_output_name = exe\n" "\n" - "\n" "build ./exe: rust_bin ../../exe/main.rs | " "../../exe/main.rs " "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.lib.o " @@ -1249,7 +1231,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar.exe: rust_bin ../../foo/main.rs | ../../foo/input3.rs " "../../foo/main.rs\n" " source_file_part = main.rs\n" @@ -1308,7 +1289,7 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" + "output_extension = \n" "output_dir = foo\n" "rustflags =\n" "rustenv =\n" @@ -1317,7 +1298,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/input.rs " "../../foo/main.rs obj/bar/librlib.rlib\n" " source_file_part = main.rs\n" @@ -1410,7 +1390,7 @@ "crate_name = rlibcrate\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1418,7 +1398,6 @@ "target_out_dir = obj/foo\n" "target_output_name = librlibcrate\n" "\n" - "\n" "build obj/foo/librlibcrate.rlib: rust_rlib ../../foo/input.rs | " "../../foo/input.rs obj/bar/libpubliclib.rlib obj/clib/libstatic.a\n" " source_file_part = input.rs\n" @@ -1495,7 +1474,7 @@ "crate_name = mymacro\n" "crate_type = proc-macro\n" "output_extension = .so\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1503,7 +1482,6 @@ "target_out_dir = obj/bar\n" "target_output_name = libmymacro\n" "\n" - "\n" "build obj/bar/libmymacro.so: rust_macro ../../bar/lib.rs | " "../../bar/mylib.rs ../../bar/lib.rs " "obj/baz/public/libmymacropublicdep.rlib " @@ -1542,8 +1520,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1551,7 +1529,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs obj/bar/libmymacro.so\n" " source_file_part = main.rs\n" @@ -1590,7 +1567,7 @@ "crate_name = mylib\n" "crate_type = rlib\n" "output_extension = .rlib\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1598,7 +1575,6 @@ "target_out_dir = obj/bar\n" "target_output_name = libmylib\n" "\n" - "\n" "build obj/bar/libmylib.rlib: rust_rlib ../../bar/lib.rs | " "../../bar/mylib.rs ../../bar/lib.rs\n" " source_file_part = lib.rs\n" @@ -1639,8 +1615,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1648,7 +1624,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | " "../../foo/source.rs ../../foo/main.rs obj/bar/libmylib.rlib || " "obj/bar/libmylib.rlib\n" @@ -1695,8 +1670,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1704,7 +1679,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs ../../foo/lib1.rlib\n" " source_file_part = main.rs\n" @@ -1743,10 +1717,12 @@ writer.Run(); const char expected[] = + "build phony/foo/bar.inputs: phony ../../foo/config.json " + "../../foo/template.h\n" "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1754,10 +1730,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" - "build phony/foo/bar.inputs: phony ../../foo/config.json " - "../../foo/template.h\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs ../../foo/config.json ../../foo/template.h " "|| phony/foo/bar.inputs\n" @@ -1795,7 +1767,7 @@ "crate_name = mylib\n" "crate_type = cdylib\n" "output_extension = .so\n" - "output_dir =\n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1803,7 +1775,6 @@ "target_out_dir = obj/bar\n" "target_output_name = libmylib\n" "\n" - "\n" "build obj/bar/libmylib.so: rust_cdylib ../../bar/lib.rs | " "../../bar/lib.rs\n" " source_file_part = lib.rs\n" @@ -1836,8 +1807,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1845,7 +1816,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs obj/bar/libmylib.so\n" " source_file_part = main.rs\n" @@ -1914,8 +1884,8 @@ const char expected[] = "crate_name = foo_bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -1923,7 +1893,6 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/main.rs " "obj/bar/libmylib.rlib ./libshared.so ./libimplicit.so\n" " source_file_part = main.rs\n" @@ -2009,8 +1978,8 @@ const char expected[] = "crate_name = exe\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -2018,7 +1987,6 @@ "target_out_dir = obj/linked\n" "target_output_name = exe\n" "\n" - "\n" "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs " "obj/sset/bar.input1.o obj/public/libbehind_sourceset_public.rlib " "obj/private/libbehind_sourceset_private.rlib || " @@ -2067,8 +2035,8 @@ const char expected[] = "crate_name = bar\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -2076,15 +2044,14 @@ "target_out_dir = obj/foo\n" "target_output_name = bar\n" "\n" - "\n" "build ./bar: rust_bin ../../foo/source.rs | ../../foo/source.rs\n" " source_file_part = source.rs\n" " source_name_part = source\n" - " pool = foo_pool\n" " externs =\n" " rustdeps =\n" " ldflags =\n" - " sources = ../../foo/source.rs\n"; + " sources = ../../foo/source.rs\n" + " pool = foo_pool\n"; std::string out_str = out.str(); EXPECT_EQ(expected, out_str); } @@ -2141,8 +2108,8 @@ const char expected[] = "crate_name = exe\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -2150,7 +2117,6 @@ "target_out_dir = obj/linked\n" "target_output_name = exe\n" "\n" - "\n" "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs || " "phony/bar/framework\n" " source_file_part = exe.rs\n" @@ -2200,8 +2166,8 @@ const char expected[] = "crate_name = exe\n" "crate_type = bin\n" - "output_extension =\n" - "output_dir =\n" + "output_extension = \n" + "output_dir = \n" "rustflags =\n" "rustenv =\n" "root_out_dir = .\n" @@ -2209,7 +2175,6 @@ "target_out_dir = obj/linked\n" "target_output_name = exe\n" "\n" - "\n" "build ./exe: rust_bin ../../linked/exe.rs | ../../linked/exe.rs " "obj/foo/file1.o obj/foo/file2.o || " "phony/foo/foo obj/foo/Foo.swiftmodule phony/foo/foo.linkdeps\n"
diff --git a/src/gn/ninja_target_writer.cc b/src/gn/ninja_target_writer.cc index e35d39a..d3d1eb1 100644 --- a/src/gn/ninja_target_writer.cc +++ b/src/gn/ninja_target_writer.cc
@@ -7,10 +7,12 @@ #include <algorithm> #include <sstream> +#include "base/files/file_util.h" #include "base/strings/string_util.h" #include "gn/builtin_tool.h" #include "gn/c_substitution_type.h" #include "gn/config_values_extractors.h" +#include "gn/err.h" #include "gn/escape.h" #include "gn/filesystem_utils.h" #include "gn/general_tool.h" @@ -27,6 +29,7 @@ #include "gn/rust_substitution_type.h" #include "gn/scheduler.h" #include "gn/string_output_buffer.h" +#include "gn/string_utils.h" #include "gn/substitution_writer.h" #include "gn/target.h" #include "gn/trace.h" @@ -37,55 +40,7 @@ out_(out), path_output_(settings_->build_settings()->build_dir(), settings_->build_settings()->root_path_utf8(), - ESCAPE_NINJA) { - target_group_.target = target; -} - -void NinjaTargetWriter::AddTargetVar(std::string_view name, std::string value) { - target_group_.target_vars.emplace_back(name, std::move(value)); -} - -void NinjaTargetWriter::AddEdge(NinjaBuildEdge edge) { - target_group_.edges.push_back(std::move(edge)); -} - -NinjaTargetGroup NinjaTargetWriter::GenerateTargetGroup() { - GenerateRules(); - return std::move(target_group_); -} - -void NinjaTargetWriter::SetNinjaOutputs( - std::vector<OutputFile>* ninja_outputs) { - ninja_outputs_ = ninja_outputs; -} - -void NinjaTargetWriter::Run() { - NinjaTargetGroup group = GenerateTargetGroup(); - if (ninja_outputs_) { - for (const auto& edge : group.edges) { - if (edge.is_target_output) { - ninja_outputs_->insert(ninja_outputs_->end(), edge.outputs.begin(), - edge.outputs.end()); - ninja_outputs_->insert(ninja_outputs_->end(), - edge.implicit_outputs.begin(), - edge.implicit_outputs.end()); - } - } - } - NinjaFile file; - file.AddTargetGroup(std::move(group)); - file.Serialize(out_); -} - -std::vector<OutputFile> NinjaTargetWriter::ToOutputFiles( - const std::vector<SourceFile>& sources) const { - std::vector<OutputFile> outputs; - outputs.reserve(sources.size()); - for (const auto& source : sources) { - outputs.emplace_back(settings_->build_settings(), source); - } - return outputs; -} + ESCAPE_NINJA) {} void NinjaTargetWriter::SetResolvedTargetData(ResolvedTargetData* resolved) { if (resolved) { @@ -94,6 +49,11 @@ } } +void NinjaTargetWriter::SetNinjaOutputs( + std::vector<OutputFile>* ninja_outputs) { + ninja_outputs_ = ninja_outputs; +} + ResolvedTargetData* NinjaTargetWriter::GetResolvedTargetData() { return const_cast<ResolvedTargetData*>(&resolved()); } @@ -108,6 +68,34 @@ NinjaTargetWriter::~NinjaTargetWriter() = default; +void NinjaTargetWriter::WriteOutput(const OutputFile& output) const { + path_output_.WriteFile(out_, output); + if (ninja_outputs_) + ninja_outputs_->push_back(output); +} + +void NinjaTargetWriter::WriteOutput(OutputFile&& output) const { + path_output_.WriteFile(out_, output); + if (ninja_outputs_) + ninja_outputs_->push_back(std::move(output)); +} + +void NinjaTargetWriter::WriteOutputs( + const std::vector<OutputFile>& outputs) const { + path_output_.WriteFiles(out_, outputs); + if (ninja_outputs_) + ninja_outputs_->insert(ninja_outputs_->end(), outputs.begin(), + outputs.end()); +} + +void NinjaTargetWriter::WriteOutputs(std::vector<OutputFile>&& outputs) const { + path_output_.WriteFiles(out_, outputs); + if (ninja_outputs_) { + for (auto& output : outputs) + ninja_outputs_->push_back(std::move(output)); + } +} + // static std::string NinjaTargetWriter::RunAndWriteFile( const Target* target, @@ -122,8 +110,10 @@ if (g_scheduler->verbose_logging()) g_scheduler->Log("Computing", target->label().GetUserVisibleName(true)); - StringOutputBuffer dummy_storage; - std::ostream dummy_rules(&dummy_storage); + // It's ridiculously faster to write to a string and then write that to + // disk in one operation than to use an fstream here. + StringOutputBuffer storage; + std::ostream rules(&storage); // Call out to the correct sub-type of writer. Binary targets need to be // written to separate files for compiler flag scoping, but other target @@ -140,37 +130,43 @@ // Groups and actions don't use this type of flag, they make unique rules // or write variables scoped under each build line. As a result, they don't // need the separate files. - NinjaTargetGroup group; bool needs_file_write = false; if (target->output_type() == Target::BUNDLE_DATA) { - NinjaBundleDataTargetWriter writer(target, dummy_rules); + NinjaBundleDataTargetWriter writer(target, rules); writer.SetResolvedTargetData(resolved); - group = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs); + writer.Run(); } else if (target->output_type() == Target::CREATE_BUNDLE) { - NinjaCreateBundleTargetWriter writer(target, dummy_rules); + NinjaCreateBundleTargetWriter writer(target, rules); writer.SetResolvedTargetData(resolved); - group = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs); + writer.Run(); } else if (target->output_type() == Target::COPY_FILES) { - NinjaCopyTargetWriter writer(target, dummy_rules); + NinjaCopyTargetWriter writer(target, rules); writer.SetResolvedTargetData(resolved); - group = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs); + writer.Run(); } else if (target->output_type() == Target::ACTION || target->output_type() == Target::ACTION_FOREACH) { - NinjaActionTargetWriter writer(target, dummy_rules); + NinjaActionTargetWriter writer(target, rules); writer.SetResolvedTargetData(resolved); - group = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs); + writer.Run(); } else if (target->output_type() == Target::GROUP) { - NinjaGroupTargetWriter writer(target, dummy_rules); + NinjaGroupTargetWriter writer(target, rules); writer.SetResolvedTargetData(resolved); - group = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs); + writer.Run(); } else if (target->output_type() == Target::GENERATED_FILE) { - NinjaGeneratedFileTargetWriter writer(target, dummy_rules); + NinjaGeneratedFileTargetWriter writer(target, rules); writer.SetResolvedTargetData(resolved); - group = writer.GenerateTargetGroup(); + writer.SetNinjaOutputs(ninja_outputs); + writer.Run(); } else if (target->IsBinary()) { needs_file_write = true; - NinjaBinaryTargetWriter writer(target, dummy_rules); + NinjaBinaryTargetWriter writer(target, rules); writer.SetResolvedTargetData(resolved); + writer.SetNinjaOutputs(ninja_outputs); if (target->module_type().test(Target::MODULEMAP_IS_GENERATED)) { const SourceFile* modulemap = target->modulemap_file(); CHECK(modulemap); @@ -191,32 +187,12 @@ *target->private_modulemap_file()); private_storage.WriteToFileIfChanged(private_path, nullptr); } - group = writer.GenerateTargetGroup(); + writer.Run(); } else { CHECK(0) << "Output type of target not handled."; } - if (ninja_outputs) { - for (const auto& edge : group.edges) { - if (edge.is_target_output) { - ninja_outputs->insert(ninja_outputs->end(), edge.outputs.begin(), - edge.outputs.end()); - ninja_outputs->insert(ninja_outputs->end(), - edge.implicit_outputs.begin(), - edge.implicit_outputs.end()); - } - } - } - - WritePublicInputsStampOrPhony(target, resolved, group); - - NinjaFile file; - file.AddTargetGroup(std::move(group)); - - // It's ridiculously faster to write to a string and then write that to - // disk in one operation than to use an fstream here. - StringOutputBuffer storage; - file.Serialize(storage); + WritePublicInputsStampOrPhony(target, resolved, rules); if (needs_file_write) { // Write the ninja file. @@ -245,7 +221,7 @@ void NinjaTargetWriter::WritePublicInputsStampOrPhony( const Target* target, ResolvedTargetData* resolved, - NinjaTargetGroup& group) { + std::ostream& out) { DCHECK(resolved); if (!resolved->ExportsPublicInputs(target)) return; @@ -255,7 +231,7 @@ std::vector<OutputFile> deps; for (const auto& file : target->public_inputs()) { - deps.emplace_back(build_settings, file); + deps.push_back(OutputFile(build_settings, file)); } for (const auto& dep : target->public_deps()) { if (resolved->ExportsPublicInputs(dep.ptr)) { @@ -263,91 +239,111 @@ } } - std::string rule; + PathOutput path_output(build_settings->build_dir(), + build_settings->root_path_utf8(), ESCAPE_NINJA); + + out << "build "; + path_output.WriteFile(out, output); + if (build_settings->no_stamp_files()) { - rule = BuiltinTool::kBuiltinToolPhony; + out << ": " << BuiltinTool::kBuiltinToolPhony; } else { - rule = GetNinjaRulePrefixForToolchain(target->settings()) + - GeneralTool::kGeneralToolStamp; + out << ": " << GetNinjaRulePrefixForToolchain(target->settings()) + << GeneralTool::kGeneralToolStamp; } - group.edges.push_back(NinjaBuildEdge{ - .rule = std::move(rule), - .outputs = {output}, - .explicit_inputs = std::move(deps), - .is_target_output = false, - }); + path_output.WriteFiles(out, deps); + out << std::endl << std::endl; } void NinjaTargetWriter::WriteEscapedSubstitution(const Substitution* type) { EscapeOptions opts; opts.mode = ESCAPE_NINJA; - std::ostringstream val; + out_ << type->ninja_name << " = "; EscapeStringToStream( - val, SubstitutionWriter::GetTargetSubstitution(target_, type), opts); - target_group_.target_vars.emplace_back(type->ninja_name, val.str()); + out_, SubstitutionWriter::GetTargetSubstitution(target_, type), opts); + out_ << std::endl; } void NinjaTargetWriter::WriteSharedVars(const SubstitutionBits& bits) { + bool written_anything = false; + // Target label. if (bits.used.count(&SubstitutionLabel)) { WriteEscapedSubstitution(&SubstitutionLabel); + written_anything = true; } // Target label name. if (bits.used.count(&SubstitutionLabelName)) { WriteEscapedSubstitution(&SubstitutionLabelName); + written_anything = true; } // Target label name without toolchain. if (bits.used.count(&SubstitutionLabelNoToolchain)) { WriteEscapedSubstitution(&SubstitutionLabelNoToolchain); + written_anything = true; } // Root gen dir. if (bits.used.count(&SubstitutionRootGenDir)) { WriteEscapedSubstitution(&SubstitutionRootGenDir); + written_anything = true; } // Root out dir. if (bits.used.count(&SubstitutionRootOutDir)) { WriteEscapedSubstitution(&SubstitutionRootOutDir); + written_anything = true; } // Target gen dir. if (bits.used.count(&SubstitutionTargetGenDir)) { WriteEscapedSubstitution(&SubstitutionTargetGenDir); + written_anything = true; } // Target out dir. if (bits.used.count(&SubstitutionTargetOutDir)) { WriteEscapedSubstitution(&SubstitutionTargetOutDir); + written_anything = true; } // Target output name. if (bits.used.count(&SubstitutionTargetOutputName)) { WriteEscapedSubstitution(&SubstitutionTargetOutputName); + written_anything = true; } + + // If we wrote any vars, separate them from the rest of the file that follows + // with a blank line. + if (written_anything) + out_ << std::endl; } -void NinjaTargetWriter::WriteCCompilerVars( - const SubstitutionBits& bits, - bool respect_source_used, - std::vector<NinjaVariable>& target_vars) { +void NinjaTargetWriter::WriteCCompilerVars(const SubstitutionBits& bits, + bool indent, + bool respect_source_used) { // Defines. if (bits.used.count(&CSubstitutionDefines)) { - std::ostringstream val; + if (indent) + out_ << " "; + out_ << CSubstitutionDefines.ninja_name << " ="; RecursiveTargetConfigToStream<std::string>(kRecursiveWriterSkipDuplicates, target_, &ConfigValues::defines, - DefineWriter(), val); - target_vars.emplace_back(CSubstitutionDefines.ninja_name, val.str()); + DefineWriter(), out_); + out_ << std::endl; } // Framework search path. if (bits.used.count(&CSubstitutionFrameworkDirs)) { const Tool* tool = target_->toolchain()->GetTool(CTool::kCToolLink); - std::ostringstream val; + + if (indent) + out_ << " "; + out_ << CSubstitutionFrameworkDirs.ninja_name << " ="; PathOutput framework_dirs_output( path_output_.current_dir(), settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND); @@ -355,20 +351,22 @@ kRecursiveWriterSkipDuplicates, target_, &ConfigValues::framework_dirs, FrameworkDirsWriter(framework_dirs_output, tool->framework_dir_switch()), - val); - target_vars.emplace_back(CSubstitutionFrameworkDirs.ninja_name, val.str()); + out_); + out_ << std::endl; } // Include directories. if (bits.used.count(&CSubstitutionIncludeDirs)) { - std::ostringstream val; + if (indent) + out_ << " "; + out_ << CSubstitutionIncludeDirs.ninja_name << " ="; PathOutput include_path_output( path_output_.current_dir(), settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND); RecursiveTargetConfigToStream<SourceDir>( kRecursiveWriterSkipDuplicates, target_, &ConfigValues::include_dirs, - IncludeWriter(include_path_output), val); - target_vars.emplace_back(CSubstitutionIncludeDirs.ninja_name, val.str()); + IncludeWriter(include_path_output), out_); + out_ << std::endl; } bool has_precompiled_headers = @@ -376,24 +374,13 @@ EscapeOptions opts; opts.mode = ESCAPE_NINJA_COMMAND; - - auto write_flag = - [&](const Substitution* subst, bool has_pch, const char* tool_name, - const std::vector<std::string>& (ConfigValues::*getter)() const) { - if (!target_->toolchain()->substitution_bits().used.count(subst)) - return; - std::ostringstream val; - WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, subst, has_pch, - tool_name, getter, opts, path_output_, val, - /*write_substitution=*/false, /*indent=*/false); - target_vars.emplace_back(subst->ninja_name, val.str()); - }; - if (respect_source_used ? target_->source_types_used().Get(SourceFile::SOURCE_S) : bits.used.count(&CSubstitutionAsmFlags)) { - write_flag(&CSubstitutionAsmFlags, false, Tool::kToolNone, - &ConfigValues::asmflags); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionAsmFlags, false, Tool::kToolNone, + &ConfigValues::asmflags, opts, path_output_, out_, true, + indent); } if (respect_source_used ? (target_->source_types_used().Get(SourceFile::SOURCE_C) || @@ -402,51 +389,62 @@ target_->source_types_used().Get(SourceFile::SOURCE_MM) || target_->source_types_used().Get(SourceFile::SOURCE_MODULEMAP)) : bits.used.count(&CSubstitutionCFlags)) { - write_flag(&CSubstitutionCFlags, false, Tool::kToolNone, - &ConfigValues::cflags); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, &CSubstitutionCFlags, + false, Tool::kToolNone, &ConfigValues::cflags, opts, + path_output_, out_, true, indent); } if (respect_source_used ? target_->source_types_used().Get(SourceFile::SOURCE_C) : bits.used.count(&CSubstitutionCFlagsC)) { - write_flag(&CSubstitutionCFlagsC, has_precompiled_headers, CTool::kCToolCc, - &ConfigValues::cflags_c); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, &CSubstitutionCFlagsC, + has_precompiled_headers, CTool::kCToolCc, + &ConfigValues::cflags_c, opts, path_output_, out_, true, + indent); } if (respect_source_used ? (target_->source_types_used().Get(SourceFile::SOURCE_CPP) || target_->source_types_used().Get(SourceFile::SOURCE_MODULEMAP)) : bits.used.count(&CSubstitutionCFlagsCc)) { - write_flag(&CSubstitutionCFlagsCc, has_precompiled_headers, - CTool::kCToolCxx, &ConfigValues::cflags_cc); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionCFlagsCc, has_precompiled_headers, + CTool::kCToolCxx, &ConfigValues::cflags_cc, opts, path_output_, + out_, true, indent); } if (respect_source_used ? target_->source_types_used().Get(SourceFile::SOURCE_M) : bits.used.count(&CSubstitutionCFlagsObjC)) { - write_flag(&CSubstitutionCFlagsObjC, has_precompiled_headers, - CTool::kCToolObjC, &ConfigValues::cflags_objc); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionCFlagsObjC, has_precompiled_headers, + CTool::kCToolObjC, &ConfigValues::cflags_objc, opts, + path_output_, out_, true, indent); } if (respect_source_used ? target_->source_types_used().Get(SourceFile::SOURCE_MM) : bits.used.count(&CSubstitutionCFlagsObjCc)) { - write_flag(&CSubstitutionCFlagsObjCc, has_precompiled_headers, - CTool::kCToolObjCxx, &ConfigValues::cflags_objcc); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionCFlagsObjCc, has_precompiled_headers, + CTool::kCToolObjCxx, &ConfigValues::cflags_objcc, opts, + path_output_, out_, true, indent); } if (target_->source_types_used().SwiftSourceUsed() || !respect_source_used) { if (bits.used.count(&CSubstitutionSwiftModuleName)) { - std::ostringstream val; - EscapeStringToStream(val, target_->swift_values().module_name(), opts); - target_vars.emplace_back(CSubstitutionSwiftModuleName.ninja_name, - val.str()); + if (indent) + out_ << " "; + out_ << CSubstitutionSwiftModuleName.ninja_name << " = "; + EscapeStringToStream(out_, target_->swift_values().module_name(), opts); + out_ << std::endl; } if (bits.used.count(&CSubstitutionSwiftBridgeHeader)) { - std::ostringstream val; + if (indent) + out_ << " "; + out_ << CSubstitutionSwiftBridgeHeader.ninja_name << " = "; if (!target_->swift_values().bridge_header().is_null()) { - path_output_.WriteFile(val, target_->swift_values().bridge_header()); + path_output_.WriteFile(out_, target_->swift_values().bridge_header()); } else { - val << R"("")"; + out_ << R"("")"; } - target_vars.emplace_back(CSubstitutionSwiftBridgeHeader.ninja_name, - val.str()); + out_ << std::endl; } if (bits.used.count(&CSubstitutionSwiftModuleDirs)) { @@ -456,60 +454,51 @@ for (const Target* dep : resolved().GetSwiftModuleDependencies(target_)) swiftmodule_dirs.push_back(dep->swift_values().module_output_dir()); - std::ostringstream val; + if (indent) + out_ << " "; + out_ << CSubstitutionSwiftModuleDirs.ninja_name << " ="; PathOutput swiftmodule_path_output( path_output_.current_dir(), settings_->build_settings()->root_path_utf8(), ESCAPE_NINJA_COMMAND); IncludeWriter swiftmodule_path_writer(swiftmodule_path_output); for (const SourceDir& swiftmodule_dir : swiftmodule_dirs) { - swiftmodule_path_writer(swiftmodule_dir, val); + swiftmodule_path_writer(swiftmodule_dir, out_); } - target_vars.emplace_back(CSubstitutionSwiftModuleDirs.ninja_name, - val.str()); + out_ << std::endl; } - } -} -void NinjaTargetWriter::WriteCCompilerVars(const SubstitutionBits& bits, - bool respect_source_used) { - WriteCCompilerVars(bits, respect_source_used, target_group_.target_vars); -} - -void NinjaTargetWriter::WriteRustCompilerVars( - const SubstitutionBits& bits, - bool always_write, - std::vector<NinjaVariable>& target_vars) { - EscapeOptions opts; - opts.mode = ESCAPE_NINJA_COMMAND; - - auto write_flag = - [&](const Substitution* subst, - const std::vector<std::string>& (ConfigValues::*getter)() const) { - std::ostringstream val; - WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, subst, false, - Tool::kToolNone, getter, opts, path_output_, val, - /*write_substitution=*/false, /*indent=*/false); - target_vars.emplace_back(subst->ninja_name, val.str()); - }; - - if (bits.used.count(&kRustSubstitutionRustFlags) || always_write) { - write_flag(&kRustSubstitutionRustFlags, &ConfigValues::rustflags); - } - - if (bits.used.count(&kRustSubstitutionRustEnv) || always_write) { - write_flag(&kRustSubstitutionRustEnv, &ConfigValues::rustenv); + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &CSubstitutionSwiftFlags, false, CTool::kCToolSwift, + &ConfigValues::swiftflags, opts, path_output_, out_, true, + indent); } } void NinjaTargetWriter::WriteRustCompilerVars(const SubstitutionBits& bits, + bool indent, bool always_write) { - WriteRustCompilerVars(bits, always_write, target_group_.target_vars); + EscapeOptions opts; + opts.mode = ESCAPE_NINJA_COMMAND; + + if (bits.used.count(&kRustSubstitutionRustFlags) || always_write) { + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &kRustSubstitutionRustFlags, false, Tool::kToolNone, + &ConfigValues::rustflags, opts, path_output_, out_, true, + indent); + } + + if (bits.used.count(&kRustSubstitutionRustEnv) || always_write) { + WriteOneFlag(kRecursiveWriterKeepDuplicates, target_, + &kRustSubstitutionRustEnv, false, Tool::kToolNone, + &ConfigValues::rustenv, opts, path_output_, out_, true, + indent); + } } NinjaTargetWriter::InputDeps NinjaTargetWriter::WriteInputDepsStampOrPhonyAndGetDep( const std::vector<const Target*>& additional_hard_deps, - size_t num_output_uses) { + size_t num_output_uses) const { CHECK(target_->toolchain()) << "Toolchain not set on target " << target_->label().GetUserVisibleName(true); @@ -617,7 +606,7 @@ // File input deps. for (const SourceFile* source : input_deps_sources) - deps.order_only.emplace_back(settings_->build_settings(), *source); + deps.order_only.push_back(OutputFile(settings_->build_settings(), *source)); // Target input deps. Sort by label so the output is deterministic (otherwise // some of the targets will have gone through std::sets which will have // sorted them by pointer). @@ -674,15 +663,17 @@ GeneralTool::kGeneralToolStamp; } - // These are not real outputs, so do not mark as target output. + // These are not real outputs, so do not use WriteOutput() here. // See https://gn.issues.chromium.org/448860851. - AddEdge(NinjaBuildEdge{ - .rule = tool, - .outputs = {input_stamp_or_phony}, - .explicit_inputs = deps.implicit, - .order_only_inputs = deps.order_only, - .is_target_output = false, - }); + out_ << "build "; + path_output_.WriteFile(out_, input_stamp_or_phony); + out_ << ": " << tool; + path_output_.WriteFiles(out_, deps.implicit); + if (!deps.order_only.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, deps.order_only); + } + out_ << "\n"; InputDeps result; result.implicit.push_back(input_stamp_or_phony); @@ -708,30 +699,35 @@ } } - OutputFile output_file; - std::string rule; // We should have already discerned whether this target is a stamp or a phony. // If there's a dependency_output_file, it should be a stamp. Else is a phony // or omitted phony (in which case, we don't write it). if (target_->has_dependency_output_file()) { // Make a stamp target. - output_file = target_->dependency_output_file(); + const OutputFile& stamp_file = target_->dependency_output_file(); // First validate that the target's dependency is a stamp file. Otherwise, // we shouldn't have gotten here! - CHECK(base::EndsWithCaseInsensitiveASCII(output_file.value(), ".stamp")) + CHECK(base::EndsWithCaseInsensitiveASCII(stamp_file.value(), ".stamp")) << "Output should end in \".stamp\" for stamp file output. Instead " "got: " - << "\"" << output_file.value() << "\""; + << "\"" << stamp_file.value() << "\""; - rule = GetNinjaRulePrefixForToolchain(settings_) + - GeneralTool::kGeneralToolStamp; + out_ << "build "; + WriteOutput(stamp_file); + + out_ << ": " << GetNinjaRulePrefixForToolchain(settings_) + << GeneralTool::kGeneralToolStamp; } else if (target_->has_dependency_output_alias()) { // Make a phony target. - output_file = target_->dependency_output_alias(); - CHECK(!output_file.value().empty()); + const OutputFile& phony_target = target_->dependency_output_alias(); + CHECK(!phony_target.value().empty()); - rule = BuiltinTool::kBuiltinToolPhony; + out_ << "build "; + WriteOutput(phony_target); + + out_ << ": " << BuiltinTool::kBuiltinToolPhony; + } else { // This is the omitted phony case. We should not get here if there were any // dependencies, so ensure that none got added. @@ -740,21 +736,32 @@ return; } - NinjaBuildEdge edge{ - .rule = std::move(rule), - .outputs = {output_file}, - .explicit_inputs = std::move(all_files), - .order_only_inputs = order_only_deps, - }; - AddValidationInputs(edge); - AddEdge(std::move(edge)); + path_output_.WriteFiles(out_, all_files); + + if (!order_only_deps.empty()) { + out_ << " ||"; + path_output_.WriteFiles(out_, order_only_deps); + } + WriteValidations(); + out_ << std::endl; } -void NinjaTargetWriter::AddValidationInputs(NinjaBuildEdge& edge) const { - for (const auto& pair : target_->validations()) { +void NinjaTargetWriter::WriteValidations() { + const LabelTargetVector& validations = target_->validations(); + if (validations.empty()) + return; + + bool first = true; + for (const auto& pair : validations) { // This check is needed because empty groups have no output. - if (pair.ptr->has_dependency_output()) { - edge.validation_inputs.push_back(pair.ptr->dependency_output()); + if (!pair.ptr->has_dependency_output()) { + continue; } + if (first) { + out_ << " |@"; + first = false; + } + out_ << " "; + WriteOutput(pair.ptr->dependency_output()); } }
diff --git a/src/gn/ninja_target_writer.h b/src/gn/ninja_target_writer.h index a29a590..d7b2883 100644 --- a/src/gn/ninja_target_writer.h +++ b/src/gn/ninja_target_writer.h
@@ -7,7 +7,6 @@ #include <iosfwd> -#include "gn/ninja_file.h" #include "gn/path_output.h" #include "gn/resolved_target_data.h" #include "gn/substitution_type.h" @@ -24,12 +23,6 @@ NinjaTargetWriter(const Target* target, std::ostream& out); virtual ~NinjaTargetWriter(); - NinjaTargetGroup& target_group() { return target_group_; } - const NinjaTargetGroup& target_group() const { return target_group_; } - - void AddTargetVar(std::string_view name, std::string value); - void AddEdge(NinjaBuildEdge edge); - // Returns a ResolvedTargetData that can be used to retrieve information // from targets. The instance can be set through SetResolvedTargetData() // or may be created on demand otherwise (which is useful to keep unit-tests @@ -66,19 +59,11 @@ // false. static void WritePublicInputsStampOrPhony(const Target* target, ResolvedTargetData* resolved, - NinjaTargetGroup& group); + std::ostream& out); - // Generates and returns the populated NinjaTargetGroup by value. - NinjaTargetGroup GenerateTargetGroup(); - - // Runs rule generation and serializes the target's rules to out_. - void Run(); + virtual void Run() = 0; protected: - // Generates the NinjaTargetGroup (target variables and edges) without - // serializing. - virtual void GenerateRules() = 0; - // Returns a writable pointer to resolved(). Only used internally. ResolvedTargetData* GetResolvedTargetData(); @@ -94,18 +79,15 @@ // respect the types of source code used; otherwise they will respect the bits // passed in. void WriteCCompilerVars(const SubstitutionBits& bits, - bool respect_source_used, - std::vector<NinjaVariable>& target_vars); - void WriteCCompilerVars(const SubstitutionBits& bits, + bool indent, bool respect_source_used); // Writes out the substitution values that are shared between Rust tools // and action tools. Only the substitutions identified by the given bits will // be written, unless 'always_write' is specified. void WriteRustCompilerVars(const SubstitutionBits& bits, - bool always_write, - std::vector<NinjaVariable>& target_vars); - void WriteRustCompilerVars(const SubstitutionBits& bits, bool always_write); + bool indent, + bool always_write); struct InputDeps { std::vector<OutputFile> implicit; @@ -121,7 +103,7 @@ // are passed in, this returns an empty struct. InputDeps WriteInputDepsStampOrPhonyAndGetDep( const std::vector<const Target*>& additional_hard_deps, - size_t num_output_uses); + size_t num_output_uses) const; // Writes to the output file a final phony rule for the target that aliases // the given list of files. @@ -129,18 +111,23 @@ const std::vector<OutputFile>& deps, const std::vector<OutputFile>& order_only_deps); - // Appends the target's validation dependencies to the given edge. - void AddValidationInputs(NinjaBuildEdge& edge) const; - - // Converts a list of SourceFiles to OutputFiles relative to the build dir. - std::vector<OutputFile> ToOutputFiles( - const std::vector<SourceFile>& sources) const; + // Writes the validation dependencies to the output stream. + void WriteValidations(); const Settings* settings_; // Non-owning. const Target* target_; // Non-owning. std::ostream& out_; PathOutput path_output_; + // Write a Ninja output file to out_, and also add it to |*ninja_outputs_| + // if needed. + void WriteOutput(const OutputFile& output) const; + void WriteOutput(OutputFile&& output) const; + + // Same as WriteOutput() for a list of Ninja output file paths. + void WriteOutputs(const std::vector<OutputFile>& outputs) const; + void WriteOutputs(std::vector<OutputFile>&& outputs) const; + // The list of all Ninja output file paths generated by this writer for // this target. Used to implement the --ide=ninja_outputs `gn gen` flag. // Needs to be mutable because WriteOutput() and WriteOutputs() need to @@ -153,8 +140,6 @@ mutable ResolvedTargetData* resolved_ptr_ = nullptr; mutable std::unique_ptr<ResolvedTargetData> resolved_owned_; - NinjaTargetGroup target_group_; - private: void WriteCopyRules(); void WriteEscapedSubstitution(const Substitution* type);
diff --git a/src/gn/ninja_target_writer_unittest.cc b/src/gn/ninja_target_writer_unittest.cc index 10bd166..53b1a4d 100644 --- a/src/gn/ninja_target_writer_unittest.cc +++ b/src/gn/ninja_target_writer_unittest.cc
@@ -20,27 +20,20 @@ std::ostream& out) : NinjaTargetWriter(target, out) {} - void GenerateRules() override {} + void Run() override {} // Make this public so the test can call it. NinjaTargetWriter::InputDeps WriteInputDepsStampOrPhonyAndGetDep( const std::vector<const Target*>& additional_hard_deps, size_t num_stamp_uses) { - auto deps = NinjaTargetWriter::WriteInputDepsStampOrPhonyAndGetDep( + return NinjaTargetWriter::WriteInputDepsStampOrPhonyAndGetDep( additional_hard_deps, num_stamp_uses); - NinjaFile file; - file.AddTargetGroup(std::move(target_group_)); - file.Serialize(out_); - return deps; } void WriteStampOrPhonyForTarget( const std::vector<OutputFile>& deps, const std::vector<OutputFile>& order_only_deps) { NinjaTargetWriter::WriteStampOrPhonyForTarget(deps, order_only_deps); - NinjaFile file; - file.AddTargetGroup(std::move(target_group_)); - file.Serialize(out_); } }; @@ -162,7 +155,6 @@ " description = ACTION //foo:action()\n" " restat = 1\n" "\n" - "\n" "build: __foo_action___rule | ../../foo/script.py" " ../../foo/action_source.txt ./target\n" "\n" @@ -263,7 +255,6 @@ " description = ACTION //foo:action()\n" " restat = 1\n" "\n" - "\n" "build: __foo_action___rule | ../../foo/script.py" " ../../foo/action_source.txt ./target\n" "\n" @@ -549,7 +540,6 @@ " description = ACTION //foo:b_pub()\n" " restat = 1\n" "\n" - "\n" "build b_pub.out: __foo_b_pub___rule | ../../foo/script.py " "phony/foo/a\n" "\n" @@ -568,7 +558,6 @@ " description = ACTION //foo:b_priv()\n" " restat = 1\n" "\n" - "\n" "build b_priv.out: __foo_b_priv___rule | ../../foo/script.py " "phony/foo/a\n" "\n" @@ -618,7 +607,6 @@ " description = ACTION //foo:b_data()\n" " restat = 1\n" "\n" - "\n" "build b_data.out: __foo_b_data___rule | ../../foo/script.py || " "phony/foo/a\n" "\n" @@ -637,7 +625,6 @@ " description = ACTION //foo:c_data()\n" " restat = 1\n" "\n" - "\n" "build c_data.out: __foo_c_data___rule | ../../foo/script.py " "phony/foo/b_data\n" "\n" @@ -688,13 +675,9 @@ { std::ostringstream stream; ResolvedTargetData resolved; - NinjaTargetGroup group; TestingNinjaTargetWriter::WritePublicInputsStampOrPhony(&a, &resolved, - group); - NinjaFile file; - file.AddTargetGroup(std::move(group)); - file.Serialize(stream); - EXPECT_EQ("build phony/foo/a.public_inputs: phony ../../foo/a.in\n", + stream); + EXPECT_EQ("build phony/foo/a.public_inputs: phony ../../foo/a.in\n\n", stream.str()); } @@ -756,13 +739,9 @@ { std::ostringstream stream; ResolvedTargetData resolved; - NinjaTargetGroup group; TestingNinjaTargetWriter::WritePublicInputsStampOrPhony(&g, &resolved, - group); - NinjaFile file; - file.AddTargetGroup(std::move(group)); - file.Serialize(stream); - EXPECT_EQ("build phony/foo/g.public_inputs: phony ../../foo/g.in\n", + stream); + EXPECT_EQ("build phony/foo/g.public_inputs: phony ../../foo/g.in\n\n", stream.str()); }
diff --git a/src/gn/substitution_writer.cc b/src/gn/substitution_writer.cc index 23ea92b..b6d0c48 100644 --- a/src/gn/substitution_writer.cc +++ b/src/gn/substitution_writer.cc
@@ -8,7 +8,6 @@ #include "gn/c_substitution_type.h" #include "gn/escape.h" #include "gn/filesystem_utils.h" -#include "gn/ninja_file.h" #include "gn/output_file.h" #include "gn/rust_substitution_type.h" #include "gn/rust_tool.h" @@ -323,31 +322,6 @@ const SourceFile& source, const std::vector<const Substitution*>& types, const EscapeOptions& escape_options, - std::vector<NinjaVariable>& edge_vars) { - for (const auto& type : types) { - // Don't write SOURCE since that just maps to Ninja's $in variable, which - // is implicit in the rule. RESPONSE_FILE_NAME is written separately - // only when writing target rules since it can never be used in any - // other context (like process_file_template). - if (type != &SubstitutionSource && type != &SubstitutionRspFileName) { - std::ostringstream val; - EscapeStringToStream( - val, - GetSourceSubstitution(target, settings, source, type, OUTPUT_RELATIVE, - settings->build_settings()->build_dir()), - escape_options); - edge_vars.emplace_back(type->ninja_name, val.str()); - } - } -} - -// static -void SubstitutionWriter::WriteNinjaVariablesForSource( - const Target* target, - const Settings* settings, - const SourceFile& source, - const std::vector<const Substitution*>& types, - const EscapeOptions& escape_options, std::ostream& out) { for (const auto& type : types) { // Don't write SOURCE since that just maps to Ninja's $in variable, which
diff --git a/src/gn/substitution_writer.h b/src/gn/substitution_writer.h index c7da823..95e4b94 100644 --- a/src/gn/substitution_writer.h +++ b/src/gn/substitution_writer.h
@@ -9,7 +9,6 @@ #include <string> #include <vector> -#include "gn/ninja_file.h" #include "gn/substitution_type.h" struct EscapeOptions; @@ -158,13 +157,6 @@ const SourceFile& source, const std::vector<const Substitution*>& types, const EscapeOptions& escape_options, - std::vector<NinjaVariable>& edge_vars); - static void WriteNinjaVariablesForSource( - const Target* target, - const Settings* settings, - const SourceFile& source, - const std::vector<const Substitution*>& types, - const EscapeOptions& escape_options, std::ostream& out); // Extracts the given type of substitution related to a source file from the