OLD | NEW |
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 <iostream> | 5 #include <iostream> |
6 #include <map> | 6 #include <map> |
7 #include <utility> | 7 #include <utility> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/environment.h" | 11 #include "base/environment.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
13 #include "base/time/time.h" | 13 #include "base/time/time.h" |
14 #include "tools/gn/build_settings.h" | 14 #include "tools/gn/build_settings.h" |
15 #include "tools/gn/commands.h" | 15 #include "tools/gn/commands.h" |
16 #include "tools/gn/err.h" | 16 #include "tools/gn/err.h" |
17 #include "tools/gn/gyp_helper.h" | 17 #include "tools/gn/gyp_helper.h" |
18 #include "tools/gn/gyp_target_writer.h" | 18 #include "tools/gn/gyp_target_writer.h" |
19 #include "tools/gn/item_node.h" | |
20 #include "tools/gn/location.h" | 19 #include "tools/gn/location.h" |
21 #include "tools/gn/setup.h" | 20 #include "tools/gn/setup.h" |
22 #include "tools/gn/source_file.h" | 21 #include "tools/gn/source_file.h" |
23 #include "tools/gn/standard_out.h" | 22 #include "tools/gn/standard_out.h" |
24 #include "tools/gn/target.h" | 23 #include "tools/gn/target.h" |
25 | 24 |
26 namespace commands { | 25 namespace commands { |
27 | 26 |
28 namespace { | 27 namespace { |
29 | 28 |
30 typedef GypTargetWriter::TargetGroup TargetGroup; | 29 typedef GypTargetWriter::TargetGroup TargetGroup; |
31 typedef std::map<Label, TargetGroup> CorrelatedTargetsMap; | 30 typedef std::map<Label, TargetGroup> CorrelatedTargetsMap; |
32 typedef std::map<SourceFile, std::vector<TargetGroup> > GroupedTargetsMap; | 31 typedef std::map<SourceFile, std::vector<TargetGroup> > GroupedTargetsMap; |
33 typedef std::map<std::string, std::string> StringStringMap; | 32 typedef std::map<std::string, std::string> StringStringMap; |
34 | 33 |
| 34 std::vector<const BuilderRecord*> GetAllResolvedTargetRecords( |
| 35 const Builder* builder) { |
| 36 std::vector<const BuilderRecord*> all = builder->GetAllRecords(); |
| 37 std::vector<const BuilderRecord*> result; |
| 38 result.reserve(all.size()); |
| 39 for (size_t i = 0; i < all.size(); i++) { |
| 40 if (all[i]->type() == BuilderRecord::ITEM_TARGET && |
| 41 all[i]->should_generate() && |
| 42 all[i]->item()) |
| 43 result.push_back(all[i]); |
| 44 } |
| 45 return result; |
| 46 } |
| 47 |
35 // Groups targets sharing the same label between debug and release. | 48 // Groups targets sharing the same label between debug and release. |
36 void CorrelateTargets(const std::vector<const Target*>& debug_targets, | 49 void CorrelateTargets(const std::vector<const BuilderRecord*>& debug_targets, |
37 const std::vector<const Target*>& release_targets, | 50 const std::vector<const BuilderRecord*>& release_targets, |
38 CorrelatedTargetsMap* correlated) { | 51 CorrelatedTargetsMap* correlated) { |
39 for (size_t i = 0; i < debug_targets.size(); i++) { | 52 for (size_t i = 0; i < debug_targets.size(); i++) { |
40 const Target* target = debug_targets[i]; | 53 const BuilderRecord* record = debug_targets[i]; |
41 (*correlated)[target->label()].debug = target; | 54 (*correlated)[record->label()].debug = record; |
42 } | 55 } |
43 for (size_t i = 0; i < release_targets.size(); i++) { | 56 for (size_t i = 0; i < release_targets.size(); i++) { |
44 const Target* target = release_targets[i]; | 57 const BuilderRecord* record = release_targets[i]; |
45 (*correlated)[target->label()].release = target; | 58 (*correlated)[record->label()].release = record; |
46 } | 59 } |
47 } | 60 } |
48 | 61 |
49 // Verifies that both debug and release variants match. They can differ only | 62 // Verifies that both debug and release variants match. They can differ only |
50 // by flags. | 63 // by flags. |
51 bool EnsureTargetsMatch(const TargetGroup& group, Err* err) { | 64 bool EnsureTargetsMatch(const TargetGroup& group, Err* err) { |
52 // Check that both debug and release made this target. | 65 // Check that both debug and release made this target. |
53 if (!group.debug || !group.release) { | 66 if (!group.debug || !group.release) { |
54 const Target* non_null_one = group.debug ? group.debug : group.release; | 67 const BuilderRecord* non_null_one = |
| 68 group.debug ? group.debug : group.release; |
55 *err = Err(Location(), "The debug and release builds did not both generate " | 69 *err = Err(Location(), "The debug and release builds did not both generate " |
56 "a target with the name\n" + | 70 "a target with the name\n" + |
57 non_null_one->label().GetUserVisibleName(true)); | 71 non_null_one->label().GetUserVisibleName(true)); |
58 return false; | 72 return false; |
59 } | 73 } |
60 | 74 |
| 75 const Target* debug_target = group.debug->item()->AsTarget(); |
| 76 const Target* release_target = group.release->item()->AsTarget(); |
| 77 |
61 // Check the flags that determine if and where we write the GYP file. | 78 // Check the flags that determine if and where we write the GYP file. |
62 if (group.debug->item_node()->should_generate() != | 79 if (group.debug->should_generate() != group.release->should_generate() || |
63 group.release->item_node()->should_generate() || | 80 debug_target->external() != release_target->external() || |
64 group.debug->external() != group.release->external() || | 81 debug_target->gyp_file() != release_target->gyp_file()) { |
65 group.debug->gyp_file() != group.release->gyp_file()) { | |
66 *err = Err(Location(), "The metadata for the target\n" + | 82 *err = Err(Location(), "The metadata for the target\n" + |
67 group.debug->label().GetUserVisibleName(true) + | 83 group.debug->label().GetUserVisibleName(true) + |
68 "\ndoesn't match between the debug and release builds."); | 84 "\ndoesn't match between the debug and release builds."); |
69 return false; | 85 return false; |
70 } | 86 } |
71 | 87 |
72 // Check that the sources match. | 88 // Check that the sources match. |
73 if (group.debug->sources().size() != group.release->sources().size()) { | 89 if (debug_target->sources().size() != release_target->sources().size()) { |
74 *err = Err(Location(), "The source file count for the target\n" + | 90 *err = Err(Location(), "The source file count for the target\n" + |
75 group.debug->label().GetUserVisibleName(true) + | 91 group.debug->label().GetUserVisibleName(true) + |
76 "\ndoesn't have the same number of files between the debug and " | 92 "\ndoesn't have the same number of files between the debug and " |
77 "release builds."); | 93 "release builds."); |
78 return false; | 94 return false; |
79 } | 95 } |
80 for (size_t i = 0; i < group.debug->sources().size(); i++) { | 96 for (size_t i = 0; i < debug_target->sources().size(); i++) { |
81 if (group.debug->sources()[i] != group.release->sources()[i]) { | 97 if (debug_target->sources()[i] != release_target->sources()[i]) { |
82 *err = Err(Location(), "The debug and release version of the target \n" + | 98 *err = Err(Location(), "The debug and release version of the target \n" + |
83 group.debug->label().GetUserVisibleName(true) + | 99 group.debug->label().GetUserVisibleName(true) + |
84 "\ndon't agree on the file\n" + | 100 "\ndon't agree on the file\n" + |
85 group.debug->sources()[i].value()); | 101 debug_target->sources()[i].value()); |
86 return false; | 102 return false; |
87 } | 103 } |
88 } | 104 } |
89 | 105 |
90 // Check that the deps match. | 106 // Check that the deps match. |
91 if (group.debug->deps().size() != group.release->deps().size()) { | 107 if (debug_target->deps().size() != release_target->deps().size()) { |
92 *err = Err(Location(), "The source file count for the target\n" + | 108 *err = Err(Location(), "The source file count for the target\n" + |
93 group.debug->label().GetUserVisibleName(true) + | 109 group.debug->label().GetUserVisibleName(true) + |
94 "\ndoesn't have the same number of deps between the debug and " | 110 "\ndoesn't have the same number of deps between the debug and " |
95 "release builds."); | 111 "release builds."); |
96 return false; | 112 return false; |
97 } | 113 } |
98 for (size_t i = 0; i < group.debug->deps().size(); i++) { | 114 for (size_t i = 0; i < debug_target->deps().size(); i++) { |
99 if (group.debug->deps()[i].label != group.release->deps()[i].label) { | 115 if (debug_target->deps()[i].label != release_target->deps()[i].label) { |
100 *err = Err(Location(), "The debug and release version of the target \n" + | 116 *err = Err(Location(), "The debug and release version of the target \n" + |
101 group.debug->label().GetUserVisibleName(true) + | 117 group.debug->label().GetUserVisibleName(true) + |
102 "\ndon't agree on the dep\n" + | 118 "\ndon't agree on the dep\n" + |
103 group.debug->deps()[i].label.GetUserVisibleName(true)); | 119 debug_target->deps()[i].label.GetUserVisibleName(true)); |
104 return false; | 120 return false; |
105 } | 121 } |
106 } | 122 } |
107 | |
108 return true; | 123 return true; |
109 } | 124 } |
110 | 125 |
111 // Python uses shlex.split, which we partially emulate here. | 126 // Python uses shlex.split, which we partially emulate here. |
112 // | 127 // |
113 // Advances to the next "word" in a GYP_DEFINES entry. This is something | 128 // Advances to the next "word" in a GYP_DEFINES entry. This is something |
114 // separated by whitespace or '='. We allow backslash escaping and quoting. | 129 // separated by whitespace or '='. We allow backslash escaping and quoting. |
115 // The return value will be the index into the array immediately following the | 130 // The return value will be the index into the array immediately following the |
116 // word, and the contents of the word will be placed into |*word|. | 131 // word, and the contents of the word will be placed into |*word|. |
117 size_t GetNextGypDefinesWord(const std::string& defines, | 132 size_t GetNextGypDefinesWord(const std::string& defines, |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 } | 220 } |
206 | 221 |
207 // Windows SDK path. GYP and the GN build use the same name. | 222 // Windows SDK path. GYP and the GN build use the same name. |
208 static const char kWinSdkPath[] = "windows_sdk_path"; | 223 static const char kWinSdkPath[] = "windows_sdk_path"; |
209 if (!gyp_defines[kWinSdkPath].empty()) | 224 if (!gyp_defines[kWinSdkPath].empty()) |
210 result[kWinSdkPath] = Value(NULL, gyp_defines[kWinSdkPath]); | 225 result[kWinSdkPath] = Value(NULL, gyp_defines[kWinSdkPath]); |
211 | 226 |
212 return result; | 227 return result; |
213 } | 228 } |
214 | 229 |
215 // Returns the number of targets, number of GYP files. | 230 // Returns the (number of targets, number of GYP files). |
216 std::pair<int, int> WriteGypFiles( | 231 std::pair<int, int> WriteGypFiles(CommonSetup* debug_setup, |
217 const BuildSettings& debug_settings, | 232 CommonSetup* release_setup, |
218 const BuildSettings& release_settings, | 233 Err* err) { |
219 Err* err) { | |
220 // Group all targets by output GYP file name. | 234 // Group all targets by output GYP file name. |
221 std::vector<const Target*> debug_targets; | 235 std::vector<const BuilderRecord*> debug_targets = |
222 std::vector<const Target*> release_targets; | 236 GetAllResolvedTargetRecords(debug_setup->builder()); |
223 debug_settings.target_manager().GetAllTargets(&debug_targets); | 237 std::vector<const BuilderRecord*> release_targets = |
224 release_settings.target_manager().GetAllTargets(&release_targets); | 238 GetAllResolvedTargetRecords(release_setup->builder()); |
225 | 239 |
226 // Match up the debug and release version of each target by label. | 240 // Match up the debug and release version of each target by label. |
227 CorrelatedTargetsMap correlated; | 241 CorrelatedTargetsMap correlated; |
228 CorrelateTargets(debug_targets, release_targets, &correlated); | 242 CorrelateTargets(debug_targets, release_targets, &correlated); |
229 | 243 |
230 GypHelper helper; | 244 GypHelper helper; |
231 GroupedTargetsMap grouped_targets; | 245 GroupedTargetsMap grouped_targets; |
232 int target_count = 0; | 246 int target_count = 0; |
233 for (CorrelatedTargetsMap::iterator i = correlated.begin(); | 247 for (CorrelatedTargetsMap::iterator i = correlated.begin(); |
234 i != correlated.end(); ++i) { | 248 i != correlated.end(); ++i) { |
235 const TargetGroup& group = i->second; | 249 const TargetGroup& group = i->second; |
236 if (!group.debug->item_node()->should_generate()) | 250 if (!group.debug->should_generate()) |
237 continue; // Skip non-generated ones. | 251 continue; // Skip non-generated ones. |
238 if (group.debug->external()) | 252 if (group.debug->item()->AsTarget()->external()) |
239 continue; // Skip external ones. | 253 continue; // Skip external ones. |
240 if (group.debug->gyp_file().is_null()) | 254 if (group.debug->item()->AsTarget()->gyp_file().is_null()) |
241 continue; // Skip ones without GYP files. | 255 continue; // Skip ones without GYP files. |
242 | 256 |
243 if (!EnsureTargetsMatch(group, err)) | 257 if (!EnsureTargetsMatch(group, err)) |
244 return std::make_pair(0, 0); | 258 return std::make_pair(0, 0); |
245 | 259 |
246 target_count++; | 260 target_count++; |
247 grouped_targets[helper.GetGypFileForTarget(group.debug, err)].push_back( | 261 grouped_targets[ |
248 group); | 262 helper.GetGypFileForTarget(group.debug->item()->AsTarget(), err)] |
| 263 .push_back(group); |
249 if (err->has_error()) | 264 if (err->has_error()) |
250 return std::make_pair(0, 0); | 265 return std::make_pair(0, 0); |
251 } | 266 } |
252 | 267 |
253 // Write each GYP file. | 268 // Write each GYP file. |
254 for (GroupedTargetsMap::iterator i = grouped_targets.begin(); | 269 for (GroupedTargetsMap::iterator i = grouped_targets.begin(); |
255 i != grouped_targets.end(); ++i) { | 270 i != grouped_targets.end(); ++i) { |
256 GypTargetWriter::WriteFile(i->first, i->second, err); | 271 GypTargetWriter::WriteFile(i->first, i->second, err); |
257 if (err->has_error()) | 272 if (err->has_error()) |
258 return std::make_pair(0, 0); | 273 return std::make_pair(0, 0); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 "gn_release.tmp/")); | 366 "gn_release.tmp/")); |
352 | 367 |
353 // Run both debug and release builds in parallel. | 368 // Run both debug and release builds in parallel. |
354 setup_release->RunPreMessageLoop(); | 369 setup_release->RunPreMessageLoop(); |
355 if (!setup_debug->Run()) | 370 if (!setup_debug->Run()) |
356 return 1; | 371 return 1; |
357 if (!setup_release->RunPostMessageLoop()) | 372 if (!setup_release->RunPostMessageLoop()) |
358 return 1; | 373 return 1; |
359 | 374 |
360 Err err; | 375 Err err; |
361 std::pair<int, int> counts = WriteGypFiles(setup_debug->build_settings(), | 376 std::pair<int, int> counts = WriteGypFiles(setup_debug, setup_release, &err); |
362 setup_release->build_settings(), | |
363 &err); | |
364 if (err.has_error()) { | 377 if (err.has_error()) { |
365 err.PrintToStdout(); | 378 err.PrintToStdout(); |
366 return 1; | 379 return 1; |
367 } | 380 } |
368 | 381 |
369 // Timing info. | 382 // Timing info. |
370 base::TimeTicks end_time = base::TimeTicks::Now(); | 383 base::TimeTicks end_time = base::TimeTicks::Now(); |
371 if (!cmdline->HasSwitch(kSwitchQuiet)) { | 384 if (!cmdline->HasSwitch(kSwitchQuiet)) { |
372 OutputString("Done. ", DECORATION_GREEN); | 385 OutputString("Done. ", DECORATION_GREEN); |
373 | 386 |
374 std::string stats = "Wrote " + | 387 std::string stats = "Wrote " + |
375 base::IntToString(counts.first) + " targets to " + | 388 base::IntToString(counts.first) + " targets to " + |
376 base::IntToString(counts.second) + " GYP files read from " + | 389 base::IntToString(counts.second) + " GYP files read from " + |
377 base::IntToString( | 390 base::IntToString( |
378 setup_debug->scheduler().input_file_manager()->GetInputFileCount()) | 391 setup_debug->scheduler().input_file_manager()->GetInputFileCount()) |
379 + " GN files in " + | 392 + " GN files in " + |
380 base::IntToString((end_time - begin_time).InMilliseconds()) + "ms\n"; | 393 base::IntToString((end_time - begin_time).InMilliseconds()) + "ms\n"; |
381 | 394 |
382 OutputString(stats); | 395 OutputString(stats); |
383 } | 396 } |
384 | 397 |
385 return 0; | 398 return 0; |
386 } | 399 } |
387 | 400 |
388 } // namespace commands | 401 } // namespace commands |
OLD | NEW |