Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(358)

Side by Side Diff: tools/gn/ninja_binary_target_writer.cc

Issue 1207903002: Windows precompiled header support in GN (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/gn/ninja_binary_target_writer.h" 5 #include "tools/gn/ninja_binary_target_writer.h"
6 6
7 #include <cstring>
7 #include <set> 8 #include <set>
8 #include <sstream> 9 #include <sstream>
9 10
10 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
11 #include "tools/gn/config_values_extractors.h" 12 #include "tools/gn/config_values_extractors.h"
12 #include "tools/gn/deps_iterator.h" 13 #include "tools/gn/deps_iterator.h"
13 #include "tools/gn/err.h" 14 #include "tools/gn/err.h"
14 #include "tools/gn/escape.h" 15 #include "tools/gn/escape.h"
16 #include "tools/gn/filesystem_utils.h"
15 #include "tools/gn/ninja_utils.h" 17 #include "tools/gn/ninja_utils.h"
16 #include "tools/gn/settings.h" 18 #include "tools/gn/settings.h"
19 #include "tools/gn/source_file_type.h"
17 #include "tools/gn/string_utils.h" 20 #include "tools/gn/string_utils.h"
18 #include "tools/gn/substitution_writer.h" 21 #include "tools/gn/substitution_writer.h"
19 #include "tools/gn/target.h" 22 #include "tools/gn/target.h"
20 23
21 namespace { 24 namespace {
22 25
23 // Returns the proper escape options for writing compiler and linker flags. 26 // Returns the proper escape options for writing compiler and linker flags.
24 EscapeOptions GetFlagOptions() { 27 EscapeOptions GetFlagOptions() {
25 EscapeOptions opts; 28 EscapeOptions opts;
26 opts.mode = ESCAPE_NINJA_COMMAND; 29 opts.mode = ESCAPE_NINJA_COMMAND;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 const std::string& path = path_out.str(); 61 const std::string& path = path_out.str();
59 if (path[0] == '"') 62 if (path[0] == '"')
60 out << " \"-I" << path.substr(1); 63 out << " \"-I" << path.substr(1);
61 else 64 else
62 out << " -I" << path; 65 out << " -I" << path;
63 } 66 }
64 67
65 PathOutput& path_output_; 68 PathOutput& path_output_;
66 }; 69 };
67 70
71 // Returns the language-specific prefix/suffix for precomiled header files.
72 const char* GetPCHLangForFlagType(SubstitutionType type) {
73 switch (type) {
74 case SUBSTITUTION_CFLAGS_C:
75 return "c";
76 case SUBSTITUTION_CFLAGS_CC:
77 return "cc";
78 case SUBSTITUTION_CFLAGS_OBJC:
79 return "m";
80 case SUBSTITUTION_CFLAGS_OBJCC:
81 return "mm";
82 default:
83 NOTREACHED() << "Not a valid language type";
84 return "";
85 }
86 }
87
68 } // namespace 88 } // namespace
69 89
90 // Represents a set of tool types.
91 class NinjaBinaryTargetWriter::SourceFileTypeSet {
92 public:
93 SourceFileTypeSet() {
94 memset(flags_, 0, sizeof(bool) * static_cast<int>(SOURCE_NUMTYPES));
95 }
96
97 void Set(SourceFileType type) {
98 flags_[static_cast<int>(type)] = true;
99 }
100 bool Get(SourceFileType type) const {
101 return flags_[static_cast<int>(type)];
102 }
103
104 private:
105 bool flags_[static_cast<int>(SOURCE_NUMTYPES)];
106 };
107
70 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, 108 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target,
71 std::ostream& out) 109 std::ostream& out)
72 : NinjaTargetWriter(target, out), 110 : NinjaTargetWriter(target, out),
73 tool_(target->toolchain()->GetToolForTargetFinalOutput(target)) { 111 tool_(target->toolchain()->GetToolForTargetFinalOutput(target)),
112 rule_prefix_(GetNinjaRulePrefixForToolchain(settings_)) {
74 } 113 }
75 114
76 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { 115 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
77 } 116 }
78 117
79 void NinjaBinaryTargetWriter::Run() { 118 void NinjaBinaryTargetWriter::Run() {
80 WriteCompilerVars(); 119 // Figure out what source types are needed.
120 SourceFileTypeSet used_types;
121 for (const auto& source : target_->sources())
122 used_types.Set(GetSourceFileType(source));
81 123
124 WriteCompilerVars(used_types);
125
126 // The input dependencies will be an order-only dependency. This will cause
127 // Ninja to make sure the inputs are up-to-date before compiling this source,
128 // but changes in the inputs deps won't cause the file to be recompiled.
129 //
130 // This is important to prevent changes in unrelated actions that are
131 // upstream of this target from causing everything to be recompiled
132 //
133 // Why can we get away with this rather than using implicit deps ("|", which
134 // will force rebuilds when the inputs change)? For source code, the
135 // computed dependencies of all headers will be computed by the compiler,
136 // which will cause source rebuilds if any "real" upstream dependencies
137 // change.
138 //
139 // If a .cc file is generated by an input dependency, Ninja will see the
140 // input to the build rule doesn't exist, and that it is an output from a
141 // previous step, and build the previous step first. This is a "real"
142 // dependency and doesn't need | or || to express.
143 //
144 // The only case where this rule matters is for the first build where no .d
145 // files exist, and Ninja doesn't know what that source file depends on. In
146 // this case it's sufficient to ensure that the upstream dependencies are
147 // built first. This is exactly what Ninja's order-only dependencies
148 // expresses.
149 OutputFile order_only_dep =
150 WriteInputDepsStampAndGetDep(std::vector<const Target*>());
151
152 std::vector<OutputFile> pch_obj_files;
153 WritePrecompiledHeaderCommands(used_types, order_only_dep, &pch_obj_files);
154
155 // Treat all precompiled object files as explicit dependencies of all
156 // compiles. Some notes:
157 //
158 // - Technically only the language-specific one is required for any specific
159 // compile, but that's more difficult to express and the additional logic
160 // doesn't buy much reduced parallelism. Just list them all (there's
161 // usually only one anyway).
162 //
163 // - Technically the .pch file is the input to the compile, not the
164 // precompiled header's corresponding object file that we're using here.
165 // But Ninja's depslog doesn't support multiple outputs from the
166 // precompiled header compile step (it outputs both the .pch file and a
167 // corresponding .obj file). So we consistently list the .obj file and the
168 // .pch file we really need comes along with it.
82 std::vector<OutputFile> obj_files; 169 std::vector<OutputFile> obj_files;
83 std::vector<SourceFile> other_files; 170 std::vector<SourceFile> other_files;
84 WriteSources(&obj_files, &other_files); 171 WriteSources(pch_obj_files, order_only_dep, &obj_files, &other_files);
85 172
86 if (target_->output_type() == Target::SOURCE_SET) 173 // Also link all pch object files.
174 obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end());
175
176 if (target_->output_type() == Target::SOURCE_SET) {
87 WriteSourceSetStamp(obj_files); 177 WriteSourceSetStamp(obj_files);
88 else 178 #ifndef NDEBUG
179 // Verify that the function that separately computes a source set's object
180 // files match the object files just computed.
181 UniqueVector<OutputFile> computed_obj;
182 AddSourceSetObjectFiles(target_, &computed_obj);
183 DCHECK_EQ(obj_files.size(), computed_obj.size());
184 for (const auto& obj : obj_files)
185 DCHECK_NE(static_cast<size_t>(-1), computed_obj.IndexOf(obj));
186 #endif
187 } else {
89 WriteLinkerStuff(obj_files, other_files); 188 WriteLinkerStuff(obj_files, other_files);
189 }
90 } 190 }
91 191
92 void NinjaBinaryTargetWriter::WriteCompilerVars() { 192 void NinjaBinaryTargetWriter::WriteCompilerVars(
193 const SourceFileTypeSet& used_types) {
93 const SubstitutionBits& subst = target_->toolchain()->substitution_bits(); 194 const SubstitutionBits& subst = target_->toolchain()->substitution_bits();
94 195
95 // Defines. 196 // Defines.
96 if (subst.used[SUBSTITUTION_DEFINES]) { 197 if (subst.used[SUBSTITUTION_DEFINES]) {
97 out_ << kSubstitutionNinjaNames[SUBSTITUTION_DEFINES] << " ="; 198 out_ << kSubstitutionNinjaNames[SUBSTITUTION_DEFINES] << " =";
98 RecursiveTargetConfigToStream<std::string>( 199 RecursiveTargetConfigToStream<std::string>(
99 target_, &ConfigValues::defines, DefineWriter(), out_); 200 target_, &ConfigValues::defines, DefineWriter(), out_);
100 out_ << std::endl; 201 out_ << std::endl;
101 } 202 }
102 203
103 // Include directories. 204 // Include directories.
104 if (subst.used[SUBSTITUTION_INCLUDE_DIRS]) { 205 if (subst.used[SUBSTITUTION_INCLUDE_DIRS]) {
105 out_ << kSubstitutionNinjaNames[SUBSTITUTION_INCLUDE_DIRS] << " ="; 206 out_ << kSubstitutionNinjaNames[SUBSTITUTION_INCLUDE_DIRS] << " =";
106 PathOutput include_path_output( 207 PathOutput include_path_output(
107 path_output_.current_dir(), 208 path_output_.current_dir(),
108 settings_->build_settings()->root_path_utf8(), 209 settings_->build_settings()->root_path_utf8(),
109 ESCAPE_NINJA_COMMAND); 210 ESCAPE_NINJA_COMMAND);
110 RecursiveTargetConfigToStream<SourceDir>( 211 RecursiveTargetConfigToStream<SourceDir>(
111 target_, &ConfigValues::include_dirs, 212 target_, &ConfigValues::include_dirs,
112 IncludeWriter(include_path_output), out_); 213 IncludeWriter(include_path_output), out_);
113 out_ << std::endl; 214 out_ << std::endl;
114 } 215 }
115 216
116 // C flags and friends. 217 // Some toolchains pass cflags to the assembler since it's the same command,
117 EscapeOptions flag_escape_options = GetFlagOptions(); 218 // and cflags_c might also be sent to the objective C compiler.
118 #define WRITE_FLAGS(name, subst_enum) \ 219 //
119 if (subst.used[subst_enum]) { \ 220 // TODO(brettw) remove the SOURCE_M from the CFLAGS_C writing once the Chrome
120 out_ << kSubstitutionNinjaNames[subst_enum] << " ="; \ 221 // Mac build is updated not to pass cflags_c to .m files.
121 RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \ 222 EscapeOptions opts = GetFlagOptions();
122 flag_escape_options, out_); \ 223 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_CC) ||
123 out_ << std::endl; \ 224 used_types.Get(SOURCE_M) || used_types.Get(SOURCE_MM) ||
124 } 225 used_types.Get(SOURCE_ASM))
125 226 WriteOneFlag(SUBSTITUTION_CFLAGS, &ConfigValues::cflags, opts);
126 WRITE_FLAGS(cflags, SUBSTITUTION_CFLAGS) 227 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_M) ||
127 WRITE_FLAGS(cflags_c, SUBSTITUTION_CFLAGS_C) 228 used_types.Get(SOURCE_ASM))
128 WRITE_FLAGS(cflags_cc, SUBSTITUTION_CFLAGS_CC) 229 WriteOneFlag(SUBSTITUTION_CFLAGS_C, &ConfigValues::cflags_c, opts);
129 WRITE_FLAGS(cflags_objc, SUBSTITUTION_CFLAGS_OBJC) 230 if (used_types.Get(SOURCE_CC))
130 WRITE_FLAGS(cflags_objcc, SUBSTITUTION_CFLAGS_OBJCC) 231 WriteOneFlag(SUBSTITUTION_CFLAGS_CC, &ConfigValues::cflags_cc, opts);
131 232 if (used_types.Get(SOURCE_M))
132 #undef WRITE_FLAGS 233 WriteOneFlag(SUBSTITUTION_CFLAGS_OBJC, &ConfigValues::cflags_objc, opts);
234 if (used_types.Get(SOURCE_MM))
235 WriteOneFlag(SUBSTITUTION_CFLAGS_OBJCC, &ConfigValues::cflags_objcc, opts);
133 236
134 WriteSharedVars(subst); 237 WriteSharedVars(subst);
135 } 238 }
136 239
240 void NinjaBinaryTargetWriter::WriteOneFlag(
241 SubstitutionType subst_enum,
242 const std::vector<std::string>& (ConfigValues::* getter)() const,
243 EscapeOptions flag_escape_options) {
244 if (!target_->toolchain()->substitution_bits().used[subst_enum])
245 return;
246
247 out_ << kSubstitutionNinjaNames[subst_enum] << " =";
248
249 // Write precompiled header flags.
250 if (target_->config_values().has_precompiled_headers() &&
251 (subst_enum == SUBSTITUTION_CFLAGS_C ||
252 subst_enum == SUBSTITUTION_CFLAGS_CC ||
253 subst_enum == SUBSTITUTION_CFLAGS_OBJC ||
254 subst_enum == SUBSTITUTION_CFLAGS_OBJCC)) {
255 // Name the .pch file.
256 out_ << " /Fp";
257 path_output_.WriteFile(out_, GetWindowsPCHFile(subst_enum));
258
259 // Enables precompiled headers and names the .h file. It's a string rather
260 // than a file name that needs rebasing.
261 out_ << " /Yu" << target_->config_values().precompiled_header();
262 }
263
264 RecursiveTargetConfigStringsToStream(target_, getter,
265 flag_escape_options, out_);
266 out_ << std::endl;
267 }
268
269 void NinjaBinaryTargetWriter::WritePrecompiledHeaderCommands(
270 const SourceFileTypeSet& used_types,
271 const OutputFile& order_only_dep,
272 std::vector<OutputFile>* object_files) {
273 if (!target_->config_values().has_precompiled_headers())
274 return;
275
276 if (used_types.Get(SOURCE_C)) {
277 WritePrecompiledHeaderCommand(SUBSTITUTION_CFLAGS_C,
278 Toolchain::TYPE_CC,
279 order_only_dep, object_files);
280 }
281 if (used_types.Get(SOURCE_CC)) {
282 WritePrecompiledHeaderCommand(SUBSTITUTION_CFLAGS_CC,
283 Toolchain::TYPE_CXX,
284 order_only_dep, object_files);
285 }
286 if (used_types.Get(SOURCE_M)) {
287 WritePrecompiledHeaderCommand(SUBSTITUTION_CFLAGS_OBJC,
288 Toolchain::TYPE_OBJC,
289 order_only_dep, object_files);
290 }
291 if (used_types.Get(SOURCE_MM)) {
292 WritePrecompiledHeaderCommand(SUBSTITUTION_CFLAGS_OBJCC,
293 Toolchain::TYPE_OBJCXX,
294 order_only_dep, object_files);
295 }
296 }
297
298 void NinjaBinaryTargetWriter::WritePrecompiledHeaderCommand(
299 SubstitutionType flag_type,
300 Toolchain::ToolType tool_type,
301 const OutputFile& order_only_dep,
302 std::vector<OutputFile>* object_files) {
303 // Compute the object file (it will be language-specific).
304 std::vector<OutputFile> outputs;
305 GetWindowsPCHObjectFiles(target_, flag_type, tool_type, &outputs);
306 if (outputs.empty())
307 return;
308 object_files->insert(object_files->end(), outputs.begin(), outputs.end());
309
310 // Build line to compile the file.
311 WriteCompilerBuildLine(target_->config_values().precompiled_source(),
312 std::vector<OutputFile>(), order_only_dep, tool_type,
313 outputs);
314
315 // This build line needs a custom language-specific flags value. It needs to
316 // include the switch to generate the .pch file in addition to the normal
317 // ones. Rule-specific variables are just indented underneath the rule line,
318 // and this defines the new one in terms of the old value.
319 out_ << " " << kSubstitutionNinjaNames[flag_type] << " =";
320 out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}";
321
322 // Append the command to generate the .pch file.
323 out_ << " /Yc" << target_->config_values().precompiled_header();
scottmg 2015/06/26 22:30:13 Don't you need /Fp here somewhere?
brettw 2015/06/29 21:36:10 No because this line will look like: cflags_cc =
324 out_ << std::endl;
325 }
326
137 void NinjaBinaryTargetWriter::WriteSources( 327 void NinjaBinaryTargetWriter::WriteSources(
328 const std::vector<OutputFile>& extra_deps,
329 const OutputFile& order_only_dep,
138 std::vector<OutputFile>* object_files, 330 std::vector<OutputFile>* object_files,
139 std::vector<SourceFile>* other_files) { 331 std::vector<SourceFile>* other_files) {
140 object_files->reserve(target_->sources().size()); 332 object_files->reserve(object_files->size() + target_->sources().size());
141
142 OutputFile input_dep =
143 WriteInputDepsStampAndGetDep(std::vector<const Target*>());
144
145 std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_);
146 333
147 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop. 334 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop.
148 for (const auto& source : target_->sources()) { 335 for (const auto& source : target_->sources()) {
149 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; 336 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
150 if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) { 337 if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) {
151 if (GetSourceFileType(source) == SOURCE_DEF) 338 if (GetSourceFileType(source) == SOURCE_DEF)
152 other_files->push_back(source); 339 other_files->push_back(source);
153 continue; // No output for this source. 340 continue; // No output for this source.
154 } 341 }
155 342
156 if (tool_type != Toolchain::TYPE_NONE) { 343 if (tool_type != Toolchain::TYPE_NONE) {
157 out_ << "build"; 344 WriteCompilerBuildLine(source, extra_deps, order_only_dep, tool_type,
158 path_output_.WriteFiles(out_, tool_outputs); 345 tool_outputs);
159
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.
168 //
169 // This is important to prevent changes in unrelated actions that
170 // are upstream of this target from causing everything to be recompiled.
171 //
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.
177 //
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.
182 //
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);
190 }
191 out_ << std::endl;
192 } 346 }
193 347
194 // It's theoretically possible for a compiler to produce more than one 348 // It's theoretically possible for a compiler to produce more than one
195 // output, but we'll only link to the first output. 349 // output, but we'll only link to the first output.
196 object_files->push_back(tool_outputs[0]); 350 object_files->push_back(tool_outputs[0]);
197 } 351 }
198 out_ << std::endl; 352 out_ << std::endl;
199 } 353 }
200 354
355 void NinjaBinaryTargetWriter::WriteCompilerBuildLine(
356 const SourceFile& source,
357 const std::vector<OutputFile>& extra_deps,
358 const OutputFile& order_only_dep,
359 Toolchain::ToolType tool_type,
360 const std::vector<OutputFile>& outputs) {
361 out_ << "build";
362 path_output_.WriteFiles(out_, outputs);
363
364 out_ << ": " << rule_prefix_ << Toolchain::ToolTypeToName(tool_type);
365 out_ << " ";
366 path_output_.WriteFile(out_, source);
367
368 if (!extra_deps.empty()) {
369 out_ << " |";
370 for (const OutputFile& dep : extra_deps) {
371 out_ << " ";
372 path_output_.WriteFile(out_, dep);
373 }
374 }
375
376 if (!order_only_dep.value().empty()) {
377 out_ << " || ";
378 path_output_.WriteFile(out_, order_only_dep);
379 }
380 out_ << std::endl;
381 }
382
201 void NinjaBinaryTargetWriter::WriteLinkerStuff( 383 void NinjaBinaryTargetWriter::WriteLinkerStuff(
202 const std::vector<OutputFile>& object_files, 384 const std::vector<OutputFile>& object_files,
203 const std::vector<SourceFile>& other_files) { 385 const std::vector<SourceFile>& other_files) {
204 std::vector<OutputFile> output_files; 386 std::vector<OutputFile> output_files;
205 SubstitutionWriter::ApplyListToLinkerAsOutputFile( 387 SubstitutionWriter::ApplyListToLinkerAsOutputFile(
206 target_, tool_, tool_->outputs(), &output_files); 388 target_, tool_, tool_->outputs(), &output_files);
207 389
208 out_ << "build"; 390 out_ << "build";
209 path_output_.WriteFiles(out_, output_files); 391 path_output_.WriteFiles(out_, output_files);
210 392
211 out_ << ": " 393 out_ << ": " << rule_prefix_
212 << GetNinjaRulePrefixForToolchain(settings_)
213 << Toolchain::ToolTypeToName( 394 << Toolchain::ToolTypeToName(
214 target_->toolchain()->GetToolTypeForTargetFinalOutput(target_)); 395 target_->toolchain()->GetToolTypeForTargetFinalOutput(target_));
215 396
216 UniqueVector<OutputFile> extra_object_files; 397 UniqueVector<OutputFile> extra_object_files;
217 UniqueVector<const Target*> linkable_deps; 398 UniqueVector<const Target*> linkable_deps;
218 UniqueVector<const Target*> non_linkable_deps; 399 UniqueVector<const Target*> non_linkable_deps;
219 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); 400 GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps);
220 401
221 // Object files. 402 // Object files.
222 for (const auto& obj : object_files) { 403 for (const auto& obj : object_files) {
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 // don't link at all. 616 // don't link at all.
436 bool can_link_libs = target_->IsFinal(); 617 bool can_link_libs = target_->IsFinal();
437 618
438 if (dep->output_type() == Target::SOURCE_SET) { 619 if (dep->output_type() == Target::SOURCE_SET) {
439 // Source sets have their object files linked into final targets 620 // Source sets have their object files linked into final targets
440 // (shared libraries, executables, and complete static 621 // (shared libraries, executables, and complete static
441 // libraries). Intermediate static libraries and other source sets 622 // libraries). Intermediate static libraries and other source sets
442 // just forward the dependency, otherwise the files in the source 623 // just forward the dependency, otherwise the files in the source
443 // set can easily get linked more than once which will cause 624 // set can easily get linked more than once which will cause
444 // multiple definition errors. 625 // multiple definition errors.
445 if (can_link_libs) { 626 if (can_link_libs)
446 // Linking in a source set to an executable, shared library, or 627 AddSourceSetObjectFiles(dep, extra_object_files);
447 // complete static library, so copy its object files.
448 std::vector<OutputFile> tool_outputs; // Prevent allocation in loop.
449 for (const auto& source : dep->sources()) {
450 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
451 if (GetOutputFilesForSource(dep, source, &tool_type, &tool_outputs)) {
452 // Only link the first output if there are more than one.
453 extra_object_files->push_back(tool_outputs[0]);
454 }
455 }
456 }
457 628
458 // Add the source set itself as a non-linkable dependency on the current 629 // Add the source set itself as a non-linkable dependency on the current
459 // target. This will make sure that anything the source set's stamp file 630 // target. This will make sure that anything the source set's stamp file
460 // depends on (like data deps) are also built before the current target 631 // depends on (like data deps) are also built before the current target
461 // can be complete. Otherwise, these will be skipped since this target 632 // can be complete. Otherwise, these will be skipped since this target
462 // will depend only on the source set's object files. 633 // will depend only on the source set's object files.
463 non_linkable_deps->push_back(dep); 634 non_linkable_deps->push_back(dep);
464 } else if (can_link_libs && dep->IsLinkable()) { 635 } else if (can_link_libs && dep->IsLinkable()) {
465 linkable_deps->push_back(dep); 636 linkable_deps->push_back(dep);
466 } else { 637 } else {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 return false; // No tool for this file (it's a header file or something). 675 return false; // No tool for this file (it's a header file or something).
505 const Tool* tool = target->toolchain()->GetTool(*computed_tool_type); 676 const Tool* tool = target->toolchain()->GetTool(*computed_tool_type);
506 if (!tool) 677 if (!tool)
507 return false; // Tool does not apply for this toolchain.file. 678 return false; // Tool does not apply for this toolchain.file.
508 679
509 // Figure out what output(s) this compiler produces. 680 // Figure out what output(s) this compiler produces.
510 SubstitutionWriter::ApplyListToCompilerAsOutputFile( 681 SubstitutionWriter::ApplyListToCompilerAsOutputFile(
511 target, source, tool->outputs(), outputs); 682 target, source, tool->outputs(), outputs);
512 return !outputs->empty(); 683 return !outputs->empty();
513 } 684 }
685
686 OutputFile NinjaBinaryTargetWriter::GetWindowsPCHFile(
687 SubstitutionType flag_type) const {
688 // Use "obj/{dir}/{target_name}.{lang}.pch" which ends up
689 // looking like "obj/chrome/browser/browser.cc.precompile.h.pch"
690 OutputFile ret = GetTargetOutputDirAsOutputFile(target_);
691 ret.value().append(target_->label().name());
692 ret.value().push_back('.');
693 ret.value().append(GetPCHLangForFlagType(flag_type));
694 ret.value().append(".pch");
695
696 return ret;
697 }
698
699 void NinjaBinaryTargetWriter::GetWindowsPCHObjectFiles(
700 const Target* target,
701 SubstitutionType flag_type,
702 Toolchain::ToolType tool_type,
703 std::vector<OutputFile>* outputs) const {
704 outputs->clear();
705
706 // Compute the tool. This must use the tool type passed in rather than the
707 // detected file type of the precompiled source file since the same
708 // precompiled source file will be used for separate C/C++ compiles.
709 const Tool* tool = target->toolchain()->GetTool(tool_type);
710 if (!tool)
711 return;
712 SubstitutionWriter::ApplyListToCompilerAsOutputFile(
713 target, target->config_values().precompiled_source(),
714 tool->outputs(), outputs);
715
716 if (outputs->empty())
717 return;
718 if (outputs->size() > 1)
719 outputs->resize(1); // Only link the first output from the compiler tool.
720
721 // Need to annotate the obj files with the language type. For example:
722 // obj/foo/target_name.precompile.obj ->
723 // obj/foo/target_name.precompile.cc.obj
724 const char* lang_suffix = GetPCHLangForFlagType(flag_type);
725 std::string& output_value = (*outputs)[0].value();
726 size_t extension_offset = FindExtensionOffset(output_value);
727 if (extension_offset == std::string::npos) {
728 NOTREACHED() << "No extension found";
729 } else {
730 DCHECK(extension_offset >= 1);
731 DCHECK(output_value[extension_offset - 1] == '.');
732 output_value.insert(extension_offset - 1, ".");
733 output_value.insert(extension_offset, lang_suffix);
734 }
735 }
736
737 void NinjaBinaryTargetWriter::AddSourceSetObjectFiles(
738 const Target* source_set,
739 UniqueVector<OutputFile>* obj_files) const {
740 std::vector<OutputFile> tool_outputs; // Prevent allocation in loop.
741 SourceFileTypeSet used_types;
742
743 // Compute object files for all sources. Only link the first output from
744 // teh tool if there are more than one.
745 for (const auto& source : source_set->sources()) {
746 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
747 if (GetOutputFilesForSource(source_set, source, &tool_type, &tool_outputs))
748 obj_files->push_back(tool_outputs[0]);
749
750 used_types.Set(GetSourceFileType(source));
751 }
752
753 // Precompiled header object files.
754 if (source_set->config_values().has_precompiled_headers()) {
755 if (used_types.Get(SOURCE_C)) {
756 GetWindowsPCHObjectFiles(source_set, SUBSTITUTION_CFLAGS_C,
757 Toolchain::TYPE_CC, &tool_outputs);
758 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
759 }
760 if (used_types.Get(SOURCE_CC)) {
761 GetWindowsPCHObjectFiles(source_set, SUBSTITUTION_CFLAGS_CC,
762 Toolchain::TYPE_CXX, &tool_outputs);
763 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
764 }
765 if (used_types.Get(SOURCE_M)) {
766 GetWindowsPCHObjectFiles(source_set, SUBSTITUTION_CFLAGS_OBJC,
767 Toolchain::TYPE_OBJC, &tool_outputs);
768 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
769 }
770 if (used_types.Get(SOURCE_MM)) {
771 GetWindowsPCHObjectFiles(source_set, SUBSTITUTION_CFLAGS_OBJCC,
772 Toolchain::TYPE_OBJCXX, &tool_outputs);
773 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
774 }
775 }
776 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698