// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include "base/command_line.h" #include "tools/gn/commands.h" #include "tools/gn/config.h" #include "tools/gn/config_values_extractors.h" #include "tools/gn/deps_iterator.h" #include "tools/gn/filesystem_utils.h" #include "tools/gn/item.h" #include "tools/gn/label.h" #include "tools/gn/runtime_deps.h" #include "tools/gn/setup.h" #include "tools/gn/standard_out.h" #include "tools/gn/substitution_writer.h" #include "tools/gn/target.h" #include "tools/gn/variables.h" namespace commands { namespace { // The switch for displaying blame. const char kBlame[] = "blame"; // Prints the given directory in a nice way for the user to view. std::string FormatSourceDir(const SourceDir& dir) { #if defined(OS_WIN) // On Windows we fix up system absolute paths to look like native ones. // Internally, they'll look like "/C:\foo\bar/" if (dir.is_system_absolute()) { std::string buf = dir.value(); if (buf.size() > 3 && buf[2] == ':') { buf.erase(buf.begin()); // Erase beginning slash. return buf; } } #endif return dir.value(); } void RecursiveCollectChildDeps(const Target* target, std::set* result); void RecursiveCollectDeps(const Target* target, std::set* result) { if (result->find(target) != result->end()) return; // Already did this target. result->insert(target); RecursiveCollectChildDeps(target, result); } void RecursiveCollectChildDeps(const Target* target, std::set* result) { for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) RecursiveCollectDeps(pair.ptr, result); } // Prints dependencies of the given target (not the target itself). If the // set is non-null, new targets encountered will be added to the set, and if // a dependency is in the set already, it will not be recused into. When the // set is null, all dependencies will be printed. void RecursivePrintDeps(const Target* target, const Label& default_toolchain, std::set* seen_targets, int indent_level) { // Combine all deps into one sorted list. std::vector sorted_deps; for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) sorted_deps.push_back(pair); std::sort(sorted_deps.begin(), sorted_deps.end(), LabelPtrLabelLess()); std::string indent(indent_level * 2, ' '); for (const auto& pair : sorted_deps) { const Target* cur_dep = pair.ptr; OutputString(indent + cur_dep->label().GetUserVisibleName(default_toolchain)); bool print_children = true; if (seen_targets) { if (seen_targets->find(cur_dep) == seen_targets->end()) { // New target, mark it visited. seen_targets->insert(cur_dep); } else { // Already seen. print_children = false; // Only print "..." if something is actually elided, which means that // the current target has children. if (!cur_dep->public_deps().empty() || !cur_dep->private_deps().empty() || !cur_dep->data_deps().empty()) OutputString("..."); } } OutputString("\n"); if (print_children) { RecursivePrintDeps(cur_dep, default_toolchain, seen_targets, indent_level + 1); } } } void PrintDeps(const Target* target, bool display_header) { const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); Label toolchain_label = target->label().GetToolchainLabel(); // Tree mode is separate. if (cmdline->HasSwitch("tree")) { if (display_header) OutputString("\nDependency tree:\n"); if (cmdline->HasSwitch("all")) { // Show all tree deps with no eliding. RecursivePrintDeps(target, toolchain_label, nullptr, 1); } else { // Don't recurse into duplicates. std::set seen_targets; RecursivePrintDeps(target, toolchain_label, &seen_targets, 1); } return; } // Collect the deps to display. if (cmdline->HasSwitch("all")) { // Show all dependencies. if (display_header) OutputString("\nAll recursive dependencies:\n"); std::set all_deps; RecursiveCollectChildDeps(target, &all_deps); FilterAndPrintTargetSet(display_header, all_deps); } else { std::vector deps; // Show direct dependencies only. if (display_header) { OutputString( "\nDirect dependencies " "(try also \"--all\", \"--tree\", or even \"--all --tree\"):\n"); } for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) deps.push_back(pair.ptr); std::sort(deps.begin(), deps.end()); FilterAndPrintTargets(display_header, &deps); } } void PrintForwardDependentConfigsFrom(const Target* target, bool display_header) { if (target->forward_dependent_configs().empty()) return; if (display_header) OutputString("\nforward_dependent_configs_from:\n"); // Collect the sorted list of deps. std::vector