|  | // Copyright 2019 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/ninja_rust_binary_target_writer.h" | 
|  |  | 
|  | #include <sstream> | 
|  |  | 
|  | #include "tools/gn/deps_iterator.h" | 
|  | #include "tools/gn/general_tool.h" | 
|  | #include "tools/gn/ninja_target_command_util.h" | 
|  | #include "tools/gn/ninja_utils.h" | 
|  | #include "tools/gn/rust_substitution_type.h" | 
|  | #include "tools/gn/substitution_writer.h" | 
|  | #include "tools/gn/target.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Returns the proper escape options for writing compiler and linker flags. | 
|  | EscapeOptions GetFlagOptions() { | 
|  | EscapeOptions opts; | 
|  | opts.mode = ESCAPE_NINJA_COMMAND; | 
|  | return opts; | 
|  | } | 
|  |  | 
|  | void WriteVar(const char* name, | 
|  | const std::string& value, | 
|  | EscapeOptions opts, | 
|  | std::ostream& out) { | 
|  | out << name << " = "; | 
|  | EscapeStringToStream(out, value, opts); | 
|  | out << std::endl; | 
|  | } | 
|  |  | 
|  | void WriteCrateVars(const Target* target, | 
|  | const Tool* tool, | 
|  | EscapeOptions opts, | 
|  | std::ostream& out) { | 
|  | WriteVar(kRustSubstitutionCrateName.ninja_name, | 
|  | target->rust_values().crate_name(), opts, out); | 
|  |  | 
|  | std::string crate_type; | 
|  | switch (target->output_type()) { | 
|  | case Target::EXECUTABLE: | 
|  | crate_type = "bin"; | 
|  | break; | 
|  | case Target::STATIC_LIBRARY: | 
|  | crate_type = "staticlib"; | 
|  | break; | 
|  | case Target::RUST_LIBRARY: | 
|  | crate_type = "rlib"; | 
|  | break; | 
|  | case Target::SHARED_LIBRARY: | 
|  | switch (target->rust_values().crate_type()) { | 
|  | case RustValues::CRATE_DYLIB: | 
|  | crate_type = "dylib"; | 
|  | break; | 
|  | case RustValues::CRATE_CDYLIB: | 
|  | crate_type = "cdylib"; | 
|  | break; | 
|  | case RustValues::CRATE_PROC_MACRO: | 
|  | crate_type = "proc-macro"; | 
|  | break; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | } | 
|  | default: | 
|  | NOTREACHED(); | 
|  | } | 
|  | WriteVar(kRustSubstitutionCrateType.ninja_name, crate_type, opts, out); | 
|  |  | 
|  | if (!target->output_extension_set()) { | 
|  | DCHECK(tool->AsRust()); | 
|  | WriteVar(kRustSubstitutionOutputExtension.ninja_name, | 
|  | tool->AsRust()->rustc_output_extension( | 
|  | target->output_type(), target->rust_values().crate_type()), | 
|  | opts, out); | 
|  | } else if (target->output_extension().empty()) { | 
|  | WriteVar(kRustSubstitutionOutputExtension.ninja_name, "", opts, out); | 
|  | } else { | 
|  | WriteVar(kRustSubstitutionOutputExtension.ninja_name, | 
|  | std::string(".") + target->output_extension(), opts, out); | 
|  | } | 
|  |  | 
|  | if (target->output_type() == Target::RUST_LIBRARY || | 
|  | target->output_type() == Target::SHARED_LIBRARY) | 
|  | WriteVar(kRustSubstitutionOutputPrefix.ninja_name, "lib", opts, out); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | NinjaRustBinaryTargetWriter::NinjaRustBinaryTargetWriter(const Target* target, | 
|  | std::ostream& out) | 
|  | : NinjaBinaryTargetWriter(target, out), | 
|  | tool_(target->toolchain()->GetToolForTargetFinalOutputAsRust(target)) {} | 
|  |  | 
|  | NinjaRustBinaryTargetWriter::~NinjaRustBinaryTargetWriter() = default; | 
|  |  | 
|  | // TODO(juliehockett): add inherited library support? and IsLinkable support? | 
|  | // for c-cross-compat | 
|  | void NinjaRustBinaryTargetWriter::Run() { | 
|  | OutputFile input_dep = WriteInputsStampAndGetDep(); | 
|  |  | 
|  | // The input dependencies will be an order-only dependency. This will cause | 
|  | // Ninja to make sure the inputs are up to date before compiling this source, | 
|  | // but changes in the inputs deps won't cause the file to be recompiled. See | 
|  | // the comment on NinjaCBinaryTargetWriter::Run for more detailed explanation. | 
|  | size_t num_stamp_uses = target_->sources().size(); | 
|  | std::vector<OutputFile> order_only_deps = WriteInputDepsStampAndGetDep( | 
|  | std::vector<const Target*>(), num_stamp_uses); | 
|  |  | 
|  | // Public rust_library deps go in a --extern rlibs, public non-rust deps go in | 
|  | // -Ldependency rustdeps, and non-public source_sets get passed in as normal | 
|  | // source files | 
|  | UniqueVector<OutputFile> deps; | 
|  | AddSourceSetFiles(target_, &deps); | 
|  | if (target_->output_type() == Target::SOURCE_SET) { | 
|  | WriteSharedVars(target_->toolchain()->substitution_bits()); | 
|  | WriteSourceSetStamp(deps.vector()); | 
|  | } else { | 
|  | WriteCompilerVars(); | 
|  | UniqueVector<const Target*> linkable_deps; | 
|  | UniqueVector<const Target*> non_linkable_deps; | 
|  | GetDeps(&deps, &linkable_deps, &non_linkable_deps); | 
|  |  | 
|  | if (!input_dep.value().empty()) | 
|  | order_only_deps.push_back(input_dep); | 
|  |  | 
|  | std::vector<OutputFile> rustdeps; | 
|  | for (const auto* non_linkable_dep : non_linkable_deps) { | 
|  | order_only_deps.push_back(non_linkable_dep->dependency_output_file()); | 
|  | } | 
|  |  | 
|  | for (const auto* linkable_dep : linkable_deps) { | 
|  | rustdeps.push_back(linkable_dep->dependency_output_file()); | 
|  | deps.push_back(linkable_dep->dependency_output_file()); | 
|  | } | 
|  |  | 
|  | std::vector<OutputFile> tool_outputs; | 
|  | SubstitutionWriter::ApplyListToLinkerAsOutputFile( | 
|  | target_, tool_, tool_->outputs(), &tool_outputs); | 
|  | WriteCompilerBuildLine(target_->rust_values().crate_root(), deps.vector(), | 
|  | order_only_deps, tool_->name(), tool_outputs); | 
|  | WriteExterns(); | 
|  | WriteRustdeps(rustdeps); | 
|  | WriteEdition(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void NinjaRustBinaryTargetWriter::WriteCompilerVars() { | 
|  | const SubstitutionBits& subst = target_->toolchain()->substitution_bits(); | 
|  |  | 
|  | EscapeOptions opts = GetFlagOptions(); | 
|  | WriteCrateVars(target_, tool_, opts, out_); | 
|  |  | 
|  | WriteOneFlag(target_, &kRustSubstitutionRustFlags, false, | 
|  | RustTool::kRsToolRustc, &ConfigValues::rustflags, opts, | 
|  | path_output_, out_); | 
|  |  | 
|  | WriteOneFlag(target_, &kRustSubstitutionRustEnv, false, | 
|  | RustTool::kRsToolRustc, &ConfigValues::rustenv, opts, | 
|  | path_output_, out_); | 
|  |  | 
|  | WriteSharedVars(subst); | 
|  | } | 
|  |  | 
|  | void NinjaRustBinaryTargetWriter::WriteExterns() { | 
|  | std::vector<const Target*> externs; | 
|  | for (const auto& pair : target_->GetDeps(Target::DEPS_LINKED)) { | 
|  | if (pair.ptr->output_type() == Target::RUST_LIBRARY) { | 
|  | externs.push_back(pair.ptr); | 
|  | } | 
|  | } | 
|  | if (externs.empty()) | 
|  | return; | 
|  | out_ << "  externs ="; | 
|  | for (const Target* ex : externs) { | 
|  | out_ << " --extern "; | 
|  |  | 
|  | const auto& renamed_dep = | 
|  | target_->rust_values().aliased_deps().find(ex->label()); | 
|  | if (renamed_dep != target_->rust_values().aliased_deps().end()) { | 
|  | out_ << renamed_dep->second << "="; | 
|  | } else { | 
|  | out_ << std::string(ex->rust_values().crate_name()) << "="; | 
|  | } | 
|  |  | 
|  | path_output_.WriteFile(out_, ex->dependency_output_file()); | 
|  | } | 
|  | out_ << std::endl; | 
|  | } | 
|  |  | 
|  | void NinjaRustBinaryTargetWriter::WriteRustdeps( | 
|  | std::vector<OutputFile>& rustdeps) { | 
|  | if (rustdeps.empty()) | 
|  | return; | 
|  | out_ << "  rustdeps ="; | 
|  | for (const auto& rustdep : rustdeps) { | 
|  | out_ << " -Ldependency="; | 
|  | path_output_.WriteDir( | 
|  | out_, rustdep.AsSourceFile(settings_->build_settings()).GetDir(), | 
|  | PathOutput::DIR_NO_LAST_SLASH); | 
|  | } | 
|  | out_ << std::endl; | 
|  | } | 
|  |  | 
|  | void NinjaRustBinaryTargetWriter::WriteEdition() { | 
|  | DCHECK(!target_->rust_values().edition().empty()); | 
|  | out_ << "  edition = " << target_->rust_values().edition() << std::endl; | 
|  | } |