| 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 = | 35 using TargetToTarget = std::unordered_map<const Target*, const Target*>; |
| 36 std::unordered_map<const Target*, PBXNativeTarget*>; | |
| 37 using FileToTargets = std::map<SourceFile, | |
| 38 std::vector<const Target*>, | |
| 39 bool (*)(const SourceFile&, const SourceFile&)>; | |
| 40 | 36 |
| 41 const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; | 37 const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; |
| 42 const char kXCTestFileNameIdentifier[] = "xctest.mm"; | 38 const char kXCTestFileNameIdentifier[] = "xctest.mm"; |
| 43 const char kXCTestModuleTargetNamePostfix[] = "_module"; | 39 const char kXCTestModuleTargetNamePostfix[] = "_module"; |
| 44 const char kXCTestFileReferenceFolder[] = "xctests/"; | |
| 45 | 40 |
| 46 struct SafeEnvironmentVariableInfo { | 41 struct SafeEnvironmentVariableInfo { |
| 47 const char* name; | 42 const char* name; |
| 48 bool capture_at_generation; | 43 bool capture_at_generation; |
| 49 }; | 44 }; |
| 50 | 45 |
| 51 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { | 46 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { |
| 52 {"HOME", true}, {"LANG", true}, {"PATH", true}, | 47 {"HOME", true}, {"LANG", true}, {"PATH", true}, |
| 53 {"USER", true}, {"TMPDIR", false}, | 48 {"USER", true}, {"TMPDIR", false}, |
| 54 }; | 49 }; |
| 55 | 50 |
| 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 | |
| 65 XcodeWriter::TargetOsType GetTargetOs(const Args& args) { | 51 XcodeWriter::TargetOsType GetTargetOs(const Args& args) { |
| 66 const Value* target_os_value = args.GetArgOverride(variables::kTargetOs); | 52 const Value* target_os_value = args.GetArgOverride(variables::kTargetOs); |
| 67 if (target_os_value) { | 53 if (target_os_value) { |
| 68 if (target_os_value->type() == Value::STRING) { | 54 if (target_os_value->type() == Value::STRING) { |
| 69 if (target_os_value->string_value() == "ios") | 55 if (target_os_value->string_value() == "ios") |
| 70 return XcodeWriter::WRITER_TARGET_OS_IOS; | 56 return XcodeWriter::WRITER_TARGET_OS_IOS; |
| 71 } | 57 } |
| 72 } | 58 } |
| 73 return XcodeWriter::WRITER_TARGET_OS_MACOS; | 59 return XcodeWriter::WRITER_TARGET_OS_MACOS; |
| 74 } | 60 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 } | 100 } |
| 115 | 101 |
| 116 bool IsXCTestModuleTarget(const Target* target) { | 102 bool IsXCTestModuleTarget(const Target* target) { |
| 117 return target->output_type() == Target::CREATE_BUNDLE && | 103 return target->output_type() == Target::CREATE_BUNDLE && |
| 118 target->bundle_data().product_type() == | 104 target->bundle_data().product_type() == |
| 119 "com.apple.product-type.bundle.unit-test" && | 105 "com.apple.product-type.bundle.unit-test" && |
| 120 base::EndsWith(target->label().name(), kXCTestModuleTargetNamePostfix, | 106 base::EndsWith(target->label().name(), kXCTestModuleTargetNamePostfix, |
| 121 base::CompareCase::SENSITIVE); | 107 base::CompareCase::SENSITIVE); |
| 122 } | 108 } |
| 123 | 109 |
| 110 bool IsXCTestFile(const SourceFile& file) { |
| 111 return base::EndsWith(file.GetName(), kEarlGreyFileNameIdentifier, |
| 112 base::CompareCase::SENSITIVE) || |
| 113 base::EndsWith(file.GetName(), kXCTestFileNameIdentifier, |
| 114 base::CompareCase::SENSITIVE); |
| 115 } |
| 116 |
| 124 const Target* FindXCTestApplicationTarget( | 117 const Target* FindXCTestApplicationTarget( |
| 125 const Target* xctest_module_target, | 118 const Target* xctest_module_target, |
| 126 const std::vector<const Target*>& targets) { | 119 const std::vector<const Target*>& targets) { |
| 127 DCHECK(IsXCTestModuleTarget(xctest_module_target)); | 120 DCHECK(IsXCTestModuleTarget(xctest_module_target)); |
| 128 DCHECK(base::EndsWith(xctest_module_target->label().name(), | 121 DCHECK(base::EndsWith(xctest_module_target->label().name(), |
| 129 kXCTestModuleTargetNamePostfix, | 122 kXCTestModuleTargetNamePostfix, |
| 130 base::CompareCase::SENSITIVE)); | 123 base::CompareCase::SENSITIVE)); |
| 131 std::string application_target_name = | 124 std::string application_target_name = |
| 132 xctest_module_target->label().name().substr( | 125 xctest_module_target->label().name().substr( |
| 133 0, xctest_module_target->label().name().size() - | 126 0, xctest_module_target->label().name().size() - |
| 134 strlen(kXCTestModuleTargetNamePostfix)); | 127 strlen(kXCTestModuleTargetNamePostfix)); |
| 135 for (const Target* target : targets) { | 128 for (const Target* target : targets) { |
| 136 if (target->label().name() == application_target_name) { | 129 if (target->label().name() == application_target_name) { |
| 137 return target; | 130 return target; |
| 138 } | 131 } |
| 139 } | 132 } |
| 140 NOTREACHED(); | 133 NOTREACHED(); |
| 141 return nullptr; | 134 return nullptr; |
| 142 } | 135 } |
| 143 | 136 |
| 144 // Returns the corresponding application targets given XCTest module targets. | 137 // Given XCTest module targets, find the corresponding application targets and |
| 138 // the mappings between them. |
| 145 void FindXCTestApplicationTargets( | 139 void FindXCTestApplicationTargets( |
| 146 const std::vector<const Target*>& xctest_module_targets, | 140 const std::vector<const Target*>& xctest_module_targets, |
| 147 const std::vector<const Target*>& targets, | 141 const std::vector<const Target*>& targets, |
| 148 std::vector<const Target*>* xctest_application_targets) { | 142 std::vector<const Target*>* xctest_application_targets, |
| 143 TargetToTarget* xctest_module_to_application_target) { |
| 149 for (const Target* xctest_module_target : xctest_module_targets) { | 144 for (const Target* xctest_module_target : xctest_module_targets) { |
| 150 xctest_application_targets->push_back( | 145 xctest_application_targets->push_back( |
| 151 FindXCTestApplicationTarget(xctest_module_target, targets)); | 146 FindXCTestApplicationTarget(xctest_module_target, targets)); |
| 147 xctest_module_to_application_target->insert(std::make_pair( |
| 148 xctest_module_target, xctest_application_targets->back())); |
| 152 } | 149 } |
| 153 } | 150 } |
| 154 | 151 |
| 155 // Searches the list of xctest files recursively under |target|. | 152 // Searches the list of xctest files recursively under |target|. |
| 156 void SearchXCTestFiles(const Target* target, | 153 void SearchXCTestFiles(const Target* target, |
| 157 TargetToFileList* xctest_files_per_target) { | 154 TargetToFileList* xctest_files_per_target) { |
| 158 // Early return if already visited and processed. | 155 // Early return if already visited and processed. |
| 159 if (xctest_files_per_target->find(target) != xctest_files_per_target->end()) | 156 if (xctest_files_per_target->find(target) != xctest_files_per_target->end()) |
| 160 return; | 157 return; |
| 161 | 158 |
| 162 Target::FileList xctest_files; | 159 Target::FileList xctest_files; |
| 163 for (const SourceFile& file : target->sources()) { | 160 for (const SourceFile& file : target->sources()) { |
| 164 if (base::EndsWith(file.GetName(), kEarlGreyFileNameIdentifier, | 161 if (IsXCTestFile(file)) { |
| 165 base::CompareCase::SENSITIVE) || | |
| 166 base::EndsWith(file.GetName(), kXCTestFileNameIdentifier, | |
| 167 base::CompareCase::SENSITIVE)) { | |
| 168 xctest_files.push_back(file); | 162 xctest_files.push_back(file); |
| 169 } | 163 } |
| 170 } | 164 } |
| 171 | 165 |
| 172 // Call recursively on public and private deps. | 166 // Call recursively on public and private deps. |
| 173 for (const auto& t : target->public_deps()) { | 167 for (const auto& t : target->public_deps()) { |
| 174 SearchXCTestFiles(t.ptr, xctest_files_per_target); | 168 SearchXCTestFiles(t.ptr, xctest_files_per_target); |
| 175 const Target::FileList& deps_xctest_files = | 169 const Target::FileList& deps_xctest_files = |
| 176 (*xctest_files_per_target)[t.ptr]; | 170 (*xctest_files_per_target)[t.ptr]; |
| 177 xctest_files.insert(xctest_files.end(), deps_xctest_files.begin(), | 171 xctest_files.insert(xctest_files.end(), deps_xctest_files.begin(), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 189 // Sort xctest_files to remove duplicates. | 183 // Sort xctest_files to remove duplicates. |
| 190 std::sort(xctest_files.begin(), xctest_files.end()); | 184 std::sort(xctest_files.begin(), xctest_files.end()); |
| 191 xctest_files.erase(std::unique(xctest_files.begin(), xctest_files.end()), | 185 xctest_files.erase(std::unique(xctest_files.begin(), xctest_files.end()), |
| 192 xctest_files.end()); | 186 xctest_files.end()); |
| 193 | 187 |
| 194 xctest_files_per_target->insert(std::make_pair(target, xctest_files)); | 188 xctest_files_per_target->insert(std::make_pair(target, xctest_files)); |
| 195 } | 189 } |
| 196 | 190 |
| 197 // Finds the list of xctest files recursively under each of the application | 191 // Finds the list of xctest files recursively under each of the application |
| 198 // targets. | 192 // targets. |
| 199 void FindXCTestFilesForTargets( | 193 void FindXCTestFilesForApplicationTargets( |
| 200 const std::vector<const Target*>& application_targets, | 194 const std::vector<const Target*>& application_targets, |
| 201 std::vector<Target::FileList>* file_lists) { | 195 TargetToFileList* xctest_files_per_application_target) { |
| 202 TargetToFileList xctest_files_per_target; | 196 TargetToFileList xctest_files_per_target; |
| 203 | |
| 204 for (const Target* target : application_targets) { | 197 for (const Target* target : application_targets) { |
| 205 DCHECK(IsApplicationTarget(target)); | 198 DCHECK(IsApplicationTarget(target)); |
| 206 SearchXCTestFiles(target, &xctest_files_per_target); | 199 SearchXCTestFiles(target, &xctest_files_per_target); |
| 207 file_lists->push_back(xctest_files_per_target[target]); | 200 xctest_files_per_application_target->insert( |
| 201 std::make_pair(target, xctest_files_per_target[target])); |
| 208 } | 202 } |
| 209 } | 203 } |
| 210 | 204 |
| 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 | |
| 236 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { | 205 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { |
| 237 public: | 206 public: |
| 238 CollectPBXObjectsPerClassHelper() {} | 207 CollectPBXObjectsPerClassHelper() {} |
| 239 | 208 |
| 240 void Visit(PBXObject* object) override { | 209 void Visit(PBXObject* object) override { |
| 241 DCHECK(object); | 210 DCHECK(object); |
| 242 objects_per_class_[object->Class()].push_back(object); | 211 objects_per_class_[object->Class()].push_back(object); |
| 243 } | 212 } |
| 244 | 213 |
| 245 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& | 214 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 config_name = config_name.substr(0, separator); | 303 config_name = config_name.substr(0, separator); |
| 335 | 304 |
| 336 std::vector<const Target*> targets; | 305 std::vector<const Target*> targets; |
| 337 std::vector<const Target*> all_targets = builder.GetAllResolvedTargets(); | 306 std::vector<const Target*> all_targets = builder.GetAllResolvedTargets(); |
| 338 if (!XcodeWriter::FilterTargets(build_settings, all_targets, | 307 if (!XcodeWriter::FilterTargets(build_settings, all_targets, |
| 339 dir_filters_string, &targets, err)) { | 308 dir_filters_string, &targets, err)) { |
| 340 return false; | 309 return false; |
| 341 } | 310 } |
| 342 | 311 |
| 343 XcodeWriter workspace(workspace_name); | 312 XcodeWriter workspace(workspace_name); |
| 344 workspace.CreateProductsProject(targets, attributes, source_path, config_name, | 313 workspace.CreateProductsProject(targets, all_targets, attributes, source_path, |
| 345 root_target_name, ninja_extra_args, | 314 config_name, root_target_name, |
| 346 build_settings, target_os); | 315 ninja_extra_args, build_settings, target_os); |
| 347 | |
| 348 workspace.CreateSourcesProject( | |
| 349 all_targets, build_settings->build_dir(), attributes, source_path, | |
| 350 build_settings->root_path_utf8(), config_name, target_os); | |
| 351 | 316 |
| 352 return workspace.WriteFiles(build_settings, err); | 317 return workspace.WriteFiles(build_settings, err); |
| 353 } | 318 } |
| 354 | 319 |
| 355 XcodeWriter::XcodeWriter(const std::string& name) : name_(name) { | 320 XcodeWriter::XcodeWriter(const std::string& name) : name_(name) { |
| 356 if (name_.empty()) | 321 if (name_.empty()) |
| 357 name_.assign("all"); | 322 name_.assign("all"); |
| 358 } | 323 } |
| 359 | 324 |
| 360 XcodeWriter::~XcodeWriter() {} | 325 XcodeWriter::~XcodeWriter() {} |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 for (const Target* target : targets) { | 385 for (const Target* target : targets) { |
| 421 if (!IsXCTestModuleTarget(target)) | 386 if (!IsXCTestModuleTarget(target)) |
| 422 continue; | 387 continue; |
| 423 | 388 |
| 424 xctest_module_targets->push_back(target); | 389 xctest_module_targets->push_back(target); |
| 425 } | 390 } |
| 426 } | 391 } |
| 427 | 392 |
| 428 void XcodeWriter::CreateProductsProject( | 393 void XcodeWriter::CreateProductsProject( |
| 429 const std::vector<const Target*>& targets, | 394 const std::vector<const Target*>& targets, |
| 395 const std::vector<const Target*>& all_targets, |
| 430 const PBXAttributes& attributes, | 396 const PBXAttributes& attributes, |
| 431 const std::string& source_path, | 397 const std::string& source_path, |
| 432 const std::string& config_name, | 398 const std::string& config_name, |
| 433 const std::string& root_target, | 399 const std::string& root_target, |
| 434 const std::string& ninja_extra_args, | 400 const std::string& ninja_extra_args, |
| 435 const BuildSettings* build_settings, | 401 const BuildSettings* build_settings, |
| 436 TargetOsType target_os) { | 402 TargetOsType target_os) { |
| 437 std::unique_ptr<PBXProject> main_project( | 403 std::unique_ptr<PBXProject> main_project( |
| 438 new PBXProject("products", config_name, source_path, attributes)); | 404 new PBXProject("products", config_name, source_path, attributes)); |
| 405 SourceDir source_dir("//"); |
| 406 |
| 407 // Add all source files for indexing. |
| 408 std::vector<SourceFile> sources; |
| 409 for (const Target* target : all_targets) { |
| 410 for (const SourceFile& source : target->sources()) { |
| 411 if (IsStringInOutputDir(build_settings->build_dir(), source.value())) |
| 412 continue; |
| 413 |
| 414 sources.push_back(source); |
| 415 } |
| 416 } |
| 417 |
| 418 // Sort sources to ensure determinisn of the project file generation and |
| 419 // remove duplicate reference to the source files (can happen due to the |
| 420 // bundle_data targets). |
| 421 std::sort(sources.begin(), sources.end()); |
| 422 sources.erase(std::unique(sources.begin(), sources.end()), sources.end()); |
| 423 |
| 424 for (const SourceFile& source : sources) { |
| 425 std::string source_file = RebasePath(source.value(), source_dir, |
| 426 build_settings->root_path_utf8()); |
| 427 main_project->AddSourceFileToIndexingTarget(source_file, source_file, |
| 428 CompilerFlags::NONE); |
| 429 } |
| 439 | 430 |
| 440 // Filter xctest module and application targets and find list of xctest files | 431 // Filter xctest module and application targets and find list of xctest files |
| 441 // recursively under them. | 432 // recursively under them. |
| 442 std::vector<const Target*> xctest_module_targets; | 433 std::vector<const Target*> xctest_module_targets; |
| 443 FilterXCTestModuleTargets(targets, &xctest_module_targets); | 434 FilterXCTestModuleTargets(targets, &xctest_module_targets); |
| 444 | 435 |
| 436 // There is a 1 on 1 mapping between |xctest_module_targets| and |
| 437 // |xctest_application_targets|. |
| 445 std::vector<const Target*> xctest_application_targets; | 438 std::vector<const Target*> xctest_application_targets; |
| 439 TargetToTarget xctest_module_to_application_target; |
| 446 FindXCTestApplicationTargets(xctest_module_targets, targets, | 440 FindXCTestApplicationTargets(xctest_module_targets, targets, |
| 447 &xctest_application_targets); | 441 &xctest_application_targets, |
| 442 &xctest_module_to_application_target); |
| 448 DCHECK_EQ(xctest_module_targets.size(), xctest_application_targets.size()); | 443 DCHECK_EQ(xctest_module_targets.size(), xctest_application_targets.size()); |
| 444 DCHECK_EQ(xctest_module_targets.size(), |
| 445 xctest_module_to_application_target.size()); |
| 449 | 446 |
| 450 std::vector<Target::FileList> xctest_file_lists; | 447 TargetToFileList xctest_files_per_application_target; |
| 451 FindXCTestFilesForTargets(xctest_application_targets, &xctest_file_lists); | 448 FindXCTestFilesForApplicationTargets(xctest_application_targets, |
| 452 DCHECK_EQ(xctest_application_targets.size(), xctest_file_lists.size()); | 449 &xctest_files_per_application_target); |
| 450 DCHECK_EQ(xctest_application_targets.size(), |
| 451 xctest_files_per_application_target.size()); |
| 453 | 452 |
| 454 std::string build_path; | 453 std::string build_path; |
| 455 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 454 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
| 456 | 455 |
| 457 main_project->AddAggregateTarget( | 456 main_project->AddAggregateTarget( |
| 458 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); | 457 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); |
| 459 | 458 |
| 460 TargetToNativeTarget xctest_application_to_module_native_target; | |
| 461 | |
| 462 for (const Target* target : targets) { | 459 for (const Target* target : targets) { |
| 463 switch (target->output_type()) { | 460 switch (target->output_type()) { |
| 464 case Target::EXECUTABLE: | 461 case Target::EXECUTABLE: |
| 465 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) | 462 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) |
| 466 continue; | 463 continue; |
| 467 | 464 |
| 468 main_project->AddNativeTarget( | 465 main_project->AddNativeTarget( |
| 469 target->label().name(), "compiled.mach-o.executable", | 466 target->label().name(), "compiled.mach-o.executable", |
| 470 target->output_name().empty() ? target->label().name() | 467 target->output_name().empty() ? target->label().name() |
| 471 : target->output_name(), | 468 : target->output_name(), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 495 .GetBundleRootDirOutput(target->settings()) | 492 .GetBundleRootDirOutput(target->settings()) |
| 496 .value(), | 493 .value(), |
| 497 build_settings->build_dir()), | 494 build_settings->build_dir()), |
| 498 target->bundle_data().product_type(), | 495 target->bundle_data().product_type(), |
| 499 GetBuildScript(target->label().name(), ninja_extra_args, env.get()), | 496 GetBuildScript(target->label().name(), ninja_extra_args, env.get()), |
| 500 extra_attributes); | 497 extra_attributes); |
| 501 | 498 |
| 502 if (!IsXCTestModuleTarget(target)) | 499 if (!IsXCTestModuleTarget(target)) |
| 503 continue; | 500 continue; |
| 504 | 501 |
| 505 // Populate |xctest_application_to_module_native_target| for XCTest | 502 // Add xctest files to the "Compiler Sources" of corresponding xctest |
| 506 // module targets. | 503 // native targets. |
| 507 const Target* application_target = | 504 const Target::FileList& xctest_file_list = |
| 508 FindXCTestApplicationTarget(target, xctest_application_targets); | 505 xctest_files_per_application_target |
| 509 xctest_application_to_module_native_target.insert( | 506 [xctest_module_to_application_target[target]]; |
| 510 std::make_pair(application_target, native_target)); | 507 |
| 508 for (const SourceFile& source : xctest_file_list) { |
| 509 std::string source_path = RebasePath( |
| 510 source.value(), source_dir, build_settings->root_path_utf8()); |
| 511 |
| 512 // Test files need to be known to Xcode for proper indexing and for |
| 513 // discovery of tests function for XCTest, but the compilation is done |
| 514 // via ninja and thus must prevent Xcode from compiling the files by |
| 515 // adding '-help' as per file compiler flag. |
| 516 main_project->AddSourceFile(source_path, source_path, |
| 517 CompilerFlags::HELP, native_target); |
| 518 } |
| 511 | 519 |
| 512 break; | 520 break; |
| 513 } | 521 } |
| 514 | 522 |
| 515 default: | 523 default: |
| 516 break; | 524 break; |
| 517 } | 525 } |
| 518 } | 526 } |
| 519 | 527 |
| 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 | |
| 548 projects_.push_back(std::move(main_project)); | 528 projects_.push_back(std::move(main_project)); |
| 549 } | 529 } |
| 550 | 530 |
| 551 void XcodeWriter::CreateSourcesProject( | |
| 552 const std::vector<const Target*>& targets, | |
| 553 const SourceDir& root_build_dir, | |
| 554 const PBXAttributes& attributes, | |
| 555 const std::string& source_path, | |
| 556 const std::string& absolute_source_path, | |
| 557 const std::string& config_name, | |
| 558 TargetOsType target_os) { | |
| 559 std::vector<SourceFile> sources; | |
| 560 for (const Target* target : targets) { | |
| 561 for (const SourceFile& source : target->sources()) { | |
| 562 if (IsStringInOutputDir(root_build_dir, source.value())) | |
| 563 continue; | |
| 564 | |
| 565 sources.push_back(source); | |
| 566 } | |
| 567 } | |
| 568 | |
| 569 std::unique_ptr<PBXProject> sources_for_indexing( | |
| 570 new PBXProject("sources", config_name, source_path, attributes)); | |
| 571 | |
| 572 // Sort sources to ensure determinisn of the project file generation and | |
| 573 // remove duplicate reference to the source files (can happen due to the | |
| 574 // bundle_data targets). | |
| 575 std::sort(sources.begin(), sources.end()); | |
| 576 sources.erase(std::unique(sources.begin(), sources.end()), sources.end()); | |
| 577 | |
| 578 SourceDir source_dir("//"); | |
| 579 for (const SourceFile& source : sources) { | |
| 580 std::string source_file = | |
| 581 RebasePath(source.value(), source_dir, absolute_source_path); | |
| 582 sources_for_indexing->AddSourceFileToIndexingTarget( | |
| 583 source_file, source_file, CompilerFlags::NONE); | |
| 584 } | |
| 585 | |
| 586 projects_.push_back(std::move(sources_for_indexing)); | |
| 587 } | |
| 588 | |
| 589 bool XcodeWriter::WriteFiles(const BuildSettings* build_settings, Err* err) { | 531 bool XcodeWriter::WriteFiles(const BuildSettings* build_settings, Err* err) { |
| 590 for (const auto& project : projects_) { | 532 for (const auto& project : projects_) { |
| 591 if (!WriteProjectFile(build_settings, project.get(), err)) | 533 if (!WriteProjectFile(build_settings, project.get(), err)) |
| 592 return false; | 534 return false; |
| 593 } | 535 } |
| 594 | 536 |
| 595 SourceFile xcworkspacedata_file = | 537 SourceFile xcworkspacedata_file = |
| 596 build_settings->build_dir().ResolveRelativeFile( | 538 build_settings->build_dir().ResolveRelativeFile( |
| 597 Value(nullptr, name_ + ".xcworkspace/contents.xcworkspacedata"), err); | 539 Value(nullptr, name_ + ".xcworkspace/contents.xcworkspacedata"), err); |
| 598 if (xcworkspacedata_file.is_null()) | 540 if (xcworkspacedata_file.is_null()) |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 for (auto* object : pair.second) { | 596 for (auto* object : pair.second) { |
| 655 object->Print(out, 2); | 597 object->Print(out, 2); |
| 656 } | 598 } |
| 657 out << "/* End " << ToString(pair.first) << " section */\n"; | 599 out << "/* End " << ToString(pair.first) << " section */\n"; |
| 658 } | 600 } |
| 659 | 601 |
| 660 out << "\t};\n" | 602 out << "\t};\n" |
| 661 << "\trootObject = " << project->Reference() << ";\n" | 603 << "\trootObject = " << project->Reference() << ";\n" |
| 662 << "}\n"; | 604 << "}\n"; |
| 663 } | 605 } |
| OLD | NEW |