Home | History | Annotate | Download | only in gn
      1 // Copyright (c) 2013 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/ninja_toolchain_writer.h"
      6 
      7 #include <fstream>
      8 
      9 #include "base/files/file_util.h"
     10 #include "base/strings/stringize_macros.h"
     11 #include "tools/gn/build_settings.h"
     12 #include "tools/gn/filesystem_utils.h"
     13 #include "tools/gn/ninja_utils.h"
     14 #include "tools/gn/settings.h"
     15 #include "tools/gn/substitution_writer.h"
     16 #include "tools/gn/target.h"
     17 #include "tools/gn/toolchain.h"
     18 #include "tools/gn/trace.h"
     19 
     20 namespace {
     21 
     22 const char kIndent[] = "  ";
     23 
     24 }  // namespace
     25 
     26 NinjaToolchainWriter::NinjaToolchainWriter(
     27     const Settings* settings,
     28     const Toolchain* toolchain,
     29     const std::vector<const Target*>& targets,
     30     std::ostream& out)
     31     : settings_(settings),
     32       toolchain_(toolchain),
     33       targets_(targets),
     34       out_(out),
     35       path_output_(settings_->build_settings()->build_dir(), ESCAPE_NINJA) {
     36 }
     37 
     38 NinjaToolchainWriter::~NinjaToolchainWriter() {
     39 }
     40 
     41 void NinjaToolchainWriter::Run() {
     42   WriteRules();
     43   WriteSubninjas();
     44 }
     45 
     46 // static
     47 bool NinjaToolchainWriter::RunAndWriteFile(
     48     const Settings* settings,
     49     const Toolchain* toolchain,
     50     const std::vector<const Target*>& targets) {
     51   base::FilePath ninja_file(settings->build_settings()->GetFullPath(
     52       GetNinjaFileForToolchain(settings)));
     53   ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, FilePathToUTF8(ninja_file));
     54 
     55   base::CreateDirectory(ninja_file.DirName());
     56 
     57   std::ofstream file;
     58   file.open(FilePathToUTF8(ninja_file).c_str(),
     59             std::ios_base::out | std::ios_base::binary);
     60   if (file.fail())
     61     return false;
     62 
     63   NinjaToolchainWriter gen(settings, toolchain, targets, file);
     64   gen.Run();
     65   return true;
     66 }
     67 
     68 void NinjaToolchainWriter::WriteRules() {
     69   std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_);
     70 
     71   for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) {
     72     Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
     73     const Tool* tool = toolchain_->GetTool(tool_type);
     74     if (tool)
     75       WriteToolRule(tool_type, tool, rule_prefix);
     76   }
     77   out_ << std::endl;
     78 }
     79 
     80 void NinjaToolchainWriter::WriteToolRule(const Toolchain::ToolType type,
     81                                          const Tool* tool,
     82                                          const std::string& rule_prefix) {
     83   out_ << "rule " << rule_prefix << Toolchain::ToolTypeToName(type)
     84        << std::endl;
     85 
     86   // Rules explicitly include shell commands, so don't try to escape.
     87   EscapeOptions options;
     88   options.mode = ESCAPE_NINJA_PREFORMATTED_COMMAND;
     89 
     90   CHECK(!tool->command().empty()) << "Command should not be empty";
     91   WriteRulePattern("command", tool->command(), options);
     92 
     93   WriteRulePattern("description", tool->description(), options);
     94   WriteRulePattern("rspfile", tool->rspfile(), options);
     95   WriteRulePattern("rspfile_content", tool->rspfile_content(), options);
     96 
     97   if (tool->depsformat() == Tool::DEPS_GCC) {
     98     // GCC-style deps require a depfile.
     99     if (!tool->depfile().empty()) {
    100       WriteRulePattern("depfile", tool->depfile(), options);
    101       out_ << kIndent << "deps = gcc" << std::endl;
    102     }
    103   } else if (tool->depsformat() == Tool::DEPS_MSVC) {
    104     // MSVC deps don't have a depfile.
    105     out_ << kIndent << "deps = msvc" << std::endl;
    106   }
    107 
    108   // The link pool applies to linker tools. Don't count TYPE_ALINK since
    109   // static libraries are not generally intensive to write.
    110   if (type == Toolchain::TYPE_SOLINK || type == Toolchain::TYPE_LINK)
    111     out_ << kIndent << "pool = link_pool\n";
    112 
    113   if (tool->restat())
    114     out_ << kIndent << "restat = 1" << std::endl;
    115 }
    116 
    117 void NinjaToolchainWriter::WriteRulePattern(const char* name,
    118                                             const SubstitutionPattern& pattern,
    119                                             const EscapeOptions& options) {
    120   if (pattern.empty())
    121     return;
    122   out_ << kIndent << name << " = ";
    123   SubstitutionWriter::WriteWithNinjaVariables(pattern, options, out_);
    124   out_ << std::endl;
    125 }
    126 
    127 void NinjaToolchainWriter::WriteSubninjas() {
    128   // Write subninja commands for each generated target.
    129   for (size_t i = 0; i < targets_.size(); i++) {
    130     OutputFile ninja_file(targets_[i]->settings()->build_settings(),
    131                           GetNinjaFileForTarget(targets_[i]));
    132     out_ << "subninja ";
    133     path_output_.WriteFile(out_, ninja_file);
    134     out_ << std::endl;
    135   }
    136   out_ << std::endl;
    137 }
    138