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 |