Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / gn / command_desc.cc
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 <algorithm>
6 #include <set>
7 #include <sstream>
8
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/setup.h"
18 #include "tools/gn/standard_out.h"
19 #include "tools/gn/substitution_writer.h"
20 #include "tools/gn/target.h"
21 #include "tools/gn/variables.h"
22
23 namespace commands {
24
25 namespace {
26
27 // Prints the given directory in a nice way for the user to view.
28 std::string FormatSourceDir(const SourceDir& dir) {
29 #if defined(OS_WIN)
30   // On Windows we fix up system absolute paths to look like native ones.
31   // Internally, they'll look like "/C:\foo\bar/"
32   if (dir.is_system_absolute()) {
33     std::string buf = dir.value();
34     if (buf.size() > 3 && buf[2] == ':') {
35       buf.erase(buf.begin());  // Erase beginning slash.
36       return buf;
37     }
38   }
39 #endif
40   return dir.value();
41 }
42
43 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result);
44
45 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
46   if (result->find(target->label()) != result->end())
47     return;  // Already did this target.
48   result->insert(target->label());
49
50   RecursiveCollectChildDeps(target, result);
51 }
52
53 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result) {
54   for (DepsIterator iter(target); !iter.done(); iter.Advance())
55     RecursiveCollectDeps(iter.target(), result);
56 }
57
58 // Prints dependencies of the given target (not the target itself). If the
59 // set is non-null, new targets encountered will be added to the set, and if
60 // a dependency is in the set already, it will not be recused into. When the
61 // set is null, all dependencies will be printed.
62 void RecursivePrintDeps(const Target* target,
63                         const Label& default_toolchain,
64                         std::set<const Target*>* seen_targets,
65                         int indent_level) {
66   // Combine all deps into one sorted list.
67   std::vector<LabelTargetPair> sorted_deps;
68   for (DepsIterator iter(target); !iter.done(); iter.Advance())
69     sorted_deps.push_back(iter.pair());
70   std::sort(sorted_deps.begin(), sorted_deps.end(),
71             LabelPtrLabelLess<Target>());
72
73   std::string indent(indent_level * 2, ' ');
74   for (size_t i = 0; i < sorted_deps.size(); i++) {
75     const Target* cur_dep = sorted_deps[i].ptr;
76
77     OutputString(indent +
78         cur_dep->label().GetUserVisibleName(default_toolchain));
79     bool print_children = true;
80     if (seen_targets) {
81       if (seen_targets->find(cur_dep) == seen_targets->end()) {
82         // New target, mark it visited.
83         seen_targets->insert(cur_dep);
84       } else {
85         // Already seen.
86         print_children = false;
87         // Only print "..." if something is actually elided, which means that
88         // the current target has children.
89         if (!cur_dep->public_deps().empty() ||
90             !cur_dep->private_deps().empty() ||
91             !cur_dep->data_deps().empty())
92           OutputString("...");
93       }
94     }
95
96     OutputString("\n");
97     if (print_children) {
98       RecursivePrintDeps(cur_dep, default_toolchain, seen_targets,
99                          indent_level + 1);
100     }
101   }
102 }
103
104 void PrintDeps(const Target* target, bool display_header) {
105   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
106   Label toolchain_label = target->label().GetToolchainLabel();
107
108   // Tree mode is separate.
109   if (cmdline->HasSwitch("tree")) {
110     if (display_header)
111       OutputString("\nDependency tree:\n");
112
113     if (cmdline->HasSwitch("all")) {
114       // Show all tree deps with no eliding.
115       RecursivePrintDeps(target, toolchain_label, NULL, 1);
116     } else {
117       // Don't recurse into duplicates.
118       std::set<const Target*> seen_targets;
119       RecursivePrintDeps(target, toolchain_label, &seen_targets, 1);
120     }
121     return;
122   }
123
124   // Collect the deps to display.
125   std::vector<Label> deps;
126   if (cmdline->HasSwitch("all")) {
127     // Show all dependencies.
128     if (display_header)
129       OutputString("\nAll recursive dependencies:\n");
130
131     std::set<Label> all_deps;
132     RecursiveCollectChildDeps(target, &all_deps);
133     for (std::set<Label>::iterator i = all_deps.begin();
134          i != all_deps.end(); ++i)
135       deps.push_back(*i);
136   } else {
137     // Show direct dependencies only.
138     if (display_header) {
139       OutputString(
140           "\nDirect dependencies "
141           "(try also \"--all\", \"--tree\", or even \"--all --tree\"):\n");
142     }
143     for (DepsIterator iter(target); !iter.done(); iter.Advance())
144       deps.push_back(iter.label());
145   }
146
147   std::sort(deps.begin(), deps.end());
148   for (size_t i = 0; i < deps.size(); i++)
149     OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
150 }
151
152 void PrintForwardDependentConfigsFrom(const Target* target,
153                                       bool display_header) {
154   if (target->forward_dependent_configs().empty())
155     return;
156
157   if (display_header)
158     OutputString("\nforward_dependent_configs_from:\n");
159
160   // Collect the sorted list of deps.
161   std::vector<Label> forward;
162   for (size_t i = 0; i < target->forward_dependent_configs().size(); i++)
163     forward.push_back(target->forward_dependent_configs()[i].label);
164   std::sort(forward.begin(), forward.end());
165
166   Label toolchain_label = target->label().GetToolchainLabel();
167   for (size_t i = 0; i < forward.size(); i++)
168     OutputString("  " + forward[i].GetUserVisibleName(toolchain_label) + "\n");
169 }
170
171 // libs and lib_dirs are special in that they're inherited. We don't currently
172 // implement a blame feature for this since the bottom-up inheritance makes
173 // this difficult.
174 void PrintLibDirs(const Target* target, bool display_header) {
175   const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
176   if (lib_dirs.empty())
177     return;
178
179   if (display_header)
180     OutputString("\nlib_dirs\n");
181
182   for (size_t i = 0; i < lib_dirs.size(); i++)
183     OutputString("    " + FormatSourceDir(lib_dirs[i]) + "\n");
184 }
185
186 void PrintLibs(const Target* target, bool display_header) {
187   const OrderedSet<std::string>& libs = target->all_libs();
188   if (libs.empty())
189     return;
190
191   if (display_header)
192     OutputString("\nlibs\n");
193
194   for (size_t i = 0; i < libs.size(); i++)
195     OutputString("    " + libs[i] + "\n");
196 }
197
198 void PrintPublic(const Target* target, bool display_header) {
199   if (display_header)
200     OutputString("\npublic:\n");
201
202   if (target->all_headers_public()) {
203     OutputString("  [All headers listed in the sources are public.]\n");
204     return;
205   }
206
207   Target::FileList public_headers = target->public_headers();
208   std::sort(public_headers.begin(), public_headers.end());
209   for (size_t i = 0; i < public_headers.size(); i++)
210     OutputString("  " + public_headers[i].value() + "\n");
211 }
212
213 void PrintCheckIncludes(const Target* target, bool display_header) {
214   if (display_header)
215     OutputString("\ncheck_includes:\n");
216
217   if (target->check_includes())
218     OutputString("  true\n");
219   else
220     OutputString("  false\n");
221 }
222
223 void PrintAllowCircularIncludesFrom(const Target* target, bool display_header) {
224   if (display_header)
225     OutputString("\nallow_circular_includes_from:\n");
226
227   Label toolchain_label = target->label().GetToolchainLabel();
228   const std::set<Label>& allow = target->allow_circular_includes_from();
229   for (std::set<Label>::const_iterator iter = allow.begin();
230        iter != allow.end(); ++iter)
231     OutputString("  " + iter->GetUserVisibleName(toolchain_label) + "\n");
232 }
233
234 void PrintVisibility(const Target* target, bool display_header) {
235   if (display_header)
236     OutputString("\nvisibility:\n");
237
238   OutputString(target->visibility().Describe(2, false));
239 }
240
241 void PrintTestonly(const Target* target, bool display_header) {
242   if (display_header)
243     OutputString("\ntestonly:\n");
244
245   if (target->testonly())
246     OutputString("  true\n");
247   else
248     OutputString("  false\n");
249 }
250
251 void PrintConfigsVector(const Target* target,
252                         const LabelConfigVector& configs,
253                         const std::string& heading,
254                         bool display_header) {
255   if (configs.empty())
256     return;
257
258   // Don't sort since the order determines how things are processed.
259   if (display_header)
260     OutputString("\n" + heading + " (in order applying):\n");
261
262   Label toolchain_label = target->label().GetToolchainLabel();
263   for (size_t i = 0; i < configs.size(); i++) {
264     OutputString("  " +
265         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
266   }
267 }
268
269 void PrintConfigsVector(const Target* target,
270                         const UniqueVector<LabelConfigPair>& configs,
271                         const std::string& heading,
272                         bool display_header) {
273   if (configs.empty())
274     return;
275
276   // Don't sort since the order determines how things are processed.
277   if (display_header)
278     OutputString("\n" + heading + " (in order applying):\n");
279
280   Label toolchain_label = target->label().GetToolchainLabel();
281   for (size_t i = 0; i < configs.size(); i++) {
282     OutputString("  " +
283         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
284   }
285 }
286
287 void PrintConfigs(const Target* target, bool display_header) {
288   PrintConfigsVector(target, target->configs().vector(), "configs",
289                      display_header);
290 }
291
292 void PrintPublicConfigs(const Target* target, bool display_header) {
293   PrintConfigsVector(target, target->public_configs(),
294                      "public_configs", display_header);
295 }
296
297 void PrintAllDependentConfigs(const Target* target, bool display_header) {
298   PrintConfigsVector(target, target->all_dependent_configs(),
299                      "all_dependent_configs", display_header);
300 }
301
302 void PrintFileList(const Target::FileList& files,
303                    const std::string& header,
304                    bool indent_extra,
305                    bool display_header) {
306   if (files.empty())
307     return;
308
309   if (display_header)
310     OutputString("\n" + header + ":\n");
311
312   std::string indent = indent_extra ? "    " : "  ";
313
314   Target::FileList sorted = files;
315   std::sort(sorted.begin(), sorted.end());
316   for (size_t i = 0; i < sorted.size(); i++)
317     OutputString(indent + sorted[i].value() + "\n");
318 }
319
320 void PrintSources(const Target* target, bool display_header) {
321   PrintFileList(target->sources(), "sources", false, display_header);
322 }
323
324 void PrintInputs(const Target* target, bool display_header) {
325   PrintFileList(target->inputs(), "inputs", false, display_header);
326 }
327
328 void PrintOutputs(const Target* target, bool display_header) {
329   if (display_header)
330     OutputString("\noutputs:\n");
331
332   if (target->output_type() == Target::ACTION) {
333     // Action, print out outputs, don't apply sources to it.
334     for (size_t i = 0; i < target->action_values().outputs().list().size();
335          i++) {
336       OutputString("  " +
337                    target->action_values().outputs().list()[i].AsString() +
338                    "\n");
339     }
340   } else {
341     const SubstitutionList& outputs = target->action_values().outputs();
342     if (!outputs.required_types().empty()) {
343       // Display the pattern and resolved pattern separately, since there are
344       // subtitutions used.
345       OutputString("  Output pattern:\n");
346       for (size_t i = 0; i < outputs.list().size(); i++)
347         OutputString("    " + outputs.list()[i].AsString() + "\n");
348
349       // Now display what that resolves to given the sources.
350       OutputString("\n  Resolved output file list:\n");
351     }
352
353     // Resolved output list.
354     std::vector<SourceFile> output_files;
355     SubstitutionWriter::ApplyListToSources(target->settings(), outputs,
356                                            target->sources(), &output_files);
357     PrintFileList(output_files, "", true, false);
358   }
359 }
360
361 void PrintScript(const Target* target, bool display_header) {
362   if (display_header)
363     OutputString("\nscript:\n");
364   OutputString("  " + target->action_values().script().value() + "\n");
365 }
366
367 void PrintArgs(const Target* target, bool display_header) {
368   if (display_header)
369     OutputString("\nargs:\n");
370   for (size_t i = 0; i < target->action_values().args().list().size(); i++) {
371     OutputString("  " +
372                  target->action_values().args().list()[i].AsString() + "\n");
373   }
374 }
375
376 void PrintDepfile(const Target* target, bool display_header) {
377   if (target->action_values().depfile().empty())
378     return;
379   if (display_header)
380     OutputString("\ndepfile:\n");
381   OutputString("  " + target->action_values().depfile().AsString() + "\n");
382 }
383
384 // Attribute the origin for attributing from where a target came from. Does
385 // nothing if the input is null or it does not have a location.
386 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
387   if (!origin)
388     return;
389   Location location = origin->GetRange().begin();
390   out << "       (Added by " + location.file()->name().value() << ":"
391       << location.line_number() << ")\n";
392 }
393
394 // Templatized writer for writing out different config value types.
395 template<typename T> struct DescValueWriter {};
396 template<> struct DescValueWriter<std::string> {
397   void operator()(const std::string& str, std::ostream& out) const {
398     out << "    " << str << "\n";
399   }
400 };
401 template<> struct DescValueWriter<SourceDir> {
402   void operator()(const SourceDir& dir, std::ostream& out) const {
403     out << "    " << FormatSourceDir(dir) << "\n";
404   }
405 };
406
407 // Writes a given config value type to the string, optionally with attribution.
408 // This should match RecursiveTargetConfigToStream in the order it traverses.
409 template<typename T> void OutputRecursiveTargetConfig(
410     const Target* target,
411     const char* header_name,
412     const std::vector<T>& (ConfigValues::* getter)() const) {
413   bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
414
415   DescValueWriter<T> writer;
416   std::ostringstream out;
417
418   for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
419     if ((iter.cur().*getter)().empty())
420       continue;
421
422     // Optional blame sub-head.
423     if (display_blame) {
424       const Config* config = iter.GetCurrentConfig();
425       if (config) {
426         // Source of this value is a config.
427         out << "  From " << config->label().GetUserVisibleName(false) << "\n";
428         OutputSourceOfDep(iter.origin(), out);
429       } else {
430         // Source of this value is the target itself.
431         out << "  From " << target->label().GetUserVisibleName(false) << "\n";
432       }
433     }
434
435     // Actual values.
436     ConfigValuesToStream(iter.cur(), getter, writer, out);
437   }
438
439   std::string out_str = out.str();
440   if (!out_str.empty()) {
441     OutputString("\n" + std::string(header_name) + "\n");
442     OutputString(out_str);
443   }
444 }
445
446 }  // namespace
447
448 // desc ------------------------------------------------------------------------
449
450 const char kDesc[] = "desc";
451 const char kDesc_HelpShort[] =
452     "desc: Show lots of insightful information about a target.";
453 const char kDesc_Help[] =
454     "gn desc <out_dir> <target label> [<what to show>]\n"
455     "        [--blame] [--all | --tree]\n"
456     "\n"
457     "  Displays information about a given labeled target for the given build.\n"
458     "  The build parameters will be taken for the build in the given\n"
459     "  <out_dir>.\n"
460     "\n"
461     "Possibilities for <what to show>:\n"
462     "  (If unspecified an overall summary will be displayed.)\n"
463     "\n"
464     "  sources\n"
465     "      Source files.\n"
466     "\n"
467     "  inputs\n"
468     "      Additional input dependencies.\n"
469     "\n"
470     "  public\n"
471     "      Public header files.\n"
472     "\n"
473     "  check_includes\n"
474     "      Whether \"gn check\" checks this target for include usage.\n"
475     "\n"
476     "  allow_circular_includes_from\n"
477     "      Permit includes from these targets.\n"
478     "\n"
479     "  visibility\n"
480     "      Prints which targets can depend on this one.\n"
481     "\n"
482     "  testonly\n"
483     "      Whether this target may only be used in tests.\n"
484     "\n"
485     "  configs\n"
486     "      Shows configs applied to the given target, sorted in the order\n"
487     "      they're specified. This includes both configs specified in the\n"
488     "      \"configs\" variable, as well as configs pushed onto this target\n"
489     "      via dependencies specifying \"all\" or \"direct\" dependent\n"
490     "      configs.\n"
491     "\n"
492     "  deps [--all | --tree]\n"
493     "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
494     "      recursive) dependencies of the given target. \"--tree\" shows them\n"
495     "      in a tree format with duplicates elided (noted by \"...\").\n"
496     "      \"--all\" shows them sorted alphabetically. Using both flags will\n"
497     "      print a tree with no omissions. The \"deps\", \"public_deps\", and\n"
498     "      \"data_deps\" will all be included.\n"
499     "\n"
500     "  public_configs\n"
501     "  all_dependent_configs\n"
502     "      Shows the labels of configs applied to targets that depend on this\n"
503     "      one (either directly or all of them).\n"
504     "\n"
505     "  forward_dependent_configs_from\n"
506     "      Shows the labels of dependencies for which dependent configs will\n"
507     "      be pushed to targets depending on the current one.\n"
508     "\n"
509     "  script\n"
510     "  args\n"
511     "  depfile\n"
512     "      Actions only. The script and related values.\n"
513     "\n"
514     "  outputs\n"
515     "      Outputs for script and copy target types.\n"
516     "\n"
517     "  defines       [--blame]\n"
518     "  include_dirs  [--blame]\n"
519     "  cflags        [--blame]\n"
520     "  cflags_cc     [--blame]\n"
521     "  cflags_cxx    [--blame]\n"
522     "  ldflags       [--blame]\n"
523     "  lib_dirs\n"
524     "  libs\n"
525     "      Shows the given values taken from the target and all configs\n"
526     "      applying. See \"--blame\" below.\n"
527     "\n"
528     "  --blame\n"
529     "      Used with any value specified by a config, this will name\n"
530     "      the config that specified the value. This doesn't currently work\n"
531     "      for libs and lib_dirs because those are inherited and are more\n"
532     "      complicated to figure out the blame (patches welcome).\n"
533     "\n"
534     "Note:\n"
535     "  This command will show the full name of directories and source files,\n"
536     "  but when directories and source paths are written to the build file,\n"
537     "  they will be adjusted to be relative to the build directory. So the\n"
538     "  values for paths displayed by this command won't match (but should\n"
539     "  mean the same thing).\n"
540     "\n"
541     "Examples:\n"
542     "  gn desc out/Debug //base:base\n"
543     "      Summarizes the given target.\n"
544     "\n"
545     "  gn desc out/Foo :base_unittests deps --tree\n"
546     "      Shows a dependency tree of the \"base_unittests\" project in\n"
547     "      the current directory.\n"
548     "\n"
549     "  gn desc out/Debug //base defines --blame\n"
550     "      Shows defines set for the //base:base target, annotated by where\n"
551     "      each one was set from.\n";
552
553 #define OUTPUT_CONFIG_VALUE(name, type) \
554     OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
555
556 int RunDesc(const std::vector<std::string>& args) {
557   if (args.size() != 2 && args.size() != 3) {
558     Err(Location(), "You're holding it wrong.",
559         "Usage: \"gn desc <out_dir> <target_name> [<what to display>]\"")
560         .PrintToStdout();
561     return 1;
562   }
563
564   // Deliberately leaked to avoid expensive process teardown.
565   Setup* setup = new Setup;
566   if (!setup->DoSetup(args[0], false))
567     return 1;
568   if (!setup->Run())
569     return 1;
570
571   const Target* target = ResolveTargetFromCommandLineString(setup, args[1]);
572   if (!target)
573     return 1;
574
575 #define CONFIG_VALUE_HANDLER(name, type) \
576     } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
577
578   if (args.size() == 3) {
579     // User specified one thing to display.
580     const std::string& what = args[2];
581     if (what == variables::kConfigs) {
582       PrintConfigs(target, false);
583     } else if (what == variables::kPublicConfigs) {
584       PrintPublicConfigs(target, false);
585     } else if (what == variables::kAllDependentConfigs) {
586       PrintAllDependentConfigs(target, false);
587     } else if (what == variables::kForwardDependentConfigsFrom) {
588       PrintForwardDependentConfigsFrom(target, false);
589     } else if (what == variables::kSources) {
590       PrintSources(target, false);
591     } else if (what == variables::kPublic) {
592       PrintPublic(target, false);
593     } else if (what == variables::kCheckIncludes) {
594       PrintCheckIncludes(target, false);
595     } else if (what == variables::kAllowCircularIncludesFrom) {
596       PrintAllowCircularIncludesFrom(target, false);
597     } else if (what == variables::kVisibility) {
598       PrintVisibility(target, false);
599     } else if (what == variables::kTestonly) {
600       PrintTestonly(target, false);
601     } else if (what == variables::kInputs) {
602       PrintInputs(target, false);
603     } else if (what == variables::kScript) {
604       PrintScript(target, false);
605     } else if (what == variables::kArgs) {
606       PrintArgs(target, false);
607     } else if (what == variables::kDepfile) {
608       PrintDepfile(target, false);
609     } else if (what == variables::kOutputs) {
610       PrintOutputs(target, false);
611     } else if (what == variables::kDeps) {
612       PrintDeps(target, false);
613     } else if (what == variables::kLibDirs) {
614       PrintLibDirs(target, false);
615     } else if (what == variables::kLibs) {
616       PrintLibs(target, false);
617
618     CONFIG_VALUE_HANDLER(defines, std::string)
619     CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
620     CONFIG_VALUE_HANDLER(cflags, std::string)
621     CONFIG_VALUE_HANDLER(cflags_c, std::string)
622     CONFIG_VALUE_HANDLER(cflags_cc, std::string)
623     CONFIG_VALUE_HANDLER(cflags_objc, std::string)
624     CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
625     CONFIG_VALUE_HANDLER(ldflags, std::string)
626
627     } else {
628       OutputString("Don't know how to display \"" + what + "\".\n");
629       return 1;
630     }
631
632 #undef CONFIG_VALUE_HANDLER
633     return 0;
634   }
635
636   // Display summary.
637
638   // Display this only applicable to binary targets.
639   bool is_binary_output =
640     target->output_type() != Target::GROUP &&
641     target->output_type() != Target::COPY_FILES &&
642     target->output_type() != Target::ACTION &&
643     target->output_type() != Target::ACTION_FOREACH;
644
645   // Generally we only want to display toolchains on labels when the toolchain
646   // is different than the default one for this target (which we always print
647   // in the header).
648   Label target_toolchain = target->label().GetToolchainLabel();
649
650   // Header.
651   OutputString("Target: ", DECORATION_YELLOW);
652   OutputString(target->label().GetUserVisibleName(false) + "\n");
653   OutputString("Type: ", DECORATION_YELLOW);
654   OutputString(std::string(
655       Target::GetStringForOutputType(target->output_type())) + "\n");
656   OutputString("Toolchain: ", DECORATION_YELLOW);
657   OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
658
659   PrintSources(target, true);
660   if (is_binary_output) {
661     PrintPublic(target, true);
662     PrintCheckIncludes(target, true);
663     PrintAllowCircularIncludesFrom(target, true);
664   }
665   PrintVisibility(target, true);
666   if (is_binary_output) {
667     PrintTestonly(target, true);
668     PrintConfigs(target, true);
669   }
670
671   PrintPublicConfigs(target, true);
672   PrintAllDependentConfigs(target, true);
673   PrintForwardDependentConfigsFrom(target, true);
674
675   PrintInputs(target, true);
676
677   if (is_binary_output) {
678     OUTPUT_CONFIG_VALUE(defines, std::string)
679     OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
680     OUTPUT_CONFIG_VALUE(cflags, std::string)
681     OUTPUT_CONFIG_VALUE(cflags_c, std::string)
682     OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
683     OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
684     OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
685     OUTPUT_CONFIG_VALUE(ldflags, std::string)
686   }
687
688   if (target->output_type() == Target::ACTION ||
689       target->output_type() == Target::ACTION_FOREACH) {
690     PrintScript(target, true);
691     PrintArgs(target, true);
692     PrintDepfile(target, true);
693   }
694
695   if (target->output_type() == Target::ACTION ||
696       target->output_type() == Target::ACTION_FOREACH ||
697       target->output_type() == Target::COPY_FILES) {
698     PrintOutputs(target, true);
699   }
700
701   // Libs can be part of any target and get recursively pushed up the chain,
702   // so always display them, even for groups and such.
703   PrintLibs(target, true);
704   PrintLibDirs(target, true);
705
706   PrintDeps(target, true);
707
708   return 0;
709 }
710
711 }  // namespace commands