mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
991 lines
32 KiB
C++
991 lines
32 KiB
C++
// 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 <memory>
|
|
#include <sstream>
|
|
#include <utility>
|
|
|
|
#include "base/logging.h"
|
|
#include "base/macros.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "tools/gn/filesystem_utils.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();
|
|
}
|
|
|
|
struct SourceTypeForExt {
|
|
const char* ext;
|
|
const char* source_type;
|
|
};
|
|
|
|
const SourceTypeForExt kSourceTypeForExt[] = {
|
|
{"a", "archive.ar"},
|
|
{"app", "wrapper.application"},
|
|
{"appex", "wrapper.app-extension"},
|
|
{"bdic", "file"},
|
|
{"bundle", "wrapper.cfbundle"},
|
|
{"c", "sourcecode.c.c"},
|
|
{"cc", "sourcecode.cpp.cpp"},
|
|
{"cpp", "sourcecode.cpp.cpp"},
|
|
{"css", "text.css"},
|
|
{"cxx", "sourcecode.cpp.cpp"},
|
|
{"dart", "sourcecode"},
|
|
{"dylib", "compiled.mach-o.dylib"},
|
|
{"framework", "wrapper.framework"},
|
|
{"h", "sourcecode.c.h"},
|
|
{"hxx", "sourcecode.cpp.h"},
|
|
{"icns", "image.icns"},
|
|
{"java", "sourcecode.java"},
|
|
{"js", "sourcecode.javascript"},
|
|
{"kext", "wrapper.kext"},
|
|
{"m", "sourcecode.c.objc"},
|
|
{"mm", "sourcecode.cpp.objcpp"},
|
|
{"nib", "wrapper.nib"},
|
|
{"o", "compiled.mach-o.objfile"},
|
|
{"pdf", "image.pdf"},
|
|
{"pl", "text.script.perl"},
|
|
{"plist", "text.plist.xml"},
|
|
{"pm", "text.script.perl"},
|
|
{"png", "image.png"},
|
|
{"py", "text.script.python"},
|
|
{"r", "sourcecode.rez"},
|
|
{"rez", "sourcecode.rez"},
|
|
{"s", "sourcecode.asm"},
|
|
{"storyboard", "file.storyboard"},
|
|
{"strings", "text.plist.strings"},
|
|
{"swift", "sourcecode.swift"},
|
|
{"ttf", "file"},
|
|
{"xcassets", "folder.assetcatalog"},
|
|
{"xcconfig", "text.xcconfig"},
|
|
{"xcdatamodel", "wrapper.xcdatamodel"},
|
|
{"xcdatamodeld", "wrapper.xcdatamodeld"},
|
|
{"xib", "file.xib"},
|
|
{"y", "sourcecode.yacc"},
|
|
};
|
|
|
|
const char* GetSourceType(const base::StringPiece& ext) {
|
|
for (size_t i = 0; i < arraysize(kSourceTypeForExt); ++i) {
|
|
if (kSourceTypeForExt[i].ext == ext)
|
|
return kSourceTypeForExt[i].source_type;
|
|
}
|
|
|
|
return "text";
|
|
}
|
|
|
|
bool HasExplicitFileType(const base::StringPiece& ext) {
|
|
return ext == "dart";
|
|
}
|
|
|
|
bool IsSourceFileForIndexing(const base::StringPiece& ext) {
|
|
return ext == "c" || ext == "cc" || ext == "cpp" || ext == "cxx" ||
|
|
ext == "m" || ext == "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 PBXContainerItemProxyClass:
|
|
return "PBXContainerItemProxy";
|
|
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 PBXTargetDependencyClass:
|
|
return "PBXTargetDependency";
|
|
case XCBuildConfigurationClass:
|
|
return "XCBuildConfiguration";
|
|
case XCConfigurationListClass:
|
|
return "XCConfigurationList";
|
|
}
|
|
NOTREACHED();
|
|
return nullptr;
|
|
}
|
|
|
|
// PBXObjectVisitor -----------------------------------------------------------
|
|
|
|
PBXObjectVisitor::PBXObjectVisitor() = default;
|
|
|
|
PBXObjectVisitor::~PBXObjectVisitor() = default;
|
|
|
|
// PBXObject ------------------------------------------------------------------
|
|
|
|
PBXObject::PBXObject() = default;
|
|
|
|
PBXObject::~PBXObject() = default;
|
|
|
|
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() = default;
|
|
|
|
PBXBuildPhase::~PBXBuildPhase() = default;
|
|
|
|
// 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(
|
|
std::make_unique<PBXShellScriptBuildPhase>(name, shell_script));
|
|
}
|
|
}
|
|
|
|
PBXTarget::~PBXTarget() = default;
|
|
|
|
void PBXTarget::AddDependency(std::unique_ptr<PBXTargetDependency> dependency) {
|
|
DCHECK(dependency);
|
|
dependencies_.push_back(std::move(dependency));
|
|
}
|
|
|
|
std::string PBXTarget::Name() const {
|
|
return name_;
|
|
}
|
|
|
|
void PBXTarget::Visit(PBXObjectVisitor& visitor) {
|
|
PBXObject::Visit(visitor);
|
|
configurations_->Visit(visitor);
|
|
for (const auto& dependency : dependencies_)
|
|
dependency->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() = default;
|
|
|
|
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,
|
|
const CompilerFlags compiler_flag)
|
|
: file_reference_(file_reference),
|
|
build_phase_(build_phase),
|
|
compiler_flag_(compiler_flag) {
|
|
DCHECK(file_reference_);
|
|
DCHECK(build_phase_);
|
|
}
|
|
|
|
PBXBuildFile::~PBXBuildFile() = default;
|
|
|
|
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_);
|
|
if (compiler_flag_ == CompilerFlags::HELP) {
|
|
std::map<std::string, std::string> settings = {
|
|
{"COMPILER_FLAGS", "--help"},
|
|
};
|
|
PrintProperty(out, rules, "settings", settings);
|
|
}
|
|
out << "};\n";
|
|
}
|
|
|
|
// PBXContainerItemProxy ------------------------------------------------------
|
|
PBXContainerItemProxy::PBXContainerItemProxy(const PBXProject* project,
|
|
const PBXTarget* target)
|
|
: project_(project), target_(target) {}
|
|
|
|
PBXContainerItemProxy::~PBXContainerItemProxy() = default;
|
|
|
|
PBXObjectClass PBXContainerItemProxy::Class() const {
|
|
return PBXContainerItemProxyClass;
|
|
}
|
|
|
|
void PBXContainerItemProxy::Visit(PBXObjectVisitor& visitor) {
|
|
PBXObject::Visit(visitor);
|
|
}
|
|
|
|
std::string PBXContainerItemProxy::Name() const {
|
|
return "PBXContainerItemProxy";
|
|
}
|
|
|
|
void PBXContainerItemProxy::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, "containerPortal", project_);
|
|
PrintProperty(out, rules, "proxyType", 1u);
|
|
PrintProperty(out, rules, "remoteGlobalIDString", target_);
|
|
PrintProperty(out, rules, "remoteInfo", target_->Name());
|
|
out << indent_str << "};\n";
|
|
}
|
|
|
|
// PBXFileReference -----------------------------------------------------------
|
|
|
|
PBXFileReference::PBXFileReference(const std::string& name,
|
|
const std::string& path,
|
|
const std::string& type)
|
|
: name_(name), path_(path), type_(type) {}
|
|
|
|
PBXFileReference::~PBXFileReference() = default;
|
|
|
|
PBXObjectClass PBXFileReference::Class() const {
|
|
return PBXFileReferenceClass;
|
|
}
|
|
|
|
std::string PBXFileReference::Name() const {
|
|
return name_;
|
|
}
|
|
|
|
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 {
|
|
base::StringPiece ext = FindExtension(&name_);
|
|
if (HasExplicitFileType(ext))
|
|
PrintProperty(out, rules, "explicitFileType", GetSourceType(ext));
|
|
else
|
|
PrintProperty(out, rules, "lastKnownFileType", GetSourceType(ext));
|
|
}
|
|
|
|
if (!name_.empty())
|
|
PrintProperty(out, rules, "name", name_);
|
|
|
|
DCHECK(!path_.empty());
|
|
PrintProperty(out, rules, "path", path_);
|
|
PrintProperty(out, rules, "sourceTree",
|
|
type_.empty() ? "<group>" : "BUILT_PRODUCTS_DIR");
|
|
out << "};\n";
|
|
}
|
|
|
|
// PBXFrameworksBuildPhase ----------------------------------------------------
|
|
|
|
PBXFrameworksBuildPhase::PBXFrameworksBuildPhase() = default;
|
|
|
|
PBXFrameworksBuildPhase::~PBXFrameworksBuildPhase() = default;
|
|
|
|
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() = default;
|
|
|
|
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& navigator_path,
|
|
const std::string& source_path) {
|
|
DCHECK(!navigator_path.empty());
|
|
DCHECK(!source_path.empty());
|
|
std::string::size_type sep = navigator_path.find("/");
|
|
if (sep == std::string::npos) {
|
|
// Prevent same file reference being created and added multiple times.
|
|
for (const auto& child : children_) {
|
|
if (child->Class() != PBXFileReferenceClass)
|
|
continue;
|
|
|
|
PBXFileReference* child_as_file_reference =
|
|
static_cast<PBXFileReference*>(child.get());
|
|
if (child_as_file_reference->Name() == navigator_path &&
|
|
child_as_file_reference->path() == source_path) {
|
|
return child_as_file_reference;
|
|
}
|
|
}
|
|
|
|
children_.push_back(std::make_unique<PBXFileReference>(
|
|
navigator_path, source_path, std::string()));
|
|
return static_cast<PBXFileReference*>(children_.back().get());
|
|
}
|
|
|
|
PBXGroup* group = nullptr;
|
|
base::StringPiece component(navigator_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->name_ == component) {
|
|
group = child_as_group;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!group) {
|
|
children_.push_back(std::make_unique<PBXGroup>(component.as_string(),
|
|
component.as_string()));
|
|
group = static_cast<PBXGroup*>(children_.back().get());
|
|
}
|
|
|
|
DCHECK(group);
|
|
DCHECK(group->name_ == component);
|
|
return group->AddSourceFile(navigator_path.substr(sep + 1), source_path);
|
|
}
|
|
|
|
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 (is_source_ && !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 std::string& product_name,
|
|
const PBXFileReference* product_reference)
|
|
: PBXTarget(name, shell_script, config_name, attributes),
|
|
product_reference_(product_reference),
|
|
product_type_(product_type),
|
|
product_name_(product_name) {
|
|
DCHECK(product_reference_);
|
|
build_phases_.push_back(std::make_unique<PBXSourcesBuildPhase>());
|
|
source_build_phase_ =
|
|
static_cast<PBXSourcesBuildPhase*>(build_phases_.back().get());
|
|
|
|
build_phases_.push_back(std::make_unique<PBXFrameworksBuildPhase>());
|
|
}
|
|
|
|
PBXNativeTarget::~PBXNativeTarget() = default;
|
|
|
|
void PBXNativeTarget::AddFileForIndexing(const PBXFileReference* file_reference,
|
|
const CompilerFlags compiler_flag) {
|
|
DCHECK(file_reference);
|
|
source_build_phase_->AddBuildFile(std::make_unique<PBXBuildFile>(
|
|
file_reference, source_build_phase_, compiler_flag));
|
|
}
|
|
|
|
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", dependencies_);
|
|
PrintProperty(out, rules, "name", name_);
|
|
PrintProperty(out, rules, "productName", product_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(std::make_unique<PBXGroup>(source_path, "Source")));
|
|
sources_->set_is_source(true);
|
|
products_ = static_cast<PBXGroup*>(main_group_->AddChild(
|
|
std::make_unique<PBXGroup>(std::string(), "Product")));
|
|
main_group_->AddChild(std::make_unique<PBXGroup>(std::string(), "Build"));
|
|
|
|
configurations_.reset(new XCConfigurationList(config_name, attributes, this));
|
|
}
|
|
|
|
PBXProject::~PBXProject() = default;
|
|
|
|
void PBXProject::AddSourceFileToIndexingTarget(
|
|
const std::string& navigator_path,
|
|
const std::string& source_path,
|
|
const CompilerFlags compiler_flag) {
|
|
if (!target_for_indexing_) {
|
|
AddIndexingTarget();
|
|
}
|
|
AddSourceFile(navigator_path, source_path, compiler_flag,
|
|
target_for_indexing_);
|
|
}
|
|
|
|
void PBXProject::AddSourceFile(const std::string& navigator_path,
|
|
const std::string& source_path,
|
|
const CompilerFlags compiler_flag,
|
|
PBXNativeTarget* target) {
|
|
PBXFileReference* file_reference =
|
|
sources_->AddSourceFile(navigator_path, source_path);
|
|
base::StringPiece ext = FindExtension(&source_path);
|
|
if (!IsSourceFileForIndexing(ext))
|
|
return;
|
|
|
|
DCHECK(target);
|
|
target->AddFileForIndexing(file_reference, compiler_flag);
|
|
}
|
|
|
|
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(std::make_unique<PBXAggregateTarget>(
|
|
name, shell_script, config_name_, attributes));
|
|
}
|
|
|
|
void PBXProject::AddIndexingTarget() {
|
|
DCHECK(!target_for_indexing_);
|
|
PBXAttributes attributes;
|
|
attributes["EXECUTABLE_PREFIX"] = "";
|
|
attributes["HEADER_SEARCH_PATHS"] = sources_->path();
|
|
attributes["PRODUCT_NAME"] = "sources";
|
|
|
|
PBXFileReference* product_reference = static_cast<PBXFileReference*>(
|
|
products_->AddChild(std::make_unique<PBXFileReference>(
|
|
std::string(), "sources", "compiled.mach-o.executable")));
|
|
|
|
const char product_type[] = "com.apple.product-type.tool";
|
|
targets_.push_back(std::make_unique<PBXNativeTarget>(
|
|
"sources", std::string(), config_name_, attributes, product_type,
|
|
"sources", product_reference));
|
|
target_for_indexing_ = static_cast<PBXNativeTarget*>(targets_.back().get());
|
|
}
|
|
|
|
PBXNativeTarget* 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 PBXAttributes& extra_attributes) {
|
|
base::StringPiece ext = FindExtension(&output_name);
|
|
PBXFileReference* product = static_cast<PBXFileReference*>(
|
|
products_->AddChild(std::make_unique<PBXFileReference>(
|
|
std::string(), output_name,
|
|
type.empty() ? GetSourceType(ext) : type)));
|
|
|
|
// Per Xcode build settings documentation: Product Name (PRODUCT_NAME) should
|
|
// the basename of the product generated by the target.
|
|
// Therefore, take the basename of output name without file extension as the
|
|
// "PRODUCT_NAME".
|
|
size_t basename_offset = FindFilenameOffset(output_name);
|
|
std::string output_basename = basename_offset != std::string::npos
|
|
? output_name.substr(basename_offset)
|
|
: output_name;
|
|
size_t ext_offset = FindExtensionOffset(output_basename);
|
|
std::string product_name = ext_offset != std::string::npos
|
|
? output_basename.substr(0, ext_offset - 1)
|
|
: output_basename;
|
|
|
|
PBXAttributes attributes = extra_attributes;
|
|
attributes["CODE_SIGNING_REQUIRED"] = "NO";
|
|
attributes["CONFIGURATION_BUILD_DIR"] = ".";
|
|
attributes["PRODUCT_NAME"] = product_name;
|
|
|
|
targets_.push_back(std::make_unique<PBXNativeTarget>(
|
|
name, shell_script, config_name_, attributes, output_type, product_name,
|
|
product));
|
|
return static_cast<PBXNativeTarget*>(targets_.back().get());
|
|
}
|
|
|
|
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() = default;
|
|
|
|
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() = default;
|
|
|
|
PBXSourcesBuildPhase::~PBXSourcesBuildPhase() = default;
|
|
|
|
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";
|
|
}
|
|
|
|
PBXTargetDependency::PBXTargetDependency(
|
|
const PBXTarget* target,
|
|
std::unique_ptr<PBXContainerItemProxy> container_item_proxy)
|
|
: target_(target), container_item_proxy_(std::move(container_item_proxy)) {}
|
|
|
|
PBXTargetDependency::~PBXTargetDependency() = default;
|
|
|
|
PBXObjectClass PBXTargetDependency::Class() const {
|
|
return PBXTargetDependencyClass;
|
|
}
|
|
std::string PBXTargetDependency::Name() const {
|
|
return "PBXTargetDependency";
|
|
}
|
|
void PBXTargetDependency::Visit(PBXObjectVisitor& visitor) {
|
|
PBXObject::Visit(visitor);
|
|
container_item_proxy_->Visit(visitor);
|
|
}
|
|
void PBXTargetDependency::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, "target", target_);
|
|
PrintProperty(out, rules, "targetProxy", container_item_proxy_);
|
|
out << indent_str << "};\n";
|
|
}
|
|
|
|
// XCBuildConfiguration -------------------------------------------------------
|
|
|
|
XCBuildConfiguration::XCBuildConfiguration(const std::string& name,
|
|
const PBXAttributes& attributes)
|
|
: attributes_(attributes), name_(name) {}
|
|
|
|
XCBuildConfiguration::~XCBuildConfiguration() = default;
|
|
|
|
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(
|
|
std::make_unique<XCBuildConfiguration>(name, attributes));
|
|
}
|
|
|
|
XCConfigurationList::~XCConfigurationList() = default;
|
|
|
|
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";
|
|
}
|