Index: tools/gn/command_desc.cc |
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bf91776c73fd491ca8f784f8a03cc34ce4d15a49 |
--- /dev/null |
+++ b/tools/gn/command_desc.cc |
@@ -0,0 +1,201 @@ |
+// 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 <algorithm> |
+#include <set> |
+ |
+#include "tools/gn/commands.h" |
+#include "tools/gn/config.h" |
+#include "tools/gn/item.h" |
+#include "tools/gn/item_node.h" |
+#include "tools/gn/label.h" |
+#include "tools/gn/setup.h" |
+#include "tools/gn/standard_out.h" |
+#include "tools/gn/target.h" |
+ |
+namespace { |
+ |
+struct CompareTargetLabel { |
+ bool operator()(const Target* a, const Target* b) const { |
+ return a->label() < b->label(); |
+ } |
+}; |
+ |
+const Target* GetTargetForDesc(const std::vector<std::string>& args) { |
+ // Deliberately leaked to avoid expensive process teardown. |
+ Setup* setup = new Setup; |
+ if (!setup->DoSetup()) |
+ return NULL; |
+ |
+ // FIXME(brettw): set the output dir to be a sandbox one to avoid polluting |
+ // the real output dir with files written by the build scripts. |
+ |
+ // Do the actual load. This will also write out the target ninja files. |
+ if (!setup->Run()) |
+ return NULL; |
+ |
+ // Need to resolve the label after we know the default toolchain. |
+ // TODO(brettw) find the current directory and resolve the input label |
+ // relative to that. |
+ Label default_toolchain = setup->build_settings().toolchain_manager() |
+ .GetDefaultToolchainUnlocked(); |
+ Value arg_value(NULL, args[0]); |
+ Err err; |
+ Label label = Label::Resolve(SourceDir(), default_toolchain, arg_value, &err); |
+ if (err.has_error()) { |
+ err.PrintToStdout(); |
+ return NULL; |
+ } |
+ |
+ ItemNode* node; |
+ { |
+ base::AutoLock lock(setup->build_settings().item_tree().lock()); |
+ node = setup->build_settings().item_tree().GetExistingNodeLocked(label); |
+ } |
+ if (!node) { |
+ Err(Location(), "", |
+ "I don't know about this \"" + label.GetUserVisibleName(false) + |
+ "\"").PrintToStdout(); |
+ return NULL; |
+ } |
+ |
+ const Target* target = node->item()->AsTarget(); |
+ if (!target) { |
+ Err(Location(), "Not a target.", |
+ "The \"" + label.GetUserVisibleName(false) + "\" thing\n" |
+ "is not a target. Somebody should probably implement this command for " |
+ "other\nitem types."); |
+ return NULL; |
+ } |
+ |
+ return target; |
+} |
+ |
+void RecursiveCollectDeps(const Target* target, std::set<Label>* result) { |
+ if (result->find(target->label()) != result->end()) |
+ return; // Already did this target. |
+ result->insert(target->label()); |
+ |
+ const std::vector<const Target*>& deps = target->deps(); |
+ for (size_t i = 0; i < deps.size(); i++) |
+ RecursiveCollectDeps(deps[i], result); |
+} |
+ |
+// Prints dependencies of the given target (not the target itself). |
+void RecursivePrintDeps(const Target* target, |
+ const Label& default_toolchain, |
+ int indent_level) { |
+ std::vector<const Target*> sorted_deps = target->deps(); |
+ std::sort(sorted_deps.begin(), sorted_deps.end(), CompareTargetLabel()); |
+ |
+ std::string indent(indent_level * 2, ' '); |
+ for (size_t i = 0; i < sorted_deps.size(); i++) { |
+ OutputString(indent + |
+ sorted_deps[i]->label().GetUserVisibleName(default_toolchain) + "\n"); |
+ RecursivePrintDeps(sorted_deps[i], default_toolchain, indent_level + 1); |
+ } |
+} |
+ |
+} // namespace |
+ |
+int RunDescCommand(const std::vector<std::string>& args) { |
+ if (args.size() != 1) { |
+ Err(Location(), "You're holding it wrong.", |
+ "Usage: \"gn desc <target_name>\"").PrintToStdout(); |
+ return NULL; |
+ } |
+ |
+ const Target* target = GetTargetForDesc(args); |
+ if (!target) |
+ return 1; |
+ |
+ // Generally we only want to display toolchains on labels when the toolchain |
+ // is different than the default one for this target (which we always print |
+ // in the header). |
+ Label target_toolchain = target->label().GetToolchainLabel(); |
+ |
+ // Header. |
+ std::string title_target = |
+ "Target: " + target->label().GetUserVisibleName(false); |
+ std::string title_toolchain = |
+ "Toolchain: " + target_toolchain.GetUserVisibleName(false); |
+ OutputString(title_target + "\n", DECORATION_YELLOW); |
+ OutputString(title_toolchain + "\n", DECORATION_YELLOW); |
+ OutputString(std::string( |
+ std::max(title_target.size(), title_toolchain.size()), '=') + "\n"); |
+ |
+ OutputString("Sources:\n"); |
+ const Target::FileList& sources = target->sources(); |
+ for (size_t i = 0; i < sources.size(); i++) |
+ OutputString(" " + sources[i].value() + "\n"); |
+ |
+ // Configs (don't sort since the order determines how things are processed). |
+ OutputString("\nConfigs:\n"); |
+ const std::vector<const Config*>& configs = target->configs(); |
+ for (size_t i = 0; i < configs.size(); i++) { |
+ OutputString(" " + |
+ configs[i]->label().GetUserVisibleName(target_toolchain) + "\n"); |
+ } |
+ |
+ // Deps. Sorted for convenience. Sort the labels rather than the strings so |
+ // that "//foo:bar" comes before "//foo/third_party:bar". |
+ OutputString("\nDirect dependencies:\n" |
+ "(Use \"gn deps\" or \"gn tree\" to display recursive deps.)\n"); |
+ const std::vector<const Target*>& deps = target->deps(); |
+ std::vector<Label> sorted_deps; |
+ for (size_t i = 0; i < deps.size(); i++) |
+ sorted_deps.push_back(deps[i]->label()); |
+ std::sort(sorted_deps.begin(), sorted_deps.end()); |
+ for (size_t i = 0; i < sorted_deps.size(); i++) { |
+ OutputString(" " + sorted_deps[i].GetUserVisibleName(target_toolchain) + |
+ "\n"); |
+ } |
+ return 0; |
+} |
+ |
+int RunDepsCommand(const std::vector<std::string>& args) { |
+ if (args.size() != 1) { |
+ Err(Location(), "You're holding it wrong.", |
+ "Usage: \"gn deps <target_name>\"").PrintToStdout(); |
+ return NULL; |
+ } |
+ |
+ const Target* target = GetTargetForDesc(args); |
+ if (!target) |
+ return 1; |
+ |
+ // Generally we only want to display toolchains on labels when the toolchain |
+ // is different than the default one for this target (which we always print |
+ // in the header). |
+ Label target_toolchain = target->label().GetToolchainLabel(); |
+ |
+ std::set<Label> all_deps; |
+ RecursiveCollectDeps(target, &all_deps); |
+ |
+ OutputString("Recursive dependencies of " + |
+ target->label().GetUserVisibleName(true) + "\n", |
+ DECORATION_YELLOW); |
+ |
+ for (std::set<Label>::iterator i = all_deps.begin(); |
+ i != all_deps.end(); ++i) |
+ OutputString(" " + i->GetUserVisibleName(target_toolchain) + "\n"); |
+ return 0; |
+} |
+ |
+int RunTreeCommand(const std::vector<std::string>& args) { |
+ if (args.size() != 1) { |
+ Err(Location(), "You're holding it wrong.", |
+ "Usage: \"gn tree <target_name>\"").PrintToStdout(); |
+ return NULL; |
+ } |
+ |
+ const Target* target = GetTargetForDesc(args); |
+ if (!target) |
+ return 1; |
+ |
+ OutputString(target->label().GetUserVisibleName(false) + "\n"); |
+ RecursivePrintDeps(target, target->label().GetToolchainLabel(), 1); |
+ |
+ return 0; |
+} |