Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "tools/gn/xcode_writer.h" | 5 #include "tools/gn/xcode_writer.h" |
| 6 | 6 |
| 7 #include <iomanip> | 7 #include <iomanip> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <sstream> | 10 #include <sstream> |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 #include "tools/gn/filesystem_utils.h" | 24 #include "tools/gn/filesystem_utils.h" |
| 25 #include "tools/gn/settings.h" | 25 #include "tools/gn/settings.h" |
| 26 #include "tools/gn/source_file.h" | 26 #include "tools/gn/source_file.h" |
| 27 #include "tools/gn/target.h" | 27 #include "tools/gn/target.h" |
| 28 #include "tools/gn/value.h" | 28 #include "tools/gn/value.h" |
| 29 #include "tools/gn/variables.h" | 29 #include "tools/gn/variables.h" |
| 30 #include "tools/gn/xcode_object.h" | 30 #include "tools/gn/xcode_object.h" |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 const char kXCTestTargetNamePostfix[] = "_module"; | |
| 35 const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; | |
| 36 | |
| 37 typedef std::unordered_map<const Target*, Target::FileList> TargetToFileList; | |
|
sdefresne
2016/12/14 13:00:03
nit: it is recommend to use "using" instead of "ty
liaoyuke
2016/12/15 00:03:11
Done.
| |
| 38 | |
| 34 struct SafeEnvironmentVariableInfo { | 39 struct SafeEnvironmentVariableInfo { |
| 35 const char* name; | 40 const char* name; |
| 36 bool capture_at_generation; | 41 bool capture_at_generation; |
| 37 }; | 42 }; |
| 38 | 43 |
| 39 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { | 44 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { |
| 40 {"HOME", true}, {"LANG", true}, {"PATH", true}, | 45 {"HOME", true}, {"LANG", true}, {"PATH", true}, |
| 41 {"USER", true}, {"TMPDIR", false}, | 46 {"USER", true}, {"TMPDIR", false}, |
| 42 }; | 47 }; |
| 43 | 48 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 80 | 85 |
| 81 script << "ninja -C ."; | 86 script << "ninja -C ."; |
| 82 if (!ninja_extra_args.empty()) | 87 if (!ninja_extra_args.empty()) |
| 83 script << " " << ninja_extra_args; | 88 script << " " << ninja_extra_args; |
| 84 if (!target_name.empty()) | 89 if (!target_name.empty()) |
| 85 script << " " << target_name; | 90 script << " " << target_name; |
| 86 script << "\nexit 1\n"; | 91 script << "\nexit 1\n"; |
| 87 return script.str(); | 92 return script.str(); |
| 88 } | 93 } |
| 89 | 94 |
| 95 // Append |file_list_extra| to |file_list_base| and remove duplicate elements. | |
| 96 void AppendAndRemoveDuplicates(Target::FileList* file_list_base, | |
| 97 const Target::FileList& file_list_extra) { | |
| 98 file_list_base->insert(file_list_base->end(), file_list_extra.begin(), | |
| 99 file_list_extra.end()); | |
| 100 std::sort(file_list_base->begin(), file_list_base->end()); | |
| 101 file_list_base->erase( | |
| 102 std::unique(file_list_base->begin(), file_list_base->end()), | |
| 103 file_list_base->end()); | |
| 104 } | |
| 105 | |
| 106 // Find the list of earl grey files recursively under |target|. | |
| 107 void GetEarlGreyFiles(const Target* target, | |
| 108 TargetToFileList* eg_files_per_target) { | |
| 109 // Early return if already visited and processed. | |
| 110 if (eg_files_per_target->find(target) != eg_files_per_target->end()) { | |
|
sdefresne
2016/12/14 13:00:03
No braces here (since there are not used in the re
liaoyuke
2016/12/15 00:03:11
Done.
| |
| 111 return; | |
| 112 } | |
| 113 | |
| 114 Target::FileList eg_files; | |
| 115 for (const SourceFile& file : target->sources()) { | |
| 116 if (base::EndsWith(file.GetName(), kEarlGreyFileNameIdentifier, | |
| 117 base::CompareCase::SENSITIVE)) { | |
| 118 eg_files.push_back(file); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 // Call recursively on public and private deps. | |
| 123 for (const auto& target : target->public_deps()) { | |
| 124 GetEarlGreyFiles(target.ptr, eg_files_per_target); | |
| 125 Target::FileList deps_eg_files = eg_files_per_target->at(target.ptr); | |
| 126 if (!deps_eg_files.empty()) { | |
|
sdefresne
2016/12/14 13:00:02
No braces here.
liaoyuke
2016/12/15 00:03:11
Done.
| |
| 127 AppendAndRemoveDuplicates(&eg_files, deps_eg_files); | |
|
sdefresne
2016/12/14 13:00:03
I think it would be better to just add everything
liaoyuke
2016/12/15 00:03:11
Done.
| |
| 128 } | |
| 129 } | |
| 130 | |
| 131 for (const auto& target : target->private_deps()) { | |
| 132 GetEarlGreyFiles(target.ptr, eg_files_per_target); | |
| 133 Target::FileList deps_eg_files = eg_files_per_target->at(target.ptr); | |
| 134 if (!deps_eg_files.empty()) { | |
| 135 AppendAndRemoveDuplicates(&eg_files, deps_eg_files); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 // Sort eg_files to remove duplicates. | |
| 140 std::sort(eg_files.begin(), eg_files.end()); | |
| 141 eg_files.erase(std::unique(eg_files.begin(), eg_files.end()), eg_files.end()); | |
| 142 | |
| 143 eg_files_per_target->insert(std::make_pair(target, eg_files)); | |
| 144 } | |
| 145 | |
| 146 // Find the list of earl grey files recursively under each of the application | |
|
sdefresne
2016/12/14 13:00:02
nit: Find -> Finds
liaoyuke
2016/12/15 00:03:11
Done.
| |
| 147 // and xctest bundle pair. | |
| 148 void GetEarlGreyFilesForAll( | |
|
sdefresne
2016/12/14 13:00:02
I'm not sure we need to check source file in xctes
liaoyuke
2016/12/15 00:03:11
You are right, I have double-checked, there is no
| |
| 149 const std::vector<const Target*>& xctest_targets, | |
| 150 const std::vector<const Target*>& application_targets, | |
| 151 std::vector<Target::FileList>* file_lists) { | |
|
sdefresne
2016/12/14 13:00:03
DCHECK_EQ(xctest_targets.size(), application_targe
liaoyuke
2016/12/15 00:03:11
Acknowledged.
| |
| 152 TargetToFileList eg_files_per_target; | |
| 153 | |
| 154 for (size_t i = 0; i < xctest_targets.size(); ++i) { | |
| 155 GetEarlGreyFiles(xctest_targets[i], &eg_files_per_target); | |
| 156 GetEarlGreyFiles(application_targets[i], &eg_files_per_target); | |
| 157 | |
| 158 Target::FileList eg_files; | |
| 159 AppendAndRemoveDuplicates(&eg_files, | |
| 160 eg_files_per_target.at(xctest_targets[i])); | |
| 161 AppendAndRemoveDuplicates(&eg_files, | |
| 162 eg_files_per_target.at(application_targets[i])); | |
| 163 file_lists->push_back(eg_files); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 // Returns the corresponding application target given a XCTest target. Returns | |
|
sdefresne
2016/12/14 13:00:03
I would change this function to DCHECK if it does
liaoyuke
2016/12/15 00:03:11
Thank you for the note. I will this logic when I w
liaoyuke
2016/12/15 00:03:11
Acknowledged.
| |
| 168 // NULL if not found. | |
| 169 const Target* FindApplicationTarget(const Target* xctest_target, | |
| 170 const std::vector<const Target*>& targets) { | |
| 171 for (const Target* target : targets) { | |
| 172 if ((target->label().name() + kXCTestTargetNamePostfix) | |
| 173 .compare(xctest_target->label().name()) == 0) { | |
| 174 return target; | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 return NULL; | |
| 179 } | |
| 180 | |
| 90 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { | 181 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { |
| 91 public: | 182 public: |
| 92 CollectPBXObjectsPerClassHelper() {} | 183 CollectPBXObjectsPerClassHelper() {} |
| 93 | 184 |
| 94 void Visit(PBXObject* object) override { | 185 void Visit(PBXObject* object) override { |
| 95 DCHECK(object); | 186 DCHECK(object); |
| 96 objects_per_class_[object->Class()].push_back(object); | 187 objects_per_class_[object->Class()].push_back(object); |
| 97 } | 188 } |
| 98 | 189 |
| 99 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& | 190 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 // Sort the list of targets per-label to get a consistent ordering of them | 351 // Sort the list of targets per-label to get a consistent ordering of them |
| 261 // in the generated Xcode project (and thus stability of the file generated). | 352 // in the generated Xcode project (and thus stability of the file generated). |
| 262 std::sort(targets->begin(), targets->end(), | 353 std::sort(targets->begin(), targets->end(), |
| 263 [](const Target* a, const Target* b) { | 354 [](const Target* a, const Target* b) { |
| 264 return a->label().name() < b->label().name(); | 355 return a->label().name() < b->label().name(); |
| 265 }); | 356 }); |
| 266 | 357 |
| 267 return true; | 358 return true; |
| 268 } | 359 } |
| 269 | 360 |
| 361 // static | |
| 362 void XcodeWriter::FilterXCTestTargets( | |
| 363 const std::vector<const Target*>& targets, | |
| 364 std::vector<const Target*>* xctest_targets, | |
| 365 std::vector<const Target*>* application_targets) { | |
| 366 // Filter out all targets of type CREATE_BUNDLE and whose bundle_data has | |
| 367 // product_type: "com.apple.product-type.bundle.unit-test". | |
| 368 for (const Target* target : targets) { | |
| 369 if (target->output_type() != Target::CREATE_BUNDLE) { | |
|
sdefresne
2016/12/14 13:00:02
nit: I would use an helper method IsXCTestTarget h
| |
| 370 continue; | |
| 371 } | |
| 372 if (target->bundle_data().product_type().compare( | |
| 373 "com.apple.product-type.bundle.unit-test") == 0) { | |
| 374 xctest_targets->push_back(target); | |
| 375 const Target* application_target = FindApplicationTarget(target, targets); | |
| 376 DCHECK(application_target); | |
| 377 application_targets->push_back(application_target); | |
| 378 } | |
| 379 } | |
| 380 } | |
| 381 | |
| 270 void XcodeWriter::CreateProductsProject( | 382 void XcodeWriter::CreateProductsProject( |
| 271 const std::vector<const Target*>& targets, | 383 const std::vector<const Target*>& targets, |
| 272 const PBXAttributes& attributes, | 384 const PBXAttributes& attributes, |
| 273 const std::string& source_path, | 385 const std::string& source_path, |
| 274 const std::string& config_name, | 386 const std::string& config_name, |
| 275 const std::string& root_target, | 387 const std::string& root_target, |
| 276 const std::string& ninja_extra_args, | 388 const std::string& ninja_extra_args, |
| 277 const BuildSettings* build_settings, | 389 const BuildSettings* build_settings, |
| 278 TargetOsType target_os) { | 390 TargetOsType target_os) { |
| 279 std::unique_ptr<PBXProject> main_project( | 391 std::unique_ptr<PBXProject> main_project( |
| 280 new PBXProject("products", config_name, source_path, attributes)); | 392 new PBXProject("products", config_name, source_path, attributes)); |
| 281 | 393 |
| 394 // Filter XCTest targets and their corresponding application targets and find | |
| 395 // list of earl grey test files recursively under the pairs. | |
| 396 std::vector<const Target*> xctest_targets; | |
| 397 std::vector<const Target*> application_targets; | |
| 398 std::vector<Target::FileList> earl_grey_file_lists; | |
| 399 XcodeWriter::FilterXCTestTargets(targets, &xctest_targets, | |
| 400 &application_targets); | |
| 401 GetEarlGreyFilesForAll(xctest_targets, application_targets, | |
| 402 &earl_grey_file_lists); | |
| 403 | |
| 282 std::string build_path; | 404 std::string build_path; |
| 283 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 405 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
| 284 | 406 |
| 285 main_project->AddAggregateTarget( | 407 main_project->AddAggregateTarget( |
| 286 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); | 408 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); |
| 287 | 409 |
| 288 for (const Target* target : targets) { | 410 for (const Target* target : targets) { |
| 289 switch (target->output_type()) { | 411 switch (target->output_type()) { |
| 290 case Target::EXECUTABLE: | 412 case Target::EXECUTABLE: |
| 291 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) | 413 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 428 for (auto* object : pair.second) { | 550 for (auto* object : pair.second) { |
| 429 object->Print(out, 2); | 551 object->Print(out, 2); |
| 430 } | 552 } |
| 431 out << "/* End " << ToString(pair.first) << " section */\n"; | 553 out << "/* End " << ToString(pair.first) << " section */\n"; |
| 432 } | 554 } |
| 433 | 555 |
| 434 out << "\t};\n" | 556 out << "\t};\n" |
| 435 << "\trootObject = " << project->Reference() << ";\n" | 557 << "\trootObject = " << project->Reference() << ";\n" |
| 436 << "}\n"; | 558 << "}\n"; |
| 437 } | 559 } |
| OLD | NEW |