Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / gn / ninja_binary_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_binary_target_writer.h"
6
7 #include <set>
8 #include <sstream>
9
10 #include "base/strings/string_util.h"
11 #include "tools/gn/config_values_extractors.h"
12 #include "tools/gn/deps_iterator.h"
13 #include "tools/gn/err.h"
14 #include "tools/gn/escape.h"
15 #include "tools/gn/ninja_utils.h"
16 #include "tools/gn/settings.h"
17 #include "tools/gn/string_utils.h"
18 #include "tools/gn/substitution_writer.h"
19 #include "tools/gn/target.h"
20
21 namespace {
22
23 // Returns the proper escape options for writing compiler and linker flags.
24 EscapeOptions GetFlagOptions() {
25   EscapeOptions opts;
26   opts.mode = ESCAPE_NINJA_COMMAND;
27
28   // Some flag strings are actually multiple flags that expect to be just
29   // added to the command line. We assume that quoting is done by the
30   // buildfiles if it wants such things quoted.
31   opts.inhibit_quoting = true;
32
33   return opts;
34 }
35
36 struct DefineWriter {
37   DefineWriter() {
38     options.mode = ESCAPE_NINJA_COMMAND;
39   }
40
41   void operator()(const std::string& s, std::ostream& out) const {
42     out << " -D";
43     EscapeStringToStream(out, s, options);
44   }
45
46   EscapeOptions options;
47 };
48
49 struct IncludeWriter {
50   IncludeWriter(PathOutput& path_output) : path_output_(path_output) {
51   }
52   ~IncludeWriter() {
53   }
54
55   void operator()(const SourceDir& d, std::ostream& out) const {
56     std::ostringstream path_out;
57     path_output_.WriteDir(path_out, d, PathOutput::DIR_NO_LAST_SLASH);
58     const std::string& path = path_out.str();
59     if (path[0] == '"')
60       out << " \"-I" << path.substr(1);
61     else
62       out << " -I" << path;
63   }
64
65   PathOutput& path_output_;
66 };
67
68 }  // namespace
69
70 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target,
71                                                  std::ostream& out)
72     : NinjaTargetWriter(target, out),
73       tool_(target->toolchain()->GetToolForTargetFinalOutput(target)) {
74 }
75
76 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
77 }
78
79 void NinjaBinaryTargetWriter::Run() {
80   WriteCompilerVars();
81
82   std::vector<OutputFile> obj_files;
83   WriteSources(&obj_files);
84
85   if (target_->output_type() == Target::SOURCE_SET)
86     WriteSourceSetStamp(obj_files);
87   else
88     WriteLinkerStuff(obj_files);
89 }
90
91 void NinjaBinaryTargetWriter::WriteCompilerVars() {
92   const SubstitutionBits& subst = target_->toolchain()->substitution_bits();
93
94   // Defines.
95   if (subst.used[SUBSTITUTION_DEFINES]) {
96     out_ << kSubstitutionNinjaNames[SUBSTITUTION_DEFINES] << " =";
97     RecursiveTargetConfigToStream<std::string>(
98         target_, &ConfigValues::defines, DefineWriter(), out_);
99     out_ << std::endl;
100   }
101
102   // Include directories.
103   if (subst.used[SUBSTITUTION_INCLUDE_DIRS]) {
104     out_ << kSubstitutionNinjaNames[SUBSTITUTION_INCLUDE_DIRS] << " =";
105     PathOutput include_path_output(path_output_.current_dir(),
106                                    ESCAPE_NINJA_COMMAND);
107     RecursiveTargetConfigToStream<SourceDir>(
108         target_, &ConfigValues::include_dirs,
109         IncludeWriter(include_path_output), out_);
110     out_ << std::endl;
111   }
112
113   // C flags and friends.
114   EscapeOptions flag_escape_options = GetFlagOptions();
115 #define WRITE_FLAGS(name, subst_enum) \
116     if (subst.used[subst_enum]) { \
117       out_ << kSubstitutionNinjaNames[subst_enum] << " ="; \
118       RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \
119                                            flag_escape_options, out_); \
120       out_ << std::endl; \
121     }
122
123   WRITE_FLAGS(cflags, SUBSTITUTION_CFLAGS)
124   WRITE_FLAGS(cflags_c, SUBSTITUTION_CFLAGS_C)
125   WRITE_FLAGS(cflags_cc, SUBSTITUTION_CFLAGS_CC)
126   WRITE_FLAGS(cflags_objc, SUBSTITUTION_CFLAGS_OBJC)
127   WRITE_FLAGS(cflags_objcc, SUBSTITUTION_CFLAGS_OBJCC)
128
129 #undef WRITE_FLAGS
130
131   WriteSharedVars(subst);
132 }
133
134 void NinjaBinaryTargetWriter::WriteSources(
135     std::vector<OutputFile>* object_files) {
136   object_files->reserve(target_->sources().size());
137
138   OutputFile input_dep =
139       WriteInputDepsStampAndGetDep(std::vector<const Target*>());
140
141   std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_);
142
143   std::vector<OutputFile> tool_outputs;  // Prevent reallocation in loop.
144   for (const auto& source : target_->sources()) {
145     Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
146     if (!GetOutputFilesForSource(target_, source,
147                                  &tool_type, &tool_outputs))
148       continue;  // No output for this source.
149
150     if (tool_type != Toolchain::TYPE_NONE) {
151       out_ << "build";
152       path_output_.WriteFiles(out_, tool_outputs);
153       out_ << ": " << rule_prefix << Toolchain::ToolTypeToName(tool_type);
154       out_ << " ";
155       path_output_.WriteFile(out_, source);
156       if (!input_dep.value().empty()) {
157         // Write out the input dependencies as an order-only dependency. This
158         // will cause Ninja to make sure the inputs are up-to-date before
159         // compiling this source, but changes in the inputs deps won't cause
160         // the file to be recompiled.
161         //
162         // This is important to prevent changes in unrelated actions that
163         // are upstream of this target from causing everything to be recompiled.
164         //
165         // Why can we get away with this rather than using implicit deps ("|",
166         // which will force rebuilds when the inputs change)?  For source code,
167         // the computed dependencies of all headers will be computed by the
168         // compiler, which will cause source rebuilds if any "real" upstream
169         // dependencies change.
170         //
171         // If a .cc file is generated by an input dependency, Ninja will see
172         // the input to the build rule doesn't exist, and that it is an output
173         // from a previous step, and build the previous step first.  This is a
174         // "real" dependency and doesn't need | or || to express.
175         //
176         // The only case where this rule matters is for the first build where
177         // no .d files exist, and Ninja doesn't know what that source file
178         // depends on. In this case it's sufficient to ensure that the upstream
179         // dependencies are built first. This is exactly what Ninja's order-
180         // only dependencies expresses.
181         out_ << " || ";
182         path_output_.WriteFile(out_, input_dep);
183       }
184       out_ << std::endl;
185     }
186
187     // It's theoretically possible for a compiler to produce more than one
188     // output, but we'll only link to the first output.
189     object_files->push_back(tool_outputs[0]);
190   }
191   out_ << std::endl;
192 }
193
194 void NinjaBinaryTargetWriter::WriteLinkerStuff(
195     const std::vector<OutputFile>& object_files) {
196   std::vector<OutputFile> output_files;
197   SubstitutionWriter::ApplyListToLinkerAsOutputFile(
198       target_, tool_, tool_->outputs(), &output_files);
199
200   out_ << "build";
201   path_output_.WriteFiles(out_, output_files);
202
203   out_ << ": "
204        << GetNinjaRulePrefixForToolchain(settings_)
205        << Toolchain::ToolTypeToName(
206               target_->toolchain()->GetToolTypeForTargetFinalOutput(target_));
207
208   UniqueVector<OutputFile> extra_object_files;
209   UniqueVector<const Target*> linkable_deps;
210   UniqueVector<const Target*> non_linkable_deps;
211   GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
212
213   // Object files.
214   for (const auto& obj : object_files) {
215     out_ << " ";
216     path_output_.WriteFile(out_, obj);
217   }
218   for (const auto& obj : extra_object_files) {
219     out_ << " ";
220     path_output_.WriteFile(out_, obj);
221   }
222
223   std::vector<OutputFile> implicit_deps;
224   std::vector<OutputFile> solibs;
225
226   for (const Target* cur : linkable_deps) {
227     // All linkable deps should have a link output file.
228     DCHECK(!cur->link_output_file().value().empty())
229         << "No link output file for "
230         << target_->label().GetUserVisibleName(false);
231
232     if (cur->dependency_output_file().value() !=
233         cur->link_output_file().value()) {
234       // This is a shared library with separate link and deps files. Save for
235       // later.
236       implicit_deps.push_back(cur->dependency_output_file());
237       solibs.push_back(cur->link_output_file());
238     } else {
239       // Normal case, just link to this target.
240       out_ << " ";
241       path_output_.WriteFile(out_, cur->link_output_file());
242     }
243   }
244
245   // Append implicit dependencies collected above.
246   if (!implicit_deps.empty()) {
247     out_ << " |";
248     path_output_.WriteFiles(out_, implicit_deps);
249   }
250
251   // Append data dependencies as order-only dependencies.
252   //
253   // This will include data dependencies and input dependencies (like when
254   // this target depends on an action). Having the data dependencies in this
255   // list ensures that the data is available at runtime when the user builds
256   // this target.
257   //
258   // The action dependencies are not strictly necessary in this case. They
259   // should also have been collected via the input deps stamp that each source
260   // file has for an order-only dependency, and since this target depends on
261   // the sources, there is already an implicit order-only dependency. However,
262   // it's extra work to separate these out and there's no disadvantage to
263   // listing them again.
264   WriteOrderOnlyDependencies(non_linkable_deps);
265
266   // End of the link "build" line.
267   out_ << std::endl;
268
269   // These go in the inner scope of the link line.
270   WriteLinkerFlags();
271   WriteLibs();
272   WriteOutputExtension();
273   WriteSolibs(solibs);
274 }
275
276 void NinjaBinaryTargetWriter::WriteLinkerFlags() {
277   out_ << "  ldflags =";
278
279   // First the ldflags from the target and its config.
280   EscapeOptions flag_options = GetFlagOptions();
281   RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags,
282                                        flag_options, out_);
283
284   // Followed by library search paths that have been recursively pushed
285   // through the dependency tree.
286   const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs();
287   if (!all_lib_dirs.empty()) {
288     // Since we're passing these on the command line to the linker and not
289     // to Ninja, we need to do shell escaping.
290     PathOutput lib_path_output(path_output_.current_dir(),
291                                ESCAPE_NINJA_COMMAND);
292     for (size_t i = 0; i < all_lib_dirs.size(); i++) {
293       out_ << " " << tool_->lib_dir_switch();
294       lib_path_output.WriteDir(out_, all_lib_dirs[i],
295                                PathOutput::DIR_NO_LAST_SLASH);
296     }
297   }
298   out_ << std::endl;
299 }
300
301 void NinjaBinaryTargetWriter::WriteLibs() {
302   out_ << "  libs =";
303
304   // Libraries that have been recursively pushed through the dependency tree.
305   EscapeOptions lib_escape_opts;
306   lib_escape_opts.mode = ESCAPE_NINJA_COMMAND;
307   const OrderedSet<std::string> all_libs = target_->all_libs();
308   const std::string framework_ending(".framework");
309   for (size_t i = 0; i < all_libs.size(); i++) {
310     if (settings_->IsMac() && EndsWith(all_libs[i], framework_ending, false)) {
311       // Special-case libraries ending in ".framework" on Mac. Add the
312       // -framework switch and don't add the extension to the output.
313       out_ << " -framework ";
314       EscapeStringToStream(out_,
315           all_libs[i].substr(0, all_libs[i].size() - framework_ending.size()),
316           lib_escape_opts);
317     } else {
318       out_ << " " << tool_->lib_switch();
319       EscapeStringToStream(out_, all_libs[i], lib_escape_opts);
320     }
321   }
322   out_ << std::endl;
323 }
324
325 void NinjaBinaryTargetWriter::WriteOutputExtension() {
326   out_ << "  output_extension = ";
327   if (target_->output_extension().empty()) {
328     // Use the default from the tool.
329     out_ << tool_->default_output_extension();
330   } else {
331     // Use the one specified in the target. Note that the one in the target
332     // does not include the leading dot, so add that.
333     out_ << "." << target_->output_extension();
334   }
335   out_ << std::endl;
336 }
337
338 void NinjaBinaryTargetWriter::WriteSolibs(
339     const std::vector<OutputFile>& solibs) {
340   if (solibs.empty())
341     return;
342
343   out_ << "  solibs =";
344   path_output_.WriteFiles(out_, solibs);
345   out_ << std::endl;
346 }
347
348 void NinjaBinaryTargetWriter::WriteSourceSetStamp(
349     const std::vector<OutputFile>& object_files) {
350   // The stamp rule for source sets is generally not used, since targets that
351   // depend on this will reference the object files directly. However, writing
352   // this rule allows the user to type the name of the target and get a build
353   // which can be convenient for development.
354   UniqueVector<OutputFile> extra_object_files;
355   UniqueVector<const Target*> linkable_deps;
356   UniqueVector<const Target*> non_linkable_deps;
357   GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
358
359   // The classifier should never put extra object files in a source set:
360   // any source sets that we depend on should appear in our non-linkable
361   // deps instead.
362   DCHECK(extra_object_files.empty());
363
364   std::vector<OutputFile> order_only_deps;
365   for (const auto& dep : non_linkable_deps)
366     order_only_deps.push_back(dep->dependency_output_file());
367
368   WriteStampForTarget(object_files, order_only_deps);
369 }
370
371 void NinjaBinaryTargetWriter::GetDeps(
372     UniqueVector<OutputFile>* extra_object_files,
373     UniqueVector<const Target*>* linkable_deps,
374     UniqueVector<const Target*>* non_linkable_deps) const {
375   // Normal public/private deps.
376   for (const auto& pair : target_->GetDeps(Target::DEPS_LINKED)) {
377     ClassifyDependency(pair.ptr, extra_object_files,
378                        linkable_deps, non_linkable_deps);
379   }
380
381   // Inherited libraries.
382   for (const auto& inherited_target : target_->inherited_libraries()) {
383     ClassifyDependency(inherited_target, extra_object_files,
384                        linkable_deps, non_linkable_deps);
385   }
386
387   // Data deps.
388   for (const auto& data_dep_pair : target_->data_deps())
389     non_linkable_deps->push_back(data_dep_pair.ptr);
390 }
391
392 void NinjaBinaryTargetWriter::ClassifyDependency(
393     const Target* dep,
394     UniqueVector<OutputFile>* extra_object_files,
395     UniqueVector<const Target*>* linkable_deps,
396     UniqueVector<const Target*>* non_linkable_deps) const {
397   // Only the following types of outputs have libraries linked into them:
398   //  EXECUTABLE
399   //  SHARED_LIBRARY
400   //  _complete_ STATIC_LIBRARY
401   //
402   // Child deps of intermediate static libraries get pushed up the
403   // dependency tree until one of these is reached, and source sets
404   // don't link at all.
405   bool can_link_libs = target_->IsFinal();
406
407   if (dep->output_type() == Target::SOURCE_SET) {
408     // Source sets have their object files linked into final targets
409     // (shared libraries, executables, and complete static
410     // libraries). Intermediate static libraries and other source sets
411     // just forward the dependency, otherwise the files in the source
412     // set can easily get linked more than once which will cause
413     // multiple definition errors.
414     if (can_link_libs) {
415       // Linking in a source set to an executable, shared library, or
416       // complete static library, so copy its object files.
417       std::vector<OutputFile> tool_outputs;  // Prevent allocation in loop.
418       for (const auto& source : dep->sources()) {
419         Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
420         if (GetOutputFilesForSource(dep, source, &tool_type, &tool_outputs)) {
421           // Only link the first output if there are more than one.
422           extra_object_files->push_back(tool_outputs[0]);
423         }
424       }
425     }
426   } else if (can_link_libs && dep->IsLinkable()) {
427     linkable_deps->push_back(dep);
428   } else {
429     non_linkable_deps->push_back(dep);
430   }
431 }
432
433 void NinjaBinaryTargetWriter::WriteOrderOnlyDependencies(
434     const UniqueVector<const Target*>& non_linkable_deps) {
435   const std::vector<SourceFile>& data = target_->data();
436   if (!non_linkable_deps.empty() || !data.empty()) {
437     out_ << " ||";
438
439     // Non-linkable targets.
440     for (size_t i = 0; i < non_linkable_deps.size(); i++) {
441       out_ << " ";
442       path_output_.WriteFile(
443           out_, non_linkable_deps[i]->dependency_output_file());
444     }
445   }
446 }
447
448 bool NinjaBinaryTargetWriter::GetOutputFilesForSource(
449     const Target* target,
450     const SourceFile& source,
451     Toolchain::ToolType* computed_tool_type,
452     std::vector<OutputFile>* outputs) const {
453   outputs->clear();
454   *computed_tool_type = Toolchain::TYPE_NONE;
455
456   SourceFileType file_type = GetSourceFileType(source);
457   if (file_type == SOURCE_UNKNOWN)
458     return false;
459   if (file_type == SOURCE_O) {
460     // Object files just get passed to the output and not compiled.
461     outputs->push_back(OutputFile(settings_->build_settings(), source));
462     return true;
463   }
464
465   *computed_tool_type =
466       target->toolchain()->GetToolTypeForSourceType(file_type);
467   if (*computed_tool_type == Toolchain::TYPE_NONE)
468     return false;  // No tool for this file (it's a header file or something).
469   const Tool* tool = target->toolchain()->GetTool(*computed_tool_type);
470   if (!tool)
471     return false;  // Tool does not apply for this toolchain.file.
472
473   // Figure out what output(s) this compiler produces.
474   SubstitutionWriter::ApplyListToCompilerAsOutputFile(
475       target, source, tool->outputs(), outputs);
476   return !outputs->empty();
477 }