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