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 |