• 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/commands.h"
6 
7 #include <optional>
8 
9 #include "base/command_line.h"
10 #include "base/environment.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "gn/builder.h"
15 #include "gn/config_values_extractors.h"
16 #include "gn/filesystem_utils.h"
17 #include "gn/item.h"
18 #include "gn/label.h"
19 #include "gn/label_pattern.h"
20 #include "gn/setup.h"
21 #include "gn/standard_out.h"
22 #include "gn/switches.h"
23 #include "gn/target.h"
24 #include "util/build_config.h"
25 
26 namespace commands {
27 
28 namespace {
29 
30 // Like above but the input string can be a pattern that matches multiple
31 // targets. If the input does not parse as a pattern, prints and error and
32 // returns false. If the pattern is valid, fills the vector (which might be
33 // empty if there are no matches) and returns true.
34 //
35 // If default_toolchain_only is true, a pattern with an unspecified toolchain
36 // will match the default toolchain only. If true, all toolchains will be
37 // matched.
ResolveTargetsFromCommandLinePattern(Setup * setup,const std::string & label_pattern,bool default_toolchain_only,std::vector<const Target * > * matches)38 bool ResolveTargetsFromCommandLinePattern(Setup* setup,
39                                           const std::string& label_pattern,
40                                           bool default_toolchain_only,
41                                           std::vector<const Target*>* matches) {
42   Value pattern_value(nullptr, label_pattern);
43 
44   Err err;
45   LabelPattern pattern = LabelPattern::GetPattern(
46       SourceDirForCurrentDirectory(setup->build_settings().root_path()),
47       setup->build_settings().root_path_utf8(), pattern_value, &err);
48   if (err.has_error()) {
49     err.PrintToStdout();
50     return false;
51   }
52 
53   if (default_toolchain_only) {
54     // By default a pattern with an empty toolchain will match all toolchains.
55     // If the caller wants to default to the main toolchain only, set it
56     // explicitly.
57     if (pattern.toolchain().is_null()) {
58       // No explicit toolchain set.
59       pattern.set_toolchain(setup->loader()->default_toolchain_label());
60     }
61   }
62 
63   std::vector<LabelPattern> pattern_vector;
64   pattern_vector.push_back(pattern);
65   FilterTargetsByPatterns(setup->builder().GetAllResolvedTargets(),
66                           pattern_vector, matches);
67   return true;
68 }
69 
70 // If there's an error, it will be printed and false will be returned.
ResolveStringFromCommandLineInput(Setup * setup,const SourceDir & current_dir,const std::string & input,bool default_toolchain_only,UniqueVector<const Target * > * target_matches,UniqueVector<const Config * > * config_matches,UniqueVector<const Toolchain * > * toolchain_matches,UniqueVector<SourceFile> * file_matches)71 bool ResolveStringFromCommandLineInput(
72     Setup* setup,
73     const SourceDir& current_dir,
74     const std::string& input,
75     bool default_toolchain_only,
76     UniqueVector<const Target*>* target_matches,
77     UniqueVector<const Config*>* config_matches,
78     UniqueVector<const Toolchain*>* toolchain_matches,
79     UniqueVector<SourceFile>* file_matches) {
80   if (LabelPattern::HasWildcard(input)) {
81     // For now, only match patterns against targets. It might be nice in the
82     // future to allow the user to specify which types of things they want to
83     // match, but it should probably only match targets by default.
84     std::vector<const Target*> target_match_vector;
85     if (!ResolveTargetsFromCommandLinePattern(
86             setup, input, default_toolchain_only, &target_match_vector))
87       return false;
88     for (const Target* target : target_match_vector)
89       target_matches->push_back(target);
90     return true;
91   }
92 
93   // Try to figure out what this thing is.
94   Err err;
95   Label label = Label::Resolve(
96       current_dir, setup->build_settings().root_path_utf8(),
97       setup->loader()->default_toolchain_label(), Value(nullptr, input), &err);
98   if (err.has_error()) {
99     // Not a valid label, assume this must be a file.
100     err = Err();
101     file_matches->push_back(current_dir.ResolveRelativeFile(
102         Value(nullptr, input), &err, setup->build_settings().root_path_utf8()));
103     if (err.has_error()) {
104       err.PrintToStdout();
105       return false;
106     }
107     return true;
108   }
109 
110   const Item* item = setup->builder().GetItem(label);
111   if (item) {
112     if (const Config* as_config = item->AsConfig())
113       config_matches->push_back(as_config);
114     else if (const Target* as_target = item->AsTarget())
115       target_matches->push_back(as_target);
116     else if (const Toolchain* as_toolchain = item->AsToolchain())
117       toolchain_matches->push_back(as_toolchain);
118   } else {
119     // Not an item, assume this must be a file.
120     file_matches->push_back(current_dir.ResolveRelativeFile(
121         Value(nullptr, input), &err, setup->build_settings().root_path_utf8()));
122     if (err.has_error()) {
123       err.PrintToStdout();
124       return false;
125     }
126   }
127 
128   return true;
129 }
130 
131 // Retrieves the target printing mode based on the command line flags for the
132 // current process. Returns true on success. On error, prints a message to the
133 // console and returns false.
GetTargetPrintingMode(CommandSwitches::TargetPrintMode * mode)134 bool GetTargetPrintingMode(CommandSwitches::TargetPrintMode* mode) {
135   *mode = CommandSwitches::Get().target_print_mode();
136   return true;
137 }
138 
139 // Returns the target type filter based on the command line flags for the
140 // current process. Returns true on success. On error, prints a message to the
141 // console and returns false.
142 //
143 // Target::UNKNOWN will be set if there is no filter. Target::ACTION_FOREACH
144 // will never be returned. Code applying the filters should apply Target::ACTION
145 // to both ACTION and ACTION_FOREACH.
GetTargetTypeFilter(Target::OutputType * type)146 bool GetTargetTypeFilter(Target::OutputType* type) {
147   *type = CommandSwitches::Get().target_type();
148   return true;
149 }
150 
151 // Applies any testonly filtering specified on the command line to the given
152 // target set. On failure, prints an error and returns false.
ApplyTestonlyFilter(std::vector<const Target * > * targets)153 bool ApplyTestonlyFilter(std::vector<const Target*>* targets) {
154   CommandSwitches::TestonlyMode testonly_mode =
155       CommandSwitches::Get().testonly_mode();
156 
157   if (targets->empty() || testonly_mode == CommandSwitches::TESTONLY_NONE)
158     return true;
159 
160   bool testonly = (testonly_mode == CommandSwitches::TESTONLY_TRUE);
161 
162   // Filter into a copy of the vector, then replace the output.
163   std::vector<const Target*> result;
164   result.reserve(targets->size());
165 
166   for (const Target* target : *targets) {
167     if (target->testonly() == testonly)
168       result.push_back(target);
169   }
170 
171   *targets = std::move(result);
172   return true;
173 }
174 
175 // Applies any target type filtering specified on the command line to the given
176 // target set. On failure, prints an error and returns false.
ApplyTypeFilter(std::vector<const Target * > * targets)177 bool ApplyTypeFilter(std::vector<const Target*>* targets) {
178   Target::OutputType type = Target::UNKNOWN;
179   if (!GetTargetTypeFilter(&type))
180     return false;
181   if (targets->empty() || type == Target::UNKNOWN)
182     return true;  // Nothing to filter out.
183 
184   // Filter into a copy of the vector, then replace the output.
185   std::vector<const Target*> result;
186   result.reserve(targets->size());
187 
188   for (const Target* target : *targets) {
189     // Make "action" also apply to ACTION_FOREACH.
190     if (target->output_type() == type ||
191         (type == Target::ACTION &&
192          target->output_type() == Target::ACTION_FOREACH))
193       result.push_back(target);
194   }
195 
196   *targets = std::move(result);
197   return true;
198 }
199 
200 // Returns the file path generating this item.
BuildFileForItem(const Item * item)201 base::FilePath BuildFileForItem(const Item* item) {
202   return item->defined_from()->GetRange().begin().file()->physical_name();
203 }
204 
PrintTargetsAsBuildfiles(const std::vector<const Target * > & targets,base::ListValue * out)205 void PrintTargetsAsBuildfiles(const std::vector<const Target*>& targets,
206                               base::ListValue* out) {
207   // Output the set of unique source files.
208   std::set<std::string> unique_files;
209   for (const Target* target : targets)
210     unique_files.insert(FilePathToUTF8(BuildFileForItem(target)));
211 
212   for (const std::string& file : unique_files) {
213     out->AppendString(file);
214   }
215 }
216 
PrintTargetsAsLabels(const std::vector<const Target * > & targets,base::ListValue * out)217 void PrintTargetsAsLabels(const std::vector<const Target*>& targets,
218                           base::ListValue* out) {
219   // Putting the labels into a set automatically sorts them for us.
220   std::set<Label> unique_labels;
221   for (auto* target : targets)
222     unique_labels.insert(target->label());
223 
224   // Grab the label of the default toolchain from the first target.
225   Label default_tc_label = targets[0]->settings()->default_toolchain_label();
226 
227   for (const Label& label : unique_labels) {
228     // Print toolchain only for ones not in the default toolchain.
229     out->AppendString(label.GetUserVisibleName(label.GetToolchainLabel() !=
230                                                default_tc_label));
231   }
232 }
233 
PrintTargetsAsOutputs(const std::vector<const Target * > & targets,base::ListValue * out)234 void PrintTargetsAsOutputs(const std::vector<const Target*>& targets,
235                            base::ListValue* out) {
236   if (targets.empty())
237     return;
238 
239   // Grab the build settings from a random target.
240   const BuildSettings* build_settings =
241       targets[0]->settings()->build_settings();
242 
243   for (const Target* target : targets) {
244     // Use the link output file if there is one, otherwise fall back to the
245     // dependency output file (for actions, for example).
246     OutputFile output_file = target->link_output_file();
247     if (output_file.value().empty())
248       output_file = target->dependency_output_file();
249 
250     SourceFile output_as_source = output_file.AsSourceFile(build_settings);
251     std::string result =
252         RebasePath(output_as_source.value(), build_settings->build_dir(),
253                    build_settings->root_path_utf8());
254     out->AppendString(result);
255   }
256 }
257 
258 #if defined(OS_WIN)
259 // Git bash will remove the first "/" in "//" paths
260 // This also happens for labels assigned to command line parameters, e.g.
261 // --filters
262 // Fix "//" paths, but not absolute and relative paths
FixGitBashLabelEdit(const std::string & label)263 inline std::string FixGitBashLabelEdit(const std::string& label) {
264   static std::unique_ptr<base::Environment> git_bash_env;
265   if (!git_bash_env)
266     git_bash_env = base::Environment::Create();
267 
268   std::string temp_label(label);
269 
270   if (git_bash_env->HasVar(
271           "MSYSTEM") &&        // Only for MinGW based shells like Git Bash
272       temp_label[0] == '/' &&  // Only fix for //foo paths, not /f:oo paths
273       (temp_label.length() < 2 ||
274        (temp_label[1] != '/' &&
275         (temp_label.length() < 3 || temp_label[1] != ':'))))
276     temp_label.insert(0, "/");
277   return temp_label;
278 }
279 #else
280 // Only repair on Windows
FixGitBashLabelEdit(const std::string & label)281 inline std::string FixGitBashLabelEdit(const std::string& label) {
282   return label;
283 }
284 #endif
285 
TargetContainsFile(const Target * target,const SourceFile & file)286 std::optional<HowTargetContainsFile> TargetContainsFile(
287     const Target* target,
288     const SourceFile& file) {
289   for (const auto& cur_file : target->sources()) {
290     if (cur_file == file)
291       return HowTargetContainsFile::kSources;
292   }
293   for (const auto& cur_file : target->public_headers()) {
294     if (cur_file == file)
295       return HowTargetContainsFile::kPublic;
296   }
297   for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
298     for (const auto& cur_file : iter.cur().inputs()) {
299       if (cur_file == file)
300         return HowTargetContainsFile::kInputs;
301     }
302   }
303   for (const auto& cur_file : target->data()) {
304     if (cur_file == file.value())
305       return HowTargetContainsFile::kData;
306     if (cur_file.back() == '/' &&
307         base::StartsWith(file.value(), cur_file, base::CompareCase::SENSITIVE))
308       return HowTargetContainsFile::kData;
309   }
310 
311   if (target->action_values().script().value() == file.value())
312     return HowTargetContainsFile::kScript;
313 
314   std::vector<SourceFile> output_sources;
315   target->action_values().GetOutputsAsSourceFiles(target, &output_sources);
316   for (const auto& cur_file : output_sources) {
317     if (cur_file == file)
318       return HowTargetContainsFile::kOutput;
319   }
320 
321   for (const auto& cur_file : target->computed_outputs()) {
322     if (cur_file.AsSourceFile(target->settings()->build_settings()) == file)
323       return HowTargetContainsFile::kOutput;
324   }
325   return std::nullopt;
326 }
327 
328 }  // namespace
329 
CommandInfo()330 CommandInfo::CommandInfo()
331     : help_short(nullptr), help(nullptr), runner(nullptr) {}
332 
CommandInfo(const char * in_help_short,const char * in_help,CommandRunner in_runner)333 CommandInfo::CommandInfo(const char* in_help_short,
334                          const char* in_help,
335                          CommandRunner in_runner)
336     : help_short(in_help_short), help(in_help), runner(in_runner) {}
337 
GetCommands()338 const CommandInfoMap& GetCommands() {
339   static CommandInfoMap info_map;
340   if (info_map.empty()) {
341 #define INSERT_COMMAND(cmd) \
342   info_map[k##cmd] = CommandInfo(k##cmd##_HelpShort, k##cmd##_Help, &Run##cmd);
343 
344     INSERT_COMMAND(Analyze)
345     INSERT_COMMAND(Args)
346     INSERT_COMMAND(Check)
347     INSERT_COMMAND(Clean)
348     INSERT_COMMAND(Desc)
349     INSERT_COMMAND(Gen)
350     INSERT_COMMAND(Format)
351     INSERT_COMMAND(Help)
352     INSERT_COMMAND(Meta)
353     INSERT_COMMAND(Ls)
354     INSERT_COMMAND(Outputs)
355     INSERT_COMMAND(Path)
356     INSERT_COMMAND(Refs)
357     INSERT_COMMAND(CleanStale)
358 
359 #undef INSERT_COMMAND
360   }
361   return info_map;
362 }
363 
364 // static
365 CommandSwitches CommandSwitches::s_global_switches_ = {};
366 
367 // static
Init(const base::CommandLine & cmdline)368 bool CommandSwitches::Init(const base::CommandLine& cmdline) {
369   CHECK(!s_global_switches_.is_initialized())
370       << "Only call this once from main()";
371   return s_global_switches_.InitFrom(cmdline);
372 }
373 
374 // static
Get()375 const CommandSwitches& CommandSwitches::Get() {
376   CHECK(s_global_switches_.is_initialized())
377       << "Missing previous succesful call to CommandSwitches::Init()";
378   return s_global_switches_;
379 }
380 
381 // static
Set(CommandSwitches new_switches)382 CommandSwitches CommandSwitches::Set(CommandSwitches new_switches) {
383   CHECK(s_global_switches_.is_initialized())
384       << "Missing previous succesful call to CommandSwitches::Init()";
385   CommandSwitches result = std::move(s_global_switches_);
386   s_global_switches_ = std::move(new_switches);
387   return result;
388 }
389 
InitFrom(const base::CommandLine & cmdline)390 bool CommandSwitches::InitFrom(const base::CommandLine& cmdline) {
391   CommandSwitches result;
392   result.initialized_ = true;
393   result.has_quiet_ = cmdline.HasSwitch("a");
394   result.has_force_ = cmdline.HasSwitch("force");
395   result.has_all_ = cmdline.HasSwitch("all");
396   result.has_blame_ = cmdline.HasSwitch("blame");
397   result.has_tree_ = cmdline.HasSwitch("tree");
398   result.has_format_json_ = cmdline.GetSwitchValueASCII("format") == "json";
399   result.has_default_toolchain_ =
400       cmdline.HasSwitch(switches::kDefaultToolchain);
401 
402   result.has_check_generated_ = cmdline.HasSwitch("check-generated");
403   result.has_check_system_ = cmdline.HasSwitch("check-system");
404   result.has_public_ = cmdline.HasSwitch("public");
405   result.has_with_data_ = cmdline.HasSwitch("with-data");
406 
407   std::string_view target_print_switch = "as";
408   if (cmdline.HasSwitch(target_print_switch)) {
409     std::string value = cmdline.GetSwitchValueASCII(target_print_switch);
410     if (value == "buildfile") {
411       result.target_print_mode_ = TARGET_PRINT_BUILDFILE;
412     } else if (value == "label") {
413       result.target_print_mode_ = TARGET_PRINT_LABEL;
414     } else if (value == "output") {
415       result.target_print_mode_ = TARGET_PRINT_OUTPUT;
416     } else {
417       Err(Location(), "Invalid value for \"--as\".",
418           "I was expecting \"buildfile\", \"label\", or \"output\" but you\n"
419           "said \"" +
420               value + "\".")
421           .PrintToStdout();
422       return false;
423     }
424   }
425 
426   std::string_view target_type_switch = "type";
427   if (cmdline.HasSwitch(target_type_switch)) {
428     std::string value = cmdline.GetSwitchValueASCII(target_type_switch);
429     static const struct {
430       const char* name;
431       Target::OutputType type;
432     } kTypes[] = {
433         {"group", Target::GROUP},
434         {"executable", Target::EXECUTABLE},
435         {"shared_library", Target::SHARED_LIBRARY},
436         {"loadable_module", Target::LOADABLE_MODULE},
437         {"static_library", Target::STATIC_LIBRARY},
438         {"source_set", Target::SOURCE_SET},
439         {"copy", Target::COPY_FILES},
440         {"action", Target::ACTION},
441     };
442     bool found = false;
443     for (const auto& type : kTypes) {
444       if (value == type.name) {
445         result.target_type_ = type.type;
446         found = true;
447         break;
448       }
449     }
450     if (!found) {
451       Err(Location(), "Invalid value for \"--type\".").PrintToStdout();
452       return false;
453     }
454   }
455   std::string_view testonly_switch = "testonly";
456   if (cmdline.HasSwitch(testonly_switch)) {
457     std::string value = cmdline.GetSwitchValueASCII(testonly_switch);
458     if (value == "true") {
459       testonly_mode_ = TESTONLY_TRUE;
460     } else if (value == "false") {
461       testonly_mode_ = TESTONLY_FALSE;
462     } else {
463       Err(Location(), "Bad value for --testonly.",
464           "I was expecting --testonly=true or --testonly=false.")
465           .PrintToStdout();
466       return false;
467     }
468   }
469 
470   result.meta_rebase_dir_ = cmdline.GetSwitchValueASCII("rebase");
471   result.meta_data_keys_ = cmdline.GetSwitchValueASCII("data");
472   result.meta_walk_keys_ = cmdline.GetSwitchValueASCII("walk");
473   *this = result;
474   return true;
475 }
476 
ResolveTargetFromCommandLineString(Setup * setup,const std::string & label_string)477 const Target* ResolveTargetFromCommandLineString(
478     Setup* setup,
479     const std::string& label_string) {
480   // Need to resolve the label after we know the default toolchain.
481   Label default_toolchain = setup->loader()->default_toolchain_label();
482   Value arg_value(nullptr, FixGitBashLabelEdit(label_string));
483   Err err;
484   Label label = Label::Resolve(
485       SourceDirForCurrentDirectory(setup->build_settings().root_path()),
486       setup->build_settings().root_path_utf8(), default_toolchain, arg_value,
487       &err);
488   if (err.has_error()) {
489     err.PrintToStdout();
490     return nullptr;
491   }
492 
493   const Item* item = setup->builder().GetItem(label);
494   if (!item) {
495     Err(Location(), "Label not found.",
496         label.GetUserVisibleName(false) + " not found.")
497         .PrintToStdout();
498     return nullptr;
499   }
500 
501   const Target* target = item->AsTarget();
502   if (!target) {
503     Err(Location(), "Not a target.",
504         "The \"" + label.GetUserVisibleName(false) +
505             "\" thing\n"
506             "is not a target. Somebody should probably implement this command "
507             "for "
508             "other\nitem types.")
509         .PrintToStdout();
510     return nullptr;
511   }
512 
513   return target;
514 }
515 
ResolveFromCommandLineInput(Setup * setup,const std::vector<std::string> & input,bool default_toolchain_only,UniqueVector<const Target * > * target_matches,UniqueVector<const Config * > * config_matches,UniqueVector<const Toolchain * > * toolchain_matches,UniqueVector<SourceFile> * file_matches)516 bool ResolveFromCommandLineInput(
517     Setup* setup,
518     const std::vector<std::string>& input,
519     bool default_toolchain_only,
520     UniqueVector<const Target*>* target_matches,
521     UniqueVector<const Config*>* config_matches,
522     UniqueVector<const Toolchain*>* toolchain_matches,
523     UniqueVector<SourceFile>* file_matches) {
524   if (input.empty()) {
525     Err(Location(), "You need to specify a label, file, or pattern.")
526         .PrintToStdout();
527     return false;
528   }
529 
530   SourceDir cur_dir =
531       SourceDirForCurrentDirectory(setup->build_settings().root_path());
532   for (const auto& cur : input) {
533     if (!ResolveStringFromCommandLineInput(
534             setup, cur_dir, cur, default_toolchain_only, target_matches,
535             config_matches, toolchain_matches, file_matches))
536       return false;
537   }
538   return true;
539 }
540 
FilterTargetsByPatterns(const std::vector<const Target * > & input,const std::vector<LabelPattern> & filter,std::vector<const Target * > * output)541 void FilterTargetsByPatterns(const std::vector<const Target*>& input,
542                              const std::vector<LabelPattern>& filter,
543                              std::vector<const Target*>* output) {
544   for (auto* target : input) {
545     for (const auto& pattern : filter) {
546       if (pattern.Matches(target->label())) {
547         output->push_back(target);
548         break;
549       }
550     }
551   }
552 }
553 
FilterTargetsByPatterns(const std::vector<const Target * > & input,const std::vector<LabelPattern> & filter,UniqueVector<const Target * > * output)554 void FilterTargetsByPatterns(const std::vector<const Target*>& input,
555                              const std::vector<LabelPattern>& filter,
556                              UniqueVector<const Target*>* output) {
557   for (auto* target : input) {
558     for (const auto& pattern : filter) {
559       if (pattern.Matches(target->label())) {
560         output->push_back(target);
561         break;
562       }
563     }
564   }
565 }
566 
FilterOutTargetsByPatterns(const std::vector<const Target * > & input,const std::vector<LabelPattern> & filter,std::vector<const Target * > * output)567 void FilterOutTargetsByPatterns(const std::vector<const Target*>& input,
568                                 const std::vector<LabelPattern>& filter,
569                                 std::vector<const Target*>* output) {
570   for (auto* target : input) {
571     bool match = false;
572     for (const auto& pattern : filter) {
573       if (pattern.Matches(target->label())) {
574         match = true;
575         break;
576       }
577     }
578     if (!match) {
579       output->push_back(target);
580     }
581   }
582 }
583 
FilterPatternsFromString(const BuildSettings * build_settings,const std::string & label_list_string,std::vector<LabelPattern> * filters,Err * err)584 bool FilterPatternsFromString(const BuildSettings* build_settings,
585                               const std::string& label_list_string,
586                               std::vector<LabelPattern>* filters,
587                               Err* err) {
588   std::vector<std::string> tokens = base::SplitString(
589       label_list_string, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
590   SourceDir root_dir("//");
591 
592   filters->reserve(tokens.size());
593   for (const std::string& token : tokens) {
594     LabelPattern pattern = LabelPattern::GetPattern(
595         root_dir, build_settings->root_path_utf8(),
596         Value(nullptr, FixGitBashLabelEdit(token)), err);
597     if (err->has_error())
598       return false;
599     filters->push_back(pattern);
600   }
601 
602   return true;
603 }
604 
FilterAndPrintTargets(std::vector<const Target * > * targets,base::ListValue * out)605 void FilterAndPrintTargets(std::vector<const Target*>* targets,
606                            base::ListValue* out) {
607   if (targets->empty())
608     return;
609 
610   if (!ApplyTestonlyFilter(targets))
611     return;
612   if (!ApplyTypeFilter(targets))
613     return;
614 
615   CommandSwitches::TargetPrintMode printing_mode =
616       CommandSwitches::TARGET_PRINT_LABEL;
617   if (targets->empty() || !GetTargetPrintingMode(&printing_mode))
618     return;
619   switch (printing_mode) {
620     case CommandSwitches::TARGET_PRINT_BUILDFILE:
621       PrintTargetsAsBuildfiles(*targets, out);
622       break;
623     case CommandSwitches::TARGET_PRINT_LABEL:
624       PrintTargetsAsLabels(*targets, out);
625       break;
626     case CommandSwitches::TARGET_PRINT_OUTPUT:
627       PrintTargetsAsOutputs(*targets, out);
628       break;
629   }
630 }
631 
FilterAndPrintTargets(bool indent,std::vector<const Target * > * targets)632 void FilterAndPrintTargets(bool indent, std::vector<const Target*>* targets) {
633   base::ListValue tmp;
634   FilterAndPrintTargets(targets, &tmp);
635   for (const auto& value : tmp) {
636     std::string string;
637     value.GetAsString(&string);
638     if (indent)
639       OutputString("  ");
640     OutputString(string);
641     OutputString("\n");
642   }
643 }
644 
FilterAndPrintTargetSet(bool indent,const TargetSet & targets)645 void FilterAndPrintTargetSet(bool indent, const TargetSet& targets) {
646   std::vector<const Target*> target_vector(targets.begin(), targets.end());
647   FilterAndPrintTargets(indent, &target_vector);
648 }
649 
FilterAndPrintTargetSet(const TargetSet & targets,base::ListValue * out)650 void FilterAndPrintTargetSet(const TargetSet& targets, base::ListValue* out) {
651   std::vector<const Target*> target_vector(targets.begin(), targets.end());
652   FilterAndPrintTargets(&target_vector, out);
653 }
654 
GetTargetsContainingFile(Setup * setup,const std::vector<const Target * > & all_targets,const SourceFile & file,bool default_toolchain_only,std::vector<TargetContainingFile> * matches)655 void GetTargetsContainingFile(Setup* setup,
656                               const std::vector<const Target*>& all_targets,
657                               const SourceFile& file,
658                               bool default_toolchain_only,
659                               std::vector<TargetContainingFile>* matches) {
660   Label default_toolchain = setup->loader()->default_toolchain_label();
661   for (auto* target : all_targets) {
662     if (default_toolchain_only) {
663       // Only check targets in the default toolchain.
664       if (target->label().GetToolchainLabel() != default_toolchain)
665         continue;
666     }
667     if (auto how = TargetContainsFile(target, file))
668       matches->emplace_back(target, *how);
669   }
670 }
671 
672 }  // namespace commands
673