[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / tools / gn / command_desc.cc
blob59dc3e61ebbd96c43ae41dcf8d456b5723d0b378
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.
5 #include <algorithm>
6 #include <set>
7 #include <sstream>
9 #include "base/command_line.h"
10 #include "tools/gn/commands.h"
11 #include "tools/gn/config.h"
12 #include "tools/gn/config_values_extractors.h"
13 #include "tools/gn/deps_iterator.h"
14 #include "tools/gn/filesystem_utils.h"
15 #include "tools/gn/item.h"
16 #include "tools/gn/label.h"
17 #include "tools/gn/runtime_deps.h"
18 #include "tools/gn/setup.h"
19 #include "tools/gn/standard_out.h"
20 #include "tools/gn/substitution_writer.h"
21 #include "tools/gn/target.h"
22 #include "tools/gn/variables.h"
24 namespace commands {
26 namespace {
28 // Desc-specific command line switches.
29 const char kBlame[] = "blame";
30 const char kTree[] = "tree";
32 // Prints the given directory in a nice way for the user to view.
33 std::string FormatSourceDir(const SourceDir& dir) {
34 #if defined(OS_WIN)
35 // On Windows we fix up system absolute paths to look like native ones.
36 // Internally, they'll look like "/C:\foo\bar/"
37 if (dir.is_system_absolute()) {
38 std::string buf = dir.value();
39 if (buf.size() > 3 && buf[2] == ':') {
40 buf.erase(buf.begin()); // Erase beginning slash.
41 return buf;
44 #endif
45 return dir.value();
48 void RecursiveCollectChildDeps(const Target* target,
49 std::set<const Target*>* result);
51 void RecursiveCollectDeps(const Target* target,
52 std::set<const Target*>* result) {
53 if (result->find(target) != result->end())
54 return; // Already did this target.
55 result->insert(target);
57 RecursiveCollectChildDeps(target, result);
60 void RecursiveCollectChildDeps(const Target* target,
61 std::set<const Target*>* result) {
62 for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
63 RecursiveCollectDeps(pair.ptr, result);
66 // Prints dependencies of the given target (not the target itself). If the
67 // set is non-null, new targets encountered will be added to the set, and if
68 // a dependency is in the set already, it will not be recused into. When the
69 // set is null, all dependencies will be printed.
70 void RecursivePrintDeps(const Target* target,
71 const Label& default_toolchain,
72 std::set<const Target*>* seen_targets,
73 int indent_level) {
74 // Combine all deps into one sorted list.
75 std::vector<LabelTargetPair> sorted_deps;
76 for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
77 sorted_deps.push_back(pair);
78 std::sort(sorted_deps.begin(), sorted_deps.end(),
79 LabelPtrLabelLess<Target>());
81 std::string indent(indent_level * 2, ' ');
82 for (const auto& pair : sorted_deps) {
83 const Target* cur_dep = pair.ptr;
85 OutputString(indent +
86 cur_dep->label().GetUserVisibleName(default_toolchain));
87 bool print_children = true;
88 if (seen_targets) {
89 if (seen_targets->find(cur_dep) == seen_targets->end()) {
90 // New target, mark it visited.
91 seen_targets->insert(cur_dep);
92 } else {
93 // Already seen.
94 print_children = false;
95 // Only print "..." if something is actually elided, which means that
96 // the current target has children.
97 if (!cur_dep->public_deps().empty() ||
98 !cur_dep->private_deps().empty() ||
99 !cur_dep->data_deps().empty())
100 OutputString("...");
104 OutputString("\n");
105 if (print_children) {
106 RecursivePrintDeps(cur_dep, default_toolchain, seen_targets,
107 indent_level + 1);
112 void PrintDeps(const Target* target, bool display_header) {
113 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
114 Label toolchain_label = target->label().GetToolchainLabel();
116 // Tree mode is separate.
117 if (cmdline->HasSwitch(kTree)) {
118 if (display_header)
119 OutputString("\nDependency tree:\n");
121 if (cmdline->HasSwitch("all")) {
122 // Show all tree deps with no eliding.
123 RecursivePrintDeps(target, toolchain_label, nullptr, 1);
124 } else {
125 // Don't recurse into duplicates.
126 std::set<const Target*> seen_targets;
127 RecursivePrintDeps(target, toolchain_label, &seen_targets, 1);
129 return;
132 // Collect the deps to display.
133 if (cmdline->HasSwitch("all")) {
134 // Show all dependencies.
135 if (display_header)
136 OutputString("\nAll recursive dependencies:\n");
138 std::set<const Target*> all_deps;
139 RecursiveCollectChildDeps(target, &all_deps);
140 FilterAndPrintTargetSet(display_header, all_deps);
141 } else {
142 std::vector<const Target*> deps;
143 // Show direct dependencies only.
144 if (display_header) {
145 OutputString(
146 "\nDirect dependencies "
147 "(try also \"--all\", \"--tree\", or even \"--all --tree\"):\n");
149 for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
150 deps.push_back(pair.ptr);
151 std::sort(deps.begin(), deps.end());
152 FilterAndPrintTargets(display_header, &deps);
156 void PrintForwardDependentConfigsFrom(const Target* target,
157 bool display_header) {
158 if (target->forward_dependent_configs().empty())
159 return;
161 if (display_header)
162 OutputString("\nforward_dependent_configs_from:\n");
164 // Collect the sorted list of deps.
165 std::vector<Label> forward;
166 for (const auto& pair : target->forward_dependent_configs())
167 forward.push_back(pair.label);
168 std::sort(forward.begin(), forward.end());
170 Label toolchain_label = target->label().GetToolchainLabel();
171 for (const auto& fwd : forward)
172 OutputString(" " + fwd.GetUserVisibleName(toolchain_label) + "\n");
175 // libs and lib_dirs are special in that they're inherited. We don't currently
176 // implement a blame feature for this since the bottom-up inheritance makes
177 // this difficult.
178 void PrintLibDirs(const Target* target, bool display_header) {
179 const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
180 if (lib_dirs.empty())
181 return;
183 if (display_header)
184 OutputString("\nlib_dirs\n");
186 for (size_t i = 0; i < lib_dirs.size(); i++)
187 OutputString(" " + FormatSourceDir(lib_dirs[i]) + "\n");
190 void PrintLibs(const Target* target, bool display_header) {
191 const OrderedSet<std::string>& libs = target->all_libs();
192 if (libs.empty())
193 return;
195 if (display_header)
196 OutputString("\nlibs\n");
198 for (size_t i = 0; i < libs.size(); i++)
199 OutputString(" " + libs[i] + "\n");
202 void PrintPublic(const Target* target, bool display_header) {
203 if (display_header)
204 OutputString("\npublic:\n");
206 if (target->all_headers_public()) {
207 OutputString(" [All headers listed in the sources are public.]\n");
208 return;
211 Target::FileList public_headers = target->public_headers();
212 std::sort(public_headers.begin(), public_headers.end());
213 for (const auto& hdr : public_headers)
214 OutputString(" " + hdr.value() + "\n");
217 void PrintCheckIncludes(const Target* target, bool display_header) {
218 if (display_header)
219 OutputString("\ncheck_includes:\n");
221 if (target->check_includes())
222 OutputString(" true\n");
223 else
224 OutputString(" false\n");
227 void PrintAllowCircularIncludesFrom(const Target* target, bool display_header) {
228 if (display_header)
229 OutputString("\nallow_circular_includes_from:\n");
231 Label toolchain_label = target->label().GetToolchainLabel();
232 for (const auto& cur : target->allow_circular_includes_from())
233 OutputString(" " + cur.GetUserVisibleName(toolchain_label) + "\n");
236 void PrintVisibility(const Target* target, bool display_header) {
237 if (display_header)
238 OutputString("\nvisibility:\n");
240 OutputString(target->visibility().Describe(2, false));
243 void PrintTestonly(const Target* target, bool display_header) {
244 if (display_header)
245 OutputString("\ntestonly:\n");
247 if (target->testonly())
248 OutputString(" true\n");
249 else
250 OutputString(" false\n");
253 // Recursively prints subconfigs of a config.
254 void PrintSubConfigs(const Config* config, int indent_level) {
255 if (config->configs().empty())
256 return;
258 std::string indent(indent_level * 2, ' ');
259 Label toolchain_label = config->label().GetToolchainLabel();
260 for (const auto& pair : config->configs()) {
261 OutputString(
262 indent + pair.label.GetUserVisibleName(toolchain_label) + "\n");
263 PrintSubConfigs(pair.ptr, indent_level + 1);
267 // This allows configs stored as either std::vector<LabelConfigPair> or
268 // UniqueVector<LabelConfigPair> to be printed.
269 template <class VectorType>
270 void PrintConfigsVector(const Target* target,
271 const VectorType& configs,
272 const std::string& heading,
273 bool display_header) {
274 if (configs.empty())
275 return;
277 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
279 // Don't sort since the order determines how things are processed.
280 if (display_header) {
281 if (tree)
282 OutputString("\n" + heading + " tree (in order applying):\n");
283 else
284 OutputString("\n" + heading + " (in order applying, try also --tree):\n");
287 Label toolchain_label = target->label().GetToolchainLabel();
288 for (const auto& config : configs) {
289 OutputString(" " + config.label.GetUserVisibleName(toolchain_label) +
290 "\n");
291 if (tree)
292 PrintSubConfigs(config.ptr, 2); // 2 = start with double-indent.
296 void PrintConfigs(const Target* target, bool display_header) {
297 PrintConfigsVector(target, target->configs().vector(), "configs",
298 display_header);
301 void PrintPublicConfigs(const Target* target, bool display_header) {
302 PrintConfigsVector(target, target->public_configs(),
303 "public_configs", display_header);
306 void PrintAllDependentConfigs(const Target* target, bool display_header) {
307 PrintConfigsVector(target, target->all_dependent_configs(),
308 "all_dependent_configs", display_header);
311 void PrintFileList(const Target::FileList& files,
312 const std::string& header,
313 bool indent_extra,
314 bool display_header) {
315 if (files.empty())
316 return;
318 if (display_header)
319 OutputString("\n" + header + ":\n");
321 std::string indent = indent_extra ? " " : " ";
323 Target::FileList sorted = files;
324 std::sort(sorted.begin(), sorted.end());
325 for (const auto& elem : sorted)
326 OutputString(indent + elem.value() + "\n");
329 void PrintSources(const Target* target, bool display_header) {
330 PrintFileList(target->sources(), "sources", false, display_header);
333 void PrintInputs(const Target* target, bool display_header) {
334 PrintFileList(target->inputs(), "inputs", false, display_header);
337 void PrintOutputs(const Target* target, bool display_header) {
338 if (display_header)
339 OutputString("\noutputs:\n");
341 if (target->output_type() == Target::ACTION) {
342 // Action, print out outputs, don't apply sources to it.
343 for (const auto& elem : target->action_values().outputs().list()) {
344 OutputString(" " + elem.AsString() + "\n");
346 } else {
347 const SubstitutionList& outputs = target->action_values().outputs();
348 if (!outputs.required_types().empty()) {
349 // Display the pattern and resolved pattern separately, since there are
350 // subtitutions used.
351 OutputString(" Output pattern:\n");
352 for (const auto& elem : outputs.list())
353 OutputString(" " + elem.AsString() + "\n");
355 // Now display what that resolves to given the sources.
356 OutputString("\n Resolved output file list:\n");
359 // Resolved output list.
360 std::vector<SourceFile> output_files;
361 SubstitutionWriter::ApplyListToSources(target->settings(), outputs,
362 target->sources(), &output_files);
363 PrintFileList(output_files, "", true, false);
367 void PrintScript(const Target* target, bool display_header) {
368 if (display_header)
369 OutputString("\nscript:\n");
370 OutputString(" " + target->action_values().script().value() + "\n");
373 void PrintArgs(const Target* target, bool display_header) {
374 if (display_header)
375 OutputString("\nargs:\n");
376 for (const auto& elem : target->action_values().args().list()) {
377 OutputString(" " + elem.AsString() + "\n");
381 void PrintDepfile(const Target* target, bool display_header) {
382 if (target->action_values().depfile().empty())
383 return;
384 if (display_header)
385 OutputString("\ndepfile:\n");
386 OutputString(" " + target->action_values().depfile().AsString() + "\n");
389 // Attribute the origin for attributing from where a target came from. Does
390 // nothing if the input is null or it does not have a location.
391 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
392 if (!origin)
393 return;
394 Location location = origin->GetRange().begin();
395 out << " (Added by " + location.file()->name().value() << ":"
396 << location.line_number() << ")\n";
399 // Templatized writer for writing out different config value types.
400 template<typename T> struct DescValueWriter {};
401 template<> struct DescValueWriter<std::string> {
402 void operator()(const std::string& str, std::ostream& out) const {
403 out << " " << str << "\n";
406 template<> struct DescValueWriter<SourceDir> {
407 void operator()(const SourceDir& dir, std::ostream& out) const {
408 out << " " << FormatSourceDir(dir) << "\n";
412 // Writes a given config value type to the string, optionally with attribution.
413 // This should match RecursiveTargetConfigToStream in the order it traverses.
414 template<typename T> void OutputRecursiveTargetConfig(
415 const Target* target,
416 const char* header_name,
417 const std::vector<T>& (ConfigValues::* getter)() const) {
418 bool display_blame =
419 base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
421 DescValueWriter<T> writer;
422 std::ostringstream out;
424 for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
425 if ((iter.cur().*getter)().empty())
426 continue;
428 // Optional blame sub-head.
429 if (display_blame) {
430 const Config* config = iter.GetCurrentConfig();
431 if (config) {
432 // Source of this value is a config.
433 out << " From " << config->label().GetUserVisibleName(false) << "\n";
434 OutputSourceOfDep(iter.origin(), out);
435 } else {
436 // Source of this value is the target itself.
437 out << " From " << target->label().GetUserVisibleName(false) << "\n";
441 // Actual values.
442 ConfigValuesToStream(iter.cur(), getter, writer, out);
445 std::string out_str = out.str();
446 if (!out_str.empty()) {
447 OutputString("\n" + std::string(header_name) + "\n");
448 OutputString(out_str);
452 void PrintRuntimeDeps(const Target* target) {
453 bool display_blame =
454 base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
455 Label toolchain = target->label().GetToolchainLabel();
457 const Target* previous_from = NULL;
458 for (const auto& pair : ComputeRuntimeDeps(target)) {
459 if (display_blame) {
460 // Generally a target's runtime deps will be listed sequentially, so
461 // group them and don't duplicate the "from" label for two in a row.
462 if (previous_from == pair.second) {
463 OutputString(" "); // Just indent.
464 } else {
465 previous_from = pair.second;
466 OutputString("From ");
467 OutputString(pair.second->label().GetUserVisibleName(toolchain));
468 OutputString("\n "); // Make the file name indented.
471 OutputString(pair.first.value());
472 OutputString("\n");
476 } // namespace
478 // desc ------------------------------------------------------------------------
480 const char kDesc[] = "desc";
481 const char kDesc_HelpShort[] =
482 "desc: Show lots of insightful information about a target.";
483 const char kDesc_Help[] =
484 "gn desc <out_dir> <target label> [<what to show>] [--blame]\n"
485 "\n"
486 " Displays information about a given labeled target for the given build.\n"
487 " The build parameters will be taken for the build in the given\n"
488 " <out_dir>.\n"
489 "\n"
490 "Possibilities for <what to show>\n"
491 " (If unspecified an overall summary will be displayed.)\n"
492 "\n"
493 " sources\n"
494 " Source files.\n"
495 "\n"
496 " inputs\n"
497 " Additional input dependencies.\n"
498 "\n"
499 " public\n"
500 " Public header files.\n"
501 "\n"
502 " check_includes\n"
503 " Whether \"gn check\" checks this target for include usage.\n"
504 "\n"
505 " allow_circular_includes_from\n"
506 " Permit includes from these targets.\n"
507 "\n"
508 " visibility\n"
509 " Prints which targets can depend on this one.\n"
510 "\n"
511 " testonly\n"
512 " Whether this target may only be used in tests.\n"
513 "\n"
514 " configs\n"
515 " Shows configs applied to the given target, sorted in the order\n"
516 " they're specified. This includes both configs specified in the\n"
517 " \"configs\" variable, as well as configs pushed onto this target\n"
518 " via dependencies specifying \"all\" or \"direct\" dependent\n"
519 " configs.\n"
520 "\n"
521 " deps\n"
522 " Show immediate or recursive dependencies. See below for flags that\n"
523 " control deps printing.\n"
524 "\n"
525 " public_configs\n"
526 " all_dependent_configs\n"
527 " Shows the labels of configs applied to targets that depend on this\n"
528 " one (either directly or all of them).\n"
529 "\n"
530 " forward_dependent_configs_from\n"
531 " Shows the labels of dependencies for which dependent configs will\n"
532 " be pushed to targets depending on the current one.\n"
533 "\n"
534 " script\n"
535 " args\n"
536 " depfile\n"
537 " Actions only. The script and related values.\n"
538 "\n"
539 " outputs\n"
540 " Outputs for script and copy target types.\n"
541 "\n"
542 " defines [--blame]\n"
543 " include_dirs [--blame]\n"
544 " cflags [--blame]\n"
545 " cflags_cc [--blame]\n"
546 " cflags_cxx [--blame]\n"
547 " ldflags [--blame]\n"
548 " lib_dirs\n"
549 " libs\n"
550 " Shows the given values taken from the target and all configs\n"
551 " applying. See \"--blame\" below.\n"
552 "\n"
553 " runtime_deps\n"
554 " Compute all runtime deps for the given target. This is a\n"
555 " computed list and does not correspond to any GN variable, unlike\n"
556 " most other values here.\n"
557 "\n"
558 " The output is a list of file names relative to the build\n"
559 " directory. See \"gn help runtime_deps\" for how this is computed.\n"
560 " This also works with \"--blame\" to see the source of the\n"
561 " dependency.\n"
562 "\n"
563 "Shared flags\n"
564 "\n"
565 " --blame\n"
566 " Used with any value specified by a config, this will name\n"
567 " the config that specified the value. This doesn't currently work\n"
568 " for libs and lib_dirs because those are inherited and are more\n"
569 " complicated to figure out the blame (patches welcome).\n"
570 "\n"
571 "Flags that control how deps are printed\n"
572 "\n"
573 " --all\n"
574 " Collects all recursive dependencies and prints a sorted flat list.\n"
575 " Also usable with --tree (see below).\n"
576 "\n"
577 TARGET_PRINTING_MODE_COMMAND_LINE_HELP
578 "\n"
579 TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP
580 "\n"
581 " --tree\n"
582 " Print a dependency tree. By default, duplicates will be elided\n"
583 " with \"...\" but when --all and -tree are used together, no\n"
584 " eliding will be performed.\n"
585 "\n"
586 " The \"deps\", \"public_deps\", and \"data_deps\" will all be\n"
587 " included in the tree.\n"
588 "\n"
589 " Tree output can not be used with the filtering or output flags:\n"
590 " --as, --type, --testonly.\n"
591 "\n"
592 TARGET_TYPE_FILTER_COMMAND_LINE_HELP
593 "\n"
594 "Note\n"
595 "\n"
596 " This command will show the full name of directories and source files,\n"
597 " but when directories and source paths are written to the build file,\n"
598 " they will be adjusted to be relative to the build directory. So the\n"
599 " values for paths displayed by this command won't match (but should\n"
600 " mean the same thing).\n"
601 "\n"
602 "Examples\n"
603 "\n"
604 " gn desc out/Debug //base:base\n"
605 " Summarizes the given target.\n"
606 "\n"
607 " gn desc out/Foo :base_unittests deps --tree\n"
608 " Shows a dependency tree of the \"base_unittests\" project in\n"
609 " the current directory.\n"
610 "\n"
611 " gn desc out/Debug //base defines --blame\n"
612 " Shows defines set for the //base:base target, annotated by where\n"
613 " each one was set from.\n";
615 #define OUTPUT_CONFIG_VALUE(name, type) \
616 OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
618 int RunDesc(const std::vector<std::string>& args) {
619 if (args.size() != 2 && args.size() != 3) {
620 Err(Location(), "You're holding it wrong.",
621 "Usage: \"gn desc <out_dir> <target_name> [<what to display>]\"")
622 .PrintToStdout();
623 return 1;
626 // Deliberately leaked to avoid expensive process teardown.
627 Setup* setup = new Setup;
628 setup->build_settings().set_check_for_bad_items(false);
629 if (!setup->DoSetup(args[0], false))
630 return 1;
631 if (!setup->Run())
632 return 1;
634 const Target* target = ResolveTargetFromCommandLineString(setup, args[1]);
635 if (!target)
636 return 1;
638 #define CONFIG_VALUE_HANDLER(name, type) \
639 } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
641 if (args.size() == 3) {
642 // User specified one thing to display.
643 const std::string& what = args[2];
644 if (what == variables::kConfigs) {
645 PrintConfigs(target, false);
646 } else if (what == variables::kPublicConfigs) {
647 PrintPublicConfigs(target, false);
648 } else if (what == variables::kAllDependentConfigs) {
649 PrintAllDependentConfigs(target, false);
650 } else if (what == variables::kForwardDependentConfigsFrom) {
651 PrintForwardDependentConfigsFrom(target, false);
652 } else if (what == variables::kSources) {
653 PrintSources(target, false);
654 } else if (what == variables::kPublic) {
655 PrintPublic(target, false);
656 } else if (what == variables::kCheckIncludes) {
657 PrintCheckIncludes(target, false);
658 } else if (what == variables::kAllowCircularIncludesFrom) {
659 PrintAllowCircularIncludesFrom(target, false);
660 } else if (what == variables::kVisibility) {
661 PrintVisibility(target, false);
662 } else if (what == variables::kTestonly) {
663 PrintTestonly(target, false);
664 } else if (what == variables::kInputs) {
665 PrintInputs(target, false);
666 } else if (what == variables::kScript) {
667 PrintScript(target, false);
668 } else if (what == variables::kArgs) {
669 PrintArgs(target, false);
670 } else if (what == variables::kDepfile) {
671 PrintDepfile(target, false);
672 } else if (what == variables::kOutputs) {
673 PrintOutputs(target, false);
674 } else if (what == variables::kDeps) {
675 PrintDeps(target, false);
676 } else if (what == variables::kLibDirs) {
677 PrintLibDirs(target, false);
678 } else if (what == variables::kLibs) {
679 PrintLibs(target, false);
680 } else if (what == "runtime_deps") {
681 PrintRuntimeDeps(target);
683 CONFIG_VALUE_HANDLER(defines, std::string)
684 CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
685 CONFIG_VALUE_HANDLER(cflags, std::string)
686 CONFIG_VALUE_HANDLER(cflags_c, std::string)
687 CONFIG_VALUE_HANDLER(cflags_cc, std::string)
688 CONFIG_VALUE_HANDLER(cflags_objc, std::string)
689 CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
690 CONFIG_VALUE_HANDLER(ldflags, std::string)
692 } else {
693 OutputString("Don't know how to display \"" + what + "\".\n");
694 return 1;
697 #undef CONFIG_VALUE_HANDLER
698 return 0;
701 // Display summary.
703 // Display this only applicable to binary targets.
704 bool is_binary_output =
705 target->output_type() != Target::GROUP &&
706 target->output_type() != Target::COPY_FILES &&
707 target->output_type() != Target::ACTION &&
708 target->output_type() != Target::ACTION_FOREACH;
710 // Generally we only want to display toolchains on labels when the toolchain
711 // is different than the default one for this target (which we always print
712 // in the header).
713 Label target_toolchain = target->label().GetToolchainLabel();
715 // Header.
716 OutputString("Target: ", DECORATION_YELLOW);
717 OutputString(target->label().GetUserVisibleName(false) + "\n");
718 OutputString("Type: ", DECORATION_YELLOW);
719 OutputString(std::string(
720 Target::GetStringForOutputType(target->output_type())) + "\n");
721 OutputString("Toolchain: ", DECORATION_YELLOW);
722 OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
724 PrintSources(target, true);
725 if (is_binary_output) {
726 PrintPublic(target, true);
727 PrintCheckIncludes(target, true);
728 PrintAllowCircularIncludesFrom(target, true);
730 PrintVisibility(target, true);
731 if (is_binary_output) {
732 PrintTestonly(target, true);
733 PrintConfigs(target, true);
736 PrintPublicConfigs(target, true);
737 PrintAllDependentConfigs(target, true);
738 PrintForwardDependentConfigsFrom(target, true);
740 PrintInputs(target, true);
742 if (is_binary_output) {
743 OUTPUT_CONFIG_VALUE(defines, std::string)
744 OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
745 OUTPUT_CONFIG_VALUE(cflags, std::string)
746 OUTPUT_CONFIG_VALUE(cflags_c, std::string)
747 OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
748 OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
749 OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
750 OUTPUT_CONFIG_VALUE(ldflags, std::string)
753 if (target->output_type() == Target::ACTION ||
754 target->output_type() == Target::ACTION_FOREACH) {
755 PrintScript(target, true);
756 PrintArgs(target, true);
757 PrintDepfile(target, true);
760 if (target->output_type() == Target::ACTION ||
761 target->output_type() == Target::ACTION_FOREACH ||
762 target->output_type() == Target::COPY_FILES) {
763 PrintOutputs(target, true);
766 // Libs can be part of any target and get recursively pushed up the chain,
767 // so always display them, even for groups and such.
768 PrintLibs(target, true);
769 PrintLibDirs(target, true);
771 PrintDeps(target, true);
773 return 0;
776 } // namespace commands