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 20namespace { 21 22const char kIndent[] = " "; 23 24} // namespace 25 26NinjaToolchainWriter::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 38NinjaToolchainWriter::~NinjaToolchainWriter() { 39} 40 41void NinjaToolchainWriter::Run() { 42 WriteRules(); 43 WriteSubninjas(); 44} 45 46// static 47bool 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 68void 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 80void 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 117void 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 127void 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