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

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

Issue 1292983004: [GN]: Precompiled header support for GCC. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 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
« no previous file with comments | « tools/gn/ninja_binary_target_writer.h ('k') | tools/gn/ninja_binary_target_writer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <cstring>
8 #include <set> 8 #include <set>
9 #include <sstream> 9 #include <sstream>
10 10
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 const Tool* tool = target->toolchain()->GetTool(*computed_tool_type); 125 const Tool* tool = target->toolchain()->GetTool(*computed_tool_type);
126 if (!tool) 126 if (!tool)
127 return false; // Tool does not apply for this toolchain.file. 127 return false; // Tool does not apply for this toolchain.file.
128 128
129 // Figure out what output(s) this compiler produces. 129 // Figure out what output(s) this compiler produces.
130 SubstitutionWriter::ApplyListToCompilerAsOutputFile( 130 SubstitutionWriter::ApplyListToCompilerAsOutputFile(
131 target, source, tool->outputs(), outputs); 131 target, source, tool->outputs(), outputs);
132 return !outputs->empty(); 132 return !outputs->empty();
133 } 133 }
134 134
135 // Returns the language-specific prefix/suffix for precomiled header files. 135 // Returns the language-specific suffix for precompiled header files.
136 const char* GetPCHLangForToolType(Toolchain::ToolType type) { 136 const char* GetPCHLangSuffixForToolType(Toolchain::ToolType type) {
137 switch (type) { 137 switch (type) {
138 case Toolchain::TYPE_CC: 138 case Toolchain::TYPE_CC:
139 return "c"; 139 return "c";
140 case Toolchain::TYPE_CXX: 140 case Toolchain::TYPE_CXX:
141 return "cc"; 141 return "cc";
142 case Toolchain::TYPE_OBJC: 142 case Toolchain::TYPE_OBJC:
143 return "m"; 143 return "m";
144 case Toolchain::TYPE_OBJCXX: 144 case Toolchain::TYPE_OBJCXX:
145 return "mm"; 145 return "mm";
146 default: 146 default:
147 NOTREACHED() << "Not a valid PCH tool type type"; 147 NOTREACHED() << "Not a valid PCH tool type: " << type;
148 return ""; 148 return "";
149 } 149 }
150 } 150 }
151 151
152 // Returns the object files for the precompiled header of the given type (flag 152 std::string GetWindowsPCHObjectExtension(Toolchain::ToolType tool_type) {
153 // type and tool type must match). 153 const char* lang_suffix = GetPCHLangSuffixForToolType(tool_type);
154 void GetWindowsPCHObjectFiles(const Target* target, 154 std::string result = ".";
155 Toolchain::ToolType tool_type, 155 // For MSVC, annotate the obj files with the language type. For example:
156 std::vector<OutputFile>* outputs) { 156 // obj/foo/target_name.precompile.o ->
157 // obj/foo/target_name.precompile.cc.o
158 result += lang_suffix;
159 result += ".o";
160 return result;
161 }
162
163 std::string GetGCCPCHOutputExtension(Toolchain::ToolType tool_type) {
164 const char* lang_suffix = GetPCHLangSuffixForToolType(tool_type);
165 std::string result = ".";
166 // For GCC, the output name must have a .gch suffix and be annotated with
167 // the language type. For example:
168 // obj/foo/target_name.header.h ->
169 // obj/foo/target_name.header.h-cc.gch
170 // In order for the compiler to pick it up, the output name (minus the .gch
171 // suffix MUST match whatever is passed to the -include flag).
172 result += "h-";
173 result += lang_suffix;
174 result += ".gch";
175 return result;
176 }
177
178 // Returns the language-specific lang recognized by gcc’s -x flag for
179 // precompiled header files.
180 const char* GetPCHLangForToolType(Toolchain::ToolType type) {
181 switch (type) {
182 case Toolchain::TYPE_CC:
183 return "c-header";
184 case Toolchain::TYPE_CXX:
185 return "c++-header";
186 case Toolchain::TYPE_OBJC:
187 return "objective-c-header";
188 case Toolchain::TYPE_OBJCXX:
189 return "objective-c++-header";
190 default:
191 NOTREACHED() << "Not a valid PCH tool type: " << type;
192 return "";
193 }
194 }
195
196 // Fills |outputs| with the object or gch file for the precompiled header of the
197 // given type (flag type and tool type must match).
198 void GetPCHOutputFiles(const Target* target,
199 Toolchain::ToolType tool_type,
200 std::vector<OutputFile>* outputs) {
157 outputs->clear(); 201 outputs->clear();
158 202
159 // Compute the tool. This must use the tool type passed in rather than the 203 // Compute the tool. This must use the tool type passed in rather than the
160 // detected file type of the precompiled source file since the same 204 // detected file type of the precompiled source file since the same
161 // precompiled source file will be used for separate C/C++ compiles. 205 // precompiled source file will be used for separate C/C++ compiles.
162 const Tool* tool = target->toolchain()->GetTool(tool_type); 206 const Tool* tool = target->toolchain()->GetTool(tool_type);
163 if (!tool) 207 if (!tool)
164 return; 208 return;
165 SubstitutionWriter::ApplyListToCompilerAsOutputFile( 209 SubstitutionWriter::ApplyListToCompilerAsOutputFile(
166 target, target->config_values().precompiled_source(), 210 target, target->config_values().precompiled_source(),
167 tool->outputs(), outputs); 211 tool->outputs(), outputs);
168 212
169 if (outputs->empty()) 213 if (outputs->empty())
170 return; 214 return;
171 if (outputs->size() > 1) 215 if (outputs->size() > 1)
172 outputs->resize(1); // Only link the first output from the compiler tool. 216 outputs->resize(1); // Only link the first output from the compiler tool.
173 217
174 // Need to annotate the obj files with the language type. For example:
175 // obj/foo/target_name.precompile.obj ->
176 // obj/foo/target_name.precompile.cc.obj
177 const char* lang_suffix = GetPCHLangForToolType(tool_type);
178 std::string& output_value = (*outputs)[0].value(); 218 std::string& output_value = (*outputs)[0].value();
179 size_t extension_offset = FindExtensionOffset(output_value); 219 size_t extension_offset = FindExtensionOffset(output_value);
180 if (extension_offset == std::string::npos) { 220 if (extension_offset == std::string::npos) {
181 NOTREACHED() << "No extension found"; 221 // No extension found.
182 } else { 222 return;
183 DCHECK(extension_offset >= 1);
184 DCHECK(output_value[extension_offset - 1] == '.');
185 output_value.insert(extension_offset - 1, ".");
186 output_value.insert(extension_offset, lang_suffix);
187 } 223 }
224 DCHECK(extension_offset >= 1);
225 DCHECK(output_value[extension_offset - 1] == '.');
226
227 std::string output_extension;
228 Tool::PrecompiledHeaderType header_type = tool->precompiled_header_type();
229 switch (header_type) {
230 case Tool::PCH_MSVC:
231 output_extension = GetWindowsPCHObjectExtension(tool_type);
232 break;
233 case Tool::PCH_GCC:
234 output_extension = GetGCCPCHOutputExtension(tool_type);
235 break;
236 case Tool::PCH_NONE:
237 NOTREACHED() << "No outputs for no PCH type.";
238 break;
239 }
240 output_value.replace(extension_offset - 1,
241 std::string::npos,
242 output_extension);
188 } 243 }
189 244
190 // Appends the object files generated by the given source set to the given 245 // Appends the object files generated by the given source set to the given
191 // output vector. 246 // output vector.
192 void AddSourceSetObjectFiles(const Target* source_set, 247 void AddSourceSetObjectFiles(const Target* source_set,
193 UniqueVector<OutputFile>* obj_files) { 248 UniqueVector<OutputFile>* obj_files) {
194 std::vector<OutputFile> tool_outputs; // Prevent allocation in loop. 249 std::vector<OutputFile> tool_outputs; // Prevent allocation in loop.
195 NinjaBinaryTargetWriter::SourceFileTypeSet used_types; 250 NinjaBinaryTargetWriter::SourceFileTypeSet used_types;
196 251
197 // Compute object files for all sources. Only link the first output from 252 // Compute object files for all sources. Only link the first output from
198 // the tool if there are more than one. 253 // the tool if there are more than one.
199 for (const auto& source : source_set->sources()) { 254 for (const auto& source : source_set->sources()) {
200 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; 255 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
201 if (GetOutputFilesForSource(source_set, source, &tool_type, &tool_outputs)) 256 if (GetOutputFilesForSource(source_set, source, &tool_type, &tool_outputs))
202 obj_files->push_back(tool_outputs[0]); 257 obj_files->push_back(tool_outputs[0]);
203 258
204 used_types.Set(GetSourceFileType(source)); 259 used_types.Set(GetSourceFileType(source));
205 } 260 }
206 261
207 // Precompiled header object files. 262 // Add MSVC precompiled header object files. GCC .gch files are not object
263 // files so they are omitted.
208 if (source_set->config_values().has_precompiled_headers()) { 264 if (source_set->config_values().has_precompiled_headers()) {
209 if (used_types.Get(SOURCE_C)) { 265 if (used_types.Get(SOURCE_C)) {
210 GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_CC, &tool_outputs); 266 const Tool* tool = source_set->toolchain()->GetTool(Toolchain::TYPE_CC);
211 obj_files->Append(tool_outputs.begin(), tool_outputs.end()); 267 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) {
268 GetPCHOutputFiles(source_set, Toolchain::TYPE_CC, &tool_outputs);
269 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
270 }
212 } 271 }
213 if (used_types.Get(SOURCE_CPP)) { 272 if (used_types.Get(SOURCE_CPP)) {
214 GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_CXX, &tool_outputs); 273 const Tool* tool = source_set->toolchain()->GetTool(Toolchain::TYPE_CXX);
215 obj_files->Append(tool_outputs.begin(), tool_outputs.end()); 274 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) {
275 GetPCHOutputFiles(source_set, Toolchain::TYPE_CXX, &tool_outputs);
276 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
277 }
216 } 278 }
217 if (used_types.Get(SOURCE_M)) { 279 if (used_types.Get(SOURCE_M)) {
218 GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_OBJC, &tool_outputs); 280 const Tool* tool = source_set->toolchain()->GetTool(Toolchain::TYPE_OBJC);
219 obj_files->Append(tool_outputs.begin(), tool_outputs.end()); 281 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) {
282 GetPCHOutputFiles(source_set, Toolchain::TYPE_OBJC, &tool_outputs);
283 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
284 }
220 } 285 }
221 if (used_types.Get(SOURCE_MM)) { 286 if (used_types.Get(SOURCE_MM)) {
222 GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_OBJCXX, 287 const Tool* tool = source_set->toolchain()->GetTool(
223 &tool_outputs); 288 Toolchain::TYPE_OBJCXX);
224 obj_files->Append(tool_outputs.begin(), tool_outputs.end()); 289 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) {
290 GetPCHOutputFiles(source_set, Toolchain::TYPE_OBJCXX, &tool_outputs);
291 obj_files->Append(tool_outputs.begin(), tool_outputs.end());
292 }
225 } 293 }
226 } 294 }
227 } 295 }
228 296
229 } // namespace 297 } // namespace
230 298
231 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, 299 NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target,
232 std::ostream& out) 300 std::ostream& out)
233 : NinjaTargetWriter(target, out), 301 : NinjaTargetWriter(target, out),
234 tool_(target->toolchain()->GetToolForTargetFinalOutput(target)), 302 tool_(target->toolchain()->GetToolForTargetFinalOutput(target)),
235 rule_prefix_(GetNinjaRulePrefixForToolchain(settings_)) { 303 rule_prefix_(GetNinjaRulePrefixForToolchain(settings_)) {
236 } 304 }
237 305
238 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { 306 NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
239 } 307 }
240 308
241 void NinjaBinaryTargetWriter::Run() { 309 void NinjaBinaryTargetWriter::Run() {
242 // Figure out what source types are needed. 310 // Figure out what source types are needed.
243 SourceFileTypeSet used_types; 311 SourceFileTypeSet used_types;
244 for (const auto& source : target_->sources()) 312 for (const auto& source : target_->sources())
245 used_types.Set(GetSourceFileType(source)); 313 used_types.Set(GetSourceFileType(source));
246 314
247 WriteCompilerVars(used_types); 315 WriteCompilerVars(used_types);
248 316
249 // The input dependencies will be an order-only dependency. This will cause 317 // The input dependencies will be an order-only dependency. This will cause
250 // Ninja to make sure the inputs are up-to-date before compiling this source, 318 // Ninja to make sure the inputs are up-to-date before compiling this source,
251 // but changes in the inputs deps won't cause the file to be recompiled. 319 // but changes in the inputs deps won't cause the file to be recompiled.
252 // 320 //
253 // This is important to prevent changes in unrelated actions that are 321 // This is important to prevent changes in unrelated actions that are
254 // upstream of this target from causing everything to be recompiled 322 // upstream of this target from causing everything to be recompiled.
255 // 323 //
256 // Why can we get away with this rather than using implicit deps ("|", which 324 // Why can we get away with this rather than using implicit deps ("|", which
257 // will force rebuilds when the inputs change)? For source code, the 325 // will force rebuilds when the inputs change)? For source code, the
258 // computed dependencies of all headers will be computed by the compiler, 326 // computed dependencies of all headers will be computed by the compiler,
259 // which will cause source rebuilds if any "real" upstream dependencies 327 // which will cause source rebuilds if any "real" upstream dependencies
260 // change. 328 // change.
261 // 329 //
262 // If a .cc file is generated by an input dependency, Ninja will see the 330 // If a .cc file is generated by an input dependency, Ninja will see the
263 // input to the build rule doesn't exist, and that it is an output from a 331 // input to the build rule doesn't exist, and that it is an output from a
264 // previous step, and build the previous step first. This is a "real" 332 // previous step, and build the previous step first. This is a "real"
265 // dependency and doesn't need | or || to express. 333 // dependency and doesn't need | or || to express.
266 // 334 //
267 // The only case where this rule matters is for the first build where no .d 335 // The only case where this rule matters is for the first build where no .d
268 // files exist, and Ninja doesn't know what that source file depends on. In 336 // files exist, and Ninja doesn't know what that source file depends on. In
269 // this case it's sufficient to ensure that the upstream dependencies are 337 // this case it's sufficient to ensure that the upstream dependencies are
270 // built first. This is exactly what Ninja's order-only dependencies 338 // built first. This is exactly what Ninja's order-only dependencies
271 // expresses. 339 // expresses.
272 OutputFile order_only_dep = 340 OutputFile order_only_dep =
273 WriteInputDepsStampAndGetDep(std::vector<const Target*>()); 341 WriteInputDepsStampAndGetDep(std::vector<const Target*>());
274 342
343 // For GCC builds, the .gch files are not object files, but still need to be
344 // added as explicit dependencies below. The .gch output files are placed in
345 // |pch_other_files|. This is to prevent linking against them.
275 std::vector<OutputFile> pch_obj_files; 346 std::vector<OutputFile> pch_obj_files;
276 WritePrecompiledHeaderCommands(used_types, order_only_dep, &pch_obj_files); 347 std::vector<OutputFile> pch_other_files;
348 WritePCHCommands(used_types, order_only_dep,
349 &pch_obj_files, &pch_other_files);
350 std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ?
351 &pch_obj_files : &pch_other_files;
277 352
278 // Treat all precompiled object files as explicit dependencies of all 353 // Treat all pch output files as explicit dependencies of all
279 // compiles. Some notes: 354 // compiles. Some notes:
280 // 355 //
281 // - Technically only the language-specific one is required for any specific 356 // - Only the language-specific one is required for any specific compile, but
282 // compile, but that's more difficult to express and the additional logic 357 // that's more difficult to express and the additional logic doesn't buy
283 // doesn't buy much reduced parallelism. Just list them all (there's 358 // much reduced parallelism. Just list them all (there's usually only one
284 // usually only one anyway). 359 // anyway).
285 // 360 //
286 // - Technically the .pch file is the input to the compile, not the 361 // - On Windows, the .pch file is the input to the compile, not the
287 // precompiled header's corresponding object file that we're using here. 362 // precompiled header's corresponding object file that we're using here.
288 // But Ninja's depslog doesn't support multiple outputs from the 363 // But Ninja's depslog doesn't support multiple outputs from the
289 // precompiled header compile step (it outputs both the .pch file and a 364 // precompiled header compile step (it outputs both the .pch file and a
290 // corresponding .obj file). So we consistently list the .obj file and the 365 // corresponding .obj file). So we consistently list the .obj file and the
291 // .pch file we really need comes along with it. 366 // .pch file we really need comes along with it.
367 //
368 // - GCC .gch files are not object files, therefore they are not added to the
369 // object file list.
292 std::vector<OutputFile> obj_files; 370 std::vector<OutputFile> obj_files;
293 std::vector<SourceFile> other_files; 371 std::vector<SourceFile> other_files;
294 WriteSources(pch_obj_files, order_only_dep, &obj_files, &other_files); 372 WriteSources(*pch_files, order_only_dep, &obj_files, &other_files);
295 373
296 // Also link all pch object files. 374 // Link all MSVC pch object files. The vector will be empty on GCC toolchains.
297 obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end()); 375 obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end());
298
299 if (!CheckForDuplicateObjectFiles(obj_files)) 376 if (!CheckForDuplicateObjectFiles(obj_files))
300 return; 377 return;
301 378
302 if (target_->output_type() == Target::SOURCE_SET) { 379 if (target_->output_type() == Target::SOURCE_SET) {
303 WriteSourceSetStamp(obj_files); 380 WriteSourceSetStamp(obj_files);
304 #ifndef NDEBUG 381 #ifndef NDEBUG
305 // Verify that the function that separately computes a source set's object 382 // Verify that the function that separately computes a source set's object
306 // files match the object files just computed. 383 // files match the object files just computed.
307 UniqueVector<OutputFile> computed_obj; 384 UniqueVector<OutputFile> computed_obj;
308 AddSourceSetObjectFiles(target_, &computed_obj); 385 AddSourceSetObjectFiles(target_, &computed_obj);
(...skipping 27 matching lines...) Expand all
336 ESCAPE_NINJA_COMMAND); 413 ESCAPE_NINJA_COMMAND);
337 RecursiveTargetConfigToStream<SourceDir>( 414 RecursiveTargetConfigToStream<SourceDir>(
338 target_, &ConfigValues::include_dirs, 415 target_, &ConfigValues::include_dirs,
339 IncludeWriter(include_path_output), out_); 416 IncludeWriter(include_path_output), out_);
340 out_ << std::endl; 417 out_ << std::endl;
341 } 418 }
342 419
343 bool has_precompiled_headers = 420 bool has_precompiled_headers =
344 target_->config_values().has_precompiled_headers(); 421 target_->config_values().has_precompiled_headers();
345 422
346 // Some toolchains pass cflags to the assembler since it's the same command, 423 // Some toolchains pass cflags to the assembler since it's the same command.
347 // and cflags_c might also be sent to the objective C compiler.
348 //
349 // TODO(brettw) remove the SOURCE_M from the CFLAGS_C writing once the Chrome
350 // Mac build is updated not to pass cflags_c to .m files.
351 EscapeOptions opts = GetFlagOptions(); 424 EscapeOptions opts = GetFlagOptions();
352 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_CPP) || 425 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_CPP) ||
353 used_types.Get(SOURCE_M) || used_types.Get(SOURCE_MM) || 426 used_types.Get(SOURCE_M) || used_types.Get(SOURCE_MM) ||
354 used_types.Get(SOURCE_S) || used_types.Get(SOURCE_ASM)) { 427 used_types.Get(SOURCE_S) || used_types.Get(SOURCE_ASM)) {
355 WriteOneFlag(SUBSTITUTION_CFLAGS, false, Toolchain::TYPE_NONE, 428 WriteOneFlag(SUBSTITUTION_CFLAGS, false, Toolchain::TYPE_NONE,
356 &ConfigValues::cflags, opts); 429 &ConfigValues::cflags, opts);
357 } 430 }
358 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_M) || 431 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_S) ||
359 used_types.Get(SOURCE_S) || used_types.Get(SOURCE_ASM)) { 432 used_types.Get(SOURCE_ASM)) {
360 WriteOneFlag(SUBSTITUTION_CFLAGS_C, has_precompiled_headers, 433 WriteOneFlag(SUBSTITUTION_CFLAGS_C, has_precompiled_headers,
361 Toolchain::TYPE_CC, &ConfigValues::cflags_c, opts); 434 Toolchain::TYPE_CC, &ConfigValues::cflags_c, opts);
362 } 435 }
363 if (used_types.Get(SOURCE_CPP)) { 436 if (used_types.Get(SOURCE_CPP)) {
364 WriteOneFlag(SUBSTITUTION_CFLAGS_CC, has_precompiled_headers, 437 WriteOneFlag(SUBSTITUTION_CFLAGS_CC, has_precompiled_headers,
365 Toolchain::TYPE_CXX, &ConfigValues::cflags_cc, opts); 438 Toolchain::TYPE_CXX, &ConfigValues::cflags_cc, opts);
366 } 439 }
367 if (used_types.Get(SOURCE_M)) { 440 if (used_types.Get(SOURCE_M)) {
368 WriteOneFlag(SUBSTITUTION_CFLAGS_OBJC, has_precompiled_headers, 441 WriteOneFlag(SUBSTITUTION_CFLAGS_OBJC, has_precompiled_headers,
369 Toolchain::TYPE_OBJC, &ConfigValues::cflags_objc, opts); 442 Toolchain::TYPE_OBJC, &ConfigValues::cflags_objc, opts);
(...skipping 20 matching lines...) Expand all
390 if (has_precompiled_headers) { 463 if (has_precompiled_headers) {
391 const Tool* tool = target_->toolchain()->GetTool(tool_type); 464 const Tool* tool = target_->toolchain()->GetTool(tool_type);
392 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) { 465 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) {
393 // Name the .pch file. 466 // Name the .pch file.
394 out_ << " /Fp"; 467 out_ << " /Fp";
395 path_output_.WriteFile(out_, GetWindowsPCHFile(tool_type)); 468 path_output_.WriteFile(out_, GetWindowsPCHFile(tool_type));
396 469
397 // Enables precompiled headers and names the .h file. It's a string 470 // Enables precompiled headers and names the .h file. It's a string
398 // rather than a file name (so no need to rebase or use path_output_). 471 // rather than a file name (so no need to rebase or use path_output_).
399 out_ << " /Yu" << target_->config_values().precompiled_header(); 472 out_ << " /Yu" << target_->config_values().precompiled_header();
473 RecursiveTargetConfigStringsToStream(target_, getter,
474 flag_escape_options, out_);
475 } else if (tool && tool->precompiled_header_type() == Tool::PCH_GCC) {
476 // The targets to build the .gch files should omit the -include flag
477 // below. To accomplish this, each substitution flag is overwritten in the
478 // target rule and these values are repeated. The -include flag is omitted
479 // in place of the required -x <header lang> flag for .gch targets.
480 RecursiveTargetConfigStringsToStream(target_, getter,
481 flag_escape_options, out_);
482
483 // Compute the gch file (it will be language-specific).
484 std::vector<OutputFile> outputs;
485 GetPCHOutputFiles(target_, tool_type, &outputs);
486 if (!outputs.empty()) {
487 // Trim the .gch suffix for the -include flag.
488 // e.g. for gch file foo/bar/target.precompiled.h.gch:
489 // -include foo/bar/target.precompiled.h
490 std::string pch_file = outputs[0].value();
491 pch_file.erase(pch_file.length() - 4);
492 out_ << " -include " << pch_file;
493 }
400 } 494 }
401 } 495 }
402
403 RecursiveTargetConfigStringsToStream(target_, getter,
404 flag_escape_options, out_);
405 out_ << std::endl; 496 out_ << std::endl;
406 } 497 }
407 498
408 void NinjaBinaryTargetWriter::WritePrecompiledHeaderCommands( 499 void NinjaBinaryTargetWriter::WritePCHCommands(
409 const SourceFileTypeSet& used_types, 500 const SourceFileTypeSet& used_types,
410 const OutputFile& order_only_dep, 501 const OutputFile& order_only_dep,
411 std::vector<OutputFile>* object_files) { 502 std::vector<OutputFile>* object_files,
503 std::vector<OutputFile>* other_files) {
412 if (!target_->config_values().has_precompiled_headers()) 504 if (!target_->config_values().has_precompiled_headers())
413 return; 505 return;
414 506
415 const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC); 507 const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC);
416 if (tool_c && 508 if (tool_c &&
417 tool_c->precompiled_header_type() == Tool::PCH_MSVC && 509 tool_c->precompiled_header_type() != Tool::PCH_NONE &&
418 used_types.Get(SOURCE_C)) { 510 used_types.Get(SOURCE_C)) {
419 WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_C, 511 WritePCHCommand(SUBSTITUTION_CFLAGS_C,
420 Toolchain::TYPE_CC, 512 Toolchain::TYPE_CC,
421 order_only_dep, object_files); 513 tool_c->precompiled_header_type(),
514 order_only_dep, object_files, other_files);
422 } 515 }
423 const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX); 516 const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX);
424 if (tool_cxx && 517 if (tool_cxx &&
425 tool_cxx->precompiled_header_type() == Tool::PCH_MSVC && 518 tool_cxx->precompiled_header_type() != Tool::PCH_NONE &&
426 used_types.Get(SOURCE_CPP)) { 519 used_types.Get(SOURCE_CPP)) {
427 WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_CC, 520 WritePCHCommand(SUBSTITUTION_CFLAGS_CC,
428 Toolchain::TYPE_CXX, 521 Toolchain::TYPE_CXX,
429 order_only_dep, object_files); 522 tool_cxx->precompiled_header_type(),
523 order_only_dep, object_files, other_files);
430 } 524 }
525
526 const Tool* tool_objc = target_->toolchain()->GetTool(Toolchain::TYPE_OBJC);
527 if (tool_objc &&
528 tool_objc->precompiled_header_type() == Tool::PCH_GCC &&
529 used_types.Get(SOURCE_M)) {
530 WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC,
531 Toolchain::TYPE_OBJC,
532 tool_objc->precompiled_header_type(),
533 order_only_dep, object_files, other_files);
534 }
535
536 const Tool* tool_objcxx =
537 target_->toolchain()->GetTool(Toolchain::TYPE_OBJCXX);
538 if (tool_objcxx &&
539 tool_objcxx->precompiled_header_type() == Tool::PCH_GCC &&
540 used_types.Get(SOURCE_MM)) {
541 WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC,
542 Toolchain::TYPE_OBJCXX,
543 tool_objcxx->precompiled_header_type(),
544 order_only_dep, object_files, other_files);
545 }
546 }
547
548 void NinjaBinaryTargetWriter::WritePCHCommand(
549 SubstitutionType flag_type,
550 Toolchain::ToolType tool_type,
551 Tool::PrecompiledHeaderType header_type,
552 const OutputFile& order_only_dep,
553 std::vector<OutputFile>* object_files,
554 std::vector<OutputFile>* other_files) {
555 switch (header_type) {
556 case Tool::PCH_MSVC:
557 WriteWindowsPCHCommand(flag_type, tool_type, order_only_dep,
558 object_files);
559 break;
560 case Tool::PCH_GCC:
561 WriteGCCPCHCommand(flag_type, tool_type, order_only_dep,
562 other_files);
563 break;
564 case Tool::PCH_NONE:
565 NOTREACHED() << "Cannot write a PCH command with no PCH header type";
566 break;
567 }
568 }
569
570 void NinjaBinaryTargetWriter::WriteGCCPCHCommand(
571 SubstitutionType flag_type,
572 Toolchain::ToolType tool_type,
573 const OutputFile& order_only_dep,
574 std::vector<OutputFile>* gch_files) {
575 // Compute the pch output file (it will be language-specific).
576 std::vector<OutputFile> outputs;
577 GetPCHOutputFiles(target_, tool_type, &outputs);
578 if (outputs.empty())
579 return;
580
581 gch_files->insert(gch_files->end(), outputs.begin(), outputs.end());
582
583 // Build line to compile the file.
584 WriteCompilerBuildLine(target_->config_values().precompiled_source(),
585 std::vector<OutputFile>(), order_only_dep, tool_type,
586 outputs);
587
588 // This build line needs a custom language-specific flags value. Rule-specific
589 // variables are just indented underneath the rule line.
590 out_ << " " << kSubstitutionNinjaNames[flag_type] << " =";
591
592 // Each substitution flag is overwritten in the target rule to replace the
593 // implicitly generated -include flag with the -x <header lang> flag required
594 // for .gch targets.
595 EscapeOptions opts = GetFlagOptions();
596 if (tool_type == Toolchain::TYPE_CC) {
597 RecursiveTargetConfigStringsToStream(target_,
598 &ConfigValues::cflags_c, opts, out_);
599 } else if (tool_type == Toolchain::TYPE_CXX) {
600 RecursiveTargetConfigStringsToStream(target_,
601 &ConfigValues::cflags_cc, opts, out_);
602 } else if (tool_type == Toolchain::TYPE_OBJC) {
603 RecursiveTargetConfigStringsToStream(target_,
604 &ConfigValues::cflags_objc, opts, out_);
605 } else if (tool_type == Toolchain::TYPE_OBJCXX) {
606 RecursiveTargetConfigStringsToStream(target_,
607 &ConfigValues::cflags_objcc, opts, out_);
608 }
609
610 // Append the command to specify the language of the .gch file.
611 out_ << " -x " << GetPCHLangForToolType(tool_type);
612
613 // Write two blank lines to help separate the PCH build lines from the
614 // regular source build lines.
615 out_ << std::endl << std::endl;
431 } 616 }
432 617
433 void NinjaBinaryTargetWriter::WriteWindowsPCHCommand( 618 void NinjaBinaryTargetWriter::WriteWindowsPCHCommand(
434 SubstitutionType flag_type, 619 SubstitutionType flag_type,
435 Toolchain::ToolType tool_type, 620 Toolchain::ToolType tool_type,
436 const OutputFile& order_only_dep, 621 const OutputFile& order_only_dep,
437 std::vector<OutputFile>* object_files) { 622 std::vector<OutputFile>* object_files) {
438 // Compute the object file (it will be language-specific). 623 // Compute the pch output file (it will be language-specific).
439 std::vector<OutputFile> outputs; 624 std::vector<OutputFile> outputs;
440 GetWindowsPCHObjectFiles(target_, tool_type, &outputs); 625 GetPCHOutputFiles(target_, tool_type, &outputs);
441 if (outputs.empty()) 626 if (outputs.empty())
442 return; 627 return;
628
443 object_files->insert(object_files->end(), outputs.begin(), outputs.end()); 629 object_files->insert(object_files->end(), outputs.begin(), outputs.end());
444 630
445 // Build line to compile the file. 631 // Build line to compile the file.
446 WriteCompilerBuildLine(target_->config_values().precompiled_source(), 632 WriteCompilerBuildLine(target_->config_values().precompiled_source(),
447 std::vector<OutputFile>(), order_only_dep, tool_type, 633 std::vector<OutputFile>(), order_only_dep, tool_type,
448 outputs); 634 outputs);
449 635
450 // This build line needs a custom language-specific flags value. It needs to 636 // This build line needs a custom language-specific flags value. Rule-specific
451 // include the switch to generate the .pch file in addition to the normal 637 // variables are just indented underneath the rule line.
452 // ones. Rule-specific variables are just indented underneath the rule line,
453 // and this defines the new one in terms of the old value.
454 out_ << " " << kSubstitutionNinjaNames[flag_type] << " ="; 638 out_ << " " << kSubstitutionNinjaNames[flag_type] << " =";
455 out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}";
456 639
457 // Append the command to generate the .pch file. 640 // Append the command to generate the .pch file.
641 // This adds the value to the existing flag instead of overwriting it.
642 out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}";
458 out_ << " /Yc" << target_->config_values().precompiled_header(); 643 out_ << " /Yc" << target_->config_values().precompiled_header();
459 644
460 // Write two blank lines to help separate the PCH build lines from the 645 // Write two blank lines to help separate the PCH build lines from the
461 // regular source build lines. 646 // regular source build lines.
462 out_ << std::endl << std::endl; 647 out_ << std::endl << std::endl;
463 } 648 }
464 649
465 void NinjaBinaryTargetWriter::WriteSources( 650 void NinjaBinaryTargetWriter::WriteSources(
466 const std::vector<OutputFile>& extra_deps, 651 const std::vector<OutputFile>& pch_deps,
467 const OutputFile& order_only_dep, 652 const OutputFile& order_only_dep,
468 std::vector<OutputFile>* object_files, 653 std::vector<OutputFile>* object_files,
469 std::vector<SourceFile>* other_files) { 654 std::vector<SourceFile>* other_files) {
470 object_files->reserve(object_files->size() + target_->sources().size()); 655 object_files->reserve(object_files->size() + target_->sources().size());
471 656
472 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop. 657 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop.
658 std::vector<OutputFile> deps;
473 for (const auto& source : target_->sources()) { 659 for (const auto& source : target_->sources()) {
660 // Clear the vector but maintain the max capacity to prevent reallocations.
661 deps.resize(0);
474 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; 662 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
475 if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) { 663 if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) {
476 if (GetSourceFileType(source) == SOURCE_DEF) 664 if (GetSourceFileType(source) == SOURCE_DEF)
477 other_files->push_back(source); 665 other_files->push_back(source);
478 continue; // No output for this source. 666 continue; // No output for this source.
479 } 667 }
480 668
481 if (tool_type != Toolchain::TYPE_NONE) { 669 if (tool_type != Toolchain::TYPE_NONE) {
482 WriteCompilerBuildLine(source, extra_deps, order_only_dep, tool_type, 670 // Only include PCH deps that correspond to the tool type, for instance,
671 // do not specify target_name.precompile.cc.o (a CXX PCH file) as a dep
672 // for the output of a C tool type.
673 //
674 // This makes the assumption that pch_deps only contains pch output files
675 // with the naming scheme specified in GetWindowsPCHObjectExtension or
676 // GetGCCPCHOutputExtension.
677 const Tool* tool = target_->toolchain()->GetTool(tool_type);
678 for (const auto& dep : pch_deps) {
679 const std::string& output_value = dep.value();
680 std::string output_extension;
681 if (tool->precompiled_header_type() == Tool::PCH_MSVC) {
682 output_extension = GetWindowsPCHObjectExtension(tool_type);
683 } else if (tool->precompiled_header_type() == Tool::PCH_GCC) {
684 output_extension = GetGCCPCHOutputExtension(tool_type);
685 }
686 if (output_value.compare(output_value.size() - output_extension.size(),
687 output_extension.size(), output_extension) == 0) {
688 deps.push_back(dep);
689 }
690 }
691 WriteCompilerBuildLine(source, deps, order_only_dep, tool_type,
483 tool_outputs); 692 tool_outputs);
484 } 693 }
485 694
486 // It's theoretically possible for a compiler to produce more than one 695 // It's theoretically possible for a compiler to produce more than one
487 // output, but we'll only link to the first output. 696 // output, but we'll only link to the first output.
488 object_files->push_back(tool_outputs[0]); 697 object_files->push_back(tool_outputs[0]);
489 } 698 }
490 out_ << std::endl; 699 out_ << std::endl;
491 } 700 }
492 701
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 for (const auto& non_linkable_dep : non_linkable_deps) { 990 for (const auto& non_linkable_dep : non_linkable_deps) {
782 out_ << " "; 991 out_ << " ";
783 path_output_.WriteFile(out_, non_linkable_dep->dependency_output_file()); 992 path_output_.WriteFile(out_, non_linkable_dep->dependency_output_file());
784 } 993 }
785 } 994 }
786 } 995 }
787 996
788 OutputFile NinjaBinaryTargetWriter::GetWindowsPCHFile( 997 OutputFile NinjaBinaryTargetWriter::GetWindowsPCHFile(
789 Toolchain::ToolType tool_type) const { 998 Toolchain::ToolType tool_type) const {
790 // Use "obj/{dir}/{target_name}_{lang}.pch" which ends up 999 // Use "obj/{dir}/{target_name}_{lang}.pch" which ends up
791 // looking like "obj/chrome/browser/browser.cc.pch" 1000 // looking like "obj/chrome/browser/browser_cc.pch"
792 OutputFile ret = GetTargetOutputDirAsOutputFile(target_); 1001 OutputFile ret = GetTargetOutputDirAsOutputFile(target_);
793 ret.value().append(target_->label().name()); 1002 ret.value().append(target_->label().name());
794 ret.value().push_back('_'); 1003 ret.value().push_back('_');
795 ret.value().append(GetPCHLangForToolType(tool_type)); 1004 ret.value().append(GetPCHLangSuffixForToolType(tool_type));
796 ret.value().append(".pch"); 1005 ret.value().append(".pch");
797 1006
798 return ret; 1007 return ret;
799 } 1008 }
800 1009
801 bool NinjaBinaryTargetWriter::CheckForDuplicateObjectFiles( 1010 bool NinjaBinaryTargetWriter::CheckForDuplicateObjectFiles(
802 const std::vector<OutputFile>& files) const { 1011 const std::vector<OutputFile>& files) const {
803 base::hash_set<std::string> set; 1012 base::hash_set<std::string> set;
804 for (const auto& file : files) { 1013 for (const auto& file : files) {
805 if (!set.insert(file.value()).second) { 1014 if (!set.insert(file.value()).second) {
(...skipping 11 matching lines...) Expand all
817 "\n" 1026 "\n"
818 "In the latter case, either rename one of the files or move one of\n" 1027 "In the latter case, either rename one of the files or move one of\n"
819 "the sources to a separate source_set to avoid them both being in\n" 1028 "the sources to a separate source_set to avoid them both being in\n"
820 "the same target."); 1029 "the same target.");
821 g_scheduler->FailWithError(err); 1030 g_scheduler->FailWithError(err);
822 return false; 1031 return false;
823 } 1032 }
824 } 1033 }
825 return true; 1034 return true;
826 } 1035 }
OLDNEW
« no previous file with comments | « tools/gn/ninja_binary_target_writer.h ('k') | tools/gn/ninja_binary_target_writer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698