Mac: Only allow NSOpenGLContext displaying on the main display
[chromium-blink-merge.git] / tools / gn / ninja_binary_target_writer.cc
blob7a611dbdd015303ae21485dbf68f8218aeccc0cf
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.
5 #include "tools/gn/ninja_binary_target_writer.h"
7 #include <set>
8 #include <sstream>
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"
21 namespace {
23 // Returns the proper escape options for writing compiler and linker flags.
24 EscapeOptions GetFlagOptions() {
25 EscapeOptions opts;
26 opts.mode = ESCAPE_NINJA_COMMAND;
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;
33 return opts;
36 struct DefineWriter {
37 DefineWriter() {
38 options.mode = ESCAPE_NINJA_COMMAND;
41 void operator()(const std::string& s, std::ostream& out) const {
42 out << " -D";
43 EscapeStringToStream(out, s, options);
46 EscapeOptions options;
49 struct IncludeWriter {
50 explicit IncludeWriter(PathOutput& path_output) : path_output_(path_output) {
52 ~IncludeWriter() {
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;
65 PathOutput& path_output_;
68 } // namespace
70 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target,
71 std::ostream& out)
72 : NinjaTargetWriter(target, out),
73 tool_(target->toolchain()->GetToolForTargetFinalOutput(target)) {
76 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
79 void NinjaBinaryTargetWriter::Run() {
80 WriteCompilerVars();
82 std::vector<OutputFile> obj_files;
83 std::vector<SourceFile> other_files;
84 WriteSources(&obj_files, &other_files);
86 if (target_->output_type() == Target::SOURCE_SET)
87 WriteSourceSetStamp(obj_files);
88 else
89 WriteLinkerStuff(obj_files, other_files);
92 void NinjaBinaryTargetWriter::WriteCompilerVars() {
93 const SubstitutionBits& subst = target_->toolchain()->substitution_bits();
95 // Defines.
96 if (subst.used[SUBSTITUTION_DEFINES]) {
97 out_ << kSubstitutionNinjaNames[SUBSTITUTION_DEFINES] << " =";
98 RecursiveTargetConfigToStream<std::string>(
99 target_, &ConfigValues::defines, DefineWriter(), out_);
100 out_ << std::endl;
103 // Include directories.
104 if (subst.used[SUBSTITUTION_INCLUDE_DIRS]) {
105 out_ << kSubstitutionNinjaNames[SUBSTITUTION_INCLUDE_DIRS] << " =";
106 PathOutput include_path_output(
107 path_output_.current_dir(),
108 settings_->build_settings()->root_path_utf8(),
109 ESCAPE_NINJA_COMMAND);
110 RecursiveTargetConfigToStream<SourceDir>(
111 target_, &ConfigValues::include_dirs,
112 IncludeWriter(include_path_output), out_);
113 out_ << std::endl;
116 // C flags and friends.
117 EscapeOptions flag_escape_options = GetFlagOptions();
118 #define WRITE_FLAGS(name, subst_enum) \
119 if (subst.used[subst_enum]) { \
120 out_ << kSubstitutionNinjaNames[subst_enum] << " ="; \
121 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \
122 flag_escape_options, out_); \
123 out_ << std::endl; \
126 WRITE_FLAGS(cflags, SUBSTITUTION_CFLAGS)
127 WRITE_FLAGS(cflags_c, SUBSTITUTION_CFLAGS_C)
128 WRITE_FLAGS(cflags_cc, SUBSTITUTION_CFLAGS_CC)
129 WRITE_FLAGS(cflags_objc, SUBSTITUTION_CFLAGS_OBJC)
130 WRITE_FLAGS(cflags_objcc, SUBSTITUTION_CFLAGS_OBJCC)
132 #undef WRITE_FLAGS
134 WriteSharedVars(subst);
137 void NinjaBinaryTargetWriter::WriteSources(
138 std::vector<OutputFile>* object_files,
139 std::vector<SourceFile>* other_files) {
140 object_files->reserve(target_->sources().size());
142 OutputFile input_dep =
143 WriteInputDepsStampAndGetDep(std::vector<const Target*>());
145 std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_);
147 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop.
148 for (const auto& source : target_->sources()) {
149 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
150 if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) {
151 if (GetSourceFileType(source) == SOURCE_DEF)
152 other_files->push_back(source);
153 continue; // No output for this source.
156 if (tool_type != Toolchain::TYPE_NONE) {
157 out_ << "build";
158 path_output_.WriteFiles(out_, tool_outputs);
160 out_ << ": " << rule_prefix << Toolchain::ToolTypeToName(tool_type);
161 out_ << " ";
162 path_output_.WriteFile(out_, source);
163 if (!input_dep.value().empty()) {
164 // Write out the input dependencies as an order-only dependency. This
165 // will cause Ninja to make sure the inputs are up-to-date before
166 // compiling this source, but changes in the inputs deps won't cause
167 // the file to be recompiled.
169 // This is important to prevent changes in unrelated actions that
170 // are upstream of this target from causing everything to be recompiled.
172 // Why can we get away with this rather than using implicit deps ("|",
173 // which will force rebuilds when the inputs change)? For source code,
174 // the computed dependencies of all headers will be computed by the
175 // compiler, which will cause source rebuilds if any "real" upstream
176 // dependencies change.
178 // If a .cc file is generated by an input dependency, Ninja will see
179 // the input to the build rule doesn't exist, and that it is an output
180 // from a previous step, and build the previous step first. This is a
181 // "real" dependency and doesn't need | or || to express.
183 // The only case where this rule matters is for the first build where
184 // no .d files exist, and Ninja doesn't know what that source file
185 // depends on. In this case it's sufficient to ensure that the upstream
186 // dependencies are built first. This is exactly what Ninja's order-
187 // only dependencies expresses.
188 out_ << " || ";
189 path_output_.WriteFile(out_, input_dep);
191 out_ << std::endl;
194 // It's theoretically possible for a compiler to produce more than one
195 // output, but we'll only link to the first output.
196 object_files->push_back(tool_outputs[0]);
198 out_ << std::endl;
201 void NinjaBinaryTargetWriter::WriteLinkerStuff(
202 const std::vector<OutputFile>& object_files,
203 const std::vector<SourceFile>& other_files) {
204 std::vector<OutputFile> output_files;
205 SubstitutionWriter::ApplyListToLinkerAsOutputFile(
206 target_, tool_, tool_->outputs(), &output_files);
208 out_ << "build";
209 path_output_.WriteFiles(out_, output_files);
211 out_ << ": "
212 << GetNinjaRulePrefixForToolchain(settings_)
213 << Toolchain::ToolTypeToName(
214 target_->toolchain()->GetToolTypeForTargetFinalOutput(target_));
216 UniqueVector<OutputFile> extra_object_files;
217 UniqueVector<const Target*> linkable_deps;
218 UniqueVector<const Target*> non_linkable_deps;
219 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
221 // Object files.
222 for (const auto& obj : object_files) {
223 out_ << " ";
224 path_output_.WriteFile(out_, obj);
226 for (const auto& obj : extra_object_files) {
227 out_ << " ";
228 path_output_.WriteFile(out_, obj);
231 std::vector<OutputFile> implicit_deps;
232 std::vector<OutputFile> solibs;
234 for (const Target* cur : linkable_deps) {
235 // All linkable deps should have a link output file.
236 DCHECK(!cur->link_output_file().value().empty())
237 << "No link output file for "
238 << target_->label().GetUserVisibleName(false);
240 if (cur->dependency_output_file().value() !=
241 cur->link_output_file().value()) {
242 // This is a shared library with separate link and deps files. Save for
243 // later.
244 implicit_deps.push_back(cur->dependency_output_file());
245 solibs.push_back(cur->link_output_file());
246 } else {
247 // Normal case, just link to this target.
248 out_ << " ";
249 path_output_.WriteFile(out_, cur->link_output_file());
253 const SourceFile* optional_def_file = nullptr;
254 if (!other_files.empty()) {
255 for (const SourceFile& src_file : other_files) {
256 if (GetSourceFileType(src_file) == SOURCE_DEF) {
257 optional_def_file = &src_file;
258 implicit_deps.push_back(
259 OutputFile(settings_->build_settings(), src_file));
260 break; // Only one def file is allowed.
265 // Append implicit dependencies collected above.
266 if (!implicit_deps.empty()) {
267 out_ << " |";
268 path_output_.WriteFiles(out_, implicit_deps);
271 // Append data dependencies as order-only dependencies.
273 // This will include data dependencies and input dependencies (like when
274 // this target depends on an action). Having the data dependencies in this
275 // list ensures that the data is available at runtime when the user builds
276 // this target.
278 // The action dependencies are not strictly necessary in this case. They
279 // should also have been collected via the input deps stamp that each source
280 // file has for an order-only dependency, and since this target depends on
281 // the sources, there is already an implicit order-only dependency. However,
282 // it's extra work to separate these out and there's no disadvantage to
283 // listing them again.
284 WriteOrderOnlyDependencies(non_linkable_deps);
286 // End of the link "build" line.
287 out_ << std::endl;
289 // These go in the inner scope of the link line.
290 WriteLinkerFlags(optional_def_file);
292 WriteLibs();
293 WriteOutputExtension();
294 WriteSolibs(solibs);
297 void NinjaBinaryTargetWriter::WriteLinkerFlags(
298 const SourceFile* optional_def_file) {
299 out_ << " ldflags =";
301 // First the ldflags from the target and its config.
302 EscapeOptions flag_options = GetFlagOptions();
303 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags,
304 flag_options, out_);
306 // Followed by library search paths that have been recursively pushed
307 // through the dependency tree.
308 const OrderedSet<SourceDir> all_lib_dirs = target_->all_lib_dirs();
309 if (!all_lib_dirs.empty()) {
310 // Since we're passing these on the command line to the linker and not
311 // to Ninja, we need to do shell escaping.
312 PathOutput lib_path_output(path_output_.current_dir(),
313 settings_->build_settings()->root_path_utf8(),
314 ESCAPE_NINJA_COMMAND);
315 for (size_t i = 0; i < all_lib_dirs.size(); i++) {
316 out_ << " " << tool_->lib_dir_switch();
317 lib_path_output.WriteDir(out_, all_lib_dirs[i],
318 PathOutput::DIR_NO_LAST_SLASH);
322 if (optional_def_file) {
323 out_ << " /DEF:";
324 path_output_.WriteFile(out_, *optional_def_file);
327 out_ << std::endl;
330 void NinjaBinaryTargetWriter::WriteLibs() {
331 out_ << " libs =";
333 // Libraries that have been recursively pushed through the dependency tree.
334 EscapeOptions lib_escape_opts;
335 lib_escape_opts.mode = ESCAPE_NINJA_COMMAND;
336 const OrderedSet<std::string> all_libs = target_->all_libs();
337 const std::string framework_ending(".framework");
338 for (size_t i = 0; i < all_libs.size(); i++) {
339 if (settings_->IsMac() && EndsWith(all_libs[i], framework_ending, false)) {
340 // Special-case libraries ending in ".framework" on Mac. Add the
341 // -framework switch and don't add the extension to the output.
342 out_ << " -framework ";
343 EscapeStringToStream(out_,
344 all_libs[i].substr(0, all_libs[i].size() - framework_ending.size()),
345 lib_escape_opts);
346 } else {
347 out_ << " " << tool_->lib_switch();
348 EscapeStringToStream(out_, all_libs[i], lib_escape_opts);
351 out_ << std::endl;
354 void NinjaBinaryTargetWriter::WriteOutputExtension() {
355 out_ << " output_extension = ";
356 if (target_->output_extension().empty()) {
357 // Use the default from the tool.
358 out_ << tool_->default_output_extension();
359 } else {
360 // Use the one specified in the target. Note that the one in the target
361 // does not include the leading dot, so add that.
362 out_ << "." << target_->output_extension();
364 out_ << std::endl;
367 void NinjaBinaryTargetWriter::WriteSolibs(
368 const std::vector<OutputFile>& solibs) {
369 if (solibs.empty())
370 return;
372 out_ << " solibs =";
373 path_output_.WriteFiles(out_, solibs);
374 out_ << std::endl;
377 void NinjaBinaryTargetWriter::WriteSourceSetStamp(
378 const std::vector<OutputFile>& object_files) {
379 // The stamp rule for source sets is generally not used, since targets that
380 // depend on this will reference the object files directly. However, writing
381 // this rule allows the user to type the name of the target and get a build
382 // which can be convenient for development.
383 UniqueVector<OutputFile> extra_object_files;
384 UniqueVector<const Target*> linkable_deps;
385 UniqueVector<const Target*> non_linkable_deps;
386 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
388 // The classifier should never put extra object files in a source set:
389 // any source sets that we depend on should appear in our non-linkable
390 // deps instead.
391 DCHECK(extra_object_files.empty());
393 std::vector<OutputFile> order_only_deps;
394 for (const auto& dep : non_linkable_deps)
395 order_only_deps.push_back(dep->dependency_output_file());
397 WriteStampForTarget(object_files, order_only_deps);
400 void NinjaBinaryTargetWriter::GetDeps(
401 UniqueVector<OutputFile>* extra_object_files,
402 UniqueVector<const Target*>* linkable_deps,
403 UniqueVector<const Target*>* non_linkable_deps) const {
404 // Normal public/private deps.
405 for (const auto& pair : target_->GetDeps(Target::DEPS_LINKED)) {
406 ClassifyDependency(pair.ptr, extra_object_files,
407 linkable_deps, non_linkable_deps);
410 // Inherited libraries.
411 for (const auto& inherited_target :
412 target_->inherited_libraries().GetOrdered()) {
413 ClassifyDependency(inherited_target, extra_object_files,
414 linkable_deps, non_linkable_deps);
417 // Data deps.
418 for (const auto& data_dep_pair : target_->data_deps())
419 non_linkable_deps->push_back(data_dep_pair.ptr);
422 void NinjaBinaryTargetWriter::ClassifyDependency(
423 const Target* dep,
424 UniqueVector<OutputFile>* extra_object_files,
425 UniqueVector<const Target*>* linkable_deps,
426 UniqueVector<const Target*>* non_linkable_deps) const {
427 // Only the following types of outputs have libraries linked into them:
428 // EXECUTABLE
429 // SHARED_LIBRARY
430 // _complete_ STATIC_LIBRARY
432 // Child deps of intermediate static libraries get pushed up the
433 // dependency tree until one of these is reached, and source sets
434 // don't link at all.
435 bool can_link_libs = target_->IsFinal();
437 if (dep->output_type() == Target::SOURCE_SET) {
438 // Source sets have their object files linked into final targets
439 // (shared libraries, executables, and complete static
440 // libraries). Intermediate static libraries and other source sets
441 // just forward the dependency, otherwise the files in the source
442 // set can easily get linked more than once which will cause
443 // multiple definition errors.
444 if (can_link_libs) {
445 // Linking in a source set to an executable, shared library, or
446 // complete static library, so copy its object files.
447 std::vector<OutputFile> tool_outputs; // Prevent allocation in loop.
448 for (const auto& source : dep->sources()) {
449 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
450 if (GetOutputFilesForSource(dep, source, &tool_type, &tool_outputs)) {
451 // Only link the first output if there are more than one.
452 extra_object_files->push_back(tool_outputs[0]);
457 // Add the source set itself as a non-linkable dependency on the current
458 // target. This will make sure that anything the source set's stamp file
459 // depends on (like data deps) are also built before the current target
460 // can be complete. Otherwise, these will be skipped since this target
461 // will depend only on the source set's object files.
462 non_linkable_deps->push_back(dep);
463 } else if (can_link_libs && dep->IsLinkable()) {
464 linkable_deps->push_back(dep);
465 } else {
466 non_linkable_deps->push_back(dep);
470 void NinjaBinaryTargetWriter::WriteOrderOnlyDependencies(
471 const UniqueVector<const Target*>& non_linkable_deps) {
472 if (!non_linkable_deps.empty()) {
473 out_ << " ||";
475 // Non-linkable targets.
476 for (const auto& non_linkable_dep : non_linkable_deps) {
477 out_ << " ";
478 path_output_.WriteFile(out_, non_linkable_dep->dependency_output_file());
483 bool NinjaBinaryTargetWriter::GetOutputFilesForSource(
484 const Target* target,
485 const SourceFile& source,
486 Toolchain::ToolType* computed_tool_type,
487 std::vector<OutputFile>* outputs) const {
488 outputs->clear();
489 *computed_tool_type = Toolchain::TYPE_NONE;
491 SourceFileType file_type = GetSourceFileType(source);
492 if (file_type == SOURCE_UNKNOWN)
493 return false;
494 if (file_type == SOURCE_O) {
495 // Object files just get passed to the output and not compiled.
496 outputs->push_back(OutputFile(settings_->build_settings(), source));
497 return true;
500 *computed_tool_type =
501 target->toolchain()->GetToolTypeForSourceType(file_type);
502 if (*computed_tool_type == Toolchain::TYPE_NONE)
503 return false; // No tool for this file (it's a header file or something).
504 const Tool* tool = target->toolchain()->GetTool(*computed_tool_type);
505 if (!tool)
506 return false; // Tool does not apply for this toolchain.file.
508 // Figure out what output(s) this compiler produces.
509 SubstitutionWriter::ApplyListToCompilerAsOutputFile(
510 target, source, tool->outputs(), outputs);
511 return !outputs->empty();