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"
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"
23 // Returns the proper escape options for writing compiler and linker flags.
24 EscapeOptions
GetFlagOptions() {
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;
38 options
.mode
= ESCAPE_NINJA_COMMAND
;
41 void operator()(const std::string
& s
, std::ostream
& out
) const {
43 EscapeStringToStream(out
, s
, options
);
46 EscapeOptions options
;
49 struct IncludeWriter
{
50 IncludeWriter(PathOutput
& path_output
) : path_output_(path_output
) {
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();
60 out
<< " \"-I" << path
.substr(1);
65 PathOutput
& path_output_
;
70 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target
* target
,
72 : NinjaTargetWriter(target
, out
),
73 tool_(target
->toolchain()->GetToolForTargetFinalOutput(target
)) {
76 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
79 void NinjaBinaryTargetWriter::Run() {
82 std::vector
<OutputFile
> obj_files
;
83 WriteSources(&obj_files
);
85 if (target_
->output_type() == Target::SOURCE_SET
)
86 WriteSourceSetStamp(obj_files
);
88 WriteLinkerStuff(obj_files
);
91 void NinjaBinaryTargetWriter::WriteCompilerVars() {
92 const SubstitutionBits
& subst
= target_
->toolchain()->substitution_bits();
95 if (subst
.used
[SUBSTITUTION_DEFINES
]) {
96 out_
<< kSubstitutionNinjaNames
[SUBSTITUTION_DEFINES
] << " =";
97 RecursiveTargetConfigToStream
<std::string
>(
98 target_
, &ConfigValues::defines
, DefineWriter(), out_
);
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_
);
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_); \
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
)
131 WriteSharedVars(subst
);
134 void NinjaBinaryTargetWriter::WriteSources(
135 std::vector
<OutputFile
>* object_files
) {
136 const Target::FileList
& sources
= target_
->sources();
137 object_files
->reserve(sources
.size());
139 OutputFile input_dep
=
140 WriteInputDepsStampAndGetDep(std::vector
<const Target
*>());
142 std::string rule_prefix
= GetNinjaRulePrefixForToolchain(settings_
);
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.
151 if (tool_type
!= Toolchain::TYPE_NONE
) {
153 path_output_
.WriteFiles(out_
, tool_outputs
);
154 out_
<< ": " << rule_prefix
<< Toolchain::ToolTypeToName(tool_type
);
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.
163 // This is important to prevent changes in unrelated actions that
164 // are upstream of this target from causing everything to be recompiled.
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.
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.
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.
183 path_output_
.WriteFile(out_
, input_dep
);
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]);
195 void 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
);
202 path_output_
.WriteFiles(out_
, output_files
);
205 << GetNinjaRulePrefixForToolchain(settings_
)
206 << Toolchain::ToolTypeToName(
207 target_
->toolchain()->GetToolTypeForTargetFinalOutput(target_
));
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
);
215 for (size_t i
= 0; i
< object_files
.size(); i
++) {
217 path_output_
.WriteFile(out_
, object_files
[i
]);
219 for (size_t i
= 0; i
< extra_object_files
.size(); i
++) {
221 path_output_
.WriteFile(out_
, extra_object_files
[i
]);
224 std::vector
<OutputFile
> implicit_deps
;
225 std::vector
<OutputFile
> solibs
;
227 for (size_t i
= 0; i
< linkable_deps
.size(); i
++) {
228 const Target
* cur
= linkable_deps
[i
];
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);
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
239 implicit_deps
.push_back(cur
->dependency_output_file());
240 solibs
.push_back(cur
->link_output_file());
242 // Normal case, just link to this target.
244 path_output_
.WriteFile(out_
, cur
->link_output_file());
248 // Append implicit dependencies collected above.
249 if (!implicit_deps
.empty()) {
251 path_output_
.WriteFiles(out_
, implicit_deps
);
254 // Append data dependencies as order-only dependencies.
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
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
);
269 // End of the link "build" line.
272 // These go in the inner scope of the link line.
275 WriteOutputExtension();
279 void NinjaBinaryTargetWriter::WriteLinkerFlags() {
280 out_
<< " ldflags =";
282 // First the ldflags from the target and its config.
283 EscapeOptions flag_options
= GetFlagOptions();
284 RecursiveTargetConfigStringsToStream(target_
, &ConfigValues::ldflags
,
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
);
304 void NinjaBinaryTargetWriter::WriteLibs() {
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()),
321 out_
<< " " << tool_
->lib_switch();
322 EscapeStringToStream(out_
, all_libs
[i
], lib_escape_opts
);
328 void 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();
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();
341 void NinjaBinaryTargetWriter::WriteSolibs(
342 const std::vector
<OutputFile
>& solibs
) {
347 path_output_
.WriteFiles(out_
, solibs
);
351 void 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
);
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
365 DCHECK(extra_object_files
.empty());
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());
371 WriteStampForTarget(object_files
, order_only_deps
);
374 void 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();
381 // Normal public/private deps.
382 for (DepsIterator
iter(target_
, DepsIterator::LINKED_ONLY
); !iter
.done();
384 ClassifyDependency(iter
.target(), extra_object_files
,
385 linkable_deps
, non_linkable_deps
);
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
);
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
);
400 void NinjaBinaryTargetWriter::ClassifyDependency(
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:
408 // _complete_ STATIC_LIBRARY
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();
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.
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
,
430 // Only link the first output if there are more than one.
431 extra_object_files
->push_back(tool_outputs
[0]);
435 } else if (can_link_libs
&& dep
->IsLinkable()) {
436 linkable_deps
->push_back(dep
);
438 non_linkable_deps
->push_back(dep
);
442 void 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()) {
448 // Non-linkable targets.
449 for (size_t i
= 0; i
< non_linkable_deps
.size(); i
++) {
451 path_output_
.WriteFile(
452 out_
, non_linkable_deps
[i
]->dependency_output_file());
457 bool NinjaBinaryTargetWriter::GetOutputFilesForSource(
458 const Target
* target
,
459 const SourceFile
& source
,
460 Toolchain::ToolType
* computed_tool_type
,
461 std::vector
<OutputFile
>* outputs
) const {
463 *computed_tool_type
= Toolchain::TYPE_NONE
;
465 SourceFileType file_type
= GetSourceFileType(source
);
466 if (file_type
== SOURCE_UNKNOWN
)
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
));
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
);
480 return false; // Tool does not apply for this toolchain.file.
482 // Figure out what output(s) this compiler produces.
483 SubstitutionWriter::ApplyListToCompilerAsOutputFile(
484 target
, source
, tool
->outputs(), outputs
);
485 return !outputs
->empty();