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 const char kXCTestTargetNamePostfix[] = "_module"; | |
35 const char kEarlGreyFileNameIdentifier[] = "egtest.mm"; | |
36 | |
37 typedef std::unordered_map<const Target*, Target::FileList> TargetToFileList; | |
sdefresne
2016/12/14 13:00:03
nit: it is recommend to use "using" instead of "ty
liaoyuke
2016/12/15 00:03:11
Done.
| |
38 | |
34 struct SafeEnvironmentVariableInfo { | 39 struct SafeEnvironmentVariableInfo { |
35 const char* name; | 40 const char* name; |
36 bool capture_at_generation; | 41 bool capture_at_generation; |
37 }; | 42 }; |
38 | 43 |
39 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { | 44 SafeEnvironmentVariableInfo kSafeEnvironmentVariables[] = { |
40 {"HOME", true}, {"LANG", true}, {"PATH", true}, | 45 {"HOME", true}, {"LANG", true}, {"PATH", true}, |
41 {"USER", true}, {"TMPDIR", false}, | 46 {"USER", true}, {"TMPDIR", false}, |
42 }; | 47 }; |
43 | 48 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 | 85 |
81 script << "ninja -C ."; | 86 script << "ninja -C ."; |
82 if (!ninja_extra_args.empty()) | 87 if (!ninja_extra_args.empty()) |
83 script << " " << ninja_extra_args; | 88 script << " " << ninja_extra_args; |
84 if (!target_name.empty()) | 89 if (!target_name.empty()) |
85 script << " " << target_name; | 90 script << " " << target_name; |
86 script << "\nexit 1\n"; | 91 script << "\nexit 1\n"; |
87 return script.str(); | 92 return script.str(); |
88 } | 93 } |
89 | 94 |
95 // Append |file_list_extra| to |file_list_base| and remove duplicate elements. | |
96 void AppendAndRemoveDuplicates(Target::FileList* file_list_base, | |
97 const Target::FileList& file_list_extra) { | |
98 file_list_base->insert(file_list_base->end(), file_list_extra.begin(), | |
99 file_list_extra.end()); | |
100 std::sort(file_list_base->begin(), file_list_base->end()); | |
101 file_list_base->erase( | |
102 std::unique(file_list_base->begin(), file_list_base->end()), | |
103 file_list_base->end()); | |
104 } | |
105 | |
106 // Find the list of earl grey files recursively under |target|. | |
107 void GetEarlGreyFiles(const Target* target, | |
108 TargetToFileList* eg_files_per_target) { | |
109 // Early return if already visited and processed. | |
110 if (eg_files_per_target->find(target) != eg_files_per_target->end()) { | |
sdefresne
2016/12/14 13:00:03
No braces here (since there are not used in the re
liaoyuke
2016/12/15 00:03:11
Done.
| |
111 return; | |
112 } | |
113 | |
114 Target::FileList eg_files; | |
115 for (const SourceFile& file : target->sources()) { | |
116 if (base::EndsWith(file.GetName(), kEarlGreyFileNameIdentifier, | |
117 base::CompareCase::SENSITIVE)) { | |
118 eg_files.push_back(file); | |
119 } | |
120 } | |
121 | |
122 // Call recursively on public and private deps. | |
123 for (const auto& target : target->public_deps()) { | |
124 GetEarlGreyFiles(target.ptr, eg_files_per_target); | |
125 Target::FileList deps_eg_files = eg_files_per_target->at(target.ptr); | |
126 if (!deps_eg_files.empty()) { | |
sdefresne
2016/12/14 13:00:02
No braces here.
liaoyuke
2016/12/15 00:03:11
Done.
| |
127 AppendAndRemoveDuplicates(&eg_files, deps_eg_files); | |
sdefresne
2016/12/14 13:00:03
I think it would be better to just add everything
liaoyuke
2016/12/15 00:03:11
Done.
| |
128 } | |
129 } | |
130 | |
131 for (const auto& target : target->private_deps()) { | |
132 GetEarlGreyFiles(target.ptr, eg_files_per_target); | |
133 Target::FileList deps_eg_files = eg_files_per_target->at(target.ptr); | |
134 if (!deps_eg_files.empty()) { | |
135 AppendAndRemoveDuplicates(&eg_files, deps_eg_files); | |
136 } | |
137 } | |
138 | |
139 // Sort eg_files to remove duplicates. | |
140 std::sort(eg_files.begin(), eg_files.end()); | |
141 eg_files.erase(std::unique(eg_files.begin(), eg_files.end()), eg_files.end()); | |
142 | |
143 eg_files_per_target->insert(std::make_pair(target, eg_files)); | |
144 } | |
145 | |
146 // Find the list of earl grey files recursively under each of the application | |
sdefresne
2016/12/14 13:00:02
nit: Find -> Finds
liaoyuke
2016/12/15 00:03:11
Done.
| |
147 // and xctest bundle pair. | |
148 void GetEarlGreyFilesForAll( | |
sdefresne
2016/12/14 13:00:02
I'm not sure we need to check source file in xctes
liaoyuke
2016/12/15 00:03:11
You are right, I have double-checked, there is no
| |
149 const std::vector<const Target*>& xctest_targets, | |
150 const std::vector<const Target*>& application_targets, | |
151 std::vector<Target::FileList>* file_lists) { | |
sdefresne
2016/12/14 13:00:03
DCHECK_EQ(xctest_targets.size(), application_targe
liaoyuke
2016/12/15 00:03:11
Acknowledged.
| |
152 TargetToFileList eg_files_per_target; | |
153 | |
154 for (size_t i = 0; i < xctest_targets.size(); ++i) { | |
155 GetEarlGreyFiles(xctest_targets[i], &eg_files_per_target); | |
156 GetEarlGreyFiles(application_targets[i], &eg_files_per_target); | |
157 | |
158 Target::FileList eg_files; | |
159 AppendAndRemoveDuplicates(&eg_files, | |
160 eg_files_per_target.at(xctest_targets[i])); | |
161 AppendAndRemoveDuplicates(&eg_files, | |
162 eg_files_per_target.at(application_targets[i])); | |
163 file_lists->push_back(eg_files); | |
164 } | |
165 } | |
166 | |
167 // Returns the corresponding application target given a XCTest target. Returns | |
sdefresne
2016/12/14 13:00:03
I would change this function to DCHECK if it does
liaoyuke
2016/12/15 00:03:11
Thank you for the note. I will this logic when I w
liaoyuke
2016/12/15 00:03:11
Acknowledged.
| |
168 // NULL if not found. | |
169 const Target* FindApplicationTarget(const Target* xctest_target, | |
170 const std::vector<const Target*>& targets) { | |
171 for (const Target* target : targets) { | |
172 if ((target->label().name() + kXCTestTargetNamePostfix) | |
173 .compare(xctest_target->label().name()) == 0) { | |
174 return target; | |
175 } | |
176 } | |
177 | |
178 return NULL; | |
179 } | |
180 | |
90 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { | 181 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor { |
91 public: | 182 public: |
92 CollectPBXObjectsPerClassHelper() {} | 183 CollectPBXObjectsPerClassHelper() {} |
93 | 184 |
94 void Visit(PBXObject* object) override { | 185 void Visit(PBXObject* object) override { |
95 DCHECK(object); | 186 DCHECK(object); |
96 objects_per_class_[object->Class()].push_back(object); | 187 objects_per_class_[object->Class()].push_back(object); |
97 } | 188 } |
98 | 189 |
99 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& | 190 const std::map<PBXObjectClass, std::vector<const PBXObject*>>& |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 // Sort the list of targets per-label to get a consistent ordering of them | 351 // Sort the list of targets per-label to get a consistent ordering of them |
261 // in the generated Xcode project (and thus stability of the file generated). | 352 // in the generated Xcode project (and thus stability of the file generated). |
262 std::sort(targets->begin(), targets->end(), | 353 std::sort(targets->begin(), targets->end(), |
263 [](const Target* a, const Target* b) { | 354 [](const Target* a, const Target* b) { |
264 return a->label().name() < b->label().name(); | 355 return a->label().name() < b->label().name(); |
265 }); | 356 }); |
266 | 357 |
267 return true; | 358 return true; |
268 } | 359 } |
269 | 360 |
361 // static | |
362 void XcodeWriter::FilterXCTestTargets( | |
363 const std::vector<const Target*>& targets, | |
364 std::vector<const Target*>* xctest_targets, | |
365 std::vector<const Target*>* application_targets) { | |
366 // Filter out all targets of type CREATE_BUNDLE and whose bundle_data has | |
367 // product_type: "com.apple.product-type.bundle.unit-test". | |
368 for (const Target* target : targets) { | |
369 if (target->output_type() != Target::CREATE_BUNDLE) { | |
sdefresne
2016/12/14 13:00:02
nit: I would use an helper method IsXCTestTarget h
| |
370 continue; | |
371 } | |
372 if (target->bundle_data().product_type().compare( | |
373 "com.apple.product-type.bundle.unit-test") == 0) { | |
374 xctest_targets->push_back(target); | |
375 const Target* application_target = FindApplicationTarget(target, targets); | |
376 DCHECK(application_target); | |
377 application_targets->push_back(application_target); | |
378 } | |
379 } | |
380 } | |
381 | |
270 void XcodeWriter::CreateProductsProject( | 382 void XcodeWriter::CreateProductsProject( |
271 const std::vector<const Target*>& targets, | 383 const std::vector<const Target*>& targets, |
272 const PBXAttributes& attributes, | 384 const PBXAttributes& attributes, |
273 const std::string& source_path, | 385 const std::string& source_path, |
274 const std::string& config_name, | 386 const std::string& config_name, |
275 const std::string& root_target, | 387 const std::string& root_target, |
276 const std::string& ninja_extra_args, | 388 const std::string& ninja_extra_args, |
277 const BuildSettings* build_settings, | 389 const BuildSettings* build_settings, |
278 TargetOsType target_os) { | 390 TargetOsType target_os) { |
279 std::unique_ptr<PBXProject> main_project( | 391 std::unique_ptr<PBXProject> main_project( |
280 new PBXProject("products", config_name, source_path, attributes)); | 392 new PBXProject("products", config_name, source_path, attributes)); |
281 | 393 |
394 // Filter XCTest targets and their corresponding application targets and find | |
395 // list of earl grey test files recursively under the pairs. | |
396 std::vector<const Target*> xctest_targets; | |
397 std::vector<const Target*> application_targets; | |
398 std::vector<Target::FileList> earl_grey_file_lists; | |
399 XcodeWriter::FilterXCTestTargets(targets, &xctest_targets, | |
400 &application_targets); | |
401 GetEarlGreyFilesForAll(xctest_targets, application_targets, | |
402 &earl_grey_file_lists); | |
403 | |
282 std::string build_path; | 404 std::string build_path; |
283 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 405 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
284 | 406 |
285 main_project->AddAggregateTarget( | 407 main_project->AddAggregateTarget( |
286 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); | 408 "All", GetBuildScript(root_target, ninja_extra_args, env.get())); |
287 | 409 |
288 for (const Target* target : targets) { | 410 for (const Target* target : targets) { |
289 switch (target->output_type()) { | 411 switch (target->output_type()) { |
290 case Target::EXECUTABLE: | 412 case Target::EXECUTABLE: |
291 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) | 413 if (target_os == XcodeWriter::WRITER_TARGET_OS_IOS) |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
428 for (auto* object : pair.second) { | 550 for (auto* object : pair.second) { |
429 object->Print(out, 2); | 551 object->Print(out, 2); |
430 } | 552 } |
431 out << "/* End " << ToString(pair.first) << " section */\n"; | 553 out << "/* End " << ToString(pair.first) << " section */\n"; |
432 } | 554 } |
433 | 555 |
434 out << "\t};\n" | 556 out << "\t};\n" |
435 << "\trootObject = " << project->Reference() << ";\n" | 557 << "\trootObject = " << project->Reference() << ";\n" |
436 << "}\n"; | 558 << "}\n"; |
437 } | 559 } |
OLD | NEW |