|  | // Copyright 2014 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 "gn/tool.h" | 
|  |  | 
|  | #include "gn/c_tool.h" | 
|  | #include "gn/general_tool.h" | 
|  | #include "gn/rust_tool.h" | 
|  | #include "gn/settings.h" | 
|  | #include "gn/target.h" | 
|  |  | 
|  | const char* Tool::kToolNone = ""; | 
|  |  | 
|  | Tool::Tool(const char* n) : name_(n) {} | 
|  |  | 
|  | Tool::~Tool() = default; | 
|  |  | 
|  | void Tool::SetToolComplete() { | 
|  | DCHECK(!complete_); | 
|  | complete_ = true; | 
|  |  | 
|  | command_.FillRequiredTypes(&substitution_bits_); | 
|  | depfile_.FillRequiredTypes(&substitution_bits_); | 
|  | description_.FillRequiredTypes(&substitution_bits_); | 
|  | outputs_.FillRequiredTypes(&substitution_bits_); | 
|  | rspfile_.FillRequiredTypes(&substitution_bits_); | 
|  | rspfile_content_.FillRequiredTypes(&substitution_bits_); | 
|  | } | 
|  |  | 
|  | GeneralTool* Tool::AsGeneral() { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | const GeneralTool* Tool::AsGeneral() const { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | CTool* Tool::AsC() { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | const CTool* Tool::AsC() const { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | RustTool* Tool::AsRust() { | 
|  | return nullptr; | 
|  | } | 
|  | const RustTool* Tool::AsRust() const { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | bool Tool::IsPatternInOutputList(const SubstitutionList& output_list, | 
|  | const SubstitutionPattern& pattern) const { | 
|  | for (const auto& cur : output_list.list()) { | 
|  | if (pattern.ranges().size() == cur.ranges().size() && | 
|  | std::equal(pattern.ranges().begin(), pattern.ranges().end(), | 
|  | cur.ranges().begin())) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Tool::ValidateSubstitutionList( | 
|  | const std::vector<const Substitution*>& list, | 
|  | const Value* origin, | 
|  | Err* err) const { | 
|  | for (const auto& cur_type : list) { | 
|  | if (!ValidateSubstitution(cur_type)) { | 
|  | *err = Err(*origin, "Pattern not valid here.", | 
|  | "You used the pattern " + std::string(cur_type->name) + | 
|  | " which is not valid\nfor this variable."); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Tool::ReadBool(Scope* scope, const char* var, bool* field, Err* err) { | 
|  | DCHECK(!complete_); | 
|  | const Value* v = scope->GetValue(var, true); | 
|  | if (!v) | 
|  | return true;  // Not present is fine. | 
|  | if (!v->VerifyTypeIs(Value::BOOLEAN, err)) | 
|  | return false; | 
|  | *field = v->boolean_value(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Tool::ReadString(Scope* scope, | 
|  | const char* var, | 
|  | std::string* field, | 
|  | Err* err) { | 
|  | DCHECK(!complete_); | 
|  | const Value* v = scope->GetValue(var, true); | 
|  | if (!v) | 
|  | return true;  // Not present is fine. | 
|  | if (!v->VerifyTypeIs(Value::STRING, err)) | 
|  | return false; | 
|  | *field = v->string_value(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Tool::ReadPattern(Scope* scope, | 
|  | const char* var, | 
|  | SubstitutionPattern* field, | 
|  | Err* err) { | 
|  | DCHECK(!complete_); | 
|  | const Value* value = scope->GetValue(var, true); | 
|  | if (!value) | 
|  | return true;  // Not present is fine. | 
|  | if (!value->VerifyTypeIs(Value::STRING, err)) | 
|  | return false; | 
|  |  | 
|  | SubstitutionPattern pattern; | 
|  | if (!pattern.Parse(*value, err)) | 
|  | return false; | 
|  | if (!ValidateSubstitutionList(pattern.required_types(), value, err)) | 
|  | return false; | 
|  |  | 
|  | *field = std::move(pattern); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Tool::ReadPatternList(Scope* scope, | 
|  | const char* var, | 
|  | SubstitutionList* field, | 
|  | Err* err) { | 
|  | DCHECK(!complete_); | 
|  | const Value* value = scope->GetValue(var, true); | 
|  | if (!value) | 
|  | return true;  // Not present is fine. | 
|  | if (!value->VerifyTypeIs(Value::LIST, err)) | 
|  | return false; | 
|  |  | 
|  | SubstitutionList list; | 
|  | if (!list.Parse(*value, err)) | 
|  | return false; | 
|  |  | 
|  | // Validate the right kinds of patterns are used. | 
|  | if (!ValidateSubstitutionList(list.required_types(), value, err)) | 
|  | return false; | 
|  |  | 
|  | *field = std::move(list); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Tool::ReadLabel(Scope* scope, | 
|  | const char* var, | 
|  | const Label& current_toolchain, | 
|  | LabelPtrPair<Pool>* field, | 
|  | Err* err) { | 
|  | DCHECK(!complete_); | 
|  | const Value* v = scope->GetValue(var, true); | 
|  | if (!v) | 
|  | return true;  // Not present is fine. | 
|  |  | 
|  | Label label = | 
|  | Label::Resolve(scope->GetSourceDir(), | 
|  | scope->settings()->build_settings()->root_path_utf8(), | 
|  | current_toolchain, *v, err); | 
|  | if (err->has_error()) | 
|  | return false; | 
|  |  | 
|  | LabelPtrPair<Pool> pair(label); | 
|  | pair.origin = defined_from(); | 
|  |  | 
|  | *field = std::move(pair); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Tool::ReadOutputExtension(Scope* scope, Err* err) { | 
|  | DCHECK(!complete_); | 
|  | const Value* value = scope->GetValue("default_output_extension", true); | 
|  | if (!value) | 
|  | return true;  // Not present is fine. | 
|  | if (!value->VerifyTypeIs(Value::STRING, err)) | 
|  | return false; | 
|  |  | 
|  | if (value->string_value().empty()) | 
|  | return true;  // Accept empty string. | 
|  |  | 
|  | if (value->string_value()[0] != '.') { | 
|  | *err = Err(*value, "default_output_extension must begin with a '.'"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | set_default_output_extension(value->string_value()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Tool::InitTool(Scope* scope, Toolchain* toolchain, Err* err) { | 
|  | if (!ReadPattern(scope, "command", &command_, err) || | 
|  | !ReadString(scope, "command_launcher", &command_launcher_, err) || | 
|  | !ReadOutputExtension(scope, err) || | 
|  | !ReadPattern(scope, "depfile", &depfile_, err) || | 
|  | !ReadPattern(scope, "description", &description_, err) || | 
|  | !ReadPatternList(scope, "runtime_outputs", &runtime_outputs_, err) || | 
|  | !ReadString(scope, "output_prefix", &output_prefix_, err) || | 
|  | !ReadPattern(scope, "default_output_dir", &default_output_dir_, err) || | 
|  | !ReadBool(scope, "restat", &restat_, err) || | 
|  | !ReadPattern(scope, "rspfile", &rspfile_, err) || | 
|  | !ReadPattern(scope, "rspfile_content", &rspfile_content_, err) || | 
|  | !ReadLabel(scope, "pool", toolchain->label(), &pool_, err)) { | 
|  | return false; | 
|  | } | 
|  | const bool command_is_required = name_ != GeneralTool::kGeneralToolAction; | 
|  | if (command_.empty() == command_is_required) { | 
|  | *err = Err(defined_from(), "This tool's command is bad.", | 
|  | command_is_required | 
|  | ? "This tool requires \"command\" to be defined." | 
|  | : "This tool doesn't support \"command\"."); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Tool> Tool::CreateTool(const ParseNode* function, | 
|  | const std::string& name, | 
|  | Scope* scope, | 
|  | Toolchain* toolchain, | 
|  | Err* err) { | 
|  | std::unique_ptr<Tool> tool = CreateTool(name); | 
|  | if (!tool) { | 
|  | *err = Err(function, "Unknown tool type."); | 
|  | return nullptr; | 
|  | } | 
|  | if (CTool* c_tool = tool->AsC()) { | 
|  | if (c_tool->InitTool(scope, toolchain, err)) | 
|  | return tool; | 
|  | return nullptr; | 
|  | } | 
|  | if (GeneralTool* general_tool = tool->AsGeneral()) { | 
|  | if (general_tool->InitTool(scope, toolchain, err)) | 
|  | return tool; | 
|  | return nullptr; | 
|  | } | 
|  | if (RustTool* rust_tool = tool->AsRust()) { | 
|  | if (rust_tool->InitTool(scope, toolchain, err)) | 
|  | return tool; | 
|  | return nullptr; | 
|  | } | 
|  | NOTREACHED(); | 
|  | *err = Err(function, "Unknown tool type."); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<Tool> Tool::CreateTool(const std::string& name) { | 
|  | // C tools | 
|  | if (name == CTool::kCToolCc) | 
|  | return std::make_unique<CTool>(CTool::kCToolCc); | 
|  | else if (name == CTool::kCToolCxx) | 
|  | return std::make_unique<CTool>(CTool::kCToolCxx); | 
|  | else if (name == CTool::kCToolCxxModule) | 
|  | return std::make_unique<CTool>(CTool::kCToolCxxModule); | 
|  | else if (name == CTool::kCToolObjC) | 
|  | return std::make_unique<CTool>(CTool::kCToolObjC); | 
|  | else if (name == CTool::kCToolObjCxx) | 
|  | return std::make_unique<CTool>(CTool::kCToolObjCxx); | 
|  | else if (name == CTool::kCToolRc) | 
|  | return std::make_unique<CTool>(CTool::kCToolRc); | 
|  | else if (name == CTool::kCToolAsm) | 
|  | return std::make_unique<CTool>(CTool::kCToolAsm); | 
|  | else if (name == CTool::kCToolAlink) | 
|  | return std::make_unique<CTool>(CTool::kCToolAlink); | 
|  | else if (name == CTool::kCToolSolink) | 
|  | return std::make_unique<CTool>(CTool::kCToolSolink); | 
|  | else if (name == CTool::kCToolSolinkModule) | 
|  | return std::make_unique<CTool>(CTool::kCToolSolinkModule); | 
|  | else if (name == CTool::kCToolLink) | 
|  | return std::make_unique<CTool>(CTool::kCToolLink); | 
|  |  | 
|  | // General tools | 
|  | else if (name == GeneralTool::kGeneralToolAction) | 
|  | return std::make_unique<GeneralTool>(GeneralTool::kGeneralToolAction); | 
|  | else if (name == GeneralTool::kGeneralToolStamp) | 
|  | return std::make_unique<GeneralTool>(GeneralTool::kGeneralToolStamp); | 
|  | else if (name == GeneralTool::kGeneralToolCopy) | 
|  | return std::make_unique<GeneralTool>(GeneralTool::kGeneralToolCopy); | 
|  | else if (name == GeneralTool::kGeneralToolCopyBundleData) | 
|  | return std::make_unique<GeneralTool>( | 
|  | GeneralTool::kGeneralToolCopyBundleData); | 
|  | else if (name == GeneralTool::kGeneralToolCompileXCAssets) | 
|  | return std::make_unique<GeneralTool>( | 
|  | GeneralTool::kGeneralToolCompileXCAssets); | 
|  |  | 
|  | // Rust tool | 
|  | else if (name == RustTool::kRsToolBin) | 
|  | return std::make_unique<RustTool>(RustTool::kRsToolBin); | 
|  | else if (name == RustTool::kRsToolCDylib) | 
|  | return std::make_unique<RustTool>(RustTool::kRsToolCDylib); | 
|  | else if (name == RustTool::kRsToolDylib) | 
|  | return std::make_unique<RustTool>(RustTool::kRsToolDylib); | 
|  | else if (name == RustTool::kRsToolMacro) | 
|  | return std::make_unique<RustTool>(RustTool::kRsToolMacro); | 
|  | else if (name == RustTool::kRsToolRlib) | 
|  | return std::make_unique<RustTool>(RustTool::kRsToolRlib); | 
|  | else if (name == RustTool::kRsToolStaticlib) | 
|  | return std::make_unique<RustTool>(RustTool::kRsToolStaticlib); | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // static | 
|  | const char* Tool::GetToolTypeForSourceType(SourceFile::Type type) { | 
|  | switch (type) { | 
|  | case SourceFile::SOURCE_C: | 
|  | return CTool::kCToolCc; | 
|  | case SourceFile::SOURCE_CPP: | 
|  | return CTool::kCToolCxx; | 
|  | case SourceFile::SOURCE_MODULEMAP: | 
|  | return CTool::kCToolCxxModule; | 
|  | case SourceFile::SOURCE_M: | 
|  | return CTool::kCToolObjC; | 
|  | case SourceFile::SOURCE_MM: | 
|  | return CTool::kCToolObjCxx; | 
|  | case SourceFile::SOURCE_ASM: | 
|  | case SourceFile::SOURCE_S: | 
|  | return CTool::kCToolAsm; | 
|  | case SourceFile::SOURCE_RC: | 
|  | return CTool::kCToolRc; | 
|  | case SourceFile::SOURCE_RS: | 
|  | return RustTool::kRsToolBin; | 
|  | case SourceFile::SOURCE_UNKNOWN: | 
|  | case SourceFile::SOURCE_H: | 
|  | case SourceFile::SOURCE_O: | 
|  | case SourceFile::SOURCE_DEF: | 
|  | case SourceFile::SOURCE_GO: | 
|  | return kToolNone; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | return kToolNone; | 
|  | } | 
|  | } | 
|  |  | 
|  | // static | 
|  | const char* Tool::GetToolTypeForTargetFinalOutput(const Target* target) { | 
|  | // The contents of this list might be suprising (i.e. stamp tool for copy | 
|  | // rules). See the header for why. | 
|  | // TODO(crbug.com/gn/39): Don't emit stamp files for single-output targets. | 
|  | if (target->source_types_used().RustSourceUsed()) { | 
|  | switch (target->rust_values().crate_type()) { | 
|  | case RustValues::CRATE_AUTO: { | 
|  | switch (target->output_type()) { | 
|  | case Target::EXECUTABLE: | 
|  | return RustTool::kRsToolBin; | 
|  | case Target::SHARED_LIBRARY: | 
|  | return RustTool::kRsToolDylib; | 
|  | case Target::STATIC_LIBRARY: | 
|  | return RustTool::kRsToolStaticlib; | 
|  | case Target::RUST_LIBRARY: | 
|  | return RustTool::kRsToolRlib; | 
|  | case Target::RUST_PROC_MACRO: | 
|  | return RustTool::kRsToolMacro; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case RustValues::CRATE_BIN: | 
|  | return RustTool::kRsToolBin; | 
|  | case RustValues::CRATE_CDYLIB: | 
|  | return RustTool::kRsToolCDylib; | 
|  | case RustValues::CRATE_DYLIB: | 
|  | return RustTool::kRsToolDylib; | 
|  | case RustValues::CRATE_PROC_MACRO: | 
|  | return RustTool::kRsToolMacro; | 
|  | case RustValues::CRATE_RLIB: | 
|  | return RustTool::kRsToolRlib; | 
|  | case RustValues::CRATE_STATICLIB: | 
|  | return RustTool::kRsToolStaticlib; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | } | 
|  | } | 
|  | switch (target->output_type()) { | 
|  | case Target::GROUP: | 
|  | return GeneralTool::kGeneralToolStamp; | 
|  | case Target::EXECUTABLE: | 
|  | return CTool::kCToolLink; | 
|  | case Target::SHARED_LIBRARY: | 
|  | return CTool::kCToolSolink; | 
|  | case Target::LOADABLE_MODULE: | 
|  | return CTool::kCToolSolinkModule; | 
|  | case Target::STATIC_LIBRARY: | 
|  | return CTool::kCToolAlink; | 
|  | case Target::SOURCE_SET: | 
|  | return GeneralTool::kGeneralToolStamp; | 
|  | case Target::ACTION: | 
|  | case Target::ACTION_FOREACH: | 
|  | case Target::BUNDLE_DATA: | 
|  | case Target::CREATE_BUNDLE: | 
|  | case Target::COPY_FILES: | 
|  | case Target::GENERATED_FILE: | 
|  | return GeneralTool::kGeneralToolStamp; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | return kToolNone; | 
|  | } | 
|  | } |