- add sources.
[platform/framework/web/crosswalk.git] / src / tools / gn / ninja_script_target_writer.cc
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_script_target_writer.h"
6
7 #include "base/strings/string_util.h"
8 #include "tools/gn/err.h"
9 #include "tools/gn/file_template.h"
10 #include "tools/gn/string_utils.h"
11 #include "tools/gn/target.h"
12
13 NinjaScriptTargetWriter::NinjaScriptTargetWriter(const Target* target,
14                                                  const Toolchain* toolchain,
15                                                  std::ostream& out)
16     : NinjaTargetWriter(target, toolchain, out),
17       path_output_no_escaping_(
18           target->settings()->build_settings()->build_dir(),
19           ESCAPE_NONE, false) {
20 }
21
22 NinjaScriptTargetWriter::~NinjaScriptTargetWriter() {
23 }
24
25 void NinjaScriptTargetWriter::Run() {
26   FileTemplate args_template(target_->script_values().args());
27   std::string custom_rule_name = WriteRuleDefinition(args_template);
28   std::string implicit_deps = GetSourcesImplicitDeps();
29
30   // Collects all output files for writing below.
31   std::vector<OutputFile> output_files;
32
33   if (has_sources()) {
34     // Write separate build lines for each input source file.
35     WriteSourceRules(custom_rule_name, implicit_deps, args_template,
36                      &output_files);
37   } else {
38     // No sources, write a rule that invokes the script once with the
39     // outputs as outputs, and the data as inputs.
40     out_ << "build";
41     const Target::FileList& outputs = target_->script_values().outputs();
42     for (size_t i = 0; i < outputs.size(); i++) {
43       OutputFile output_path(
44           RemovePrefix(outputs[i].value(),
45                        settings_->build_settings()->build_dir().value()));
46       output_files.push_back(output_path);
47       out_ << " ";
48       path_output_.WriteFile(out_, output_path);
49     }
50     out_ << ": " << custom_rule_name << implicit_deps << std::endl;
51   }
52   out_ << std::endl;
53
54   WriteStamp(output_files);
55 }
56
57 std::string NinjaScriptTargetWriter::WriteRuleDefinition(
58     const FileTemplate& args_template) {
59   // Make a unique name for this rule.
60   //
61   // Use a unique name for the response file when there are multiple build
62   // steps so that they don't stomp on each other. When there are no sources,
63   // there will be only one invocation so we can use a simple name.
64   std::string target_label = target_->label().GetUserVisibleName(true);
65   std::string custom_rule_name(target_label);
66   ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
67   custom_rule_name.append("_rule");
68
69   if (settings_->IsWin()) {
70     // Send through gyp-win-tool and use a response file.
71     std::string rspfile = custom_rule_name;
72     if (has_sources())
73       rspfile += ".$unique_name";
74     rspfile += ".rsp";
75
76     out_ << "rule " << custom_rule_name << std::endl;
77     out_ << "  command = ";
78     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
79     // TODO(brettw) this hardcodes "environment.x86" which is something that
80     // the Chrome Windows toolchain writes. We should have a way to invoke
81     // python without requiring this gyp_win_tool thing.
82     out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile
83          << std::endl;
84     out_ << "  description = CUSTOM " << target_label << std::endl;
85     out_ << "  restat = 1" << std::endl;
86     out_ << "  rspfile = " << rspfile << std::endl;
87
88     // The build command goes in the rsp file.
89     out_ << "  rspfile_content = ";
90     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
91     out_ << " ";
92     path_output_.WriteFile(out_, target_->script_values().script());
93     args_template.WriteWithNinjaExpansions(out_);
94     out_ << std::endl;
95   } else {
96     // Posix can execute Python directly.
97     out_ << "rule " << custom_rule_name << std::endl;
98     out_ << "  command = ";
99     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
100     out_ << " ";
101     path_output_.WriteFile(out_, target_->script_values().script());
102     args_template.WriteWithNinjaExpansions(out_);
103     out_ << std::endl;
104     out_ << "  description = CUSTOM " << target_label << std::endl;
105     out_ << "  restat = 1" << std::endl;
106   }
107
108   out_ << std::endl;
109   return custom_rule_name;
110 }
111
112 void NinjaScriptTargetWriter::WriteArgsSubstitutions(
113     const SourceFile& source,
114     const FileTemplate& args_template) {
115   std::ostringstream source_file_stream;
116   path_output_no_escaping_.WriteFile(source_file_stream, source);
117
118   EscapeOptions template_escape_options;
119   template_escape_options.mode = ESCAPE_NINJA_SHELL;
120   template_escape_options.inhibit_quoting = true;
121
122   args_template.WriteNinjaVariablesForSubstitution(
123       out_, source_file_stream.str(), template_escape_options);
124 }
125
126 void NinjaScriptTargetWriter::WriteSourceRules(
127     const std::string& custom_rule_name,
128     const std::string& implicit_deps,
129     const FileTemplate& args_template,
130     std::vector<OutputFile>* output_files) {
131   FileTemplate output_template(GetOutputTemplate());
132
133   const Target::FileList& sources = target_->sources();
134   for (size_t i = 0; i < sources.size(); i++) {
135     out_ << "build";
136     WriteOutputFilesForBuildLine(output_template, sources[i], output_files);
137
138     out_ << ": " << custom_rule_name << " ";
139     path_output_.WriteFile(out_, sources[i]);
140     out_ << implicit_deps << std::endl;
141
142     // Windows needs a unique ID for the response file.
143     if (target_->settings()->IsWin())
144       out_ << "  unique_name = " << i << std::endl;
145
146     if (args_template.has_substitutions())
147       WriteArgsSubstitutions(sources[i], args_template);
148   }
149 }
150
151 void NinjaScriptTargetWriter::WriteStamp(
152     const std::vector<OutputFile>& output_files) {
153   out_ << "build ";
154   path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
155   out_ << ": "
156        << helper_.GetRulePrefix(target_->settings())
157        << "stamp";
158   for (size_t i = 0; i < output_files.size(); i++) {
159     out_ << " ";
160     path_output_.WriteFile(out_, output_files[i]);
161   }
162   out_ << std::endl;
163 }
164
165 void NinjaScriptTargetWriter::WriteOutputFilesForBuildLine(
166     const FileTemplate& output_template,
167     const SourceFile& source,
168     std::vector<OutputFile>* output_files) {
169   std::vector<std::string> output_template_result;
170   output_template.ApplyString(source.value(), &output_template_result);
171   for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) {
172     OutputFile output_path(output_template_result[out_i]);
173     output_files->push_back(output_path);
174     out_ << " ";
175     path_output_.WriteFile(out_, output_path);
176   }
177 }