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 using TargetToFileList = std::unordered_map<const Target*, Target::FileList>; |
| 35 |
| 36 const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; |
| 37 const char kXCTestFileNameIdentifier[] = "xctest.mm"; |
| 38 const char kXCTestModuleTargetNamePostfix[] = "_module"; |
| 39 |
34 struct SafeEnvironmentVariableInfo { | 40 struct SafeEnvironmentVariableInfo { |
35 const char* name; | 41 const char* name; |
36 bool capture_at_generation; | 42 bool capture_at_generation; |
37 }; | 43 }; |
38 | 44 |
39 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { | 45 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { |
40 {"HOME", true}, {"LANG", true}, {"PATH", true}, | 46 {"HOME", true}, {"LANG", true}, {"PATH", true}, |
41 {"USER", true}, {"TMPDIR", false}, | 47 {"USER", true}, {"TMPDIR", false}, |
42 }; | 48 }; |
43 | 49 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 | 85 |
80 script << "ninja -C ."; | 86 script << "ninja -C ."; |
81 if (!ninja_extra_args.empty()) | 87 if (!ninja_extra_args.empty()) |
82 script << " " << ninja_extra_args; | 88 script << " " << ninja_extra_args; |
83 if (!target_name.empty()) | 89 if (!target_name.empty()) |
84 script << " " << target_name; | 90 script << " " << target_name; |
85 script << "\nexit 1\n"; | 91 script << "\nexit 1\n"; |
86 return script.str(); | 92 return script.str(); |
87 } | 93 } |
88 | 94 |
| 95 bool IsApplicationTarget(const Target* target) { |
| 96 return target->output_type() == Target::CREATE_BUNDLE && |
| 97 target->bundle_data().product_type() == |
| 98 "com.apple.product-type.application"; |
| 99 } |
| 100 |
| 101 bool IsXCTestModuleTarget(const Target* target) { |
| 102 return target->output_type() == Target::CREATE_BUNDLE && |
| 103 target->bundle_data().product_type() == |
| 104 "com.apple.product-type.bundle.unit-test" && |
| 105 base::EndsWith(target->label().name(), kXCTestModuleTargetNamePostfix, |
| 106 base::CompareCase::SENSITIVE); |
| 107 } |
| 108 |
| 109 const Target* FindXCTestApplicationTarget( |
| 110 const Target* xctest_module_target, |
| 111 const std::vector<const Target*>& targets) { |
| 112 DCHECK(IsXCTestModuleTarget(xctest_module_target)); |
| 113 DCHECK(base::EndsWith(xctest_module_target->label().name(), |
| 114 kXCTestModuleTargetNamePostfix, |
| 115 base::CompareCase::SENSITIVE)); |
| 116 std::string application_target_name = |
| 117 xctest_module_target->label().name().substr( |
| 118 0, xctest_module_target->label().name().size() - |
| 119 strlen(kXCTestModuleTargetNamePostfix)); |
| 120 for (const Target* target : targets) { |
| 121 if (target->label().name() == application_target_name) { |
| 122 return target; |
| 123 } |
| 124 } |
| 125 NOTREACHED(); |
| 126 return nullptr; |
| 127 } |
| 128 |
| 129 // Returns the corresponding application targets given XCTest module targets. |
| 130 void FindXCTestApplicationTargets( |
| 131 const std::vector<const Target*>& xctest_module_targets, |
| 132 const std::vector<const Target*>& targets, |
| 133 std::vector<const Target*>* xctest_application_targets) { |
| 134 for (const Target* xctest_module_target : xctest_module_targets) { |
| 135 xctest_application_targets->push_back( |
| 136 FindXCTestApplicationTarget(xctest_module_target, targets)); |
| 137 } |
| 138 } |
| 139 |
| 140 // Searches the list of xctest files recursively under |target|. |
| 141 void SearchXCTestFiles(const Target* target, |
| 142 TargetToFileList* xctest_files_per_target) { |
| 143 // Early return if already visited and processed. |
| 144 if (xctest_files_per_target->find(target) != xctest_files_per_target->end()) |
| 145 return; |
| 146 |
| 147 Target::FileList xctest_files; |
| 148 for (const SourceFile& file : target->sources()) { |
| 149 if (base::EndsWith(file.GetName(), kEarlGreyFileNameIdentifier, |
| 150 base::CompareCase::SENSITIVE) || |
| 151 base::EndsWith(file.GetName(), kXCTestFileNameIdentifier, |
| 152 base::CompareCase::SENSITIVE)) { |
| 153 xctest_files.push_back(file); |
| 154 } |
| 155 } |
| 156 |
| 157 // Call recursively on public and private deps. |
| 158 for (const auto& target : target->public_deps()) { |
| 159 SearchXCTestFiles(target.ptr, xctest_files_per_target); |
| 160 const Target::FileList& deps_xctest_files = |
| 161 (*xctest_files_per_target)[target.ptr]; |
| 162 xctest_files.insert(xctest_files.end(), deps_xctest_files.begin(), |
| 163 deps_xctest_files.end()); |
| 164 } |
| 165 |
| 166 for (const auto& target : target->private_deps()) { |
| 167 SearchXCTestFiles(target.ptr, xctest_files_per_target); |
| 168 const Target::FileList& deps_xctest_files = |
| 169 (*xctest_files_per_target)[target.ptr]; |
| 170 xctest_files.insert(xctest_files.end(), deps_xctest_files.begin(), |
| 171 deps_xctest_files.end()); |
| 172 } |
| 173 |
| 174 // Sort xctest_files to remove duplicates. |
| 175 std::sort(xctest_files.begin(), xctest_files.end()); |
| 176 xctest_files.erase(std::unique(xctest_files.begin(), xctest_files.end()), |
| 177 xctest_files.end()); |
| 178 |
| 179 xctest_files_per_target->insert(std::make_pair(target, xctest_files)); |
| 180 } |
| 181 |
| 182 // Finds the list of xctest files recursively under each of the application |
| 183 // targets. |
| 184 void FindXCTestFilesForTargets( |
| 185 const std::vector<const Target*>& application_targets, |
| 186 std::vector<Target::FileList>* file_lists) { |
| 187 TargetToFileList xctest_files_per_target; |
| 188 |
| 189 for (const Target* target : application_targets) { |
| 190 DCHECK(IsApplicationTarget(target)); |
| 191 SearchXCTestFiles(target, &xctest_files_per_target); |
| 192 file_lists->push_back(xctest_files_per_target[target]); |
| 193 } |
| 194 } |
| 195 |
89 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { | 196 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { |
90 public: | 197 public: |
91 CollectPBXObjectsPerClassHelper() {} | 198 CollectPBXObjectsPerClassHelper() {} |
92 | 199 |
93 void Visit(PBXObject* object) override { | 200 void Visit(PBXObject* object) override { |
94 DCHECK(object); | 201 DCHECK(object); |
95 objects_per_class_[object->Class()].push_back(object); | 202 objects_per_class_[object->Class()].push_back(object); |
96 } | 203 } |
97 | 204 |
98 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& | 205 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 // Sort the list of targets per-label to get a consistent ordering of them | 366 // Sort the list of targets per-label to get a consistent ordering of them |
260 // in the generated Xcode project (and thus stability of the file generated). | 367 // in the generated Xcode project (and thus stability of the file generated). |
261 std::sort(targets->begin(), targets->end(), | 368 std::sort(targets->begin(), targets->end(), |
262 [](const Target* a, const Target* b) { | 369 [](const Target* a, const Target* b) { |
263 return a->label().name() < b->label().name(); | 370 return a->label().name() < b->label().name(); |
264 }); | 371 }); |
265 | 372 |
266 return true; | 373 return true; |
267 } | 374 } |
268 | 375 |
| 376 // static |
| 377 void XcodeWriter::FilterXCTestModuleTargets( |
| 378 const std::vector<const Target*>& targets, |
| 379 std::vector<const Target*>* xctest_module_targets) { |
| 380 for (const Target* target : targets) { |
| 381 if (!IsXCTestModuleTarget(target)) |
| 382 continue; |
| 383 |
| 384 xctest_module_targets->push_back(target); |
| 385 } |
| 386 } |
| 387 |
269 void XcodeWriter::CreateProductsProject( | 388 void XcodeWriter::CreateProductsProject( |
270 const std::vector<const Target*>& targets, | 389 const std::vector<const Target*>& targets, |
271 const PBXAttributes& attributes, | 390 const PBXAttributes& attributes, |
272 const std::string& source_path, | 391 const std::string& source_path, |
273 const std::string& config_name, | 392 const std::string& config_name, |
274 const std::string& root_target, | 393 const std::string& root_target, |
275 const std::string& ninja_extra_args, | 394 const std::string& ninja_extra_args, |
276 const BuildSettings* build_settings, | 395 const BuildSettings* build_settings, |
277 TargetOsType target_os) { | 396 TargetOsType target_os) { |
278 std::unique_ptr<PBXProject> main_project( | 397 std::unique_ptr<PBXProject> main_project( |
279 new PBXProject("products", config_name, source_path, attributes)); | 398 new PBXProject("products", config_name, source_path, attributes)); |
280 | 399 |
| 400 // Filter xctest module and application targets and find list of xctest files |
| 401 // recursively under them. |
| 402 std::vector<const Target*> xctest_module_targets; |
| 403 FilterXCTestModuleTargets(targets, &xctest_module_targets); |
| 404 |
| 405 std::vector<const Target*> xctest_application_targets; |
| 406 FindXCTestApplicationTargets(xctest_module_targets, targets, |
| 407 &xctest_application_targets); |
| 408 DCHECK_EQ(xctest_module_targets.size(), xctest_application_targets.size()); |
| 409 |
| 410 std::vector<Target::FileList> xctest_file_lists; |
| 411 FindXCTestFilesForTargets(xctest_application_targets, &xctest_file_lists); |
| 412 DCHECK_EQ(xctest_application_targets.size(), xctest_file_lists.size()); |
| 413 |
281 std::string build_path; | 414 std::string build_path; |
282 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 415 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
283 | 416 |
284 main_project->AddAggregateTarget( | 417 main_project->AddAggregateTarget( |
285 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); | 418 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); |
286 | 419 |
287 for (const Target* target : targets) { | 420 for (const Target* target : targets) { |
288 switch (target->output_type()) { | 421 switch (target->output_type()) { |
289 case Target::EXECUTABLE: | 422 case Target::EXECUTABLE: |
290 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) | 423 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 for (auto* object : pair.second) { | 560 for (auto* object : pair.second) { |
428 object->Print(out, 2); | 561 object->Print(out, 2); |
429 } | 562 } |
430 out << "/* End " << ToString(pair.first) << " section */\n"; | 563 out << "/* End " << ToString(pair.first) << " section */\n"; |
431 } | 564 } |
432 | 565 |
433 out << "\t};\n" | 566 out << "\t};\n" |
434 << "\trootObject = " << project->Reference() << ";\n" | 567 << "\trootObject = " << project->Reference() << ";\n" |
435 << "}\n"; | 568 << "}\n"; |
436 } | 569 } |
OLD | NEW |