ninja_target_writer.cc revision d3868032626d59662ff73b372b5d584c1d144c53
1d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// found in the LICENSE file.
4d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/ninja_target_writer.h"
6d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
7d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include <fstream>
8d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include <sstream>
9d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
10d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/file_util.h"
11d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/logging.h"
12d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/string_util.h"
13d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/config_values_extractors.h"
14d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/err.h"
15d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/escape.h"
16d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/file_template.h"
17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/location.h"
18d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/path_output.h"
19d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/scheduler.h"
20d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/string_utils.h"
21d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/target.h"
22d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
23d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochnamespace {
24d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
25d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstatic const char kCustomTargetSourceKey[] = "{{source}}";
26d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstatic const char kCustomTargetSourceNamePartKey[] = "{{source_name_part}}";
27d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
28d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstruct DefineWriter {
29d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  void operator()(const std::string& s, std::ostream& out) const {
30d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out << " -D" << s;
31d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
32d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch};
33d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
34d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstruct IncludeWriter {
35d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  IncludeWriter(PathOutput& path_output,
36d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                const NinjaHelper& h)
37d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      : helper(h),
38d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        path_output_(path_output),
39d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        old_inhibit_quoting_(path_output.inhibit_quoting()) {
40d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Inhibit quoting since we'll put quotes around the whole thing ourselves.
41d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Since we're writing in NINJA escaping mode, this won't actually do
42d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // anything, but I think we may need to change to shell-and-then-ninja
43d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // escaping for this in the future.
44d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.set_inhibit_quoting(true);
45d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
46d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ~IncludeWriter() {
47d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.set_inhibit_quoting(old_inhibit_quoting_);
48d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
49d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
50d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  void operator()(const SourceDir& d, std::ostream& out) const {
51d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out << " \"-I";
52d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // It's important not to include the trailing slash on directories or on
53d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Windows it will be a backslash and the compiler might think we're
54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // escaping the quote!
55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH);
56d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out << "\"";
57d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
58d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
59d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const NinjaHelper& helper;
60d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  PathOutput& path_output_;
61d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  bool old_inhibit_quoting_;  // So we can put the PathOutput back.
62d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch};
63d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
64d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}  // namespace
65d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
66d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochNinjaTargetWriter::NinjaTargetWriter(const Target* target, std::ostream& out)
67d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    : settings_(target->settings()),
68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      target_(target),
69d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      out_(out),
70d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      path_output_(settings_->build_settings()->build_dir(),
71d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                   ESCAPE_NINJA, true),
72d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      helper_(settings_->build_settings()) {
73d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
74d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
75d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochNinjaTargetWriter::~NinjaTargetWriter() {
76d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
77d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
78d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::Run() {
79d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "arch = environment.x86\n";
80d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
81d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target_->output_type() == Target::COPY_FILES) {
82d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    WriteCopyRules();
83d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  } else if (target_->output_type() == Target::CUSTOM) {
84d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    WriteCustomRules();
85d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  } else {
86d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    WriteCompilerVars();
87d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
88d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    std::vector<OutputFile> obj_files;
89d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    WriteSources(&obj_files);
90d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
91d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    WriteLinkerStuff(obj_files);
92d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
93d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
94d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
95d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// static
96d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::RunAndWriteFile(const Target* target) {
97d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target->output_type() == Target::NONE)
98d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return;
99d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
100d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Settings* settings = target->settings();
101d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  NinjaHelper helper(settings->build_settings());
102d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
103d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  base::FilePath ninja_file(settings->build_settings()->GetFullPath(
104d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      helper.GetNinjaFileForTarget(target).GetSourceFile(
105d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          settings->build_settings())));
106d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
107d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  file_util::CreateDirectory(ninja_file.DirName());
108d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
109d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // It's rediculously faster to write to a string and then write that to
110d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // disk in one operation than to use an fstream here.
111d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::stringstream file;
112d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (file.fail()) {
113d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    g_scheduler->FailWithError(
114d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        Err(Location(), "Error writing ninja file.",
115d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            "Unable to open \"" + FilePathToUTF8(ninja_file) + "\"\n"
116d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            "for writing."));
117d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return;
118d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
119d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
120d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  NinjaTargetWriter gen(target, file);
121d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  gen.Run();
122d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
123d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string contents = file.str();
124d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  file_util::WriteFile(ninja_file, contents.c_str(), contents.size());
125d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
126d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
127d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::WriteCopyRules() {
128d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The dest dir should be inside the output dir so we can just remove the
129d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // prefix and get ninja-relative paths.
130d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const std::string& output_dir =
131d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      settings_->build_settings()->build_dir().value();
132d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const std::string& dest_dir = target_->destdir().value();
133d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DCHECK(StartsWithASCII(dest_dir, output_dir, true));
134d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string relative_dest_dir(&dest_dir[output_dir.size()],
135d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                dest_dir.size() - output_dir.size());
136d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
137d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Target::FileList& sources = target_->sources();
138d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::vector<OutputFile> dest_files;
139d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  dest_files.reserve(sources.size());
140d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
141d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Write out rules for each file copied.
142d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < sources.size(); i++) {
143d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const SourceFile& input_file = sources[i];
144d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
145d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // The files should have the same name but in the dest dir.
146d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    base::StringPiece name_part = FindFilename(&input_file.value());
147d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    OutputFile dest_file(relative_dest_dir);
148d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    AppendStringPiece(&dest_file.value(), name_part);
149d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    dest_files.push_back(dest_file);
151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
152d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "build ";
153d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, dest_file);
154d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << ": copy ";
155d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, input_file);
156d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
157d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
158d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
159d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Write out the rule for the target to copy all of them.
160d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl << "build ";
161d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
162d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << ": stamp";
163d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < dest_files.size(); i++) {
164d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << " ";
165d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, dest_files[i]);
166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
167d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
168d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
169d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // TODO(brettw) need some kind of stamp file for depending on this, as well
170d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // as order_only=prebuild.
171d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
172d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::WriteCustomRules() {
174d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Make a unique name for this rule.
175d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string target_label = target_->label().GetUserVisibleName(true);
176d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string custom_rule_name(target_label);
177d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
178d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  custom_rule_name.append("_rule");
179d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
180d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Run the script from the dir of the BUILD file. This has no trailing
181d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // slash.
182d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const SourceDir& script_cd = target_->label().dir();
183d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string script_cd_to_root = InvertDir(script_cd);
184d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (script_cd_to_root.empty()) {
185d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    script_cd_to_root = ".";
186d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  } else {
187d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Remove trailing slash
188d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    DCHECK(script_cd_to_root[script_cd_to_root.size() - 1] == '/');
189d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    script_cd_to_root.resize(script_cd_to_root.size() - 1);
190d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
191d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
192d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string script_relative_to_cd =
193d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      script_cd_to_root + target_->script().value();
194d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
195d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  bool no_sources = target_->sources().empty();
196d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
197d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Use a unique name for the response file when there are multiple build
198d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // steps so that they don't stomp on each other.
199d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string rspfile = custom_rule_name;
200d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!no_sources)
201d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    rspfile += ".$unique_name";
202d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  rspfile += ".rsp";
203d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
204d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // First write the custom rule.
205d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "rule " << custom_rule_name << std::endl;
206d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "  command = $pythonpath gyp-win-tool action-wrapper $arch "
207d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch       << rspfile << " ";
208d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path_output_.WriteDir(out_, script_cd, PathOutput::DIR_NO_LAST_SLASH);
209d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
210d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "  description = CUSTOM " << target_label << std::endl;
211d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "  restat = 1" << std::endl;
212d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "  rspfile = " << rspfile << std::endl;
213d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
214d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The build command goes in the rsp file.
215d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "  rspfile_content = $pythonpath " << script_relative_to_cd;
216d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < target_->script_args().size(); i++) {
217d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::string& arg = target_->script_args()[i];
218d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << " ";
219d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    WriteCustomArg(arg);
220d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
221d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl << std::endl;
222d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
223d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Precompute the common dependencies for each step. This includes the
224d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // script itself (changing the script should force a rebuild) and any data
225d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // files.
226d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::ostringstream common_deps_stream;
227d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path_output_.WriteFile(common_deps_stream, target_->script());
228d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Target::FileList& datas = target_->data();
229d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < datas.size(); i++) {
230d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    common_deps_stream << " ";
231d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(common_deps_stream, datas[i]);
232d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
233d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const std::string& common_deps = common_deps_stream.str();
234d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
235d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Collects all output files for writing below.
236d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::vector<OutputFile> output_files;
237d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
238d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (no_sources) {
239d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // No sources, write a rule that invokes the script once with the
240d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // outputs as outputs, and the data as inputs.
241d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "build";
242d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const Target::FileList& outputs = target_->outputs();
243d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    for (size_t i = 0; i < outputs.size(); i++) {
244d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      OutputFile output_path(
245d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          RemovePrefix(outputs[i].value(),
246d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                       settings_->build_settings()->build_dir().value()));
247d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      output_files.push_back(output_path);
248d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      out_ << " ";
249d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      path_output_.WriteFile(out_, output_path);
250d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
251d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << ": " << custom_rule_name << " " << common_deps << std::endl;
252d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  } else {
253d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Write separate rules for each input source file.
254d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    WriteCustomSourceRules(custom_rule_name, common_deps, script_cd,
255d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           script_cd_to_root, &output_files);
256d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
257d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
258d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
259d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Last write a stamp rule to collect all outputs.
260d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "build ";
261d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
262d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << ": stamp";
263d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < output_files.size(); i++) {
264d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << " ";
265d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, output_files[i]);
266d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
267d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
268d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
269d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
270d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::WriteCustomArg(const std::string& arg) {
271d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // This can be optimized if it's called a lot.
272d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  EscapeOptions options;
273d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  options.mode = ESCAPE_NINJA;
274d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string output_str = EscapeString(arg, options);
275d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
276d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Do this substitution after escaping our our $ will be escaped (which we
277d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // don't want).
278d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSource,
279d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               "${source}");
280d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSourceNamePart,
281d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               "${source_name_part}");
282d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << output_str;
283d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
284d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
285d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::WriteCustomSourceRules(
286d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::string& custom_rule_name,
287d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::string& common_deps,
288d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const SourceDir& script_cd,
289d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::string& script_cd_to_root,
290d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    std::vector<OutputFile>* output_files) {
291d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Construct the template for generating the output files from each source.
292d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Target::FileList& outputs = target_->outputs();
293d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::vector<std::string> output_template_args;
294d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < outputs.size(); i++) {
295d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // All outputs should be in the output dir.
296d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    output_template_args.push_back(
297d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        RemovePrefix(outputs[i].value(),
298d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     settings_->build_settings()->build_dir().value()));
299d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
300d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  FileTemplate output_template(output_template_args);
301d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
302d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Prevent re-allocating each time by initializing outside the loop.
303d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::vector<std::string> output_template_result;
304d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
305d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Path output formatter for wrigin source paths passed to the script.
306d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  PathOutput script_source_path_output(script_cd, ESCAPE_SHELL, true);
307d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
308d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Target::FileList& sources = target_->sources();
309d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < sources.size(); i++) {
310d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Write outputs for this source file computed by the template.
311d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "build";
312d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    output_template.ApplyString(sources[i].value(), &output_template_result);
313d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) {
314d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      OutputFile output_path(output_template_result[out_i]);
315d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      output_files->push_back(output_path);
316d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      out_ << " ";
317d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      path_output_.WriteFile(out_, output_path);
318d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
319d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
320d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << ": " << custom_rule_name
321d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch         << " " << common_deps
322d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch         << " ";
323d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, sources[i]);
324d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
325d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
326d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "  unique_name = " << i << std::endl;
327d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
328d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // The source file here should be relative to the script directory since
329d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // this is the variable passed to the script. Here we slightly abuse the
330d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // OutputFile object by putting a non-output-relative path in it to signal
331d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // that the PathWriter should not prepend directories.
332d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "  source = ";
333d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    script_source_path_output.WriteFile(out_, sources[i]);
334d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
335d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
336d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "  source_name_part = "
337d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch         << FindFilenameNoExtension(&sources[i].value()).as_string()
338d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch         << std::endl;
339d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
340d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
341d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
342d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::WriteCompilerVars() {
343d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Defines.
344d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "defines =";
345d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  RecursiveTargetConfigToStream(target_, &ConfigValues::defines,
346d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                DefineWriter(), out_);
347d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
348d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
349d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Includes.
350d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "includes =";
351d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  RecursiveTargetConfigToStream(target_, &ConfigValues::includes,
352d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                IncludeWriter(path_output_, helper_), out_);
353d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
354d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
355d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
356d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // C flags and friends.
357d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "cflags =";
358d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags, out_);
359d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
360d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "cflags_c =";
361d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_c, out_);
362d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
363d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "cflags_cc =";
364d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  RecursiveTargetConfigStringsToStream(target_, &ConfigValues::cflags_cc, out_);
365d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
366d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
367d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
368d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
369d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
370d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::WriteSources(
371d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    std::vector<OutputFile>* object_files) {
372d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Target::FileList& sources = target_->sources();
373d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  object_files->reserve(sources.size());
374d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
375d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < sources.size(); i++) {
376d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const SourceFile& input_file = sources[i];
377d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
378d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    SourceFileType input_file_type = GetSourceFileType(input_file,
379d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                                       settings_->target_os());
380d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (input_file_type == SOURCE_UNKNOWN)
381d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      continue;  // Skip unknown file types.
382d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const char* command = GetCommandForSourceType(input_file_type);
383d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (!command)
384d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      continue;  // Skip files not needing compilation.
385d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
386d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    OutputFile output_file = helper_.GetOutputFileForSource(
387d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        target_, input_file, input_file_type);
388d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    object_files->push_back(output_file);
389d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
390d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "build ";
391d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, output_file);
392d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << ": " << command << " ";
393d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, input_file);
394d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
395d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
396d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
397d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
398d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
399d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaTargetWriter::WriteLinkerStuff(
400d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::vector<OutputFile>& object_files) {
401d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Manifest file on Windows.
402d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // TODO(brettw) this seems not to be necessary for static libs, skip in
403d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // that case?
404d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  OutputFile windows_manifest;
405d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (settings_->IsWin()) {
406d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    windows_manifest.value().assign(helper_.GetTargetOutputDir(target_));
407d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    windows_manifest.value().append(target_->label().name());
408d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    windows_manifest.value().append(".intermediate.manifest");
409d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "manifests = ";
410d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, windows_manifest);
411d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
412d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
413d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
414d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Linker flags, append manifest flag on Windows to reference our file.
415d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "ldflags =";
416d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags, out_);
417d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (settings_->IsWin())
418d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << " /MANIFEST /ManifestFile:";
419d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, windows_manifest);
420d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  {  // HACK ERASEME BRETTW FIXME
421d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << " /DEBUG /MACHINE:X86 /LIBPATH:\"C:\\Program Files (x86)\\Windows Kits\\8.0\\Lib\\win8\\um\\x86\" /DELAYLOAD:dbghelp.dll /DELAYLOAD:dwmapi.dll /DELAYLOAD:shell32.dll /DELAYLOAD:uxtheme.dll /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat /SUBSYSTEM:CONSOLE /INCREMENTAL /FIXED:NO /DYNAMICBASE:NO wininet.lib dnsapi.lib version.lib msimg32.lib ws2_32.lib usp10.lib psapi.lib dbghelp.lib winmm.lib shlwapi.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib user32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /NXCOMPAT";
422d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
423d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
424d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
425d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Libraries to link.
426d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "libs =" << std::endl;
427d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
428d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The external output file is the one that other libs depend on.
429d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  OutputFile external_output_file = helper_.GetTargetOutputFile(target_);
430d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
431d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The internal output file is the "main thing" we think we're making. In
432d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // the case of shared libraries, this is the shared library and the external
433d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // output file is the import library. In other cases, the internal one and
434d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // the external one are the same.
435d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  OutputFile internal_output_file;
436d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target_->output_type() == Target::SHARED_LIBRARY) {
437d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (settings_->IsWin()) {
438d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      internal_output_file = OutputFile(target_->label().name() + ".dll");
439d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    } else {
440d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      NOTREACHED();  // TODO(brettw) write this.
441d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
442d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  } else {
443d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    internal_output_file = external_output_file;
444d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
445d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
446d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // TODO(brettw) should we append data files to this?
447d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
448d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // In Python see "self.ninja.build(output, command, input,"
449d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "build ";
450d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path_output_.WriteFile(out_, internal_output_file);
451d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (external_output_file != internal_output_file) {
452d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << " ";
453d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, external_output_file);
454d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
455d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << ": " << GetCommandForTargetType();
456d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < object_files.size(); i++) {
457d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << " ";
458d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, object_files[i]);
459d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
460d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
461d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target_->output_type() == Target::EXECUTABLE ||
462d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      target_->output_type() == Target::SHARED_LIBRARY ||
463d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      target_->output_type() == Target::LOADABLE_MODULE) {
464d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::vector<const Target*>& deps = target_->deps();
465d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::set<const Target*>& inherited = target_->inherited_libraries();
466d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
467d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Now append linkable libraries to the linker command.
468d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    for (size_t i = 0; i < deps.size(); i++) {
469d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (deps[i]->IsLinkable() &&
470d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          inherited.find(deps[i]) == inherited.end()) {
471d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        out_ << " ";
472d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        path_output_.WriteFile(out_,
473d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               helper_.GetTargetOutputFile(target_->deps()[i]));
474d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
475d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
476d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    for (std::set<const Target*>::const_iterator i = inherited.begin();
477d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch         i != inherited.end(); ++i) {
478d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      out_ << " ";
479d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      path_output_.WriteFile(out_, helper_.GetTargetOutputFile(*i));
480d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
481d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
482d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
483d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
484d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target_->output_type() == Target::SHARED_LIBRARY) {
485d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "  soname = ";
486d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, internal_output_file);
487d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
488d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
489d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "  lib = ";
490d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, internal_output_file);
491d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
492d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
493d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "  dll = ";
494d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    path_output_.WriteFile(out_, internal_output_file);
495d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
496d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
497d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (settings_->IsWin()) {
498d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      out_ << "  implibflag = /IMPLIB:";
499d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      path_output_.WriteFile(out_, external_output_file);
500d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      out_ << std::endl;
501d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
502d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
503d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
504d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // TODO(brettw) postbuild steps here.
505d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
506d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
507d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
508d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
509d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochconst char* NinjaTargetWriter::GetCommandForSourceType(
510d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    SourceFileType type) const {
511d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (type == SOURCE_C)
512d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return "cc";
513d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (type == SOURCE_CC)
514d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return "cxx";
515d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
516d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // TODO(brettw) asm files.
517d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
518d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (settings_->IsMac()) {
519d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (type == SOURCE_M)
520d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return "objc";
521d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (type == SOURCE_MM)
522d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return "objcxx";
523d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
524d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
525d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (settings_->IsWin()) {
526d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (type == SOURCE_RC)
527d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return "rc";
528d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
529d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
530d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // TODO(brettw) stuff about "S" files on non-Windows.
531d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return NULL;
532d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
533d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
534d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochconst char* NinjaTargetWriter::GetCommandForTargetType() const {
535d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target_->output_type() == Target::NONE) {
536d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    NOTREACHED();
537d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return "";
538d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
539d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
540d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target_->output_type() == Target::STATIC_LIBRARY) {
541d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // TODO(brettw) stuff about standalong static libraryes on Unix in
542d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // WriteTarget in the Python one, and lots of postbuild steps.
543d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return "alink";
544d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
545d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
546d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (target_->output_type() == Target::SHARED_LIBRARY)
547d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return "solink";
548d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
549d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return "link";
550d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
551