| Index: tools/gn/xcode_object.cc
|
| diff --git a/tools/gn/xcode_object.cc b/tools/gn/xcode_object.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bc8994409fe71ca5a429cf728ba7e611bb1d8e87
|
| --- /dev/null
|
| +++ b/tools/gn/xcode_object.cc
|
| @@ -0,0 +1,858 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "tools/gn/xcode_object.h"
|
| +
|
| +#include <iomanip>
|
| +#include <sstream>
|
| +#include <utility>
|
| +
|
| +#include "base/files/file_path.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/strings/string_util.h"
|
| +
|
| +// Helper methods -------------------------------------------------------------
|
| +
|
| +namespace {
|
| +struct IndentRules {
|
| + bool one_line;
|
| + unsigned level;
|
| +};
|
| +
|
| +std::vector<std::unique_ptr<PBXObject>> EmptyPBXObjectVector() {
|
| + return std::vector<std::unique_ptr<PBXObject>>();
|
| +}
|
| +
|
| +bool CharNeedEscaping(char c) {
|
| + if (base::IsAsciiAlpha(c) || base::IsAsciiDigit(c))
|
| + return false;
|
| + if (c == '$' || c == '.' || c == '/' || c == '_')
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +bool StringNeedEscaping(const std::string& string) {
|
| + if (string.empty())
|
| + return true;
|
| + if (string.find("___") != std::string::npos)
|
| + return true;
|
| +
|
| + for (char c : string) {
|
| + if (CharNeedEscaping(c))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +std::string EncodeString(const std::string& string) {
|
| + if (!StringNeedEscaping(string))
|
| + return string;
|
| +
|
| + std::stringstream buffer;
|
| + buffer << '"';
|
| + for (char c : string) {
|
| + if (c <= 31) {
|
| + switch (c) {
|
| + case '\a':
|
| + buffer << "\\a";
|
| + break;
|
| + case '\b':
|
| + buffer << "\\b";
|
| + break;
|
| + case '\t':
|
| + buffer << "\\t";
|
| + break;
|
| + case '\n':
|
| + case '\r':
|
| + buffer << "\\n";
|
| + break;
|
| + case '\v':
|
| + buffer << "\\v";
|
| + break;
|
| + case '\f':
|
| + buffer << "\\f";
|
| + break;
|
| + default:
|
| + buffer << std::hex << std::setw(4) << std::left << "\\U"
|
| + << static_cast<unsigned>(c);
|
| + break;
|
| + }
|
| + } else {
|
| + if (c == '"' || c == '\\')
|
| + buffer << '\\';
|
| + buffer << c;
|
| + }
|
| + }
|
| + buffer << '"';
|
| + return buffer.str();
|
| +}
|
| +
|
| +const char* GetSourceType(const base::FilePath::StringType& ext) {
|
| + std::map<base::FilePath::StringType, const char*> extension_map = {
|
| + {FILE_PATH_LITERAL(".a"), "archive.ar"},
|
| + {FILE_PATH_LITERAL(".app"), "wrapper.application"},
|
| + {FILE_PATH_LITERAL(".bdic"), "file"},
|
| + {FILE_PATH_LITERAL(".bundle"), "wrapper.cfbundle"},
|
| + {FILE_PATH_LITERAL(".c"), "sourcecode.c.c"},
|
| + {FILE_PATH_LITERAL(".cc"), "sourcecode.cpp.cpp"},
|
| + {FILE_PATH_LITERAL(".cpp"), "sourcecode.cpp.cpp"},
|
| + {FILE_PATH_LITERAL(".css"), "text.css"},
|
| + {FILE_PATH_LITERAL(".cxx"), "sourcecode.cpp.cpp"},
|
| + {FILE_PATH_LITERAL(".dart"), "sourcecode"},
|
| + {FILE_PATH_LITERAL(".dylib"), "compiled.mach-o.dylib"},
|
| + {FILE_PATH_LITERAL(".framework"), "wrapper.framework"},
|
| + {FILE_PATH_LITERAL(".h"), "sourcecode.c.h"},
|
| + {FILE_PATH_LITERAL(".hxx"), "sourcecode.cpp.h"},
|
| + {FILE_PATH_LITERAL(".icns"), "image.icns"},
|
| + {FILE_PATH_LITERAL(".java"), "sourcecode.java"},
|
| + {FILE_PATH_LITERAL(".js"), "sourcecode.javascript"},
|
| + {FILE_PATH_LITERAL(".kext"), "wrapper.kext"},
|
| + {FILE_PATH_LITERAL(".m"), "sourcecode.c.objc"},
|
| + {FILE_PATH_LITERAL(".mm"), "sourcecode.cpp.objcpp"},
|
| + {FILE_PATH_LITERAL(".nib"), "wrapper.nib"},
|
| + {FILE_PATH_LITERAL(".o"), "compiled.mach-o.objfile"},
|
| + {FILE_PATH_LITERAL(".pdf"), "image.pdf"},
|
| + {FILE_PATH_LITERAL(".pl"), "text.script.perl"},
|
| + {FILE_PATH_LITERAL(".plist"), "text.plist.xml"},
|
| + {FILE_PATH_LITERAL(".pm"), "text.script.perl"},
|
| + {FILE_PATH_LITERAL(".png"), "image.png"},
|
| + {FILE_PATH_LITERAL(".py"), "text.script.python"},
|
| + {FILE_PATH_LITERAL(".r"), "sourcecode.rez"},
|
| + {FILE_PATH_LITERAL(".rez"), "sourcecode.rez"},
|
| + {FILE_PATH_LITERAL(".s"), "sourcecode.asm"},
|
| + {FILE_PATH_LITERAL(".storyboard"), "file.storyboard"},
|
| + {FILE_PATH_LITERAL(".strings"), "text.plist.strings"},
|
| + {FILE_PATH_LITERAL(".swift"), "sourcecode.swift"},
|
| + {FILE_PATH_LITERAL(".ttf"), "file"},
|
| + {FILE_PATH_LITERAL(".xcassets"), "folder.assetcatalog"},
|
| + {FILE_PATH_LITERAL(".xcconfig"), "text.xcconfig"},
|
| + {FILE_PATH_LITERAL(".xcdatamodel"), "wrapper.xcdatamodel"},
|
| + {FILE_PATH_LITERAL(".xcdatamodeld"), "wrapper.xcdatamodeld"},
|
| + {FILE_PATH_LITERAL(".xib"), "file.xib"},
|
| + {FILE_PATH_LITERAL(".y"), "sourcecode.yacc"},
|
| + };
|
| +
|
| + const auto& iter = extension_map.find(ext);
|
| + if (iter != extension_map.end()) {
|
| + return iter->second;
|
| + }
|
| +
|
| + return "text";
|
| +}
|
| +
|
| +bool HasExplicitFileType(const base::FilePath::StringType& ext) {
|
| + return ext == FILE_PATH_LITERAL(".dart");
|
| +}
|
| +
|
| +bool IsSourceFileForIndexing(const base::FilePath::StringType& ext) {
|
| + return ext == FILE_PATH_LITERAL(".c") || ext == FILE_PATH_LITERAL(".cc") ||
|
| + ext == FILE_PATH_LITERAL(".cpp") || ext == FILE_PATH_LITERAL(".cxx") ||
|
| + ext == FILE_PATH_LITERAL(".m") || ext == FILE_PATH_LITERAL(".mm");
|
| +}
|
| +
|
| +void PrintValue(std::ostream& out, IndentRules rules, unsigned value) {
|
| + out << value;
|
| +}
|
| +
|
| +void PrintValue(std::ostream& out, IndentRules rules, const char* value) {
|
| + out << EncodeString(value);
|
| +}
|
| +
|
| +void PrintValue(std::ostream& out,
|
| + IndentRules rules,
|
| + const std::string& value) {
|
| + out << EncodeString(value);
|
| +}
|
| +
|
| +void PrintValue(std::ostream& out, IndentRules rules, const PBXObject* value) {
|
| + out << value->Reference();
|
| +}
|
| +
|
| +template <typename ObjectClass>
|
| +void PrintValue(std::ostream& out,
|
| + IndentRules rules,
|
| + const std::unique_ptr<ObjectClass>& value) {
|
| + PrintValue(out, rules, value.get());
|
| +}
|
| +
|
| +template <typename ValueType>
|
| +void PrintValue(std::ostream& out,
|
| + IndentRules rules,
|
| + const std::vector<ValueType>& values) {
|
| + IndentRules sub_rule{rules.one_line, rules.level + 1};
|
| + out << "(" << (rules.one_line ? " " : "\n");
|
| + for (const auto& value : values) {
|
| + if (!sub_rule.one_line)
|
| + out << std::string(sub_rule.level, '\t');
|
| +
|
| + PrintValue(out, sub_rule, value);
|
| + out << "," << (rules.one_line ? " " : "\n");
|
| + }
|
| +
|
| + if (!rules.one_line && rules.level)
|
| + out << std::string(rules.level, '\t');
|
| + out << ")";
|
| +}
|
| +
|
| +template <typename ValueType>
|
| +void PrintValue(std::ostream& out,
|
| + IndentRules rules,
|
| + const std::map<std::string, ValueType>& values) {
|
| + IndentRules sub_rule{rules.one_line, rules.level + 1};
|
| + out << "{" << (rules.one_line ? " " : "\n");
|
| + for (const auto& pair : values) {
|
| + if (!sub_rule.one_line)
|
| + out << std::string(sub_rule.level, '\t');
|
| +
|
| + out << pair.first << " = ";
|
| + PrintValue(out, sub_rule, pair.second);
|
| + out << ";" << (rules.one_line ? " " : "\n");
|
| + }
|
| +
|
| + if (!rules.one_line && rules.level)
|
| + out << std::string(rules.level, '\t');
|
| + out << "}";
|
| +}
|
| +
|
| +template <typename ValueType>
|
| +void PrintProperty(std::ostream& out,
|
| + IndentRules rules,
|
| + const char* name,
|
| + ValueType&& value) {
|
| + if (!rules.one_line && rules.level)
|
| + out << std::string(rules.level, '\t');
|
| +
|
| + out << name << " = ";
|
| + PrintValue(out, rules, std::forward<ValueType>(value));
|
| + out << ";" << (rules.one_line ? " " : "\n");
|
| +}
|
| +} // namespace
|
| +
|
| +// PBXObjectClass -------------------------------------------------------------
|
| +
|
| +const char* ToString(PBXObjectClass cls) {
|
| + switch (cls) {
|
| + case PBXAggregateTargetClass:
|
| + return "PBXAggregateTarget";
|
| + case PBXBuildFileClass:
|
| + return "PBXBuildFile";
|
| + case PBXFileReferenceClass:
|
| + return "PBXFileReference";
|
| + case PBXFrameworksBuildPhaseClass:
|
| + return "PBXFrameworksBuildPhase";
|
| + case PBXGroupClass:
|
| + return "PBXGroup";
|
| + case PBXNativeTargetClass:
|
| + return "PBXNativeTarget";
|
| + case PBXProjectClass:
|
| + return "PBXProject";
|
| + case PBXShellScriptBuildPhaseClass:
|
| + return "PBXShellScriptBuildPhase";
|
| + case PBXSourcesBuildPhaseClass:
|
| + return "PBXSourcesBuildPhase";
|
| + case XCBuildConfigurationClass:
|
| + return "XCBuildConfiguration";
|
| + case XCConfigurationListClass:
|
| + return "XCConfigurationList";
|
| + }
|
| + NOTREACHED();
|
| + return nullptr;
|
| +}
|
| +
|
| +// PBXObjectVisitor -----------------------------------------------------------
|
| +
|
| +PBXObjectVisitor::PBXObjectVisitor() {}
|
| +
|
| +PBXObjectVisitor::~PBXObjectVisitor() {}
|
| +
|
| +// PBXObject ------------------------------------------------------------------
|
| +
|
| +PBXObject::PBXObject() {}
|
| +
|
| +PBXObject::~PBXObject() {}
|
| +
|
| +void PBXObject::SetId(const std::string& id) {
|
| + DCHECK(id_.empty());
|
| + DCHECK(!id.empty());
|
| + id_.assign(id);
|
| +}
|
| +
|
| +std::string PBXObject::Reference() const {
|
| + std::string comment = Comment();
|
| + if (comment.empty())
|
| + return id_;
|
| +
|
| + return id_ + " /* " + comment + " */";
|
| +}
|
| +
|
| +std::string PBXObject::Comment() const {
|
| + return Name();
|
| +}
|
| +
|
| +void PBXObject::Visit(PBXObjectVisitor& visitor) {
|
| + visitor.Visit(this);
|
| +}
|
| +
|
| +// PBXBuildPhase --------------------------------------------------------------
|
| +
|
| +PBXBuildPhase::PBXBuildPhase() {}
|
| +
|
| +PBXBuildPhase::~PBXBuildPhase() {}
|
| +
|
| +// PBXTarget ------------------------------------------------------------------
|
| +
|
| +PBXTarget::PBXTarget(const std::string& name,
|
| + const std::string& shell_script,
|
| + const std::string& config_name,
|
| + const PBXAttributes& attributes)
|
| + : configurations_(new XCConfigurationList(config_name, attributes, this)),
|
| + name_(name) {
|
| + if (!shell_script.empty()) {
|
| + build_phases_.push_back(
|
| + base::WrapUnique(new PBXShellScriptBuildPhase(name, shell_script)));
|
| + }
|
| +}
|
| +
|
| +PBXTarget::~PBXTarget() {}
|
| +
|
| +std::string PBXTarget::Name() const {
|
| + return name_;
|
| +}
|
| +
|
| +void PBXTarget::Visit(PBXObjectVisitor& visitor) {
|
| + PBXObject::Visit(visitor);
|
| + configurations_->Visit(visitor);
|
| + for (const auto& build_phase : build_phases_) {
|
| + build_phase->Visit(visitor);
|
| + }
|
| +}
|
| +
|
| +// PBXAggregateTarget ---------------------------------------------------------
|
| +
|
| +PBXAggregateTarget::PBXAggregateTarget(const std::string& name,
|
| + const std::string& shell_script,
|
| + const std::string& config_name,
|
| + const PBXAttributes& attributes)
|
| + : PBXTarget(name, shell_script, config_name, attributes) {}
|
| +
|
| +PBXAggregateTarget::~PBXAggregateTarget() {}
|
| +
|
| +PBXObjectClass PBXAggregateTarget::Class() const {
|
| + return PBXAggregateTargetClass;
|
| +}
|
| +
|
| +void PBXAggregateTarget::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "buildConfigurationList", configurations_);
|
| + PrintProperty(out, rules, "buildPhases", build_phases_);
|
| + PrintProperty(out, rules, "dependencies", EmptyPBXObjectVector());
|
| + PrintProperty(out, rules, "name", name_);
|
| + PrintProperty(out, rules, "productName", name_);
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// PBXBuildFile ---------------------------------------------------------------
|
| +
|
| +PBXBuildFile::PBXBuildFile(const PBXFileReference* file_reference,
|
| + const PBXSourcesBuildPhase* build_phase)
|
| + : file_reference_(file_reference), build_phase_(build_phase) {
|
| + DCHECK(file_reference_);
|
| + DCHECK(build_phase_);
|
| +}
|
| +
|
| +PBXBuildFile::~PBXBuildFile() {}
|
| +
|
| +PBXObjectClass PBXBuildFile::Class() const {
|
| + return PBXBuildFileClass;
|
| +}
|
| +
|
| +std::string PBXBuildFile::Name() const {
|
| + return file_reference_->Name() + " in " + build_phase_->Name();
|
| +}
|
| +
|
| +void PBXBuildFile::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {true, 0};
|
| + out << indent_str << Reference() << " = {";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "fileRef", file_reference_);
|
| + out << "};\n";
|
| +}
|
| +
|
| +// PBXFileReference -----------------------------------------------------------
|
| +
|
| +PBXFileReference::PBXFileReference(const std::string& name,
|
| + const std::string& path,
|
| + const std::string& type)
|
| + : name_(name), path_(path), type_(type) {}
|
| +
|
| +PBXFileReference::~PBXFileReference() {}
|
| +
|
| +PBXObjectClass PBXFileReference::Class() const {
|
| + return PBXFileReferenceClass;
|
| +}
|
| +
|
| +std::string PBXFileReference::Name() const {
|
| + return path_;
|
| +}
|
| +
|
| +void PBXFileReference::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {true, 0};
|
| + out << indent_str << Reference() << " = {";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| +
|
| + if (!type_.empty()) {
|
| + PrintProperty(out, rules, "explicitFileType", type_);
|
| + PrintProperty(out, rules, "includeInIndex", 0u);
|
| + } else {
|
| + const base::FilePath::StringType ext =
|
| + base::FilePath::FromUTF8Unsafe(path_).Extension();
|
| +
|
| + if (HasExplicitFileType(ext))
|
| + PrintProperty(out, rules, "explicitFileType", GetSourceType(ext));
|
| + else
|
| + PrintProperty(out, rules, "lastKnownFileType", GetSourceType(ext));
|
| + }
|
| +
|
| + if (name_ != path_ && !name_.empty())
|
| + PrintProperty(out, rules, "name", name_);
|
| +
|
| + PrintProperty(out, rules, "path", path_);
|
| + PrintProperty(out, rules, "sourceTree",
|
| + type_.empty() ? "<group>" : "BUILT_PRODUCTS_DIR");
|
| + out << "};\n";
|
| +}
|
| +
|
| +// PBXFrameworksBuildPhase ----------------------------------------------------
|
| +
|
| +PBXFrameworksBuildPhase::PBXFrameworksBuildPhase() {}
|
| +
|
| +PBXFrameworksBuildPhase::~PBXFrameworksBuildPhase() {}
|
| +
|
| +PBXObjectClass PBXFrameworksBuildPhase::Class() const {
|
| + return PBXFrameworksBuildPhaseClass;
|
| +}
|
| +
|
| +std::string PBXFrameworksBuildPhase::Name() const {
|
| + return "Frameworks";
|
| +}
|
| +
|
| +void PBXFrameworksBuildPhase::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "buildActionMask", 0x7fffffffu);
|
| + PrintProperty(out, rules, "files", EmptyPBXObjectVector());
|
| + PrintProperty(out, rules, "runOnlyForDeploymentPostprocessing", 0u);
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// PBXGroup -------------------------------------------------------------------
|
| +
|
| +PBXGroup::PBXGroup(const std::string& path, const std::string& name)
|
| + : name_(name), path_(path) {}
|
| +
|
| +PBXGroup::~PBXGroup() {}
|
| +
|
| +PBXObject* PBXGroup::AddChild(std::unique_ptr<PBXObject> child) {
|
| + DCHECK(child);
|
| + children_.push_back(std::move(child));
|
| + return children_.back().get();
|
| +}
|
| +
|
| +PBXFileReference* PBXGroup::AddSourceFile(const std::string& source_path) {
|
| + DCHECK(!source_path.empty());
|
| + std::string::size_type sep = source_path.find("/");
|
| + if (sep == std::string::npos) {
|
| + children_.push_back(base::WrapUnique(
|
| + new PBXFileReference(std::string(), source_path, std::string())));
|
| + return static_cast<PBXFileReference*>(children_.back().get());
|
| + }
|
| +
|
| + PBXGroup* group = nullptr;
|
| + base::StringPiece component(source_path.data(), sep);
|
| + for (const auto& child : children_) {
|
| + if (child->Class() != PBXGroupClass)
|
| + continue;
|
| +
|
| + PBXGroup* child_as_group = static_cast<PBXGroup*>(child.get());
|
| + if (child_as_group->path_ == component) {
|
| + group = child_as_group;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!group) {
|
| + children_.push_back(base::WrapUnique(new PBXGroup(component.as_string())));
|
| + group = static_cast<PBXGroup*>(children_.back().get());
|
| + }
|
| +
|
| + DCHECK(group);
|
| + DCHECK(group->path_ == component);
|
| + return group->AddSourceFile(source_path.substr(sep + 1));
|
| +}
|
| +
|
| +PBXObjectClass PBXGroup::Class() const {
|
| + return PBXGroupClass;
|
| +}
|
| +
|
| +std::string PBXGroup::Name() const {
|
| + if (!name_.empty())
|
| + return name_;
|
| + if (!path_.empty())
|
| + return path_;
|
| + return std::string();
|
| +}
|
| +
|
| +void PBXGroup::Visit(PBXObjectVisitor& visitor) {
|
| + PBXObject::Visit(visitor);
|
| + for (const auto& child : children_) {
|
| + child->Visit(visitor);
|
| + }
|
| +}
|
| +
|
| +void PBXGroup::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "children", children_);
|
| + if (!name_.empty())
|
| + PrintProperty(out, rules, "name", name_);
|
| + if (!path_.empty())
|
| + PrintProperty(out, rules, "path", path_);
|
| + PrintProperty(out, rules, "sourceTree", "<group>");
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// PBXNativeTarget ------------------------------------------------------------
|
| +
|
| +PBXNativeTarget::PBXNativeTarget(const std::string& name,
|
| + const std::string& shell_script,
|
| + const std::string& config_name,
|
| + const PBXAttributes& attributes,
|
| + const std::string& product_type,
|
| + const PBXFileReference* product_reference)
|
| + : PBXTarget(name, shell_script, config_name, attributes),
|
| + product_reference_(product_reference),
|
| + product_type_(product_type) {
|
| + DCHECK(product_reference_);
|
| + build_phases_.push_back(base::WrapUnique(new PBXSourcesBuildPhase));
|
| + source_build_phase_ =
|
| + static_cast<PBXSourcesBuildPhase*>(build_phases_.back().get());
|
| +
|
| + build_phases_.push_back(base::WrapUnique(new PBXFrameworksBuildPhase));
|
| +}
|
| +
|
| +PBXNativeTarget::~PBXNativeTarget() {}
|
| +
|
| +void PBXNativeTarget::AddFileForIndexing(
|
| + const PBXFileReference* file_reference) {
|
| + DCHECK(file_reference);
|
| + source_build_phase_->AddBuildFile(
|
| + base::WrapUnique(new PBXBuildFile(file_reference, source_build_phase_)));
|
| +}
|
| +
|
| +PBXObjectClass PBXNativeTarget::Class() const {
|
| + return PBXNativeTargetClass;
|
| +}
|
| +
|
| +void PBXNativeTarget::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "buildConfigurationList", configurations_);
|
| + PrintProperty(out, rules, "buildPhases", build_phases_);
|
| + PrintProperty(out, rules, "buildRules", EmptyPBXObjectVector());
|
| + PrintProperty(out, rules, "dependencies", EmptyPBXObjectVector());
|
| + PrintProperty(out, rules, "name", name_);
|
| + PrintProperty(out, rules, "productName", name_);
|
| + PrintProperty(out, rules, "productReference", product_reference_);
|
| + PrintProperty(out, rules, "productType", product_type_);
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// PBXProject -----------------------------------------------------------------
|
| +
|
| +PBXProject::PBXProject(const std::string& name,
|
| + const std::string& config_name,
|
| + const std::string& source_path,
|
| + const PBXAttributes& attributes)
|
| + : name_(name), config_name_(config_name), target_for_indexing_(nullptr) {
|
| + attributes_["BuildIndependentTargetsInParallel"] = "YES";
|
| +
|
| + main_group_.reset(new PBXGroup);
|
| + sources_ = static_cast<PBXGroup*>(main_group_->AddChild(
|
| + base::WrapUnique(new PBXGroup(source_path, "Source"))));
|
| + products_ = static_cast<PBXGroup*>(main_group_->AddChild(
|
| + base::WrapUnique(new PBXGroup(std::string(), "Product"))));
|
| + main_group_->AddChild(base::WrapUnique(new PBXGroup(std::string(), "Build")));
|
| +
|
| + configurations_.reset(new XCConfigurationList(config_name, attributes, this));
|
| +}
|
| +
|
| +PBXProject::~PBXProject() {}
|
| +
|
| +void PBXProject::AddSourceFile(const std::string& source_path) {
|
| + PBXFileReference* file_reference = sources_->AddSourceFile(source_path);
|
| + const base::FilePath::StringType ext =
|
| + base::FilePath::FromUTF8Unsafe(source_path).Extension();
|
| + if (!IsSourceFileForIndexing(ext))
|
| + return;
|
| +
|
| + if (!target_for_indexing_) {
|
| + PBXAttributes attributes;
|
| + attributes["EXECUTABLE_PREFIX"] = "";
|
| + attributes["HEADER_SEARCH_PATHS"] = sources_->path();
|
| + attributes["PRODUCT_NAME"] = name_;
|
| +
|
| + PBXFileReference* product_reference = static_cast<PBXFileReference*>(
|
| + products_->AddChild(base::WrapUnique(new PBXFileReference(
|
| + std::string(), name_, "compiled.mach-o.executable"))));
|
| +
|
| + const char product_type[] = "com.apple.product-type.tool";
|
| + targets_.push_back(base::WrapUnique(
|
| + new PBXNativeTarget(name_, std::string(), config_name_, attributes,
|
| + product_type, product_reference)));
|
| + target_for_indexing_ = static_cast<PBXNativeTarget*>(targets_.back().get());
|
| + }
|
| +
|
| + DCHECK(target_for_indexing_);
|
| + target_for_indexing_->AddFileForIndexing(file_reference);
|
| +}
|
| +
|
| +void PBXProject::AddAggregateTarget(const std::string& name,
|
| + const std::string& shell_script) {
|
| + PBXAttributes attributes;
|
| + attributes["CODE_SIGNING_REQUIRED"] = "NO";
|
| + attributes["CONFIGURATION_BUILD_DIR"] = ".";
|
| + attributes["PRODUCT_NAME"] = name;
|
| +
|
| + targets_.push_back(base::WrapUnique(
|
| + new PBXAggregateTarget(name, shell_script, config_name_, attributes)));
|
| +}
|
| +
|
| +void PBXProject::AddNativeTarget(const std::string& name,
|
| + const std::string& type,
|
| + const std::string& output_name,
|
| + const std::string& output_type,
|
| + const std::string& shell_script) {
|
| + const base::FilePath::StringType ext =
|
| + base::FilePath::FromUTF8Unsafe(output_name).Extension();
|
| +
|
| + PBXFileReference* product = static_cast<PBXFileReference*>(
|
| + products_->AddChild(base::WrapUnique(new PBXFileReference(
|
| + name, output_name, type.empty() ? GetSourceType(ext) : type))));
|
| +
|
| + PBXAttributes attributes;
|
| + attributes["CODE_SIGNING_REQUIRED"] = "NO";
|
| + attributes["CONFIGURATION_BUILD_DIR"] = ".";
|
| + attributes["PRODUCT_NAME"] = name;
|
| +
|
| + targets_.push_back(base::WrapUnique(new PBXNativeTarget(
|
| + name, shell_script, config_name_, attributes, output_type, product)));
|
| +}
|
| +
|
| +void PBXProject::SetProjectDirPath(const std::string& project_dir_path) {
|
| + DCHECK(!project_dir_path.empty());
|
| + project_dir_path_.assign(project_dir_path);
|
| +}
|
| +
|
| +void PBXProject::SetProjectRoot(const std::string& project_root) {
|
| + DCHECK(!project_root.empty());
|
| + project_root_.assign(project_root);
|
| +}
|
| +
|
| +void PBXProject::AddTarget(std::unique_ptr<PBXTarget> target) {
|
| + DCHECK(target);
|
| + targets_.push_back(std::move(target));
|
| +}
|
| +
|
| +PBXObjectClass PBXProject::Class() const {
|
| + return PBXProjectClass;
|
| +}
|
| +
|
| +std::string PBXProject::Name() const {
|
| + return name_;
|
| +}
|
| +
|
| +std::string PBXProject::Comment() const {
|
| + return "Project object";
|
| +}
|
| +
|
| +void PBXProject::Visit(PBXObjectVisitor& visitor) {
|
| + PBXObject::Visit(visitor);
|
| + configurations_->Visit(visitor);
|
| + main_group_->Visit(visitor);
|
| + for (const auto& target : targets_) {
|
| + target->Visit(visitor);
|
| + }
|
| +}
|
| +
|
| +void PBXProject::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "attributes", attributes_);
|
| + PrintProperty(out, rules, "buildConfigurationList", configurations_);
|
| + PrintProperty(out, rules, "compatibilityVersion", "Xcode 3.2");
|
| + PrintProperty(out, rules, "developmentRegion", "English");
|
| + PrintProperty(out, rules, "hasScannedForEncodings", 1u);
|
| + PrintProperty(out, rules, "knownRegions", std::vector<std::string>({"en"}));
|
| + PrintProperty(out, rules, "mainGroup", main_group_);
|
| + PrintProperty(out, rules, "projectDirPath", project_dir_path_);
|
| + PrintProperty(out, rules, "projectRoot", project_root_);
|
| + PrintProperty(out, rules, "targets", targets_);
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// PBXShellScriptBuildPhase ---------------------------------------------------
|
| +
|
| +PBXShellScriptBuildPhase::PBXShellScriptBuildPhase(
|
| + const std::string& name,
|
| + const std::string& shell_script)
|
| + : name_("Action \"Compile and copy " + name + " via ninja\""),
|
| + shell_script_(shell_script) {}
|
| +
|
| +PBXShellScriptBuildPhase::~PBXShellScriptBuildPhase() {}
|
| +
|
| +PBXObjectClass PBXShellScriptBuildPhase::Class() const {
|
| + return PBXShellScriptBuildPhaseClass;
|
| +}
|
| +
|
| +std::string PBXShellScriptBuildPhase::Name() const {
|
| + return name_;
|
| +}
|
| +
|
| +void PBXShellScriptBuildPhase::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "buildActionMask", 0x7fffffffu);
|
| + PrintProperty(out, rules, "files", EmptyPBXObjectVector());
|
| + PrintProperty(out, rules, "inputPaths", EmptyPBXObjectVector());
|
| + PrintProperty(out, rules, "name", name_);
|
| + PrintProperty(out, rules, "outputPaths", EmptyPBXObjectVector());
|
| + PrintProperty(out, rules, "runOnlyForDeploymentPostprocessing", 0u);
|
| + PrintProperty(out, rules, "shellPath", "/bin/sh");
|
| + PrintProperty(out, rules, "shellScript", shell_script_);
|
| + PrintProperty(out, rules, "showEnvVarsInLog", 0u);
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// PBXSourcesBuildPhase -------------------------------------------------------
|
| +
|
| +PBXSourcesBuildPhase::PBXSourcesBuildPhase() {}
|
| +
|
| +PBXSourcesBuildPhase::~PBXSourcesBuildPhase() {}
|
| +
|
| +void PBXSourcesBuildPhase::AddBuildFile(
|
| + std::unique_ptr<PBXBuildFile> build_file) {
|
| + files_.push_back(std::move(build_file));
|
| +}
|
| +
|
| +PBXObjectClass PBXSourcesBuildPhase::Class() const {
|
| + return PBXSourcesBuildPhaseClass;
|
| +}
|
| +
|
| +std::string PBXSourcesBuildPhase::Name() const {
|
| + return "Sources";
|
| +}
|
| +
|
| +void PBXSourcesBuildPhase::Visit(PBXObjectVisitor& visitor) {
|
| + PBXBuildPhase::Visit(visitor);
|
| + for (const auto& file : files_) {
|
| + file->Visit(visitor);
|
| + }
|
| +}
|
| +
|
| +void PBXSourcesBuildPhase::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "buildActionMask", 0x7fffffffu);
|
| + PrintProperty(out, rules, "files", files_);
|
| + PrintProperty(out, rules, "runOnlyForDeploymentPostprocessing", 0u);
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// XCBuildConfiguration -------------------------------------------------------
|
| +
|
| +XCBuildConfiguration::XCBuildConfiguration(const std::string& name,
|
| + const PBXAttributes& attributes)
|
| + : attributes_(attributes), name_(name) {}
|
| +
|
| +XCBuildConfiguration::~XCBuildConfiguration() {}
|
| +
|
| +PBXObjectClass XCBuildConfiguration::Class() const {
|
| + return XCBuildConfigurationClass;
|
| +}
|
| +
|
| +std::string XCBuildConfiguration::Name() const {
|
| + return name_;
|
| +}
|
| +
|
| +void XCBuildConfiguration::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "buildSettings", attributes_);
|
| + PrintProperty(out, rules, "name", name_);
|
| + out << indent_str << "};\n";
|
| +}
|
| +
|
| +// XCConfigurationList --------------------------------------------------------
|
| +
|
| +XCConfigurationList::XCConfigurationList(const std::string& name,
|
| + const PBXAttributes& attributes,
|
| + const PBXObject* owner_reference)
|
| + : owner_reference_(owner_reference) {
|
| + DCHECK(owner_reference_);
|
| + configurations_.push_back(
|
| + base::WrapUnique(new XCBuildConfiguration(name, attributes)));
|
| +}
|
| +
|
| +XCConfigurationList::~XCConfigurationList() {}
|
| +
|
| +PBXObjectClass XCConfigurationList::Class() const {
|
| + return XCConfigurationListClass;
|
| +}
|
| +
|
| +std::string XCConfigurationList::Name() const {
|
| + std::stringstream buffer;
|
| + buffer << "Build configuration list for "
|
| + << ToString(owner_reference_->Class()) << " \""
|
| + << owner_reference_->Name() << "\"";
|
| + return buffer.str();
|
| +}
|
| +
|
| +void XCConfigurationList::Visit(PBXObjectVisitor& visitor) {
|
| + PBXObject::Visit(visitor);
|
| + for (const auto& configuration : configurations_) {
|
| + configuration->Visit(visitor);
|
| + }
|
| +}
|
| +
|
| +void XCConfigurationList::Print(std::ostream& out, unsigned indent) const {
|
| + const std::string indent_str(indent, '\t');
|
| + const IndentRules rules = {false, indent + 1};
|
| + out << indent_str << Reference() << " = {\n";
|
| + PrintProperty(out, rules, "isa", ToString(Class()));
|
| + PrintProperty(out, rules, "buildConfigurations", configurations_);
|
| + PrintProperty(out, rules, "defaultConfigurationIsVisible", 1u);
|
| + PrintProperty(out, rules, "defaultConfigurationName",
|
| + configurations_[0]->Name());
|
| + out << indent_str << "};\n";
|
| +}
|
|
|