Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / gn / ninja_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_target_writer.h"
6
7 #include <fstream>
8 #include <sstream>
9
10 #include "base/files/file_util.h"
11 #include "base/strings/string_util.h"
12 #include "tools/gn/err.h"
13 #include "tools/gn/filesystem_utils.h"
14 #include "tools/gn/ninja_action_target_writer.h"
15 #include "tools/gn/ninja_binary_target_writer.h"
16 #include "tools/gn/ninja_copy_target_writer.h"
17 #include "tools/gn/ninja_group_target_writer.h"
18 #include "tools/gn/ninja_utils.h"
19 #include "tools/gn/output_file.h"
20 #include "tools/gn/scheduler.h"
21 #include "tools/gn/string_utils.h"
22 #include "tools/gn/substitution_writer.h"
23 #include "tools/gn/target.h"
24 #include "tools/gn/trace.h"
25
26 NinjaTargetWriter::NinjaTargetWriter(const Target* target,
27                                      std::ostream& out)
28     : settings_(target->settings()),
29       target_(target),
30       out_(out),
31       path_output_(settings_->build_settings()->build_dir(), ESCAPE_NINJA) {
32 }
33
34 NinjaTargetWriter::~NinjaTargetWriter() {
35 }
36
37 // static
38 void NinjaTargetWriter::RunAndWriteFile(const Target* target) {
39   const Settings* settings = target->settings();
40
41   ScopedTrace trace(TraceItem::TRACE_FILE_WRITE,
42                     target->label().GetUserVisibleName(false));
43   trace.SetToolchain(settings->toolchain_label());
44
45   base::FilePath ninja_file(settings->build_settings()->GetFullPath(
46       GetNinjaFileForTarget(target)));
47
48   if (g_scheduler->verbose_logging())
49     g_scheduler->Log("Writing", FilePathToUTF8(ninja_file));
50
51   base::CreateDirectory(ninja_file.DirName());
52
53   // It's rediculously faster to write to a string and then write that to
54   // disk in one operation than to use an fstream here.
55   std::stringstream file;
56
57   // Call out to the correct sub-type of writer.
58   if (target->output_type() == Target::COPY_FILES) {
59     NinjaCopyTargetWriter writer(target, file);
60     writer.Run();
61   } else if (target->output_type() == Target::ACTION ||
62              target->output_type() == Target::ACTION_FOREACH) {
63     NinjaActionTargetWriter writer(target, file);
64     writer.Run();
65   } else if (target->output_type() == Target::GROUP) {
66     NinjaGroupTargetWriter writer(target, file);
67     writer.Run();
68   } else if (target->output_type() == Target::EXECUTABLE ||
69              target->output_type() == Target::STATIC_LIBRARY ||
70              target->output_type() == Target::SHARED_LIBRARY ||
71              target->output_type() == Target::SOURCE_SET) {
72     NinjaBinaryTargetWriter writer(target, file);
73     writer.Run();
74   } else {
75     CHECK(0);
76   }
77
78   std::string contents = file.str();
79   base::WriteFile(ninja_file, contents.c_str(),
80                   static_cast<int>(contents.size()));
81 }
82
83 void NinjaTargetWriter::WriteSharedVars(const SubstitutionBits& bits) {
84   bool written_anything = false;
85
86   // Target label.
87   if (bits.used[SUBSTITUTION_LABEL]) {
88     out_ << kSubstitutionNinjaNames[SUBSTITUTION_LABEL] << " = "
89          << SubstitutionWriter::GetTargetSubstitution(
90                 target_, SUBSTITUTION_LABEL)
91          << std::endl;
92     written_anything = true;
93   }
94
95   // Root gen dir.
96   if (bits.used[SUBSTITUTION_ROOT_GEN_DIR]) {
97     out_ << kSubstitutionNinjaNames[SUBSTITUTION_ROOT_GEN_DIR] << " = "
98          << SubstitutionWriter::GetTargetSubstitution(
99                 target_, SUBSTITUTION_ROOT_GEN_DIR)
100          << std::endl;
101     written_anything = true;
102   }
103
104   // Root out dir.
105   if (bits.used[SUBSTITUTION_ROOT_OUT_DIR]) {
106     out_ << kSubstitutionNinjaNames[SUBSTITUTION_ROOT_OUT_DIR] << " = "
107          << SubstitutionWriter::GetTargetSubstitution(
108                 target_, SUBSTITUTION_ROOT_OUT_DIR)
109          << std::endl;
110     written_anything = true;
111   }
112
113   // Target gen dir.
114   if (bits.used[SUBSTITUTION_TARGET_GEN_DIR]) {
115     out_ << kSubstitutionNinjaNames[SUBSTITUTION_TARGET_GEN_DIR] << " = "
116          << SubstitutionWriter::GetTargetSubstitution(
117                 target_, SUBSTITUTION_TARGET_GEN_DIR)
118          << std::endl;
119     written_anything = true;
120   }
121
122   // Target out dir.
123   if (bits.used[SUBSTITUTION_TARGET_OUT_DIR]) {
124     out_ << kSubstitutionNinjaNames[SUBSTITUTION_TARGET_OUT_DIR] << " = "
125          << SubstitutionWriter::GetTargetSubstitution(
126                 target_, SUBSTITUTION_TARGET_OUT_DIR)
127          << std::endl;
128     written_anything = true;
129   }
130
131   // Target output name.
132   if (bits.used[SUBSTITUTION_TARGET_OUTPUT_NAME]) {
133     out_ << kSubstitutionNinjaNames[SUBSTITUTION_TARGET_OUTPUT_NAME] << " = "
134          << SubstitutionWriter::GetTargetSubstitution(
135                 target_, SUBSTITUTION_TARGET_OUTPUT_NAME)
136          << std::endl;
137     written_anything = true;
138   }
139
140   // If we wrote any vars, separate them from the rest of the file that follows
141   // with a blank line.
142   if (written_anything)
143     out_ << std::endl;
144 }
145
146 OutputFile NinjaTargetWriter::WriteInputDepsStampAndGetDep(
147     const std::vector<const Target*>& extra_hard_deps) const {
148   CHECK(target_->toolchain())
149       << "Toolchain not set on target "
150       << target_->label().GetUserVisibleName(true);
151
152   // For an action (where we run a script only once) the sources are the same
153   // as the source prereqs.
154   bool list_sources_as_input_deps = (target_->output_type() == Target::ACTION);
155
156   // Actions get implicit dependencies on the script itself.
157   bool add_script_source_as_dep =
158       (target_->output_type() == Target::ACTION) ||
159       (target_->output_type() == Target::ACTION_FOREACH);
160
161   if (!add_script_source_as_dep &&
162       extra_hard_deps.empty() &&
163       target_->inputs().empty() &&
164       target_->recursive_hard_deps().empty() &&
165       (!list_sources_as_input_deps || target_->sources().empty()) &&
166       target_->toolchain()->deps().empty())
167     return OutputFile();  // No input/hard deps.
168
169   // One potential optimization is if there are few input dependencies (or
170   // potentially few sources that depend on these) it's better to just write
171   // all hard deps on each sources line than have this intermediate stamp. We
172   // do the stamp file because duplicating all the order-only deps for each
173   // source file can really explode the ninja file but this won't be the most
174   // optimal thing in all cases.
175
176   OutputFile input_stamp_file(
177       RebaseSourceAbsolutePath(GetTargetOutputDir(target_).value(),
178                                settings_->build_settings()->build_dir()));
179   input_stamp_file.value().append(target_->label().name());
180   input_stamp_file.value().append(".inputdeps.stamp");
181
182   out_ << "build ";
183   path_output_.WriteFile(out_, input_stamp_file);
184   out_ << ": "
185        << GetNinjaRulePrefixForToolchain(settings_)
186        << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
187
188   // Script file (if applicable).
189   if (add_script_source_as_dep) {
190     out_ << " ";
191     path_output_.WriteFile(out_, target_->action_values().script());
192   }
193
194   // Input files are order-only deps.
195   const Target::FileList& prereqs = target_->inputs();
196   for (size_t i = 0; i < prereqs.size(); i++) {
197     out_ << " ";
198     path_output_.WriteFile(out_, prereqs[i]);
199   }
200   if (list_sources_as_input_deps) {
201     const Target::FileList& sources = target_->sources();
202     for (size_t i = 0; i < sources.size(); i++) {
203       out_ << " ";
204       path_output_.WriteFile(out_, sources[i]);
205     }
206   }
207
208   // The different souces of input deps may duplicate some targets, so uniquify
209   // them (ordering doesn't matter for this case).
210   std::set<const Target*> unique_deps;
211
212   // Hard dependencies that are direct or indirect dependencies.
213   const std::set<const Target*>& hard_deps = target_->recursive_hard_deps();
214   for (std::set<const Target*>::const_iterator i = hard_deps.begin();
215        i != hard_deps.end(); ++i) {
216     unique_deps.insert(*i);
217   }
218
219   // Extra hard dependencies passed in.
220   unique_deps.insert(extra_hard_deps.begin(), extra_hard_deps.end());
221
222   // Toolchain dependencies. These must be resolved before doing anything.
223   // This just writs all toolchain deps for simplicity. If we find that
224   // toolchains often have more than one dependency, we could consider writing
225   // a toolchain-specific stamp file and only include the stamp here.
226   const LabelTargetVector& toolchain_deps = target_->toolchain()->deps();
227   for (size_t i = 0; i < toolchain_deps.size(); i++)
228     unique_deps.insert(toolchain_deps[i].ptr);
229
230   for (std::set<const Target*>::const_iterator i = unique_deps.begin();
231        i != unique_deps.end(); ++i) {
232     DCHECK(!(*i)->dependency_output_file().value().empty());
233     out_ << " ";
234     path_output_.WriteFile(out_, (*i)->dependency_output_file());
235   }
236
237   out_ << "\n";
238   return input_stamp_file;
239 }
240
241 void NinjaTargetWriter::WriteStampForTarget(
242     const std::vector<OutputFile>& files,
243     const std::vector<OutputFile>& order_only_deps) {
244   const OutputFile& stamp_file = target_->dependency_output_file();
245
246   // First validate that the target's dependency is a stamp file. Otherwise,
247   // we shouldn't have gotten here!
248   CHECK(EndsWith(stamp_file.value(), ".stamp", false))
249       << "Output should end in \".stamp\" for stamp file output. Instead got: "
250       << "\"" << stamp_file.value() << "\"";
251
252   out_ << "build ";
253   path_output_.WriteFile(out_, stamp_file);
254
255   out_ << ": "
256        << GetNinjaRulePrefixForToolchain(settings_)
257        << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
258   path_output_.WriteFiles(out_, files);
259
260   if (!order_only_deps.empty()) {
261     out_ << " ||";
262     path_output_.WriteFiles(out_, order_only_deps);
263   }
264   out_ << std::endl;
265 }