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 14 matching lines...) Expand all Loading... |
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 using TargetToFileList = std::unordered_map<const Target*, Target::FileList>; | 34 using TargetToFileList = std::unordered_map<const Target*, Target::FileList>; |
| 35 using TargetToNativeTarget = |
| 36 std::unordered_map<const Target*, PBXNativeTarget*>; |
| 37 using FileToTargets = std::map<SourceFile, |
| 38 std::vector<const Target*>, |
| 39 bool (*)(const SourceFile&, const SourceFile&)>; |
35 | 40 |
36 const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; | 41 const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; |
37 const char kXCTestFileNameIdentifier[] = "xctest.mm"; | 42 const char kXCTestFileNameIdentifier[] = "xctest.mm"; |
38 const char kXCTestModuleTargetNamePostfix[] = "_module"; | 43 const char kXCTestModuleTargetNamePostfix[] = "_module"; |
| 44 const char kXCTestFileReferenceFolder[] = "xctests/"; |
39 | 45 |
40 struct SafeEnvironmentVariableInfo { | 46 struct SafeEnvironmentVariableInfo { |
41 const char* name; | 47 const char* name; |
42 bool capture_at_generation; | 48 bool capture_at_generation; |
43 }; | 49 }; |
44 | 50 |
45 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { | 51 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { |
46 {"HOME", true}, {"LANG", true}, {"PATH", true}, | 52 {"HOME", true}, {"LANG", true}, {"PATH", true}, |
47 {"USER", true}, {"TMPDIR", false}, | 53 {"USER", true}, {"TMPDIR", false}, |
48 }; | 54 }; |
49 | 55 |
| 56 bool CompareSourceFiles(const SourceFile& lhs, const SourceFile& rhs) { |
| 57 if (lhs.GetName() < rhs.GetName()) |
| 58 return true; |
| 59 else if (lhs.GetName() > rhs.GetName()) |
| 60 return false; |
| 61 else |
| 62 return lhs.value() < rhs.value(); |
| 63 } |
| 64 |
50 XcodeWriter::TargetOsType GetTargetOs(const Args& args) { | 65 XcodeWriter::TargetOsType GetTargetOs(const Args& args) { |
51 const Value* target_os_value = args.GetArgOverride(variables::kTargetOs); | 66 const Value* target_os_value = args.GetArgOverride(variables::kTargetOs); |
52 if (target_os_value) { | 67 if (target_os_value) { |
53 if (target_os_value->type() == Value::STRING) { | 68 if (target_os_value->type() == Value::STRING) { |
54 if (target_os_value->string_value() == "ios") | 69 if (target_os_value->string_value() == "ios") |
55 return XcodeWriter::WRITER_TARGET_OS_IOS; | 70 return XcodeWriter::WRITER_TARGET_OS_IOS; |
56 } | 71 } |
57 } | 72 } |
58 return XcodeWriter::WRITER_TARGET_OS_MACOS; | 73 return XcodeWriter::WRITER_TARGET_OS_MACOS; |
59 } | 74 } |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 std::vector<Target::FileList>* file_lists) { | 201 std::vector<Target::FileList>* file_lists) { |
187 TargetToFileList xctest_files_per_target; | 202 TargetToFileList xctest_files_per_target; |
188 | 203 |
189 for (const Target* target : application_targets) { | 204 for (const Target* target : application_targets) { |
190 DCHECK(IsApplicationTarget(target)); | 205 DCHECK(IsApplicationTarget(target)); |
191 SearchXCTestFiles(target, &xctest_files_per_target); | 206 SearchXCTestFiles(target, &xctest_files_per_target); |
192 file_lists->push_back(xctest_files_per_target[target]); | 207 file_lists->push_back(xctest_files_per_target[target]); |
193 } | 208 } |
194 } | 209 } |
195 | 210 |
| 211 // Maps each xctest file to a list of xctest application targets that contains |
| 212 // the file. |
| 213 void MapXCTestFileToApplicationTargets( |
| 214 const std::vector<const Target*>& xctest_application_targets, |
| 215 const std::vector<Target::FileList>& xctest_file_lists, |
| 216 FileToTargets* xctest_file_to_application_targets) { |
| 217 DCHECK_EQ(xctest_application_targets.size(), xctest_file_lists.size()); |
| 218 |
| 219 for (size_t i = 0; i < xctest_application_targets.size(); ++i) { |
| 220 const Target* xctest_application_target = xctest_application_targets[i]; |
| 221 DCHECK(IsApplicationTarget(xctest_application_target)); |
| 222 |
| 223 for (const SourceFile& source : xctest_file_lists[i]) { |
| 224 auto iter = xctest_file_to_application_targets->find(source); |
| 225 if (iter == xctest_file_to_application_targets->end()) { |
| 226 iter = |
| 227 xctest_file_to_application_targets |
| 228 ->insert(std::make_pair(source, std::vector<const Target*>())) |
| 229 .first; |
| 230 } |
| 231 iter->second.push_back(xctest_application_target); |
| 232 } |
| 233 } |
| 234 } |
| 235 |
196 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { | 236 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { |
197 public: | 237 public: |
198 CollectPBXObjectsPerClassHelper() {} | 238 CollectPBXObjectsPerClassHelper() {} |
199 | 239 |
200 void Visit(PBXObject* object) override { | 240 void Visit(PBXObject* object) override { |
201 DCHECK(object); | 241 DCHECK(object); |
202 objects_per_class_[object->Class()].push_back(object); | 242 objects_per_class_[object->Class()].push_back(object); |
203 } | 243 } |
204 | 244 |
205 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& | 245 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 std::vector<Target::FileList> xctest_file_lists; | 450 std::vector<Target::FileList> xctest_file_lists; |
411 FindXCTestFilesForTargets(xctest_application_targets, &xctest_file_lists); | 451 FindXCTestFilesForTargets(xctest_application_targets, &xctest_file_lists); |
412 DCHECK_EQ(xctest_application_targets.size(), xctest_file_lists.size()); | 452 DCHECK_EQ(xctest_application_targets.size(), xctest_file_lists.size()); |
413 | 453 |
414 std::string build_path; | 454 std::string build_path; |
415 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 455 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
416 | 456 |
417 main_project->AddAggregateTarget( | 457 main_project->AddAggregateTarget( |
418 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); | 458 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); |
419 | 459 |
| 460 TargetToNativeTarget xctest_application_to_module_native_target; |
| 461 |
420 for (const Target* target : targets) { | 462 for (const Target* target : targets) { |
421 switch (target->output_type()) { | 463 switch (target->output_type()) { |
422 case Target::EXECUTABLE: | 464 case Target::EXECUTABLE: |
423 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) | 465 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) |
424 continue; | 466 continue; |
425 | 467 |
426 main_project->AddNativeTarget( | 468 main_project->AddNativeTarget( |
427 target->label().name(), "compiled.mach-o.executable", | 469 target->label().name(), "compiled.mach-o.executable", |
428 target->output_name().empty() ? target->label().name() | 470 target->output_name().empty() ? target->label().name() |
429 : target->output_name(), | 471 : target->output_name(), |
(...skipping 10 matching lines...) Expand all Loading... |
440 // discovery of tests function for XCTest, but the compilation is done | 482 // discovery of tests function for XCTest, but the compilation is done |
441 // via ninja and thus must prevent Xcode from linking object files via | 483 // via ninja and thus must prevent Xcode from linking object files via |
442 // this hack. | 484 // this hack. |
443 PBXAttributes extra_attributes; | 485 PBXAttributes extra_attributes; |
444 if (IsXCTestModuleTarget(target)) { | 486 if (IsXCTestModuleTarget(target)) { |
445 extra_attributes["OTHER_LDFLAGS"] = "-help"; | 487 extra_attributes["OTHER_LDFLAGS"] = "-help"; |
446 extra_attributes["ONLY_ACTIVE_ARCH"] = "YES"; | 488 extra_attributes["ONLY_ACTIVE_ARCH"] = "YES"; |
447 extra_attributes["DEBUG_INFORMATION_FORMAT"] = "dwarf"; | 489 extra_attributes["DEBUG_INFORMATION_FORMAT"] = "dwarf"; |
448 } | 490 } |
449 | 491 |
450 main_project->AddNativeTarget( | 492 PBXNativeTarget* native_target = main_project->AddNativeTarget( |
451 target->label().name(), std::string(), | 493 target->label().name(), std::string(), |
452 RebasePath(target->bundle_data() | 494 RebasePath(target->bundle_data() |
453 .GetBundleRootDirOutput(target->settings()) | 495 .GetBundleRootDirOutput(target->settings()) |
454 .value(), | 496 .value(), |
455 build_settings->build_dir()), | 497 build_settings->build_dir()), |
456 target->bundle_data().product_type(), | 498 target->bundle_data().product_type(), |
457 GetBuildScript(target->label().name(), ninja_extra_args, env.get()), | 499 GetBuildScript(target->label().name(), ninja_extra_args, env.get()), |
458 extra_attributes); | 500 extra_attributes); |
| 501 |
| 502 if (!IsXCTestModuleTarget(target)) |
| 503 continue; |
| 504 |
| 505 // Populate |xctest_application_to_module_native_target| for XCTest |
| 506 // module targets. |
| 507 const Target* application_target = |
| 508 FindXCTestApplicationTarget(target, xctest_application_targets); |
| 509 xctest_application_to_module_native_target.insert( |
| 510 std::make_pair(application_target, native_target)); |
| 511 |
459 break; | 512 break; |
460 } | 513 } |
461 | 514 |
462 default: | 515 default: |
463 break; | 516 break; |
464 } | 517 } |
465 } | 518 } |
466 | 519 |
| 520 FileToTargets xctest_file_to_application_targets(CompareSourceFiles); |
| 521 MapXCTestFileToApplicationTargets(xctest_application_targets, |
| 522 xctest_file_lists, |
| 523 &xctest_file_to_application_targets); |
| 524 |
| 525 // Add xctest files to the "Compiler Sources" of corresponding xctest native |
| 526 // targets. |
| 527 SourceDir source_dir("//"); |
| 528 for (const auto& item : xctest_file_to_application_targets) { |
| 529 const SourceFile& source = item.first; |
| 530 for (const Target* xctest_application_target : item.second) { |
| 531 std::string navigator_path = |
| 532 kXCTestFileReferenceFolder + source.GetName(); |
| 533 std::string source_path = RebasePath(source.value(), source_dir, |
| 534 build_settings->root_path_utf8()); |
| 535 PBXNativeTarget* xctest_module_native_target = |
| 536 xctest_application_to_module_native_target[xctest_application_target]; |
| 537 |
| 538 // Test files need to be known to Xcode for proper indexing and for |
| 539 // discovery of tests function for XCTest, but the compilation is done |
| 540 // via ninja and thus must prevent Xcode from compiling the files by |
| 541 // adding '-help' as per file compiler flag. |
| 542 main_project->AddSourceFile(navigator_path, source_path, |
| 543 CompilerFlags::HELP, |
| 544 xctest_module_native_target); |
| 545 } |
| 546 } |
| 547 |
467 projects_.push_back(std::move(main_project)); | 548 projects_.push_back(std::move(main_project)); |
468 } | 549 } |
469 | 550 |
470 void XcodeWriter::CreateSourcesProject( | 551 void XcodeWriter::CreateSourcesProject( |
471 const std::vector<const Target*>& targets, | 552 const std::vector<const Target*>& targets, |
472 const SourceDir& root_build_dir, | 553 const SourceDir& root_build_dir, |
473 const PBXAttributes& attributes, | 554 const PBXAttributes& attributes, |
474 const std::string& source_path, | 555 const std::string& source_path, |
475 const std::string& absolute_source_path, | 556 const std::string& absolute_source_path, |
476 const std::string& config_name, | 557 const std::string& config_name, |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 for (auto* object : pair.second) { | 654 for (auto* object : pair.second) { |
574 object->Print(out, 2); | 655 object->Print(out, 2); |
575 } | 656 } |
576 out << "/* End " << ToString(pair.first) << " section */\n"; | 657 out << "/* End " << ToString(pair.first) << " section */\n"; |
577 } | 658 } |
578 | 659 |
579 out << "\t};\n" | 660 out << "\t};\n" |
580 << "\trootObject = " << project->Reference() << ";\n" | 661 << "\trootObject = " << project->Reference() << ";\n" |
581 << "}\n"; | 662 << "}\n"; |
582 } | 663 } |
OLD | NEW |