OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "tools/gn/xcode_object.h" | |
6 | |
7 #include <iomanip> | |
8 #include <sstream> | |
9 #include <utility> | |
10 | |
11 #include "base/files/file_path.h" | |
12 #include "base/logging.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/strings/string_util.h" | |
15 | |
16 // Helper methods ------------------------------------------------------------- | |
17 | |
18 namespace { | |
brettw
2016/04/28 21:16:17
Blank line below
| |
19 struct IndentRules { | |
20 bool one_line; | |
21 unsigned level; | |
22 }; | |
23 | |
24 std::vector<std::unique_ptr<PBXObject>> EmptyPBXObjectVector() { | |
25 return std::vector<std::unique_ptr<PBXObject>>(); | |
26 } | |
27 | |
28 bool CharNeedEscaping(char c) { | |
29 if (base::IsAsciiAlpha(c) || base::IsAsciiDigit(c)) | |
30 return false; | |
31 if (c == '$' || c == '.' || c == '/' || c == '_') | |
32 return false; | |
33 return true; | |
34 } | |
35 | |
36 bool StringNeedEscaping(const std::string& string) { | |
37 if (string.empty()) | |
38 return true; | |
39 if (string.find("___") != std::string::npos) | |
40 return true; | |
41 | |
42 for (char c : string) { | |
43 if (CharNeedEscaping(c)) | |
44 return true; | |
45 } | |
46 return false; | |
47 } | |
48 | |
49 std::string EncodeString(const std::string& string) { | |
50 if (!StringNeedEscaping(string)) | |
51 return string; | |
52 | |
53 std::stringstream buffer; | |
54 buffer << '"'; | |
55 for (char c : string) { | |
56 if (c <= 31) { | |
57 switch (c) { | |
58 case '\a': | |
59 buffer << "\\a"; | |
60 break; | |
61 case '\b': | |
62 buffer << "\\b"; | |
63 break; | |
64 case '\t': | |
65 buffer << "\\t"; | |
66 break; | |
67 case '\n': | |
68 case '\r': | |
69 buffer << "\\n"; | |
70 break; | |
71 case '\v': | |
72 buffer << "\\v"; | |
73 break; | |
74 case '\f': | |
75 buffer << "\\f"; | |
76 break; | |
77 default: | |
78 buffer << std::hex << std::setw(4) << std::left << "\\U" | |
79 << static_cast<unsigned>(c); | |
80 break; | |
81 } | |
82 } else { | |
83 if (c == '"' || c == '\\') | |
84 buffer << '\\'; | |
85 buffer << c; | |
86 } | |
87 } | |
88 buffer << '"'; | |
89 return buffer.str(); | |
90 } | |
91 | |
92 const char* GetSourceType(const base::FilePath::StringType& ext) { | |
93 std::map<base::FilePath::StringType, const char*> extension_map = { | |
94 {FILE_PATH_LITERAL(".a"), "archive.ar"}, | |
95 {FILE_PATH_LITERAL(".app"), "wrapper.application"}, | |
96 {FILE_PATH_LITERAL(".bdic"), "file"}, | |
97 {FILE_PATH_LITERAL(".bundle"), "wrapper.cfbundle"}, | |
98 {FILE_PATH_LITERAL(".c"), "sourcecode.c.c"}, | |
99 {FILE_PATH_LITERAL(".cc"), "sourcecode.cpp.cpp"}, | |
100 {FILE_PATH_LITERAL(".cpp"), "sourcecode.cpp.cpp"}, | |
101 {FILE_PATH_LITERAL(".css"), "text.css"}, | |
102 {FILE_PATH_LITERAL(".cxx"), "sourcecode.cpp.cpp"}, | |
103 {FILE_PATH_LITERAL(".dart"), "sourcecode"}, | |
104 {FILE_PATH_LITERAL(".dylib"), "compiled.mach-o.dylib"}, | |
105 {FILE_PATH_LITERAL(".framework"), "wrapper.framework"}, | |
106 {FILE_PATH_LITERAL(".h"), "sourcecode.c.h"}, | |
107 {FILE_PATH_LITERAL(".hxx"), "sourcecode.cpp.h"}, | |
108 {FILE_PATH_LITERAL(".icns"), "image.icns"}, | |
109 {FILE_PATH_LITERAL(".java"), "sourcecode.java"}, | |
110 {FILE_PATH_LITERAL(".js"), "sourcecode.javascript"}, | |
111 {FILE_PATH_LITERAL(".kext"), "wrapper.kext"}, | |
112 {FILE_PATH_LITERAL(".m"), "sourcecode.c.objc"}, | |
113 {FILE_PATH_LITERAL(".mm"), "sourcecode.cpp.objcpp"}, | |
114 {FILE_PATH_LITERAL(".nib"), "wrapper.nib"}, | |
115 {FILE_PATH_LITERAL(".o"), "compiled.mach-o.objfile"}, | |
116 {FILE_PATH_LITERAL(".pdf"), "image.pdf"}, | |
117 {FILE_PATH_LITERAL(".pl"), "text.script.perl"}, | |
118 {FILE_PATH_LITERAL(".plist"), "text.plist.xml"}, | |
119 {FILE_PATH_LITERAL(".pm"), "text.script.perl"}, | |
120 {FILE_PATH_LITERAL(".png"), "image.png"}, | |
121 {FILE_PATH_LITERAL(".py"), "text.script.python"}, | |
122 {FILE_PATH_LITERAL(".r"), "sourcecode.rez"}, | |
123 {FILE_PATH_LITERAL(".rez"), "sourcecode.rez"}, | |
124 {FILE_PATH_LITERAL(".s"), "sourcecode.asm"}, | |
125 {FILE_PATH_LITERAL(".storyboard"), "file.storyboard"}, | |
126 {FILE_PATH_LITERAL(".strings"), "text.plist.strings"}, | |
127 {FILE_PATH_LITERAL(".swift"), "sourcecode.swift"}, | |
128 {FILE_PATH_LITERAL(".ttf"), "file"}, | |
129 {FILE_PATH_LITERAL(".xcassets"), "folder.assetcatalog"}, | |
130 {FILE_PATH_LITERAL(".xcconfig"), "text.xcconfig"}, | |
131 {FILE_PATH_LITERAL(".xcdatamodel"), "wrapper.xcdatamodel"}, | |
132 {FILE_PATH_LITERAL(".xcdatamodeld"), "wrapper.xcdatamodeld"}, | |
133 {FILE_PATH_LITERAL(".xib"), "file.xib"}, | |
134 {FILE_PATH_LITERAL(".y"), "sourcecode.yacc"}, | |
135 }; | |
136 | |
137 const auto& iter = extension_map.find(ext); | |
138 if (iter != extension_map.end()) { | |
brettw
2016/04/28 21:16:17
No {}
| |
139 return iter->second; | |
140 } | |
141 | |
142 return "text"; | |
143 } | |
144 | |
145 bool HasExplicitFileType(const base::FilePath::StringType& ext) { | |
146 return ext == FILE_PATH_LITERAL(".dart"); | |
147 } | |
148 | |
149 bool IsSourceFileForIndexing(const base::FilePath::StringType& ext) { | |
150 return ext == FILE_PATH_LITERAL(".c") || ext == FILE_PATH_LITERAL(".cc") || | |
151 ext == FILE_PATH_LITERAL(".cpp") || ext == FILE_PATH_LITERAL(".cxx") || | |
152 ext == FILE_PATH_LITERAL(".m") || ext == FILE_PATH_LITERAL(".mm"); | |
153 } | |
154 | |
155 void PrintValue(std::ostream& out, IndentRules rules, unsigned value) { | |
156 out << value; | |
157 } | |
158 | |
159 void PrintValue(std::ostream& out, IndentRules rules, const char* value) { | |
160 out << EncodeString(value); | |
161 } | |
162 | |
163 void PrintValue(std::ostream& out, | |
164 IndentRules rules, | |
165 const std::string& value) { | |
166 out << EncodeString(value); | |
167 } | |
168 | |
169 void PrintValue(std::ostream& out, IndentRules rules, const PBXObject* value) { | |
170 out << value->Reference(); | |
171 } | |
172 | |
173 template <typename ObjectClass> | |
174 void PrintValue(std::ostream& out, | |
175 IndentRules rules, | |
176 const std::unique_ptr<ObjectClass>& value) { | |
177 PrintValue(out, rules, value.get()); | |
178 } | |
179 | |
180 template <typename ValueType> | |
181 void PrintValue(std::ostream& out, | |
182 IndentRules rules, | |
183 const std::vector<ValueType>& values) { | |
184 IndentRules sub_rule{rules.one_line, rules.level + 1}; | |
185 out << "(" << (rules.one_line ? " " : "\n"); | |
186 for (const auto& value : values) { | |
187 if (!sub_rule.one_line) | |
188 out << std::string(sub_rule.level, '\t'); | |
189 | |
190 PrintValue(out, sub_rule, value); | |
191 out << "," << (rules.one_line ? " " : "\n"); | |
192 } | |
193 | |
194 if (!rules.one_line && rules.level) | |
195 out << std::string(rules.level, '\t'); | |
196 out << ")"; | |
197 } | |
198 | |
199 template <typename ValueType> | |
200 void PrintValue(std::ostream& out, | |
201 IndentRules rules, | |
202 const std::map<std::string, ValueType>& values) { | |
203 IndentRules sub_rule{rules.one_line, rules.level + 1}; | |
204 out << "{" << (rules.one_line ? " " : "\n"); | |
205 for (const auto& pair : values) { | |
206 if (!sub_rule.one_line) | |
207 out << std::string(sub_rule.level, '\t'); | |
208 | |
209 out << pair.first << " = "; | |
210 PrintValue(out, sub_rule, pair.second); | |
211 out << ";" << (rules.one_line ? " " : "\n"); | |
212 } | |
213 | |
214 if (!rules.one_line && rules.level) | |
215 out << std::string(rules.level, '\t'); | |
216 out << "}"; | |
217 } | |
218 | |
219 template <typename ValueType> | |
220 void PrintProperty(std::ostream& out, | |
221 IndentRules rules, | |
222 const char* name, | |
223 ValueType&& value) { | |
224 if (!rules.one_line && rules.level) | |
225 out << std::string(rules.level, '\t'); | |
226 | |
227 out << name << " = "; | |
228 PrintValue(out, rules, std::forward<ValueType>(value)); | |
229 out << ";" << (rules.one_line ? " " : "\n"); | |
230 } | |
231 } // namespace | |
brettw
2016/04/28 21:16:17
Blank line before.
| |
232 | |
233 // PBXObjectClass ------------------------------------------------------------- | |
234 | |
235 const char* ToString(PBXObjectClass cls) { | |
236 switch (cls) { | |
237 case PBXAggregateTargetClass: | |
238 return "PBXAggregateTarget"; | |
239 case PBXBuildFileClass: | |
240 return "PBXBuildFile"; | |
241 case PBXFileReferenceClass: | |
242 return "PBXFileReference"; | |
243 case PBXFrameworksBuildPhaseClass: | |
244 return "PBXFrameworksBuildPhase"; | |
245 case PBXGroupClass: | |
246 return "PBXGroup"; | |
247 case PBXNativeTargetClass: | |
248 return "PBXNativeTarget"; | |
249 case PBXProjectClass: | |
250 return "PBXProject"; | |
251 case PBXShellScriptBuildPhaseClass: | |
252 return "PBXShellScriptBuildPhase"; | |
253 case PBXSourcesBuildPhaseClass: | |
254 return "PBXSourcesBuildPhase"; | |
255 case XCBuildConfigurationClass: | |
256 return "XCBuildConfiguration"; | |
257 case XCConfigurationListClass: | |
258 return "XCConfigurationList"; | |
259 } | |
260 } | |
261 | |
262 // PBXObjectVisitor ----------------------------------------------------------- | |
263 | |
264 PBXObjectVisitor::PBXObjectVisitor() {} | |
265 | |
266 PBXObjectVisitor::~PBXObjectVisitor() {} | |
267 | |
268 // PBXObject ------------------------------------------------------------------ | |
269 | |
270 PBXObject::PBXObject() {} | |
271 | |
272 PBXObject::~PBXObject() {} | |
273 | |
274 void PBXObject::SetId(const std::string& id) { | |
275 DCHECK(id_.empty()); | |
276 DCHECK(!id.empty()); | |
277 id_.assign(id); | |
278 } | |
279 | |
280 std::string PBXObject::Reference() const { | |
281 std::string comment = Comment(); | |
282 if (comment.empty()) | |
283 return id_; | |
284 | |
285 return id_ + " /* " + comment + " */"; | |
286 } | |
287 | |
288 std::string PBXObject::Comment() const { | |
289 return Name(); | |
290 } | |
291 | |
292 void PBXObject::Visit(PBXObjectVisitor& visitor) { | |
293 visitor.Visit(this); | |
294 } | |
295 | |
296 // PBXBuildPhase -------------------------------------------------------------- | |
297 | |
298 PBXBuildPhase::PBXBuildPhase() {} | |
299 | |
300 PBXBuildPhase::~PBXBuildPhase() {} | |
301 | |
302 // PBXTarget ------------------------------------------------------------------ | |
303 | |
304 PBXTarget::PBXTarget(const std::string& name, | |
305 const std::string& shell_script, | |
306 const std::string& config_name, | |
307 const PBXAttributes& attributes) | |
308 : configurations_(new XCConfigurationList(config_name, attributes, this)), | |
309 name_(name) { | |
310 if (!shell_script.empty()) { | |
311 build_phases_.push_back( | |
312 base::WrapUnique(new PBXShellScriptBuildPhase(name, shell_script))); | |
313 } | |
314 } | |
315 | |
316 PBXTarget::~PBXTarget() {} | |
317 | |
318 std::string PBXTarget::Name() const { | |
319 return name_; | |
320 } | |
321 | |
322 void PBXTarget::Visit(PBXObjectVisitor& visitor) { | |
323 PBXObject::Visit(visitor); | |
324 configurations_->Visit(visitor); | |
325 for (const auto& build_phase : build_phases_) { | |
326 build_phase->Visit(visitor); | |
327 } | |
328 } | |
329 | |
330 // PBXAggregateTarget --------------------------------------------------------- | |
331 | |
332 PBXAggregateTarget::PBXAggregateTarget(const std::string& name, | |
333 const std::string& shell_script, | |
334 const std::string& config_name, | |
335 const PBXAttributes& attributes) | |
336 : PBXTarget(name, shell_script, config_name, attributes) {} | |
337 | |
338 PBXAggregateTarget::~PBXAggregateTarget() {} | |
339 | |
340 PBXObjectClass PBXAggregateTarget::Class() const { | |
341 return PBXAggregateTargetClass; | |
342 } | |
343 | |
344 void PBXAggregateTarget::Print(std::ostream& out, unsigned indent) const { | |
345 const std::string indent_str(indent, '\t'); | |
346 const IndentRules rules = {false, indent + 1}; | |
347 out << indent_str << Reference() << " = {\n"; | |
348 PrintProperty(out, rules, "isa", ToString(Class())); | |
349 PrintProperty(out, rules, "buildConfigurationList", configurations_); | |
350 PrintProperty(out, rules, "buildPhases", build_phases_); | |
351 PrintProperty(out, rules, "dependencies", EmptyPBXObjectVector()); | |
352 PrintProperty(out, rules, "name", name_); | |
353 PrintProperty(out, rules, "productName", name_); | |
354 out << indent_str << "};\n"; | |
355 } | |
356 | |
357 // PBXBuildFile --------------------------------------------------------------- | |
358 | |
359 PBXBuildFile::PBXBuildFile(const PBXFileReference* file_reference, | |
360 const PBXSourcesBuildPhase* build_phase) | |
361 : file_reference_(file_reference), build_phase_(build_phase) { | |
362 DCHECK(file_reference_); | |
363 DCHECK(build_phase_); | |
364 } | |
365 | |
366 PBXBuildFile::~PBXBuildFile() {} | |
367 | |
368 PBXObjectClass PBXBuildFile::Class() const { | |
369 return PBXBuildFileClass; | |
370 } | |
371 | |
372 std::string PBXBuildFile::Name() const { | |
373 return file_reference_->Name() + " in " + build_phase_->Name(); | |
374 } | |
375 | |
376 void PBXBuildFile::Print(std::ostream& out, unsigned indent) const { | |
377 const std::string indent_str(indent, '\t'); | |
378 const IndentRules rules = {true, 0}; | |
379 out << indent_str << Reference() << " = {"; | |
380 PrintProperty(out, rules, "isa", ToString(Class())); | |
381 PrintProperty(out, rules, "fileRef", file_reference_); | |
382 out << "};\n"; | |
383 } | |
384 | |
385 // PBXFileReference ----------------------------------------------------------- | |
386 | |
387 PBXFileReference::PBXFileReference(const std::string& name, | |
388 const std::string& path, | |
389 const std::string& type) | |
390 : name_(name), path_(path), type_(type) {} | |
391 | |
392 PBXFileReference::~PBXFileReference() {} | |
393 | |
394 PBXObjectClass PBXFileReference::Class() const { | |
395 return PBXFileReferenceClass; | |
396 } | |
397 | |
398 std::string PBXFileReference::Name() const { | |
399 return path_; | |
400 } | |
401 | |
402 void PBXFileReference::Print(std::ostream& out, unsigned indent) const { | |
403 const std::string indent_str(indent, '\t'); | |
404 const IndentRules rules = {true, 0}; | |
405 out << indent_str << Reference() << " = {"; | |
406 PrintProperty(out, rules, "isa", ToString(Class())); | |
407 | |
408 if (!type_.empty()) { | |
409 PrintProperty(out, rules, "explicitFileType", type_); | |
410 PrintProperty(out, rules, "includeInIndex", 0u); | |
411 } else { | |
412 const base::FilePath::StringType ext = | |
413 base::FilePath::FromUTF8Unsafe(path_).Extension(); | |
414 | |
415 if (HasExplicitFileType(ext)) | |
416 PrintProperty(out, rules, "explicitFileType", GetSourceType(ext)); | |
417 else | |
418 PrintProperty(out, rules, "lastKnownFileType", GetSourceType(ext)); | |
419 } | |
420 | |
421 if (name_ != path_ && !name_.empty()) | |
422 PrintProperty(out, rules, "name", name_); | |
423 | |
424 PrintProperty(out, rules, "path", path_); | |
425 PrintProperty(out, rules, "sourceTree", | |
426 type_.empty() ? "<group>" : "BUILT_PRODUCTS_DIR"); | |
427 out << "};\n"; | |
428 } | |
429 | |
430 // PBXFrameworksBuildPhase ---------------------------------------------------- | |
431 | |
432 PBXFrameworksBuildPhase::PBXFrameworksBuildPhase() {} | |
433 | |
434 PBXFrameworksBuildPhase::~PBXFrameworksBuildPhase() {} | |
435 | |
436 PBXObjectClass PBXFrameworksBuildPhase::Class() const { | |
437 return PBXFrameworksBuildPhaseClass; | |
438 } | |
439 | |
440 std::string PBXFrameworksBuildPhase::Name() const { | |
441 return "Frameworks"; | |
442 } | |
443 | |
444 void PBXFrameworksBuildPhase::Print(std::ostream& out, unsigned indent) const { | |
445 const std::string indent_str(indent, '\t'); | |
446 const IndentRules rules = {false, indent + 1}; | |
447 out << indent_str << Reference() << " = {\n"; | |
448 PrintProperty(out, rules, "isa", ToString(Class())); | |
449 PrintProperty(out, rules, "buildActionMask", 0x7fffffffu); | |
450 PrintProperty(out, rules, "files", EmptyPBXObjectVector()); | |
451 PrintProperty(out, rules, "runOnlyForDeploymentPostprocessing", 0u); | |
452 out << indent_str << "};\n"; | |
453 } | |
454 | |
455 // PBXGroup ------------------------------------------------------------------- | |
456 | |
457 PBXGroup::PBXGroup(const std::string& path, const std::string& name) | |
458 : name_(name), path_(path) {} | |
459 | |
460 PBXGroup::~PBXGroup() {} | |
461 | |
462 PBXObject* PBXGroup::AddChild(std::unique_ptr<PBXObject> child) { | |
463 DCHECK(child); | |
464 children_.push_back(std::move(child)); | |
465 return children_.back().get(); | |
466 } | |
467 | |
468 PBXFileReference* PBXGroup::AddSourceFile(const std::string& source_path) { | |
469 DCHECK(!source_path.empty()); | |
470 std::string::size_type sep = source_path.find(base::FilePath::kSeparators); | |
471 if (sep == std::string::npos) { | |
472 children_.push_back(base::WrapUnique( | |
473 new PBXFileReference(std::string(), source_path, std::string()))); | |
474 return static_cast<PBXFileReference*>(children_.back().get()); | |
475 } | |
476 | |
477 PBXGroup* group = nullptr; | |
478 base::StringPiece component(source_path.data(), sep); | |
479 for (const auto& child : children_) { | |
480 if (child->Class() != PBXGroupClass) | |
481 continue; | |
482 | |
483 PBXGroup* child_as_group = static_cast<PBXGroup*>(child.get()); | |
484 if (child_as_group->path_ == component) { | |
485 group = child_as_group; | |
486 break; | |
487 } | |
488 } | |
489 | |
490 if (!group) { | |
491 children_.push_back(base::WrapUnique(new PBXGroup(component.as_string()))); | |
492 group = static_cast<PBXGroup*>(children_.back().get()); | |
493 } | |
494 | |
495 DCHECK(group); | |
496 DCHECK(group->path_ == component); | |
497 return group->AddSourceFile(source_path.substr(sep + 1)); | |
498 } | |
499 | |
500 PBXObjectClass PBXGroup::Class() const { | |
501 return PBXGroupClass; | |
502 } | |
503 | |
504 std::string PBXGroup::Name() const { | |
505 if (!name_.empty()) | |
506 return name_; | |
507 if (!path_.empty()) | |
508 return path_; | |
509 return std::string(); | |
510 } | |
511 | |
512 void PBXGroup::Visit(PBXObjectVisitor& visitor) { | |
513 PBXObject::Visit(visitor); | |
514 for (const auto& child : children_) { | |
515 child->Visit(visitor); | |
516 } | |
517 } | |
518 | |
519 void PBXGroup::Print(std::ostream& out, unsigned indent) const { | |
520 const std::string indent_str(indent, '\t'); | |
521 const IndentRules rules = {false, indent + 1}; | |
522 out << indent_str << Reference() << " = {\n"; | |
523 PrintProperty(out, rules, "isa", ToString(Class())); | |
524 PrintProperty(out, rules, "children", children_); | |
525 if (!name_.empty()) | |
526 PrintProperty(out, rules, "name", name_); | |
527 if (!path_.empty()) | |
528 PrintProperty(out, rules, "path", path_); | |
529 PrintProperty(out, rules, "sourceTree", "<group>"); | |
530 out << indent_str << "};\n"; | |
531 } | |
532 | |
533 // PBXNativeTarget ------------------------------------------------------------ | |
534 | |
535 PBXNativeTarget::PBXNativeTarget(const std::string& name, | |
536 const std::string& shell_script, | |
537 const std::string& config_name, | |
538 const PBXAttributes& attributes, | |
539 const std::string& product_type, | |
540 const PBXFileReference* product_reference) | |
541 : PBXTarget(name, shell_script, config_name, attributes), | |
542 product_reference_(product_reference), | |
543 product_type_(product_type) { | |
544 DCHECK(product_reference_); | |
545 build_phases_.push_back(base::WrapUnique(new PBXSourcesBuildPhase)); | |
546 source_build_phase_ = | |
547 static_cast<PBXSourcesBuildPhase*>(build_phases_.back().get()); | |
548 | |
549 build_phases_.push_back(base::WrapUnique(new PBXFrameworksBuildPhase)); | |
550 } | |
551 | |
552 PBXNativeTarget::~PBXNativeTarget() {} | |
553 | |
554 void PBXNativeTarget::AddFileForIndexing( | |
555 const PBXFileReference* file_reference) { | |
556 DCHECK(file_reference); | |
557 source_build_phase_->AddBuildFile( | |
558 base::WrapUnique(new PBXBuildFile(file_reference, source_build_phase_))); | |
559 } | |
560 | |
561 PBXObjectClass PBXNativeTarget::Class() const { | |
562 return PBXNativeTargetClass; | |
563 } | |
564 | |
565 void PBXNativeTarget::Print(std::ostream& out, unsigned indent) const { | |
566 const std::string indent_str(indent, '\t'); | |
567 const IndentRules rules = {false, indent + 1}; | |
568 out << indent_str << Reference() << " = {\n"; | |
569 PrintProperty(out, rules, "isa", ToString(Class())); | |
570 PrintProperty(out, rules, "buildConfigurationList", configurations_); | |
571 PrintProperty(out, rules, "buildPhases", build_phases_); | |
572 PrintProperty(out, rules, "buildRules", EmptyPBXObjectVector()); | |
573 PrintProperty(out, rules, "dependencies", EmptyPBXObjectVector()); | |
574 PrintProperty(out, rules, "name", name_); | |
575 PrintProperty(out, rules, "productName", name_); | |
576 PrintProperty(out, rules, "productReference", product_reference_); | |
577 PrintProperty(out, rules, "productType", product_type_); | |
578 out << indent_str << "};\n"; | |
579 } | |
580 | |
581 // PBXProject ----------------------------------------------------------------- | |
582 | |
583 PBXProject::PBXProject(const std::string& name, | |
584 const std::string& config_name, | |
585 const std::string& source_path, | |
586 const PBXAttributes& attributes) | |
587 : name_(name), config_name_(config_name), target_for_indexing_(nullptr) { | |
588 attributes_["BuildIndependentTargetsInParallel"] = "YES"; | |
589 | |
590 main_group_.reset(new PBXGroup); | |
591 sources_ = static_cast<PBXGroup*>(main_group_->AddChild( | |
592 base::WrapUnique(new PBXGroup(source_path, "Source")))); | |
593 products_ = static_cast<PBXGroup*>(main_group_->AddChild( | |
594 base::WrapUnique(new PBXGroup(std::string(), "Product")))); | |
595 main_group_->AddChild(base::WrapUnique(new PBXGroup(std::string(), "Build"))); | |
596 | |
597 configurations_.reset(new XCConfigurationList(config_name, attributes, this)); | |
598 } | |
599 | |
600 PBXProject::~PBXProject() {} | |
601 | |
602 void PBXProject::AddSourceFile(const std::string& source_path) { | |
603 PBXFileReference* file_reference = sources_->AddSourceFile(source_path); | |
604 const base::FilePath::StringType ext = | |
605 base::FilePath::FromUTF8Unsafe(source_path).Extension(); | |
606 if (!IsSourceFileForIndexing(ext)) | |
607 return; | |
608 | |
609 if (!target_for_indexing_) { | |
610 PBXAttributes attributes; | |
611 attributes["EXECUTABLE_PREFIX"] = ""; | |
612 attributes["HEADER_SEARCH_PATHS"] = sources_->path(); | |
613 attributes["PRODUCT_NAME"] = name_; | |
614 | |
615 PBXFileReference* product_reference = static_cast<PBXFileReference*>( | |
616 products_->AddChild(base::WrapUnique(new PBXFileReference( | |
617 std::string(), name_, "compiled.mach-o.executable")))); | |
618 | |
619 const char product_type[] = "com.apple.product-type.tool"; | |
620 targets_.push_back(base::WrapUnique( | |
621 new PBXNativeTarget(name_, std::string(), config_name_, attributes, | |
622 product_type, product_reference))); | |
623 target_for_indexing_ = static_cast<PBXNativeTarget*>(targets_.back().get()); | |
624 } | |
625 | |
626 DCHECK(target_for_indexing_); | |
627 target_for_indexing_->AddFileForIndexing(file_reference); | |
628 } | |
629 | |
630 void PBXProject::AddAggregateTarget(const std::string& name, | |
631 const std::string& shell_script) { | |
632 PBXAttributes attributes; | |
633 attributes["CODE_SIGNING_REQUIRED"] = "NO"; | |
634 attributes["CONFIGURATION_BUILD_DIR"] = "."; | |
635 attributes["PRODUCT_NAME"] = name; | |
636 | |
637 targets_.push_back(base::WrapUnique( | |
638 new PBXAggregateTarget(name, shell_script, config_name_, attributes))); | |
639 } | |
640 | |
641 void PBXProject::AddNativeTarget(const std::string& name, | |
642 const std::string& type, | |
643 const std::string& output_name, | |
644 const std::string& output_type, | |
645 const std::string& shell_script) { | |
646 const base::FilePath::StringType ext = | |
647 base::FilePath::FromUTF8Unsafe(output_name).Extension(); | |
648 | |
649 PBXFileReference* product = static_cast<PBXFileReference*>( | |
650 products_->AddChild(base::WrapUnique(new PBXFileReference( | |
651 name, output_name, type.empty() ? GetSourceType(ext) : type)))); | |
652 | |
653 PBXAttributes attributes; | |
654 attributes["CODE_SIGNING_REQUIRED"] = "NO"; | |
655 attributes["CONFIGURATION_BUILD_DIR"] = "."; | |
656 attributes["PRODUCT_NAME"] = name; | |
657 | |
658 targets_.push_back(base::WrapUnique(new PBXNativeTarget( | |
659 name, shell_script, config_name_, attributes, output_type, product))); | |
660 } | |
661 | |
662 void PBXProject::SetProjectDirPath(const std::string& project_dir_path) { | |
663 DCHECK(!project_dir_path.empty()); | |
664 project_dir_path_.assign(project_dir_path); | |
665 } | |
666 | |
667 void PBXProject::SetProjectRoot(const std::string& project_root) { | |
668 DCHECK(!project_root.empty()); | |
669 project_root_.assign(project_root); | |
670 } | |
671 | |
672 void PBXProject::AddTarget(std::unique_ptr<PBXTarget> target) { | |
673 DCHECK(target); | |
674 targets_.push_back(std::move(target)); | |
675 } | |
676 | |
677 PBXObjectClass PBXProject::Class() const { | |
678 return PBXProjectClass; | |
679 } | |
680 | |
681 std::string PBXProject::Name() const { | |
682 return name_; | |
683 } | |
684 | |
685 std::string PBXProject::Comment() const { | |
686 return "Project object"; | |
687 } | |
688 | |
689 void PBXProject::Visit(PBXObjectVisitor& visitor) { | |
690 PBXObject::Visit(visitor); | |
691 configurations_->Visit(visitor); | |
692 main_group_->Visit(visitor); | |
693 for (const auto& target : targets_) { | |
694 target->Visit(visitor); | |
695 } | |
696 } | |
697 | |
698 void PBXProject::Print(std::ostream& out, unsigned indent) const { | |
699 const std::string indent_str(indent, '\t'); | |
700 const IndentRules rules = {false, indent + 1}; | |
701 out << indent_str << Reference() << " = {\n"; | |
702 PrintProperty(out, rules, "isa", ToString(Class())); | |
703 PrintProperty(out, rules, "attributes", attributes_); | |
704 PrintProperty(out, rules, "buildConfigurationList", configurations_); | |
705 PrintProperty(out, rules, "compatibilityVersion", "Xcode 3.2"); | |
706 PrintProperty(out, rules, "developmentRegion", "English"); | |
707 PrintProperty(out, rules, "hasScannedForEncodings", 1u); | |
708 PrintProperty(out, rules, "knownRegions", std::vector<std::string>({"en"})); | |
709 PrintProperty(out, rules, "mainGroup", main_group_); | |
710 PrintProperty(out, rules, "projectDirPath", project_dir_path_); | |
711 PrintProperty(out, rules, "projectRoot", project_root_); | |
712 PrintProperty(out, rules, "targets", targets_); | |
713 out << indent_str << "};\n"; | |
714 } | |
715 | |
716 // PBXShellScriptBuildPhase --------------------------------------------------- | |
717 | |
718 PBXShellScriptBuildPhase::PBXShellScriptBuildPhase( | |
719 const std::string& name, | |
720 const std::string& shell_script) | |
721 : name_("Action \"Compile and copy " + name + " via ninja\""), | |
722 shell_script_(shell_script) {} | |
723 | |
724 PBXShellScriptBuildPhase::~PBXShellScriptBuildPhase() {} | |
725 | |
726 PBXObjectClass PBXShellScriptBuildPhase::Class() const { | |
727 return PBXShellScriptBuildPhaseClass; | |
728 } | |
729 | |
730 std::string PBXShellScriptBuildPhase::Name() const { | |
731 return name_; | |
732 } | |
733 | |
734 void PBXShellScriptBuildPhase::Print(std::ostream& out, unsigned indent) const { | |
735 const std::string indent_str(indent, '\t'); | |
736 const IndentRules rules = {false, indent + 1}; | |
737 out << indent_str << Reference() << " = {\n"; | |
738 PrintProperty(out, rules, "isa", ToString(Class())); | |
739 PrintProperty(out, rules, "buildActionMask", 0x7fffffffu); | |
740 PrintProperty(out, rules, "files", EmptyPBXObjectVector()); | |
741 PrintProperty(out, rules, "inputPaths", EmptyPBXObjectVector()); | |
742 PrintProperty(out, rules, "name", name_); | |
743 PrintProperty(out, rules, "outputPaths", EmptyPBXObjectVector()); | |
744 PrintProperty(out, rules, "runOnlyForDeploymentPostprocessing", 0u); | |
745 PrintProperty(out, rules, "shellPath", "/bin/sh"); | |
746 PrintProperty(out, rules, "shellScript", shell_script_); | |
747 PrintProperty(out, rules, "showEnvVarsInLog", 0u); | |
748 out << indent_str << "};\n"; | |
749 } | |
750 | |
751 // PBXSourcesBuildPhase ------------------------------------------------------- | |
752 | |
753 PBXSourcesBuildPhase::PBXSourcesBuildPhase() {} | |
754 | |
755 PBXSourcesBuildPhase::~PBXSourcesBuildPhase() {} | |
756 | |
757 void PBXSourcesBuildPhase::AddBuildFile( | |
758 std::unique_ptr<PBXBuildFile> build_file) { | |
759 files_.push_back(std::move(build_file)); | |
760 } | |
761 | |
762 PBXObjectClass PBXSourcesBuildPhase::Class() const { | |
763 return PBXSourcesBuildPhaseClass; | |
764 } | |
765 | |
766 std::string PBXSourcesBuildPhase::Name() const { | |
767 return "Sources"; | |
768 } | |
769 | |
770 void PBXSourcesBuildPhase::Visit(PBXObjectVisitor& visitor) { | |
771 PBXBuildPhase::Visit(visitor); | |
772 for (const auto& file : files_) { | |
773 file->Visit(visitor); | |
774 } | |
775 } | |
776 | |
777 void PBXSourcesBuildPhase::Print(std::ostream& out, unsigned indent) const { | |
778 const std::string indent_str(indent, '\t'); | |
779 const IndentRules rules = {false, indent + 1}; | |
780 out << indent_str << Reference() << " = {\n"; | |
781 PrintProperty(out, rules, "isa", ToString(Class())); | |
782 PrintProperty(out, rules, "buildActionMask", 0x7fffffffu); | |
783 PrintProperty(out, rules, "files", files_); | |
784 PrintProperty(out, rules, "runOnlyForDeploymentPostprocessing", 0u); | |
785 out << indent_str << "};\n"; | |
786 } | |
787 | |
788 // XCBuildConfiguration ------------------------------------------------------- | |
789 | |
790 XCBuildConfiguration::XCBuildConfiguration(const std::string& name, | |
791 const PBXAttributes& attributes) | |
792 : attributes_(attributes), name_(name) {} | |
793 | |
794 XCBuildConfiguration::~XCBuildConfiguration() {} | |
795 | |
796 PBXObjectClass XCBuildConfiguration::Class() const { | |
797 return XCBuildConfigurationClass; | |
798 } | |
799 | |
800 std::string XCBuildConfiguration::Name() const { | |
801 return name_; | |
802 } | |
803 | |
804 void XCBuildConfiguration::Print(std::ostream& out, unsigned indent) const { | |
805 const std::string indent_str(indent, '\t'); | |
806 const IndentRules rules = {false, indent + 1}; | |
807 out << indent_str << Reference() << " = {\n"; | |
808 PrintProperty(out, rules, "isa", ToString(Class())); | |
809 PrintProperty(out, rules, "buildSettings", attributes_); | |
810 PrintProperty(out, rules, "name", name_); | |
811 out << indent_str << "};\n"; | |
812 } | |
813 | |
814 // XCConfigurationList -------------------------------------------------------- | |
815 | |
816 XCConfigurationList::XCConfigurationList(const std::string& name, | |
817 const PBXAttributes& attributes, | |
818 const PBXObject* owner_reference) | |
819 : owner_reference_(owner_reference) { | |
820 DCHECK(owner_reference_); | |
821 configurations_.push_back( | |
822 base::WrapUnique(new XCBuildConfiguration(name, attributes))); | |
823 } | |
824 | |
825 XCConfigurationList::~XCConfigurationList() {} | |
826 | |
827 PBXObjectClass XCConfigurationList::Class() const { | |
828 return XCConfigurationListClass; | |
829 } | |
830 | |
831 std::string XCConfigurationList::Name() const { | |
832 std::stringstream buffer; | |
833 buffer << "Build configuration list for " | |
834 << ToString(owner_reference_->Class()) << " \"" | |
835 << owner_reference_->Name() << "\""; | |
836 return buffer.str(); | |
837 } | |
838 | |
839 void XCConfigurationList::Visit(PBXObjectVisitor& visitor) { | |
840 PBXObject::Visit(visitor); | |
841 for (const auto& configuration : configurations_) { | |
842 configuration->Visit(visitor); | |
843 } | |
844 } | |
845 | |
846 void XCConfigurationList::Print(std::ostream& out, unsigned indent) const { | |
847 const std::string indent_str(indent, '\t'); | |
848 const IndentRules rules = {false, indent + 1}; | |
849 out << indent_str << Reference() << " = {\n"; | |
850 PrintProperty(out, rules, "isa", ToString(Class())); | |
851 PrintProperty(out, rules, "buildConfigurations", configurations_); | |
852 PrintProperty(out, rules, "defaultConfigurationIsVisible", 1u); | |
853 PrintProperty(out, rules, "defaultConfigurationName", | |
854 configurations_[0]->Name()); | |
855 out << indent_str << "};\n"; | |
856 } | |
OLD | NEW |