Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: tools/gn/commands.cc

Issue 937003002: Enhance GN introspection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/command_line.h"
6 #include "tools/gn/builder.h"
5 #include "tools/gn/commands.h" 7 #include "tools/gn/commands.h"
6 #include "tools/gn/filesystem_utils.h" 8 #include "tools/gn/filesystem_utils.h"
7 #include "tools/gn/item.h" 9 #include "tools/gn/item.h"
8 #include "tools/gn/label.h" 10 #include "tools/gn/label.h"
9 #include "tools/gn/label_pattern.h" 11 #include "tools/gn/label_pattern.h"
10 #include "tools/gn/setup.h" 12 #include "tools/gn/setup.h"
11 #include "tools/gn/standard_out.h" 13 #include "tools/gn/standard_out.h"
12 #include "tools/gn/target.h" 14 #include "tools/gn/target.h"
13 15
14 namespace commands { 16 namespace commands {
15 17
18 namespace {
19
20 // Like above but the input string can be a pattern that matches multiple
21 // targets. If the input does not parse as a pattern, prints and error and
22 // returns false. If the pattern is valid, fills the vector (which might be
23 // empty if there are no matches) and returns true.
24 //
25 // If all_tolchains is false, a pattern with an unspecified toolchain will
scottmg 2015/02/19 21:52:01 all_toolchains
26 // match the default toolchain only. If true, all toolchains will be matched.
27 bool ResolveTargetsFromCommandLinePattern(
28 Setup* setup,
29 const std::string& label_pattern,
30 bool all_toolchains,
31 std::vector<const Target*>* matches) {
32 Value pattern_value(nullptr, label_pattern);
33
34 Err err;
35 LabelPattern pattern = LabelPattern::GetPattern(
36 SourceDirForCurrentDirectory(setup->build_settings().root_path()),
37 pattern_value,
38 &err);
39 if (err.has_error()) {
40 err.PrintToStdout();
41 return false;
42 }
43
44 if (!all_toolchains) {
45 // By default a pattern with an empty toolchain will match all toolchains.
46 // If the caller wants to default to the main toolchain only, set it
47 // explicitly.
48 if (pattern.toolchain().is_null()) {
49 // No explicit toolchain set.
50 pattern.set_toolchain(setup->loader()->default_toolchain_label());
51 }
52 }
53
54 std::vector<LabelPattern> pattern_vector;
55 pattern_vector.push_back(pattern);
56 FilterTargetsByPatterns(setup->builder()->GetAllResolvedTargets(),
57 pattern_vector, matches);
58 return true;
59 }
60
61
62 // If there's an error, it will be printed and false will be returned.
63 bool ResolveStringFromCommandLineInput(
64 Setup* setup,
65 const SourceDir& current_dir,
66 const std::string& input,
67 bool all_toolchains,
68 UniqueVector<const Target*>* target_matches,
69 UniqueVector<const Config*>* config_matches,
70 UniqueVector<const Toolchain*>* toolchain_matches,
71 UniqueVector<SourceFile>* file_matches) {
72 if (LabelPattern::HasWildcard(input)) {
73 // For now, only match patterns against targets. It might be nice in the
74 // future to allow the user to specify which types of things they want to
75 // match, but it should probably only match targets by default.
76 std::vector<const Target*> target_match_vector;
77 if (!ResolveTargetsFromCommandLinePattern(setup, input, all_toolchains,
78 &target_match_vector))
79 return false;
80 for (const Target* target : target_match_vector)
81 target_matches->push_back(target);
82 return true;
83 }
84
85 // Try to figure out what this thing is.
86 Err err;
87 Label label = Label::Resolve(current_dir,
88 setup->loader()->default_toolchain_label(),
89 Value(nullptr, input), &err);
90 if (err.has_error()) {
91 err.PrintToStdout();
92 return false;
93 }
94
95 const Item* item = setup->builder()->GetItem(label);
96 if (item) {
97 if (const Config* as_config = item->AsConfig())
98 config_matches->push_back(as_config);
99 else if (const Target* as_target = item->AsTarget())
100 target_matches->push_back(as_target);
101 else if (const Toolchain* as_toolchain = item->AsToolchain())
102 toolchain_matches->push_back(as_toolchain);
103 } else {
104 // Not an item, assume this must be a file.
105 file_matches->push_back(current_dir.ResolveRelativeFile(
106 input, setup->build_settings().root_path_utf8()));
107 }
108
109 return true;
110 }
111
112 enum TargetPrintingMode {
113 TARGET_PRINT_BUILDFILE,
114 TARGET_PRINT_LABEL,
115 TARGET_PRINT_OUTPUT,
116 };
117
118 // Retrieves the target printing mode based on the command line flags for the
119 // current process. Returns true on success. On error, prints a message to the
120 // console and returns false.
121 bool GetTargetPrintingMode(TargetPrintingMode* mode) {
122 std::string switch_key = "as";
123 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
124
125 if (!cmdline->HasSwitch(switch_key)) {
126 // Default to labels.
127 *mode = TARGET_PRINT_LABEL;
128 return true;
129 }
130
131 std::string value = cmdline->GetSwitchValueASCII(switch_key);
132 if (value == "buildfile") {
133 *mode = TARGET_PRINT_BUILDFILE;
134 return true;
135 }
136 if (value == "label") {
137 *mode = TARGET_PRINT_LABEL;
138 return true;
139 }
140 if (value == "output") {
141 *mode = TARGET_PRINT_OUTPUT;
142 return true;
143 }
144
145 Err(Location(), "Invalid value for \"--as\".",
146 "I was expecting \"buildfile\", \"label\", or \"output\" but you\n"
147 "said \"" + value + "\".").PrintToStdout();
148 return false;
149 }
150
151 // Returns the target type filter based on the command line flags for the
152 // current process. Returns true on success. On error, prints a message to the
153 // console and returns false.
154 //
155 // Target::UNKNOWN will be set if there is no filter. Target::ACTION_FOREACH
156 // will never be returned. Code applying the filters should apply Target::ACTION
157 // to both ACTION and ACTION_FOREACH.
158 bool GetTargetTypeFilter(Target::OutputType* type) {
159 std::string switch_key = "type";
160 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
161
162 if (!cmdline->HasSwitch(switch_key)) {
163 // Default to unknown -> no filtering.
164 *type = Target::UNKNOWN;
165 return true;
166 }
167
168 std::string value = cmdline->GetSwitchValueASCII(switch_key);
169 if (value == "group") {
170 *type = Target::GROUP;
171 return true;
172 }
173 if (value == "executable") {
174 *type = Target::EXECUTABLE;
175 return true;
176 }
177 if (value == "shared_library") {
178 *type = Target::SHARED_LIBRARY;
179 return true;
180 }
181 if (value == "static_library") {
182 *type = Target::STATIC_LIBRARY;
183 return true;
184 }
185 if (value == "source_set") {
186 *type = Target::SOURCE_SET;
187 return true;
188 }
189 if (value == "copy") {
190 *type = Target::COPY_FILES;
191 return true;
192 }
193 if (value == "action") {
194 *type = Target::ACTION;
195 return true;
196 }
197
198 Err(Location(), "Invalid value for \"--type\".").PrintToStdout();
199 return false;
200 }
201
202
203 // Applies any testonly filtering specified on the command line to the given
204 // target set. On failure, prints an error and returns false.
205 bool ApplyTestonlyFilter(std::vector<const Target*>* targets) {
206 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
207 std::string testonly_key = "testonly";
208
209 if (targets->empty() || !cmdline->HasSwitch(testonly_key))
210 return true;
211
212 std::string testonly_value = cmdline->GetSwitchValueASCII(testonly_key);
213 bool testonly = false;
214 if (testonly_value == "true") {
215 testonly = true;
216 } else if (testonly_value != "false") {
217 Err(Location(), "Bad value for --testonly.",
218 "I was expecting --testonly=true or --testonly=false.")
219 .PrintToStdout();
220 return false;
221 }
222
223 // Filter into a copy of the vector, then swap to output.
224 std::vector<const Target*> result;
225 result.reserve(targets->size());
226
227 for (const Target* target : *targets) {
228 if (target->testonly() == testonly)
229 result.push_back(target);
230 }
231
232 targets->swap(result);
233 return true;
234 }
235
236 // Applies any target type filtering specified on the command line to the given
237 // target set. On failure, prints an error and returns false.
238 bool ApplyTypeFilter(std::vector<const Target*>* targets) {
239 Target::OutputType type = Target::UNKNOWN;
240 if (!GetTargetTypeFilter(&type))
241 return false;
242 if (targets->empty() || type == Target::UNKNOWN)
243 return true; // Nothing to filter out.
244
245 // Filter into a copy of the vector, then swap to output.
246 std::vector<const Target*> result;
247 result.reserve(targets->size());
248
249 for (const Target* target : *targets) {
250 // Make "action" also apply to ACTION_FOREACH.
251 if (target->output_type() == type ||
252 (type == Target::ACTION &&
253 target->output_type() == Target::ACTION_FOREACH))
254 result.push_back(target);
255 }
256
257 targets->swap(result);
258 return true;
259 }
260
261 // Returns the file path generating this item.
262 base::FilePath BuildFileForItem(const Item* item) {
263 return item->defined_from()->GetRange().begin().file()->physical_name();
264 }
265
266 void PrintTargetsAsBuildfiles(bool indent,
267 const std::vector<const Target*>& targets) {
268 // Output the set of unique source files.
269 std::set<std::string> unique_files;
270 for (const Target* target : targets)
271 unique_files.insert(FilePathToUTF8(BuildFileForItem(target)));
272
273 for (const std::string& file : unique_files) {
274 if (indent)
275 OutputString(" ");
276 OutputString(file + "\n");
277 }
278 }
279
280 void PrintTargetsAsLabels(bool indent,
281 const std::vector<const Target*>& targets) {
282 // Putting the labels into a set automatically sorts them for us.
283 std::set<Label> unique_labels;
284 for (const auto& target : targets)
285 unique_labels.insert(target->label());
286
287 // Grab the label of the default toolchain from the first target.
288 Label default_tc_label =
289 targets[0]->settings()->default_toolchain_label();
290
291 for (const Label& label : unique_labels) {
292 // Print toolchain only for ones not in the default toolchain.
293 if (indent)
294 OutputString(" ");
295 OutputString(label.GetUserVisibleName(
296 label.GetToolchainLabel() != default_tc_label));
297 OutputString("\n");
298 }
299 }
300
301 void PrintTargetsAsOutputs(bool indent,
302 const std::vector<const Target*>& targets) {
303 if (targets.empty())
304 return;
305
306 // Grab the build settings from a random target.
307 const BuildSettings* build_settings =
308 targets[0]->settings()->build_settings();
309
310 SourceDir current_dir = SourceDirForCurrentDirectory(
311 build_settings->root_path());
312 for (const Target* target : targets) {
313 // Use the link output file if there is one, otherwise fall back to the
314 // dependency output file (for actions, for example).
315 OutputFile output_file = target->link_output_file();
316 if (output_file.value().empty())
317 output_file = target->dependency_output_file();
318
319 SourceFile output_as_source =
320 output_file.AsSourceFile(build_settings);
321 std::string result = RebasePath(output_as_source.value(), current_dir,
322 build_settings->root_path_utf8());
323 if (indent)
324 OutputString(" ");
325 OutputString(result);
326 OutputString("\n");
327 }
328 }
329
330 } // namespace
331
16 CommandInfo::CommandInfo() 332 CommandInfo::CommandInfo()
17 : help_short(nullptr), 333 : help_short(nullptr),
18 help(nullptr), 334 help(nullptr),
19 runner(nullptr) { 335 runner(nullptr) {
20 } 336 }
21 337
22 CommandInfo::CommandInfo(const char* in_help_short, 338 CommandInfo::CommandInfo(const char* in_help_short,
23 const char* in_help, 339 const char* in_help,
24 CommandRunner in_runner) 340 CommandRunner in_runner)
25 : help_short(in_help_short), 341 : help_short(in_help_short),
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 Err(Location(), "Not a target.", 393 Err(Location(), "Not a target.",
78 "The \"" + label.GetUserVisibleName(false) + "\" thing\n" 394 "The \"" + label.GetUserVisibleName(false) + "\" thing\n"
79 "is not a target. Somebody should probably implement this command for " 395 "is not a target. Somebody should probably implement this command for "
80 "other\nitem types."); 396 "other\nitem types.");
81 return nullptr; 397 return nullptr;
82 } 398 }
83 399
84 return target; 400 return target;
85 } 401 }
86 402
87 bool ResolveTargetsFromCommandLinePattern( 403 bool ResolveFromCommandLineInput(
88 Setup* setup, 404 Setup* setup,
89 const std::string& label_pattern, 405 const std::vector<std::string>& input,
90 bool all_toolchains, 406 bool all_toolchains,
91 std::vector<const Target*>* matches) { 407 UniqueVector<const Target*>* target_matches,
92 Value pattern_value(nullptr, label_pattern); 408 UniqueVector<const Config*>* config_matches,
93 409 UniqueVector<const Toolchain*>* toolchain_matches,
94 Err err; 410 UniqueVector<SourceFile>* file_matches) {
95 LabelPattern pattern = LabelPattern::GetPattern( 411 if (input.empty()) {
96 SourceDirForCurrentDirectory(setup->build_settings().root_path()), 412 Err(Location(), "You need to specify a label, file, or pattern.")
97 pattern_value, 413 .PrintToStdout();
98 &err);
99 if (err.has_error()) {
100 err.PrintToStdout();
101 return false; 414 return false;
102 } 415 }
103 416
104 if (!all_toolchains) { 417 SourceDir cur_dir =
105 // By default a pattern with an empty toolchain will match all toolchains. 418 SourceDirForCurrentDirectory(setup->build_settings().root_path());
106 // IF the caller wants to default to the main toolchain only, set it 419 for (const auto& cur : input) {
107 // explicitly. 420 if (!ResolveStringFromCommandLineInput(setup, cur_dir, cur,
108 if (pattern.toolchain().is_null()) { 421 all_toolchains, target_matches,
109 // No explicit toolchain set. 422 config_matches, toolchain_matches,
110 pattern.set_toolchain(setup->loader()->default_toolchain_label()); 423 file_matches))
111 } 424 return false;
112 } 425 }
113
114 std::vector<LabelPattern> pattern_vector;
115 pattern_vector.push_back(pattern);
116 FilterTargetsByPatterns(setup->builder()->GetAllResolvedTargets(),
117 pattern_vector, matches);
118 return true; 426 return true;
119 } 427 }
120 428
429 void FilterTargetsByPatterns(const std::vector<const Target*>& input,
scottmg 2015/02/19 21:52:01 this could be template <class O> for output
brettw 2015/02/19 22:12:02 Yeah, but I didn't feel like I should implement th
430 const std::vector<LabelPattern>& filter,
431 std::vector<const Target*>* output) {
432 for (const auto& target : input) {
433 for (const auto& pattern : filter) {
434 if (pattern.Matches(target->label())) {
435 output->push_back(target);
436 break;
437 }
438 }
439 }
440 }
441
442 void FilterTargetsByPatterns(const std::vector<const Target*>& input,
443 const std::vector<LabelPattern>& filter,
444 UniqueVector<const Target*>* output) {
445 for (const auto& target : input) {
446 for (const auto& pattern : filter) {
447 if (pattern.Matches(target->label())) {
448 output->push_back(target);
449 break;
450 }
451 }
452 }
453 }
454
455 void FilterAndPrintTargets(bool indent, std::vector<const Target*>* targets) {
456 if (targets->empty())
457 return;
458
459 if (!ApplyTestonlyFilter(targets))
460 return;
461 if (!ApplyTypeFilter(targets))
462 return;
463
464 TargetPrintingMode printing_mode = TARGET_PRINT_LABEL;
465 if (targets->empty() || !GetTargetPrintingMode(&printing_mode))
466 return;
467 switch (printing_mode) {
468 case TARGET_PRINT_BUILDFILE:
469 PrintTargetsAsBuildfiles(indent, *targets);
470 break;
471 case TARGET_PRINT_LABEL:
472 PrintTargetsAsLabels(indent, *targets);
473 break;
474 case TARGET_PRINT_OUTPUT:
475 PrintTargetsAsOutputs(indent, *targets);
476 break;
477 }
478 }
479
480 void FilterAndPrintTargetSet(bool indent,
481 const std::set<const Target*>& targets) {
482 std::vector<const Target*> target_vector(targets.begin(), targets.end());
483 FilterAndPrintTargets(indent, &target_vector);
484 }
485
121 } // namespace commands 486 } // namespace commands
OLDNEW
« tools/gn/commands.h ('K') | « tools/gn/commands.h ('k') | tools/gn/label_pattern.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698