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 712