| 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 |