| OLD | NEW |
| (Empty) |
| 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 | |
| 8 #include "tools/gn/commands.h" | |
| 9 #include "tools/gn/config.h" | |
| 10 #include "tools/gn/item.h" | |
| 11 #include "tools/gn/item_node.h" | |
| 12 #include "tools/gn/label.h" | |
| 13 #include "tools/gn/setup.h" | |
| 14 #include "tools/gn/standard_out.h" | |
| 15 #include "tools/gn/target.h" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 struct CompareTargetLabel { | |
| 20 bool operator()(const Target* a, const Target* b) const { | |
| 21 return a->label() < b->label(); | |
| 22 } | |
| 23 }; | |
| 24 | |
| 25 const Target* GetTargetForDesc(const std::vector<std::string>& args) { | |
| 26 // Deliberately leaked to avoid expensive process teardown. | |
| 27 Setup* setup = new Setup; | |
| 28 if (!setup->DoSetup()) | |
| 29 return NULL; | |
| 30 | |
| 31 // FIXME(brettw): set the output dir to be a sandbox one to avoid polluting | |
| 32 // the real output dir with files written by the build scripts. | |
| 33 | |
| 34 // Do the actual load. This will also write out the target ninja files. | |
| 35 if (!setup->Run()) | |
| 36 return NULL; | |
| 37 | |
| 38 // Need to resolve the label after we know the default toolchain. | |
| 39 // TODO(brettw) find the current directory and resolve the input label | |
| 40 // relative to that. | |
| 41 Label default_toolchain = setup->build_settings().toolchain_manager() | |
| 42 .GetDefaultToolchainUnlocked(); | |
| 43 Value arg_value(NULL, args[0]); | |
| 44 Err err; | |
| 45 Label label = Label::Resolve(SourceDir(), default_toolchain, arg_value, &err); | |
| 46 if (err.has_error()) { | |
| 47 err.PrintToStdout(); | |
| 48 return NULL; | |
| 49 } | |
| 50 | |
| 51 ItemNode* node; | |
| 52 { | |
| 53 base::AutoLock lock(setup->build_settings().item_tree().lock()); | |
| 54 node = setup->build_settings().item_tree().GetExistingNodeLocked(label); | |
| 55 } | |
| 56 if (!node) { | |
| 57 Err(Location(), "", | |
| 58 "I don't know about this \"" + label.GetUserVisibleName(false) + | |
| 59 "\"").PrintToStdout(); | |
| 60 return NULL; | |
| 61 } | |
| 62 | |
| 63 const Target* target = node->item()->AsTarget(); | |
| 64 if (!target) { | |
| 65 Err(Location(), "Not a target.", | |
| 66 "The \"" + label.GetUserVisibleName(false) + "\" thing\n" | |
| 67 "is not a target. Somebody should probably implement this command for " | |
| 68 "other\nitem types."); | |
| 69 return NULL; | |
| 70 } | |
| 71 | |
| 72 return target; | |
| 73 } | |
| 74 | |
| 75 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) { | |
| 76 if (result->find(target->label()) != result->end()) | |
| 77 return; // Already did this target. | |
| 78 result->insert(target->label()); | |
| 79 | |
| 80 const std::vector<const Target*>& deps = target->deps(); | |
| 81 for (size_t i = 0; i < deps.size(); i++) | |
| 82 RecursiveCollectDeps(deps[i], result); | |
| 83 } | |
| 84 | |
| 85 // Prints dependencies of the given target (not the target itself). | |
| 86 void RecursivePrintDeps(const Target* target, | |
| 87 const Label& default_toolchain, | |
| 88 int indent_level) { | |
| 89 std::vector<const Target*> sorted_deps = target->deps(); | |
| 90 std::sort(sorted_deps.begin(), sorted_deps.end(), CompareTargetLabel()); | |
| 91 | |
| 92 std::string indent(indent_level * 2, ' '); | |
| 93 for (size_t i = 0; i < sorted_deps.size(); i++) { | |
| 94 OutputString(indent + | |
| 95 sorted_deps[i]->label().GetUserVisibleName(default_toolchain) + "\n"); | |
| 96 RecursivePrintDeps(sorted_deps[i], default_toolchain, indent_level + 1); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 } // namespace | |
| 101 | |
| 102 int RunDescCommand(const std::vector<std::string>& args) { | |
| 103 if (args.size() != 1) { | |
| 104 Err(Location(), "You're holding it wrong.", | |
| 105 "Usage: \"gn desc <target_name>\"").PrintToStdout(); | |
| 106 return NULL; | |
| 107 } | |
| 108 | |
| 109 const Target* target = GetTargetForDesc(args); | |
| 110 if (!target) | |
| 111 return 1; | |
| 112 | |
| 113 // Generally we only want to display toolchains on labels when the toolchain | |
| 114 // is different than the default one for this target (which we always print | |
| 115 // in the header). | |
| 116 Label target_toolchain = target->label().GetToolchainLabel(); | |
| 117 | |
| 118 // Header. | |
| 119 std::string title_target = | |
| 120 "Target: " + target->label().GetUserVisibleName(false); | |
| 121 std::string title_toolchain = | |
| 122 "Toolchain: " + target_toolchain.GetUserVisibleName(false); | |
| 123 OutputString(title_target + "\n", DECORATION_YELLOW); | |
| 124 OutputString(title_toolchain + "\n", DECORATION_YELLOW); | |
| 125 OutputString(std::string( | |
| 126 std::max(title_target.size(), title_toolchain.size()), '=') + "\n"); | |
| 127 | |
| 128 OutputString("Sources:\n"); | |
| 129 const Target::FileList& sources = target->sources(); | |
| 130 for (size_t i = 0; i < sources.size(); i++) | |
| 131 OutputString(" " + sources[i].value() + "\n"); | |
| 132 | |
| 133 // Configs (don't sort since the order determines how things are processed). | |
| 134 OutputString("\nConfigs:\n"); | |
| 135 const std::vector<const Config*>& configs = target->configs(); | |
| 136 for (size_t i = 0; i < configs.size(); i++) { | |
| 137 OutputString(" " + | |
| 138 configs[i]->label().GetUserVisibleName(target_toolchain) + "\n"); | |
| 139 } | |
| 140 | |
| 141 // Deps. Sorted for convenience. Sort the labels rather than the strings so | |
| 142 // that "//foo:bar" comes before "//foo/third_party:bar". | |
| 143 OutputString("\nDirect dependencies:\n" | |
| 144 "(Use \"gn deps\" or \"gn tree\" to display recursive deps.)\n"); | |
| 145 const std::vector<const Target*>& deps = target->deps(); | |
| 146 std::vector<Label> sorted_deps; | |
| 147 for (size_t i = 0; i < deps.size(); i++) | |
| 148 sorted_deps.push_back(deps[i]->label()); | |
| 149 std::sort(sorted_deps.begin(), sorted_deps.end()); | |
| 150 for (size_t i = 0; i < sorted_deps.size(); i++) { | |
| 151 OutputString(" " + sorted_deps[i].GetUserVisibleName(target_toolchain) + | |
| 152 "\n"); | |
| 153 } | |
| 154 return 0; | |
| 155 } | |
| 156 | |
| 157 int RunDepsCommand(const std::vector<std::string>& args) { | |
| 158 if (args.size() != 1) { | |
| 159 Err(Location(), "You're holding it wrong.", | |
| 160 "Usage: \"gn deps <target_name>\"").PrintToStdout(); | |
| 161 return NULL; | |
| 162 } | |
| 163 | |
| 164 const Target* target = GetTargetForDesc(args); | |
| 165 if (!target) | |
| 166 return 1; | |
| 167 | |
| 168 // Generally we only want to display toolchains on labels when the toolchain | |
| 169 // is different than the default one for this target (which we always print | |
| 170 // in the header). | |
| 171 Label target_toolchain = target->label().GetToolchainLabel(); | |
| 172 | |
| 173 std::set<Label> all_deps; | |
| 174 RecursiveCollectDeps(target, &all_deps); | |
| 175 | |
| 176 OutputString("Recursive dependencies of " + | |
| 177 target->label().GetUserVisibleName(true) + "\n", | |
| 178 DECORATION_YELLOW); | |
| 179 | |
| 180 for (std::set<Label>::iterator i = all_deps.begin(); | |
| 181 i != all_deps.end(); ++i) | |
| 182 OutputString(" " + i->GetUserVisibleName(target_toolchain) + "\n"); | |
| 183 return 0; | |
| 184 } | |
| 185 | |
| 186 int RunTreeCommand(const std::vector<std::string>& args) { | |
| 187 if (args.size() != 1) { | |
| 188 Err(Location(), "You're holding it wrong.", | |
| 189 "Usage: \"gn tree <target_name>\"").PrintToStdout(); | |
| 190 return NULL; | |
| 191 } | |
| 192 | |
| 193 const Target* target = GetTargetForDesc(args); | |
| 194 if (!target) | |
| 195 return 1; | |
| 196 | |
| 197 OutputString(target->label().GetUserVisibleName(false) + "\n"); | |
| 198 RecursivePrintDeps(target, target->label().GetToolchainLabel(), 1); | |
| 199 | |
| 200 return 0; | |
| 201 } | |
| OLD | NEW |