• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gn/ninja_build_writer.h"
6 
7 #include <stddef.h>
8 
9 #include <fstream>
10 #include <map>
11 #include <set>
12 #include <sstream>
13 
14 #include "base/command_line.h"
15 #include "base/files/file_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "gn/build_settings.h"
19 #include "gn/builder.h"
20 #include "gn/err.h"
21 #include "gn/escape.h"
22 #include "gn/filesystem_utils.h"
23 #include "gn/input_file_manager.h"
24 #include "gn/loader.h"
25 #include "gn/ninja_utils.h"
26 #include "gn/pool.h"
27 #include "gn/scheduler.h"
28 #include "gn/string_atom.h"
29 #include "gn/switches.h"
30 #include "gn/target.h"
31 #include "gn/trace.h"
32 #include "util/build_config.h"
33 #include "util/exe_path.h"
34 
35 #if defined(OS_WIN)
36 #include <windows.h>
37 #endif
38 
39 namespace {
40 
41 struct Counts {
Counts__anon0ef783d00111::Counts42   Counts() : count(0), last_seen(nullptr) {}
43 
44   // Number of targets of this type.
45   int count;
46 
47   // The last one we encountered.
48   const Target* last_seen;
49 };
50 
51 }  // namespace
52 
GetSelfInvocationCommandLine(const BuildSettings * build_settings)53 base::CommandLine GetSelfInvocationCommandLine(
54     const BuildSettings* build_settings) {
55   const base::FilePath build_path =
56       build_settings->build_dir().Resolve(build_settings->root_path());
57 
58   base::FilePath exe_path = GetExePath();
59   if (build_path.IsAbsolute())
60     exe_path = MakeAbsoluteFilePathRelativeIfPossible(build_path, exe_path);
61 
62   base::CommandLine cmdline(exe_path.NormalizePathSeparatorsTo('/'));
63 
64   // Use "." for the directory to generate. When Ninja runs the command it
65   // will have the build directory as the current one. Coding it explicitly
66   // will cause everything to get confused if the user renames the directory.
67   cmdline.AppendArg("gen");
68   cmdline.AppendArg(".");
69 
70   base::FilePath root_path = build_settings->root_path();
71   if (build_path.IsAbsolute())
72     root_path = MakeAbsoluteFilePathRelativeIfPossible(build_path, root_path);
73 
74   cmdline.AppendSwitchPath(std::string("--") + switches::kRoot,
75                            root_path.NormalizePathSeparatorsTo('/'));
76   // Successful automatic invocations shouldn't print output.
77   cmdline.AppendSwitch(std::string("-") + switches::kQuiet);
78 
79   EscapeOptions escape_shell;
80   escape_shell.mode = ESCAPE_NINJA_COMMAND;
81 #if defined(OS_WIN)
82   // The command line code quoting varies by platform. We have one string,
83   // possibly with spaces, that we want to quote. The Windows command line
84   // quotes again, so we don't want quoting. The Posix one doesn't.
85   escape_shell.inhibit_quoting = true;
86 #endif
87 
88   // If both --root and --dotfile are passed, make sure the --dotfile is
89   // made relative to the build dir here.
90   base::FilePath dotfile_path = build_settings->dotfile_name();
91   if (!dotfile_path.empty()) {
92     if (build_path.IsAbsolute()) {
93       dotfile_path =
94           MakeAbsoluteFilePathRelativeIfPossible(build_path, dotfile_path);
95     }
96     cmdline.AppendSwitchPath(std::string("--") + switches::kDotfile,
97                              dotfile_path.NormalizePathSeparatorsTo('/'));
98   }
99 
100   const base::CommandLine& our_cmdline =
101       *base::CommandLine::ForCurrentProcess();
102   const base::CommandLine::SwitchMap& switches = our_cmdline.GetSwitches();
103   for (base::CommandLine::SwitchMap::const_iterator i = switches.begin();
104        i != switches.end(); ++i) {
105     // Only write arguments we haven't already written. Always skip "args"
106     // since those will have been written to the file and will be used
107     // implicitly in the future. Keeping --args would mean changes to the file
108     // would be ignored.
109     if (i->first != switches::kQuiet && i->first != switches::kRoot &&
110         i->first != switches::kDotfile && i->first != switches::kArgs) {
111       std::string escaped_value =
112           EscapeString(FilePathToUTF8(i->second), escape_shell, nullptr);
113       cmdline.AppendSwitchASCII(i->first, escaped_value);
114     }
115   }
116 
117   // Add the regeneration switch if not already present. This is so that when
118   // the regeneration is invoked by ninja, the gen command is aware that it is a
119   // regeneration invocation and not an user invocation. This allows the gen
120   // command to elide ninja post processing steps that ninja will perform
121   // itself.
122   if (!cmdline.HasSwitch(switches::kRegeneration)) {
123     cmdline.AppendSwitch(switches::kRegeneration);
124   }
125 
126   return cmdline;
127 }
128 
129 namespace {
130 
GetSelfInvocationCommand(const BuildSettings * build_settings)131 std::string GetSelfInvocationCommand(const BuildSettings* build_settings) {
132   base::CommandLine cmdline = GetSelfInvocationCommandLine(build_settings);
133 #if defined(OS_WIN)
134   return base::UTF16ToUTF8(cmdline.GetCommandLineString());
135 #else
136   return cmdline.GetCommandLineString();
137 #endif
138 }
139 
140 // Given an output that appears more than once, generates an error message
141 // that describes the problem and which targets generate it.
GetDuplicateOutputError(const std::vector<const Target * > & all_targets,const OutputFile & bad_output)142 Err GetDuplicateOutputError(const std::vector<const Target*>& all_targets,
143                             const OutputFile& bad_output) {
144   std::vector<const Target*> matches;
145   for (const Target* target : all_targets) {
146     for (const auto& output : target->computed_outputs()) {
147       if (output == bad_output) {
148         matches.push_back(target);
149         break;
150       }
151     }
152   }
153 
154   // There should always be at least two targets generating this file for this
155   // function to be called in the first place.
156   DCHECK(matches.size() >= 2);
157   std::string matches_string;
158   for (const Target* target : matches)
159     matches_string += "  " + target->label().GetUserVisibleName(true) + "\n";
160 
161   Err result(matches[0]->defined_from(), "Duplicate output file.",
162              "Two or more targets generate the same output:\n  " +
163                  bad_output.value() +
164                  "\n\n"
165                  "This is can often be fixed by changing one of the target "
166                  "names, or by \n"
167                  "setting an output_name on one of them.\n"
168                  "\nCollisions:\n" +
169                  matches_string);
170   for (size_t i = 1; i < matches.size(); i++)
171     result.AppendSubErr(Err(matches[i]->defined_from(), "Collision."));
172   return result;
173 }
174 
175 // Given two toolchains with the same name, generates an error message
176 // that describes the problem.
GetDuplicateToolchainError(const SourceFile & source_file,const Toolchain * previous_toolchain,const Toolchain * toolchain)177 Err GetDuplicateToolchainError(const SourceFile& source_file,
178                                const Toolchain* previous_toolchain,
179                                const Toolchain* toolchain) {
180   Err result(
181       toolchain->defined_from(), "Duplicate toolchain.",
182       "Two or more toolchains write to the same directory:\n  " +
183           source_file.GetDir().value() +
184           "\n\n"
185           "This can be fixed by making sure that distinct toolchains have\n"
186           "distinct names.\n");
187   result.AppendSubErr(
188       Err(previous_toolchain->defined_from(), "Previous toolchain."));
189   return result;
190 }
191 
192 }  // namespace
193 
NinjaBuildWriter(const BuildSettings * build_settings,const std::unordered_map<const Settings *,const Toolchain * > & used_toolchains,const std::vector<const Target * > & all_targets,const Toolchain * default_toolchain,const std::vector<const Target * > & default_toolchain_targets,std::ostream & out,std::ostream & dep_out)194 NinjaBuildWriter::NinjaBuildWriter(
195     const BuildSettings* build_settings,
196     const std::unordered_map<const Settings*, const Toolchain*>&
197         used_toolchains,
198     const std::vector<const Target*>& all_targets,
199     const Toolchain* default_toolchain,
200     const std::vector<const Target*>& default_toolchain_targets,
201     std::ostream& out,
202     std::ostream& dep_out)
203     : build_settings_(build_settings),
204       used_toolchains_(used_toolchains),
205       all_targets_(all_targets),
206       default_toolchain_(default_toolchain),
207       default_toolchain_targets_(default_toolchain_targets),
208       out_(out),
209       dep_out_(dep_out),
210       path_output_(build_settings->build_dir(),
211                    build_settings->root_path_utf8(),
212                    ESCAPE_NINJA) {}
213 
214 NinjaBuildWriter::~NinjaBuildWriter() = default;
215 
Run(Err * err)216 bool NinjaBuildWriter::Run(Err* err) {
217   WriteNinjaRules();
218   WriteAllPools();
219   return WriteSubninjas(err) && WritePhonyAndAllRules(err);
220 }
221 
222 // static
RunAndWriteFile(const BuildSettings * build_settings,const Builder & builder,Err * err)223 bool NinjaBuildWriter::RunAndWriteFile(const BuildSettings* build_settings,
224                                        const Builder& builder,
225                                        Err* err) {
226   ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja");
227 
228   std::vector<const Target*> all_targets = builder.GetAllResolvedTargets();
229   std::unordered_map<const Settings*, const Toolchain*> used_toolchains;
230 
231   // Find the default toolchain info.
232   Label default_toolchain_label = builder.loader()->GetDefaultToolchain();
233   const Settings* default_toolchain_settings =
234       builder.loader()->GetToolchainSettings(default_toolchain_label);
235   const Toolchain* default_toolchain =
236       builder.GetToolchain(default_toolchain_label);
237 
238   // Most targets will be in the default toolchain. Add it at the beginning and
239   // skip adding it to the list every time in the loop.
240   used_toolchains[default_toolchain_settings] = default_toolchain;
241 
242   std::vector<const Target*> default_toolchain_targets;
243   default_toolchain_targets.reserve(all_targets.size());
244   for (const Target* target : all_targets) {
245     if (target->settings() == default_toolchain_settings) {
246       default_toolchain_targets.push_back(target);
247       // The default toolchain will already have been added to the used
248       // settings array.
249     } else if (used_toolchains.find(target->settings()) ==
250                used_toolchains.end()) {
251       used_toolchains[target->settings()] =
252           builder.GetToolchain(target->settings()->toolchain_label());
253     }
254   }
255 
256   std::stringstream file;
257   std::stringstream depfile;
258   NinjaBuildWriter gen(build_settings, used_toolchains, all_targets,
259                        default_toolchain, default_toolchain_targets, file,
260                        depfile);
261   if (!gen.Run(err))
262     return false;
263 
264   // Unconditionally write the build.ninja. Ninja's build-out-of-date checking
265   // will re-run GN when any build input is newer than build.ninja, so any time
266   // the build is updated, build.ninja's timestamp needs to updated also, even
267   // if the contents haven't been changed.
268   base::FilePath ninja_file_name(build_settings->GetFullPath(
269       SourceFile(build_settings->build_dir().value() + "build.ninja")));
270   base::CreateDirectory(ninja_file_name.DirName());
271   std::string ninja_contents = file.str();
272   if (base::WriteFile(ninja_file_name, ninja_contents.data(),
273                       static_cast<int>(ninja_contents.size())) !=
274       static_cast<int>(ninja_contents.size()))
275     return false;
276 
277   // Dep file listing build dependencies.
278   base::FilePath dep_file_name(build_settings->GetFullPath(
279       SourceFile(build_settings->build_dir().value() + "build.ninja.d")));
280   std::string dep_contents = depfile.str();
281   if (base::WriteFile(dep_file_name, dep_contents.data(),
282                       static_cast<int>(dep_contents.size())) !=
283       static_cast<int>(dep_contents.size()))
284     return false;
285 
286   return true;
287 }
288 
WriteNinjaRules()289 void NinjaBuildWriter::WriteNinjaRules() {
290   out_ << "ninja_required_version = "
291        << build_settings_->ninja_required_version().Describe() << "\n\n";
292   out_ << "rule gn\n";
293   out_ << "  command = " << GetSelfInvocationCommand(build_settings_) << "\n";
294   // Putting gn rule to console pool for colorful output on regeneration
295   out_ << "  pool = console\n";
296   out_ << "  description = Regenerating ninja files\n\n";
297 
298   // This rule will regenerate the ninja files when any input file has changed.
299   out_ << "build build.ninja: gn\n"
300        << "  generator = 1\n"
301        << "  depfile = build.ninja.d\n";
302 
303   // Input build files. These go in the ".d" file. If we write them as
304   // dependencies in the .ninja file itself, ninja will expect the files to
305   // exist and will error if they don't. When files are listed in a depfile,
306   // missing files are ignored.
307   dep_out_ << "build.ninja:";
308 
309   // Other files read by the build.
310   std::vector<base::FilePath> other_files = g_scheduler->GetGenDependencies();
311 
312   const InputFileManager* input_file_manager =
313       g_scheduler->input_file_manager();
314 
315   VectorSetSorter<base::FilePath> sorter(
316       input_file_manager->GetInputFileCount() + other_files.size());
317 
318   input_file_manager->AddAllPhysicalInputFileNamesToVectorSetSorter(&sorter);
319   sorter.Add(other_files.begin(), other_files.end());
320 
321   const base::FilePath build_path =
322       build_settings_->build_dir().Resolve(build_settings_->root_path());
323 
324   EscapeOptions depfile_escape;
325   depfile_escape.mode = ESCAPE_DEPFILE;
326   auto item_callback = [this, &depfile_escape,
327                         &build_path](const base::FilePath& input_file) {
328     const base::FilePath file =
329         MakeAbsoluteFilePathRelativeIfPossible(build_path, input_file);
330     dep_out_ << " ";
331     EscapeStringToStream(dep_out_,
332                          FilePathToUTF8(file.NormalizePathSeparatorsTo('/')),
333                          depfile_escape);
334   };
335 
336   sorter.IterateOver(item_callback);
337 
338   out_ << std::endl;
339 }
340 
WriteAllPools()341 void NinjaBuildWriter::WriteAllPools() {
342   // Compute the pools referenced by all tools of all used toolchains.
343   std::set<const Pool*> used_pools;
344   for (const auto& pair : used_toolchains_) {
345     for (const auto& tool : pair.second->tools()) {
346       if (tool.second->pool().ptr)
347         used_pools.insert(tool.second->pool().ptr);
348     }
349   }
350 
351   for (const Target* target : all_targets_) {
352     if (target->output_type() == Target::ACTION) {
353       const LabelPtrPair<Pool>& pool = target->action_values().pool();
354       if (pool.ptr)
355         used_pools.insert(pool.ptr);
356     }
357   }
358 
359   // Write pools sorted by their name, to make output deterministic.
360   std::vector<const Pool*> sorted_pools(used_pools.begin(), used_pools.end());
361   auto pool_name = [this](const Pool* pool) {
362     return pool->GetNinjaName(default_toolchain_->label());
363   };
364   std::sort(sorted_pools.begin(), sorted_pools.end(),
365             [&pool_name](const Pool* a, const Pool* b) {
366               return pool_name(a) < pool_name(b);
367             });
368   for (const Pool* pool : sorted_pools) {
369     std::string name = pool_name(pool);
370     if (name == "console")
371       continue;
372     out_ << "pool " << name << std::endl
373          << "  depth = " << pool->depth() << std::endl
374          << std::endl;
375   }
376 }
377 
WriteSubninjas(Err * err)378 bool NinjaBuildWriter::WriteSubninjas(Err* err) {
379   // Write toolchains sorted by their name, to make output deterministic.
380   std::vector<std::pair<const Settings*, const Toolchain*>> sorted_settings(
381       used_toolchains_.begin(), used_toolchains_.end());
382   std::sort(sorted_settings.begin(), sorted_settings.end(),
383             [this](const std::pair<const Settings*, const Toolchain*>& a,
384                    const std::pair<const Settings*, const Toolchain*>& b) {
385               // Always put the default toolchain first.
386               if (b.second == default_toolchain_)
387                 return false;
388               if (a.second == default_toolchain_)
389                 return true;
390               return GetNinjaFileForToolchain(a.first) <
391                      GetNinjaFileForToolchain(b.first);
392             });
393 
394   SourceFile previous_subninja;
395   const Toolchain* previous_toolchain = nullptr;
396 
397   for (const auto& pair : sorted_settings) {
398     SourceFile subninja = GetNinjaFileForToolchain(pair.first);
399 
400     // Since the toolchains are sorted, comparing to the previous subninja is
401     // enough to find duplicates.
402     if (subninja == previous_subninja) {
403       *err =
404           GetDuplicateToolchainError(subninja, previous_toolchain, pair.second);
405       return false;
406     }
407 
408     out_ << "subninja ";
409     path_output_.WriteFile(out_, subninja);
410     out_ << std::endl;
411     previous_subninja = subninja;
412     previous_toolchain = pair.second;
413   }
414   out_ << std::endl;
415   return true;
416 }
417 
418 const char kNinjaRules_Help[] =
419     R"(Ninja build rules
420 
421 The "all" and "default" rules
422 
423   All generated targets (see "gn help execution") will be added to an implicit
424   build rule called "all" so "ninja all" will always compile everything. The
425   default rule will be used by Ninja if no specific target is specified (just
426   typing "ninja"). If there is a target named "default" in the root build file,
427   it will be the default build rule, otherwise the implicit "all" rule will be
428   used.
429 
430 Phony rules
431 
432   GN generates Ninja "phony" rules for targets in the default toolchain.  The
433   phony rules can collide with each other and with the names of generated files
434   so are generated with the following priority:
435 
436     1. Actual files generated by the build always take precedence.
437 
438     2. Targets in the toplevel //BUILD.gn file.
439 
440     3. Targets in toplevel directories matching the names of the directories.
441        So "ninja foo" can be used to compile "//foo:foo". This only applies to
442        the first level of directories since usually these are the most
443        important (so this won't apply to "//foo/bar:bar").
444 
445     4. The short names of executables if there is only one executable with that
446        short name. Use "ninja doom_melon" to compile the
447        "//tools/fruit:doom_melon" executable.
448 
449     5. The short names of all targets if there is only one target with that
450        short name.
451 
452     6. Full label name with no leading slashes. So you can use
453        "ninja tools/fruit:doom_melon" to build "//tools/fruit:doom_melon".
454 
455     7. Labels with an implicit name part (when the short names match the
456        directory). So you can use "ninja foo/bar" to compile "//foo/bar:bar".
457 
458   These "phony" rules are provided only for running Ninja since this matches
459   people's historical expectations for building. For consistency with the rest
460   of the program, GN introspection commands accept explicit labels.
461 
462   To explicitly compile a target in a non-default toolchain, you must give
463   Ninja the exact name of the output file relative to the build directory.
464 )";
465 
WritePhonyAndAllRules(Err * err)466 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
467   // Track rules as we generate them so we don't accidentally write a phony
468   // rule that collides with something else.
469   // GN internally generates an "all" target, so don't duplicate it.
470   std::set<StringAtom, StringAtom::PtrCompare> written_rules;
471   written_rules.insert(StringAtom("all"));
472 
473   // Set if we encounter a target named "//:default".
474   const Target* default_target = nullptr;
475 
476   // Targets in the root build file.
477   std::vector<const Target*> toplevel_targets;
478 
479   // Targets with names matching their toplevel directories. For example
480   // "//foo:foo". Expect this is the naming scheme for "big components."
481   std::vector<const Target*> toplevel_dir_targets;
482 
483   // Tracks the number of each target with the given short name, as well
484   // as the short names of executables (which will be a subset of short_names).
485   std::map<std::string, Counts> short_names;
486   std::map<std::string, Counts> exes;
487 
488   // ----------------------------------------------------
489   // If you change this algorithm, update the help above!
490   // ----------------------------------------------------
491 
492   for (const Target* target : default_toolchain_targets_) {
493     const Label& label = target->label();
494     const std::string& short_name = label.name();
495 
496     if (label.dir() == build_settings_->root_target_label().dir() &&
497         short_name == "default")
498       default_target = target;
499 
500     // Count the number of targets with the given short name.
501     Counts& short_names_counts = short_names[short_name];
502     short_names_counts.count++;
503     short_names_counts.last_seen = target;
504 
505     // Count executables with the given short name.
506     if (target->output_type() == Target::EXECUTABLE) {
507       Counts& exes_counts = exes[short_name];
508       exes_counts.count++;
509       exes_counts.last_seen = target;
510     }
511 
512     // Find targets in "important" directories.
513     const std::string& dir_string = label.dir().value();
514     if (dir_string.size() == 2 && dir_string[0] == '/' &&
515         dir_string[1] == '/') {
516       toplevel_targets.push_back(target);
517     } else if (dir_string.size() == label.name().size() + 3 &&  // Size matches.
518                dir_string[0] == '/' &&
519                dir_string[1] == '/' &&  // "//" at beginning.
520                dir_string[dir_string.size() - 1] == '/' &&  // "/" at end.
521                dir_string.compare(2, label.name().size(), label.name()) == 0) {
522       toplevel_dir_targets.push_back(target);
523     }
524 
525     // Add the output files from each target to the written rules so that
526     // we don't write phony rules that collide with anything generated by the
527     // build.
528     //
529     // If at this point there is a collision (no phony rules have been
530     // generated yet), two targets make the same output so throw an error.
531     for (const auto& output : target->computed_outputs()) {
532       // Need to normalize because many toolchain outputs will be preceded
533       // with "./".
534       std::string output_string(output.value());
535       NormalizePath(&output_string);
536       const StringAtom output_string_atom(output_string);
537 
538       if (!written_rules.insert(output_string_atom).second) {
539         *err = GetDuplicateOutputError(default_toolchain_targets_, output);
540         return false;
541       }
542     }
543   }
544 
545   // First prefer the short names of toplevel targets.
546   for (const Target* target : toplevel_targets) {
547     if (written_rules.insert(target->label().name_atom()).second)
548       WritePhonyRule(target, target->label().name_atom());
549   }
550 
551   // Next prefer short names of toplevel dir targets.
552   for (const Target* target : toplevel_dir_targets) {
553     if (written_rules.insert(target->label().name_atom()).second)
554       WritePhonyRule(target, target->label().name_atom());
555   }
556 
557   // Write out the names labels of executables. Many toolchains will produce
558   // executables in the root build directory with no extensions, so the names
559   // will already exist and this will be a no-op.  But on Windows such programs
560   // will have extensions, and executables may override the output directory to
561   // go into some other place.
562   //
563   // Putting this after the "toplevel" rules above also means that you can
564   // steal the short name from an executable by outputting the executable to
565   // a different directory or using a different output name, and writing a
566   // toplevel build rule.
567   for (const auto& pair : exes) {
568     const Counts& counts = pair.second;
569     const StringAtom& short_name = counts.last_seen->label().name_atom();
570     if (counts.count == 1 && written_rules.insert(short_name).second)
571       WritePhonyRule(counts.last_seen, short_name);
572   }
573 
574   // Write short names when those names are unique and not already taken.
575   for (const auto& pair : short_names) {
576     const Counts& counts = pair.second;
577     const StringAtom& short_name = counts.last_seen->label().name_atom();
578     if (counts.count == 1 && written_rules.insert(short_name).second)
579       WritePhonyRule(counts.last_seen, short_name);
580   }
581 
582   // Write the label variants of the target name.
583   for (const Target* target : default_toolchain_targets_) {
584     const Label& label = target->label();
585 
586     // Write the long name "foo/bar:baz" for the target "//foo/bar:baz".
587     std::string long_name = label.GetUserVisibleName(false);
588     base::TrimString(long_name, "/", &long_name);
589     const StringAtom long_name_atom(long_name);
590     if (written_rules.insert(long_name_atom).second)
591       WritePhonyRule(target, long_name_atom);
592 
593     // Write the directory name with no target name if they match
594     // (e.g. "//foo/bar:bar" -> "foo/bar").
595     if (FindLastDirComponent(label.dir()) == label.name()) {
596       std::string medium_name = DirectoryWithNoLastSlash(label.dir());
597       base::TrimString(medium_name, "/", &medium_name);
598       const StringAtom medium_name_atom(medium_name);
599 
600       // That may have generated a name the same as the short name of the
601       // target which we already wrote.
602       if (medium_name != label.name() &&
603           written_rules.insert(medium_name_atom).second)
604         WritePhonyRule(target, medium_name_atom);
605     }
606   }
607 
608   // Write the autogenerated "all" rule.
609   if (!default_toolchain_targets_.empty()) {
610     out_ << "\nbuild all: phony";
611 
612     EscapeOptions ninja_escape;
613     ninja_escape.mode = ESCAPE_NINJA;
614     for (const Target* target : default_toolchain_targets_) {
615       out_ << " $\n    ";
616       path_output_.WriteFile(out_, target->dependency_output_file());
617     }
618   }
619   out_ << std::endl;
620 
621   if (default_target) {
622     // Use the short name when available
623     if (written_rules.find(StringAtom("default")) != written_rules.end()) {
624       out_ << "\ndefault default" << std::endl;
625     } else {
626       out_ << "\ndefault ";
627       path_output_.WriteFile(out_, default_target->dependency_output_file());
628       out_ << std::endl;
629     }
630   } else if (!default_toolchain_targets_.empty()) {
631     out_ << "\ndefault all" << std::endl;
632   }
633 
634   return true;
635 }
636 
WritePhonyRule(const Target * target,std::string_view phony_name)637 void NinjaBuildWriter::WritePhonyRule(const Target* target,
638                                       std::string_view phony_name) {
639   EscapeOptions ninja_escape;
640   ninja_escape.mode = ESCAPE_NINJA;
641 
642   // Escape for special chars Ninja will handle.
643   std::string escaped = EscapeString(phony_name, ninja_escape, nullptr);
644 
645   out_ << "build " << escaped << ": phony ";
646   path_output_.WriteFile(out_, target->dependency_output_file());
647   out_ << std::endl;
648 }
649