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

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: Address Brett’s comments... (hopefully) 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 if (!WritePCHCommands(used_types, order_only_dep,
349 &pch_obj_files, &pch_other_files)) {
350 return;
351 }
352 std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ?
353 &pch_obj_files : &pch_other_files;
277 354
278 // Treat all precompiled object files as explicit dependencies of all 355 // Treat all pch output files as explicit dependencies of all
279 // compiles. Some notes: 356 // compiles. Some notes:
280 // 357 //
281 // - Technically only the language-specific one is required for any specific 358 // - 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 359 // 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 360 // much reduced parallelism. Just list them all (there's usually only one
284 // usually only one anyway). 361 // anyway).
285 // 362 //
286 // - Technically the .pch file is the input to the compile, not the 363 // - 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. 364 // precompiled header's corresponding object file that we're using here.
288 // But Ninja's depslog doesn't support multiple outputs from the 365 // But Ninja's depslog doesn't support multiple outputs from the
289 // precompiled header compile step (it outputs both the .pch file and a 366 // 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 367 // corresponding .obj file). So we consistently list the .obj file and the
291 // .pch file we really need comes along with it. 368 // .pch file we really need comes along with it.
369 //
370 // - GCC .gch files are not object files, therefore they are not added to the
371 // object file list.
292 std::vector<OutputFile> obj_files; 372 std::vector<OutputFile> obj_files;
293 std::vector<SourceFile> other_files; 373 std::vector<SourceFile> other_files;
294 WriteSources(pch_obj_files, order_only_dep, &obj_files, &other_files); 374 WriteSources(*pch_files, order_only_dep, &obj_files, &other_files);
295 375
296 // Also link all pch object files. 376 // 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()); 377 obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end());
298
299 if (!CheckForDuplicateObjectFiles(obj_files)) 378 if (!CheckForDuplicateObjectFiles(obj_files))
300 return; 379 return;
301 380
302 if (target_->output_type() == Target::SOURCE_SET) { 381 if (target_->output_type() == Target::SOURCE_SET) {
303 WriteSourceSetStamp(obj_files); 382 WriteSourceSetStamp(obj_files);
304 #ifndef NDEBUG 383 #ifndef NDEBUG
305 // Verify that the function that separately computes a source set's object 384 // Verify that the function that separately computes a source set's object
306 // files match the object files just computed. 385 // files match the object files just computed.
307 UniqueVector<OutputFile> computed_obj; 386 UniqueVector<OutputFile> computed_obj;
308 AddSourceSetObjectFiles(target_, &computed_obj); 387 AddSourceSetObjectFiles(target_, &computed_obj);
(...skipping 27 matching lines...) Expand all
336 ESCAPE_NINJA_COMMAND); 415 ESCAPE_NINJA_COMMAND);
337 RecursiveTargetConfigToStream<SourceDir>( 416 RecursiveTargetConfigToStream<SourceDir>(
338 target_, &ConfigValues::include_dirs, 417 target_, &ConfigValues::include_dirs,
339 IncludeWriter(include_path_output), out_); 418 IncludeWriter(include_path_output), out_);
340 out_ << std::endl; 419 out_ << std::endl;
341 } 420 }
342 421
343 bool has_precompiled_headers = 422 bool has_precompiled_headers =
344 target_->config_values().has_precompiled_headers(); 423 target_->config_values().has_precompiled_headers();
345 424
346 // Some toolchains pass cflags to the assembler since it's the same command, 425 // 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(); 426 EscapeOptions opts = GetFlagOptions();
352 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_CPP) || 427 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_CPP) ||
353 used_types.Get(SOURCE_M) || used_types.Get(SOURCE_MM) || 428 used_types.Get(SOURCE_M) || used_types.Get(SOURCE_MM) ||
354 used_types.Get(SOURCE_S) || used_types.Get(SOURCE_ASM)) { 429 used_types.Get(SOURCE_S) || used_types.Get(SOURCE_ASM)) {
355 WriteOneFlag(SUBSTITUTION_CFLAGS, false, Toolchain::TYPE_NONE, 430 WriteOneFlag(SUBSTITUTION_CFLAGS, false, Toolchain::TYPE_NONE,
356 &ConfigValues::cflags, opts); 431 &ConfigValues::cflags, opts);
357 } 432 }
358 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_M) || 433 if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_S) ||
359 used_types.Get(SOURCE_S) || used_types.Get(SOURCE_ASM)) { 434 used_types.Get(SOURCE_ASM)) {
360 WriteOneFlag(SUBSTITUTION_CFLAGS_C, has_precompiled_headers, 435 WriteOneFlag(SUBSTITUTION_CFLAGS_C, has_precompiled_headers,
361 Toolchain::TYPE_CC, &ConfigValues::cflags_c, opts); 436 Toolchain::TYPE_CC, &ConfigValues::cflags_c, opts);
362 } 437 }
363 if (used_types.Get(SOURCE_CPP)) { 438 if (used_types.Get(SOURCE_CPP)) {
364 WriteOneFlag(SUBSTITUTION_CFLAGS_CC, has_precompiled_headers, 439 WriteOneFlag(SUBSTITUTION_CFLAGS_CC, has_precompiled_headers,
365 Toolchain::TYPE_CXX, &ConfigValues::cflags_cc, opts); 440 Toolchain::TYPE_CXX, &ConfigValues::cflags_cc, opts);
366 } 441 }
367 if (used_types.Get(SOURCE_M)) { 442 if (used_types.Get(SOURCE_M)) {
368 WriteOneFlag(SUBSTITUTION_CFLAGS_OBJC, has_precompiled_headers, 443 WriteOneFlag(SUBSTITUTION_CFLAGS_OBJC, has_precompiled_headers,
369 Toolchain::TYPE_OBJC, &ConfigValues::cflags_objc, opts); 444 Toolchain::TYPE_OBJC, &ConfigValues::cflags_objc, opts);
(...skipping 20 matching lines...) Expand all
390 if (has_precompiled_headers) { 465 if (has_precompiled_headers) {
391 const Tool* tool = target_->toolchain()->GetTool(tool_type); 466 const Tool* tool = target_->toolchain()->GetTool(tool_type);
392 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) { 467 if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) {
393 // Name the .pch file. 468 // Name the .pch file.
394 out_ << " /Fp"; 469 out_ << " /Fp";
395 path_output_.WriteFile(out_, GetWindowsPCHFile(tool_type)); 470 path_output_.WriteFile(out_, GetWindowsPCHFile(tool_type));
396 471
397 // Enables precompiled headers and names the .h file. It's a string 472 // 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_). 473 // rather than a file name (so no need to rebase or use path_output_).
399 out_ << " /Yu" << target_->config_values().precompiled_header(); 474 out_ << " /Yu" << target_->config_values().precompiled_header();
475 RecursiveTargetConfigStringsToStream(target_, getter,
476 flag_escape_options, out_);
477 } else if (tool && tool->precompiled_header_type() == Tool::PCH_GCC) {
478 // The targets to build the .gch files should omit the -include flag
479 // below. To accomplish this, each substitution flag is overwritten in the
480 // target rule and these values are repeated. The -include flag is omitted
481 // in place of the required -x <header lang> flag for .gch targets.
482 RecursiveTargetConfigStringsToStream(target_, getter,
483 flag_escape_options, out_);
484
485 // Compute the gch file (it will be language-specific).
486 std::vector<OutputFile> outputs;
487 GetPCHOutputFiles(target_, tool_type, &outputs);
488 if (!outputs.empty()) {
489 // Trim the .gch suffix for the -include flag.
490 // e.g. for gch file foo/bar/target.precompiled.h.gch:
491 // -include foo/bar/target.precompiled.h
492 std::string pch_file = outputs[0].value();
493 pch_file.erase(pch_file.length() - 4);
494 out_ << " -include " << pch_file;
495 }
496 }
497 }
498 out_ << std::endl;
499 }
500
501 bool NinjaBinaryTargetWriter::WritePCHCommands(
502 const SourceFileTypeSet& used_types,
503 const OutputFile& order_only_dep,
504 std::vector<OutputFile>* object_files,
505 std::vector<OutputFile>* other_files) {
506 if (!target_->config_values().has_precompiled_headers())
507 return true;
508
509 const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC);
510 if (tool_c &&
511 tool_c->precompiled_header_type() != Tool::PCH_NONE &&
512 used_types.Get(SOURCE_C)) {
513 if (!WritePCHCommand(SUBSTITUTION_CFLAGS_C,
514 Toolchain::TYPE_CC,
515 tool_c->precompiled_header_type(),
516 order_only_dep, object_files, other_files)) {
517 return false;
518 }
519 }
520 const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX);
521 if (tool_cxx &&
522 tool_cxx->precompiled_header_type() != Tool::PCH_NONE &&
523 used_types.Get(SOURCE_CPP)) {
524 if (!WritePCHCommand(SUBSTITUTION_CFLAGS_CC,
525 Toolchain::TYPE_CXX,
526 tool_cxx->precompiled_header_type(),
527 order_only_dep, object_files, other_files)) {
528 return false;
400 } 529 }
401 } 530 }
402 531
403 RecursiveTargetConfigStringsToStream(target_, getter, 532 const Tool* tool_objc = target_->toolchain()->GetTool(Toolchain::TYPE_OBJC);
404 flag_escape_options, out_); 533 if (tool_objc &&
405 out_ << std::endl; 534 tool_objc->precompiled_header_type() == Tool::PCH_GCC &&
535 used_types.Get(SOURCE_M)) {
536 if (!WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC,
537 Toolchain::TYPE_OBJC,
538 tool_objc->precompiled_header_type(),
539 order_only_dep, object_files, other_files)) {
540 return false;
541 }
542 }
543
544 const Tool* tool_objcxx =
545 target_->toolchain()->GetTool(Toolchain::TYPE_OBJCXX);
546 if (tool_objcxx &&
547 tool_objcxx->precompiled_header_type() == Tool::PCH_GCC &&
548 used_types.Get(SOURCE_MM)) {
549 if (!WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC,
550 Toolchain::TYPE_OBJCXX,
551 tool_objcxx->precompiled_header_type(),
552 order_only_dep, object_files, other_files)) {
553 return false;
554 }
555 }
556 return true;
406 } 557 }
407 558
408 void NinjaBinaryTargetWriter::WritePrecompiledHeaderCommands( 559 bool NinjaBinaryTargetWriter::WritePCHCommand(
409 const SourceFileTypeSet& used_types, 560 SubstitutionType flag_type,
561 Toolchain::ToolType tool_type,
562 Tool::PrecompiledHeaderType header_type,
410 const OutputFile& order_only_dep, 563 const OutputFile& order_only_dep,
411 std::vector<OutputFile>* object_files) { 564 std::vector<OutputFile>* object_files,
412 if (!target_->config_values().has_precompiled_headers()) 565 std::vector<OutputFile>* other_files) {
413 return; 566 switch (header_type) {
414 567 case Tool::PCH_MSVC:
415 const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC); 568 return WriteWindowsPCHCommand(
416 if (tool_c && 569 flag_type, tool_type, order_only_dep, object_files);
417 tool_c->precompiled_header_type() == Tool::PCH_MSVC && 570 case Tool::PCH_GCC:
418 used_types.Get(SOURCE_C)) { 571 return WriteGCCPCHCommand(
419 WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_C, 572 flag_type, tool_type, order_only_dep, other_files);
420 Toolchain::TYPE_CC, 573 case Tool::PCH_NONE:
421 order_only_dep, object_files); 574 NOTREACHED() << "Cannot write a PCH command with no PCH header type";
575 break;
422 } 576 }
423 const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX); 577 return true;
424 if (tool_cxx &&
425 tool_cxx->precompiled_header_type() == Tool::PCH_MSVC &&
426 used_types.Get(SOURCE_CPP)) {
427 WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_CC,
428 Toolchain::TYPE_CXX,
429 order_only_dep, object_files);
430 }
431 } 578 }
432 579
433 void NinjaBinaryTargetWriter::WriteWindowsPCHCommand( 580 bool NinjaBinaryTargetWriter::WriteGCCPCHCommand(
581 SubstitutionType flag_type,
582 Toolchain::ToolType tool_type,
583 const OutputFile& order_only_dep,
584 std::vector<OutputFile>* gch_files) {
585 // Ensure the precompiled source and precompiled header are the same target.
586 SourceFile source = target_->config_values().precompiled_source();
587 std::string header_str = target_->config_values().precompiled_header();
588 header_str.insert(0, "//");
brettw 2015/09/17 19:47:25 Is this checking really correct? I think GCC is th
Bons 2015/09/17 20:36:12 Done.
589 SourceFile header = SourceFile(SourceFile::SWAP_IN, &header_str);
590 if (source != header) {
591 Err err(
592 target_->defined_from(),
593 "GCC precompiled source and header are different files",
594 "The target " + target_->label().GetUserVisibleName(false) +
595 "\nspecifies a precompiled source:\n " +
596 source.value() + "\n"
597 "that is different than the precompiled header:\n " +
598 header_str + "\n"
599 "\n"
600 "For GCC toolchains, the two must be equal, for instance:\n"
601 " precompiled_header = \"build/precompile.h\""
602 " precompiled_source = \"//build/precompile.h\"");
603 g_scheduler->FailWithError(err);
604 return false;
brettw 2015/09/17 19:47:25 I think if we delete this, we can also make this f
Bons 2015/09/17 20:36:12 Done.
605 }
606
607 // Compute the pch output file (it will be language-specific).
608 std::vector<OutputFile> outputs;
609 GetPCHOutputFiles(target_, tool_type, &outputs);
610 if (outputs.empty())
611 return true;
612
613 gch_files->insert(gch_files->end(), outputs.begin(), outputs.end());
614
615 // Build line to compile the file.
616 WriteCompilerBuildLine(target_->config_values().precompiled_source(),
617 std::vector<OutputFile>(), order_only_dep, tool_type,
618 outputs);
619
620 // This build line needs a custom language-specific flags value. Rule-specific
621 // variables are just indented underneath the rule line.
622 out_ << " " << kSubstitutionNinjaNames[flag_type] << " =";
623
624 // Each substitution flag is overwritten in the target rule to replace the
625 // -include flag with the -x <header lang> flag required for .gch targets.
brettw 2015/09/17 19:47:25 You you add "implicitly generated" before "-includ
Bons 2015/09/17 20:36:12 Done.
626 EscapeOptions opts = GetFlagOptions();
627 if (tool_type == Toolchain::TYPE_CC) {
628 RecursiveTargetConfigStringsToStream(target_,
629 &ConfigValues::cflags_c, opts, out_);
630 } else if (tool_type == Toolchain::TYPE_CXX) {
631 RecursiveTargetConfigStringsToStream(target_,
632 &ConfigValues::cflags_cc, opts, out_);
633 } else if (tool_type == Toolchain::TYPE_OBJC) {
634 RecursiveTargetConfigStringsToStream(target_,
635 &ConfigValues::cflags_objc, opts, out_);
636 } else if (tool_type == Toolchain::TYPE_OBJCXX) {
637 RecursiveTargetConfigStringsToStream(target_,
638 &ConfigValues::cflags_objcc, opts, out_);
639 }
640
641 // Append the command to specify the language of the .gch file.
642 out_ << " -x " << GetPCHLangForToolType(tool_type);
643
644 // Write two blank lines to help separate the PCH build lines from the
645 // regular source build lines.
646 out_ << std::endl << std::endl;
647
648 return true;
649 }
650
651 bool NinjaBinaryTargetWriter::WriteWindowsPCHCommand(
434 SubstitutionType flag_type, 652 SubstitutionType flag_type,
435 Toolchain::ToolType tool_type, 653 Toolchain::ToolType tool_type,
436 const OutputFile& order_only_dep, 654 const OutputFile& order_only_dep,
437 std::vector<OutputFile>* object_files) { 655 std::vector<OutputFile>* object_files) {
438 // Compute the object file (it will be language-specific). 656 // Compute the pch output file (it will be language-specific).
439 std::vector<OutputFile> outputs; 657 std::vector<OutputFile> outputs;
440 GetWindowsPCHObjectFiles(target_, tool_type, &outputs); 658 GetPCHOutputFiles(target_, tool_type, &outputs);
441 if (outputs.empty()) 659 if (outputs.empty())
442 return; 660 return true;
661
443 object_files->insert(object_files->end(), outputs.begin(), outputs.end()); 662 object_files->insert(object_files->end(), outputs.begin(), outputs.end());
444 663
445 // Build line to compile the file. 664 // Build line to compile the file.
446 WriteCompilerBuildLine(target_->config_values().precompiled_source(), 665 WriteCompilerBuildLine(target_->config_values().precompiled_source(),
447 std::vector<OutputFile>(), order_only_dep, tool_type, 666 std::vector<OutputFile>(), order_only_dep, tool_type,
448 outputs); 667 outputs);
449 668
450 // This build line needs a custom language-specific flags value. It needs to 669 // 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 670 // 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] << " ="; 671 out_ << " " << kSubstitutionNinjaNames[flag_type] << " =";
455 out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}";
456 672
457 // Append the command to generate the .pch file. 673 // Append the command to generate the .pch file.
674 // This adds the value to the existing flag instead of overwriting it.
675 out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}";
458 out_ << " /Yc" << target_->config_values().precompiled_header(); 676 out_ << " /Yc" << target_->config_values().precompiled_header();
459 677
460 // Write two blank lines to help separate the PCH build lines from the 678 // Write two blank lines to help separate the PCH build lines from the
461 // regular source build lines. 679 // regular source build lines.
462 out_ << std::endl << std::endl; 680 out_ << std::endl << std::endl;
681
682 return true;
463 } 683 }
464 684
465 void NinjaBinaryTargetWriter::WriteSources( 685 void NinjaBinaryTargetWriter::WriteSources(
466 const std::vector<OutputFile>& extra_deps, 686 const std::vector<OutputFile>& pch_deps,
467 const OutputFile& order_only_dep, 687 const OutputFile& order_only_dep,
468 std::vector<OutputFile>* object_files, 688 std::vector<OutputFile>* object_files,
469 std::vector<SourceFile>* other_files) { 689 std::vector<SourceFile>* other_files) {
470 object_files->reserve(object_files->size() + target_->sources().size()); 690 object_files->reserve(object_files->size() + target_->sources().size());
471 691
472 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop. 692 std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop.
693 std::vector<OutputFile> deps;
473 for (const auto& source : target_->sources()) { 694 for (const auto& source : target_->sources()) {
695 // Clear the vector but maintain the max capacity to prevent reallocations.
696 deps.resize(0);
474 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; 697 Toolchain::ToolType tool_type = Toolchain::TYPE_NONE;
475 if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) { 698 if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) {
476 if (GetSourceFileType(source) == SOURCE_DEF) 699 if (GetSourceFileType(source) == SOURCE_DEF)
477 other_files->push_back(source); 700 other_files->push_back(source);
478 continue; // No output for this source. 701 continue; // No output for this source.
479 } 702 }
480 703
481 if (tool_type != Toolchain::TYPE_NONE) { 704 if (tool_type != Toolchain::TYPE_NONE) {
482 WriteCompilerBuildLine(source, extra_deps, order_only_dep, tool_type, 705 // Only include PCH deps that correspond to the tool type, for instance,
706 // do not specify target_name.precompile.cc.o (a CXX PCH file) as a dep
707 // for the output of a C tool type.
708 //
709 // This makes the assumption that pch_deps only contains pch output files
710 // with the naming scheme specified in GetWindowsPCHObjectExtension or
711 // GetGCCPCHOutputExtension.
712 const Tool* tool = target_->toolchain()->GetTool(tool_type);
713 for (const auto& dep : pch_deps) {
714 const std::string& output_value = dep.value();
715 std::string output_extension;
716 if (tool->precompiled_header_type() == Tool::PCH_MSVC) {
717 output_extension = GetWindowsPCHObjectExtension(tool_type);
718 } else if (tool->precompiled_header_type() == Tool::PCH_GCC) {
719 output_extension = GetGCCPCHOutputExtension(tool_type);
720 }
721 if (output_value.compare(output_value.size() - output_extension.size(),
722 output_extension.size(), output_extension) == 0) {
723 deps.push_back(dep);
724 }
725 }
726 WriteCompilerBuildLine(source, deps, order_only_dep, tool_type,
483 tool_outputs); 727 tool_outputs);
484 } 728 }
485 729
486 // It's theoretically possible for a compiler to produce more than one 730 // It's theoretically possible for a compiler to produce more than one
487 // output, but we'll only link to the first output. 731 // output, but we'll only link to the first output.
488 object_files->push_back(tool_outputs[0]); 732 object_files->push_back(tool_outputs[0]);
489 } 733 }
490 out_ << std::endl; 734 out_ << std::endl;
491 } 735 }
492 736
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 for (const auto& non_linkable_dep : non_linkable_deps) { 1025 for (const auto& non_linkable_dep : non_linkable_deps) {
782 out_ << " "; 1026 out_ << " ";
783 path_output_.WriteFile(out_, non_linkable_dep->dependency_output_file()); 1027 path_output_.WriteFile(out_, non_linkable_dep->dependency_output_file());
784 } 1028 }
785 } 1029 }
786 } 1030 }
787 1031
788 OutputFile NinjaBinaryTargetWriter::GetWindowsPCHFile( 1032 OutputFile NinjaBinaryTargetWriter::GetWindowsPCHFile(
789 Toolchain::ToolType tool_type) const { 1033 Toolchain::ToolType tool_type) const {
790 // Use "obj/{dir}/{target_name}_{lang}.pch" which ends up 1034 // Use "obj/{dir}/{target_name}_{lang}.pch" which ends up
791 // looking like "obj/chrome/browser/browser.cc.pch" 1035 // looking like "obj/chrome/browser/browser_cc.pch"
792 OutputFile ret = GetTargetOutputDirAsOutputFile(target_); 1036 OutputFile ret = GetTargetOutputDirAsOutputFile(target_);
793 ret.value().append(target_->label().name()); 1037 ret.value().append(target_->label().name());
794 ret.value().push_back('_'); 1038 ret.value().push_back('_');
795 ret.value().append(GetPCHLangForToolType(tool_type)); 1039 ret.value().append(GetPCHLangSuffixForToolType(tool_type));
796 ret.value().append(".pch"); 1040 ret.value().append(".pch");
797 1041
798 return ret; 1042 return ret;
799 } 1043 }
800 1044
801 bool NinjaBinaryTargetWriter::CheckForDuplicateObjectFiles( 1045 bool NinjaBinaryTargetWriter::CheckForDuplicateObjectFiles(
802 const std::vector<OutputFile>& files) const { 1046 const std::vector<OutputFile>& files) const {
803 base::hash_set<std::string> set; 1047 base::hash_set<std::string> set;
804 for (const auto& file : files) { 1048 for (const auto& file : files) {
805 if (!set.insert(file.value()).second) { 1049 if (!set.insert(file.value()).second) {
(...skipping 11 matching lines...) Expand all
817 "\n" 1061 "\n"
818 "In the latter case, either rename one of the files or move one of\n" 1062 "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" 1063 "the sources to a separate source_set to avoid them both being in\n"
820 "the same target."); 1064 "the same target.");
821 g_scheduler->FailWithError(err); 1065 g_scheduler->FailWithError(err);
822 return false; 1066 return false;
823 } 1067 }
824 } 1068 }
825 return true; 1069 return true;
826 } 1070 }
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