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