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
21namespace {
22
23// Returns the proper escape options for writing compiler and linker flags.
24EscapeOptions 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
36struct 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
49struct 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
70NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target,
71                                                 std::ostream& out)
72    : NinjaTargetWriter(target, out),
73      tool_(target->toolchain()->GetToolForTargetFinalOutput(target)) {
74}
75
76NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
77}
78
79void 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
91void 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
134void NinjaBinaryTargetWriter::WriteSources(
135    std::vector<OutputFile>* object_files) {
136  const Target::FileList& sources = target_->sources();
137  object_files->reserve(sources.size());
138
139  OutputFile input_dep =
140      WriteInputDepsStampAndGetDep(std::vector<const Target*>());
141
142  std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_);
143
144  std::vector<OutputFile> tool_outputs;  // Prevent reallocation in loop.
145  for (size_t i = 0; i < sources.size(); i++) {
146    Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
147    if (!GetOutputFilesForSource(target_, sources[i],
148                                 &tool_type, &tool_outputs))
149      continue;  // No output for this source.
150
151    if (tool_type != Toolchain::TYPE_NONE) {
152      out_ << "build";
153      path_output_.WriteFiles(out_, tool_outputs);
154      out_ << ": " << rule_prefix << Toolchain::ToolTypeToName(tool_type);
155      out_ << " ";
156      path_output_.WriteFile(out_, sources[i]);
157      if (!input_dep.value().empty()) {
158        // Write out the input dependencies as an order-only dependency. This
159        // will cause Ninja to make sure the inputs are up-to-date before
160        // compiling this source, but changes in the inputs deps won't cause
161        // the file to be recompiled.
162        //
163        // This is important to prevent changes in unrelated actions that
164        // are upstream of this target from causing everything to be recompiled.
165        //
166        // Why can we get away with this rather than using implicit deps ("|",
167        // which will force rebuilds when the inputs change)?  For source code,
168        // the computed dependencies of all headers will be computed by the
169        // compiler, which will cause source rebuilds if any "real" upstream
170        // dependencies change.
171        //
172        // If a .cc file is generated by an input dependency, Ninja will see
173        // the input to the build rule doesn't exist, and that it is an output
174        // from a previous step, and build the previous step first.  This is a
175        // "real" dependency and doesn't need | or || to express.
176        //
177        // The only case where this rule matters is for the first build where
178        // no .d files exist, and Ninja doesn't know what that source file
179        // depends on. In this case it's sufficient to ensure that the upstream
180        // dependencies are built first. This is exactly what Ninja's order-
181        // only dependencies expresses.
182        out_ << " || ";
183        path_output_.WriteFile(out_, input_dep);
184      }
185      out_ << std::endl;
186    }
187
188    // It's theoretically possible for a compiler to produce more than one
189    // output, but we'll only link to the first output.
190    object_files->push_back(tool_outputs[0]);
191  }
192  out_ << std::endl;
193}
194
195void NinjaBinaryTargetWriter::WriteLinkerStuff(
196    const std::vector<OutputFile>& object_files) {
197  std::vector<OutputFile> output_files;
198  SubstitutionWriter::ApplyListToLinkerAsOutputFile(
199      target_, tool_, tool_->outputs(), &output_files);
200
201  out_ << "build";
202  path_output_.WriteFiles(out_, output_files);
203
204  out_ << ": "
205       << GetNinjaRulePrefixForToolchain(settings_)
206       << Toolchain::ToolTypeToName(
207              target_->toolchain()->GetToolTypeForTargetFinalOutput(target_));
208
209  UniqueVector<OutputFile> extra_object_files;
210  UniqueVector<const Target*> linkable_deps;
211  UniqueVector<const Target*> non_linkable_deps;
212  GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
213
214  // Object files.
215  for (size_t i = 0; i < object_files.size(); i++) {
216    out_ << " ";
217    path_output_.WriteFile(out_, object_files[i]);
218  }
219  for (size_t i = 0; i < extra_object_files.size(); i++) {
220    out_ << " ";
221    path_output_.WriteFile(out_, extra_object_files[i]);
222  }
223
224  std::vector<OutputFile> implicit_deps;
225  std::vector<OutputFile> solibs;
226
227  for (size_t i = 0; i < linkable_deps.size(); i++) {
228    const Target* cur = linkable_deps[i];
229
230    // All linkable deps should have a link output file.
231    DCHECK(!cur->link_output_file().value().empty())
232        << "No link output file for "
233        << target_->label().GetUserVisibleName(false);
234
235    if (cur->dependency_output_file().value() !=
236        cur->link_output_file().value()) {
237      // This is a shared library with separate link and deps files. Save for
238      // later.
239      implicit_deps.push_back(cur->dependency_output_file());
240      solibs.push_back(cur->link_output_file());
241    } else {
242      // Normal case, just link to this target.
243      out_ << " ";
244      path_output_.WriteFile(out_, cur->link_output_file());
245    }
246  }
247
248  // Append implicit dependencies collected above.
249  if (!implicit_deps.empty()) {
250    out_ << " |";
251    path_output_.WriteFiles(out_, implicit_deps);
252  }
253
254  // Append data dependencies as order-only dependencies.
255  //
256  // This will include data dependencies and input dependencies (like when
257  // this target depends on an action). Having the data dependencies in this
258  // list ensures that the data is available at runtime when the user builds
259  // this target.
260  //
261  // The action dependencies are not strictly necessary in this case. They
262  // should also have been collected via the input deps stamp that each source
263  // file has for an order-only dependency, and since this target depends on
264  // the sources, there is already an implicit order-only dependency. However,
265  // it's extra work to separate these out and there's no disadvantage to
266  // listing them again.
267  WriteOrderOnlyDependencies(non_linkable_deps);
268
269  // End of the link "build" line.
270  out_ << std::endl;
271
272  // These go in the inner scope of the link line.
273  WriteLinkerFlags();
274  WriteLibs();
275  WriteOutputExtension();
276  WriteSolibs(solibs);
277}
278
279void NinjaBinaryTargetWriter::WriteLinkerFlags() {
280  out_ << "  ldflags =";
281
282  // First the ldflags from the target and its config.
283  EscapeOptions flag_options = GetFlagOptions();
284  RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags,
285                                       flag_options, out_);
286
287  // Followed by library search paths that have been recursively pushed
288  // through the dependency tree.
289  const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs();
290  if (!all_lib_dirs.empty()) {
291    // Since we're passing these on the command line to the linker and not
292    // to Ninja, we need to do shell escaping.
293    PathOutput lib_path_output(path_output_.current_dir(),
294                               ESCAPE_NINJA_COMMAND);
295    for (size_t i = 0; i < all_lib_dirs.size(); i++) {
296      out_ << " " << tool_->lib_dir_switch();
297      lib_path_output.WriteDir(out_, all_lib_dirs[i],
298                               PathOutput::DIR_NO_LAST_SLASH);
299    }
300  }
301  out_ << std::endl;
302}
303
304void NinjaBinaryTargetWriter::WriteLibs() {
305  out_ << "  libs =";
306
307  // Libraries that have been recursively pushed through the dependency tree.
308  EscapeOptions lib_escape_opts;
309  lib_escape_opts.mode = ESCAPE_NINJA_COMMAND;
310  const OrderedSet<std::string> all_libs = target_->all_libs();
311  const std::string framework_ending(".framework");
312  for (size_t i = 0; i < all_libs.size(); i++) {
313    if (settings_->IsMac() && EndsWith(all_libs[i], framework_ending, false)) {
314      // Special-case libraries ending in ".framework" on Mac. Add the
315      // -framework switch and don't add the extension to the output.
316      out_ << " -framework ";
317      EscapeStringToStream(out_,
318          all_libs[i].substr(0, all_libs[i].size() - framework_ending.size()),
319          lib_escape_opts);
320    } else {
321      out_ << " " << tool_->lib_switch();
322      EscapeStringToStream(out_, all_libs[i], lib_escape_opts);
323    }
324  }
325  out_ << std::endl;
326}
327
328void NinjaBinaryTargetWriter::WriteOutputExtension() {
329  out_ << "  output_extension = ";
330  if (target_->output_extension().empty()) {
331    // Use the default from the tool.
332    out_ << tool_->default_output_extension();
333  } else {
334    // Use the one specified in the target. Note that the one in the target
335    // does not include the leading dot, so add that.
336    out_ << "." << target_->output_extension();
337  }
338  out_ << std::endl;
339}
340
341void NinjaBinaryTargetWriter::WriteSolibs(
342    const std::vector<OutputFile>& solibs) {
343  if (solibs.empty())
344    return;
345
346  out_ << "  solibs =";
347  path_output_.WriteFiles(out_, solibs);
348  out_ << std::endl;
349}
350
351void NinjaBinaryTargetWriter::WriteSourceSetStamp(
352    const std::vector<OutputFile>& object_files) {
353  // The stamp rule for source sets is generally not used, since targets that
354  // depend on this will reference the object files directly. However, writing
355  // this rule allows the user to type the name of the target and get a build
356  // which can be convenient for development.
357  UniqueVector<OutputFile> extra_object_files;
358  UniqueVector<const Target*> linkable_deps;
359  UniqueVector<const Target*> non_linkable_deps;
360  GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
361
362  // The classifier should never put extra object files in a source set:
363  // any source sets that we depend on should appear in our non-linkable
364  // deps instead.
365  DCHECK(extra_object_files.empty());
366
367  std::vector<OutputFile> order_only_deps;
368  for (size_t i = 0; i < non_linkable_deps.size(); i++)
369    order_only_deps.push_back(non_linkable_deps[i]->dependency_output_file());
370
371  WriteStampForTarget(object_files, order_only_deps);
372}
373
374void NinjaBinaryTargetWriter::GetDeps(
375    UniqueVector<OutputFile>* extra_object_files,
376    UniqueVector<const Target*>* linkable_deps,
377    UniqueVector<const Target*>* non_linkable_deps) const {
378  const UniqueVector<const Target*>& inherited =
379      target_->inherited_libraries();
380
381  // Normal public/private deps.
382  for (DepsIterator iter(target_, DepsIterator::LINKED_ONLY); !iter.done();
383       iter.Advance()) {
384    ClassifyDependency(iter.target(), extra_object_files,
385                       linkable_deps, non_linkable_deps);
386  }
387
388  // Inherited libraries.
389  for (size_t i = 0; i < inherited.size(); i++) {
390    ClassifyDependency(inherited[i], extra_object_files,
391                       linkable_deps, non_linkable_deps);
392  }
393
394  // Data deps.
395  const LabelTargetVector& data_deps = target_->data_deps();
396  for (size_t i = 0; i < data_deps.size(); i++)
397    non_linkable_deps->push_back(data_deps[i].ptr);
398}
399
400void NinjaBinaryTargetWriter::ClassifyDependency(
401    const Target* dep,
402    UniqueVector<OutputFile>* extra_object_files,
403    UniqueVector<const Target*>* linkable_deps,
404    UniqueVector<const Target*>* non_linkable_deps) const {
405  // Only the following types of outputs have libraries linked into them:
406  //  EXECUTABLE
407  //  SHARED_LIBRARY
408  //  _complete_ STATIC_LIBRARY
409  //
410  // Child deps of intermediate static libraries get pushed up the
411  // dependency tree until one of these is reached, and source sets
412  // don't link at all.
413  bool can_link_libs = target_->IsFinal();
414
415  if (dep->output_type() == Target::SOURCE_SET) {
416    // Source sets have their object files linked into final targets
417    // (shared libraries, executables, and complete static
418    // libraries). Intermediate static libraries and other source sets
419    // just forward the dependency, otherwise the files in the source
420    // set can easily get linked more than once which will cause
421    // multiple definition errors.
422    if (can_link_libs) {
423      // Linking in a source set to an executable, shared library, or
424      // complete static library, so copy its object files.
425      std::vector<OutputFile> tool_outputs;  // Prevent allocation in loop.
426      for (size_t i = 0; i < dep->sources().size(); i++) {
427        Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
428        if (GetOutputFilesForSource(dep, dep->sources()[i], &tool_type,
429                                    &tool_outputs)) {
430          // Only link the first output if there are more than one.
431          extra_object_files->push_back(tool_outputs[0]);
432        }
433      }
434    }
435  } else if (can_link_libs && dep->IsLinkable()) {
436    linkable_deps->push_back(dep);
437  } else {
438    non_linkable_deps->push_back(dep);
439  }
440}
441
442void NinjaBinaryTargetWriter::WriteOrderOnlyDependencies(
443    const UniqueVector<const Target*>& non_linkable_deps) {
444  const std::vector<SourceFile>& data = target_->data();
445  if (!non_linkable_deps.empty() || !data.empty()) {
446    out_ << " ||";
447
448    // Non-linkable targets.
449    for (size_t i = 0; i < non_linkable_deps.size(); i++) {
450      out_ << " ";
451      path_output_.WriteFile(
452          out_, non_linkable_deps[i]->dependency_output_file());
453    }
454  }
455}
456
457bool NinjaBinaryTargetWriter::GetOutputFilesForSource(
458    const Target* target,
459    const SourceFile& source,
460    Toolchain::ToolType* computed_tool_type,
461    std::vector<OutputFile>* outputs) const {
462  outputs->clear();
463  *computed_tool_type = Toolchain::TYPE_NONE;
464
465  SourceFileType file_type = GetSourceFileType(source);
466  if (file_type == SOURCE_UNKNOWN)
467    return false;
468  if (file_type == SOURCE_O) {
469    // Object files just get passed to the output and not compiled.
470    outputs->push_back(OutputFile(settings_->build_settings(), source));
471    return true;
472  }
473
474  *computed_tool_type =
475      target->toolchain()->GetToolTypeForSourceType(file_type);
476  if (*computed_tool_type == Toolchain::TYPE_NONE)
477    return false;  // No tool for this file (it's a header file or something).
478  const Tool* tool = target->toolchain()->GetTool(*computed_tool_type);
479  if (!tool)
480    return false;  // Tool does not apply for this toolchain.file.
481
482  // Figure out what output(s) this compiler produces.
483  SubstitutionWriter::ApplyListToCompilerAsOutputFile(
484      target, source, tool->outputs(), outputs);
485  return !outputs->empty();
486}
487