| Index: tools/gn/ninja_binary_target_writer.cc | 
| diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc | 
| index 971f4d87f439bbb3ff4941a263a0603069dab438..1a6fe5bedc767060096d57c294f91e42ede01e8c 100644 | 
| --- a/tools/gn/ninja_binary_target_writer.cc | 
| +++ b/tools/gn/ninja_binary_target_writer.cc | 
| @@ -132,8 +132,8 @@ bool GetOutputFilesForSource(const Target* target, | 
| return !outputs->empty(); | 
| } | 
|  | 
| -// Returns the language-specific prefix/suffix for precomiled header files. | 
| -const char* GetPCHLangForToolType(Toolchain::ToolType type) { | 
| +// Returns the language-specific suffix for precompiled header files. | 
| +const char* GetPCHLangSuffixForToolType(Toolchain::ToolType type) { | 
| switch (type) { | 
| case Toolchain::TYPE_CC: | 
| return "c"; | 
| @@ -144,16 +144,60 @@ const char* GetPCHLangForToolType(Toolchain::ToolType type) { | 
| case Toolchain::TYPE_OBJCXX: | 
| return "mm"; | 
| default: | 
| -      NOTREACHED() << "Not a valid PCH tool type type"; | 
| +      NOTREACHED() << "Not a valid PCH tool type: " << type; | 
| +      return ""; | 
| +  } | 
| +} | 
| + | 
| +std::string GetWindowsPCHObjectExtension(Toolchain::ToolType tool_type) { | 
| +  const char* lang_suffix = GetPCHLangSuffixForToolType(tool_type); | 
| +  std::string result = "."; | 
| +  // For MSVC, annotate the obj files with the language type. For example: | 
| +  //   obj/foo/target_name.precompile.o -> | 
| +  //   obj/foo/target_name.precompile.cc.o | 
| +  result += lang_suffix; | 
| +  result += ".o"; | 
| +  return result; | 
| +} | 
| + | 
| +std::string GetGCCPCHOutputExtension(Toolchain::ToolType tool_type) { | 
| +  const char* lang_suffix = GetPCHLangSuffixForToolType(tool_type); | 
| +  std::string result = "."; | 
| +  // For GCC, the output name must have a .gch suffix and be annotated with | 
| +  // the language type. For example: | 
| +  //   obj/foo/target_name.header.h -> | 
| +  //   obj/foo/target_name.header.h-cc.gch | 
| +  // In order for the compiler to pick it up, the output name (minus the .gch | 
| +  // suffix MUST match whatever is passed to the -include flag). | 
| +  result += "h-"; | 
| +  result += lang_suffix; | 
| +  result += ".gch"; | 
| +  return result; | 
| +} | 
| + | 
| +// Returns the language-specific lang recognized by gcc’s -x flag for | 
| +// precompiled header files. | 
| +const char* GetPCHLangForToolType(Toolchain::ToolType type) { | 
| +  switch (type) { | 
| +    case Toolchain::TYPE_CC: | 
| +      return "c-header"; | 
| +    case Toolchain::TYPE_CXX: | 
| +      return "c++-header"; | 
| +    case Toolchain::TYPE_OBJC: | 
| +      return "objective-c-header"; | 
| +    case Toolchain::TYPE_OBJCXX: | 
| +      return "objective-c++-header"; | 
| +    default: | 
| +      NOTREACHED() << "Not a valid PCH tool type: " << type; | 
| return ""; | 
| } | 
| } | 
|  | 
| -// Returns the object files for the precompiled header of the given type (flag | 
| -// type and tool type must match). | 
| -void GetWindowsPCHObjectFiles(const Target* target, | 
| -                              Toolchain::ToolType tool_type, | 
| -                              std::vector<OutputFile>* outputs) { | 
| +// Fills |outputs| with the object or gch file for the precompiled header of the | 
| +// given type (flag type and tool type must match). | 
| +void GetPCHOutputFiles(const Target* target, | 
| +                       Toolchain::ToolType tool_type, | 
| +                       std::vector<OutputFile>* outputs) { | 
| outputs->clear(); | 
|  | 
| // Compute the tool. This must use the tool type passed in rather than the | 
| @@ -171,20 +215,31 @@ void GetWindowsPCHObjectFiles(const Target* target, | 
| if (outputs->size() > 1) | 
| outputs->resize(1);  // Only link the first output from the compiler tool. | 
|  | 
| -  // Need to annotate the obj files with the language type. For example: | 
| -  //   obj/foo/target_name.precompile.obj -> | 
| -  //   obj/foo/target_name.precompile.cc.obj | 
| -  const char* lang_suffix = GetPCHLangForToolType(tool_type); | 
| std::string& output_value = (*outputs)[0].value(); | 
| size_t extension_offset = FindExtensionOffset(output_value); | 
| if (extension_offset == std::string::npos) { | 
| -    NOTREACHED() << "No extension found"; | 
| -  } else { | 
| -    DCHECK(extension_offset >= 1); | 
| -    DCHECK(output_value[extension_offset - 1] == '.'); | 
| -    output_value.insert(extension_offset - 1, "."); | 
| -    output_value.insert(extension_offset, lang_suffix); | 
| +    // No extension found. | 
| +    return; | 
| } | 
| +  DCHECK(extension_offset >= 1); | 
| +  DCHECK(output_value[extension_offset - 1] == '.'); | 
| + | 
| +  std::string output_extension; | 
| +  Tool::PrecompiledHeaderType header_type = tool->precompiled_header_type(); | 
| +  switch (header_type) { | 
| +    case Tool::PCH_MSVC: | 
| +      output_extension = GetWindowsPCHObjectExtension(tool_type); | 
| +      break; | 
| +    case Tool::PCH_GCC: | 
| +      output_extension = GetGCCPCHOutputExtension(tool_type); | 
| +      break; | 
| +    case Tool::PCH_NONE: | 
| +      NOTREACHED() << "No outputs for no PCH type."; | 
| +      break; | 
| +  } | 
| +  output_value.replace(extension_offset - 1, | 
| +                       std::string::npos, | 
| +                       output_extension); | 
| } | 
|  | 
| // Appends the object files generated by the given source set to the given | 
| @@ -204,24 +259,37 @@ void AddSourceSetObjectFiles(const Target* source_set, | 
| used_types.Set(GetSourceFileType(source)); | 
| } | 
|  | 
| -  // Precompiled header object files. | 
| +  // Add MSVC precompiled header object files. GCC .gch files are not object | 
| +  // files so they are omitted. | 
| if (source_set->config_values().has_precompiled_headers()) { | 
| if (used_types.Get(SOURCE_C)) { | 
| -      GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_CC, &tool_outputs); | 
| -      obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      const Tool* tool = source_set->toolchain()->GetTool(Toolchain::TYPE_CC); | 
| +      if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) { | 
| +        GetPCHOutputFiles(source_set, Toolchain::TYPE_CC, &tool_outputs); | 
| +        obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      } | 
| } | 
| if (used_types.Get(SOURCE_CPP)) { | 
| -      GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_CXX, &tool_outputs); | 
| -      obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      const Tool* tool = source_set->toolchain()->GetTool(Toolchain::TYPE_CXX); | 
| +      if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) { | 
| +        GetPCHOutputFiles(source_set, Toolchain::TYPE_CXX, &tool_outputs); | 
| +        obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      } | 
| } | 
| if (used_types.Get(SOURCE_M)) { | 
| -      GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_OBJC, &tool_outputs); | 
| -      obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      const Tool* tool = source_set->toolchain()->GetTool(Toolchain::TYPE_OBJC); | 
| +      if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) { | 
| +        GetPCHOutputFiles(source_set, Toolchain::TYPE_OBJC, &tool_outputs); | 
| +        obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      } | 
| } | 
| if (used_types.Get(SOURCE_MM)) { | 
| -      GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_OBJCXX, | 
| -                               &tool_outputs); | 
| -      obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      const Tool* tool = source_set->toolchain()->GetTool( | 
| +          Toolchain::TYPE_OBJCXX); | 
| +      if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) { | 
| +        GetPCHOutputFiles(source_set, Toolchain::TYPE_OBJCXX, &tool_outputs); | 
| +        obj_files->Append(tool_outputs.begin(), tool_outputs.end()); | 
| +      } | 
| } | 
| } | 
| } | 
| @@ -251,10 +319,10 @@ void NinjaBinaryTargetWriter::Run() { | 
| // but changes in the inputs deps won't cause the file to be recompiled. | 
| // | 
| // This is important to prevent changes in unrelated actions that are | 
| -  // upstream of this target from causing everything to be recompiled | 
| +  // upstream of this target from causing everything to be recompiled. | 
| // | 
| // Why can we get away with this rather than using implicit deps ("|", which | 
| -  // will force rebuilds when the inputs change)?  For source code, the | 
| +  // will force rebuilds when the inputs change)? For source code, the | 
| // computed dependencies of all headers will be computed by the compiler, | 
| // which will cause source rebuilds if any "real" upstream dependencies | 
| // change. | 
| @@ -272,30 +340,39 @@ void NinjaBinaryTargetWriter::Run() { | 
| OutputFile order_only_dep = | 
| WriteInputDepsStampAndGetDep(std::vector<const Target*>()); | 
|  | 
| +  // For GCC builds, the .gch files are not object files, but still need to be | 
| +  // added as explicit dependencies below. The .gch output files are placed in | 
| +  // |pch_other_files|. This is to prevent linking against them. | 
| std::vector<OutputFile> pch_obj_files; | 
| -  WritePrecompiledHeaderCommands(used_types, order_only_dep, &pch_obj_files); | 
| +  std::vector<OutputFile> pch_other_files; | 
| +  WritePCHCommands(used_types, order_only_dep, | 
| +                   &pch_obj_files, &pch_other_files); | 
| +  std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ? | 
| +      &pch_obj_files : &pch_other_files; | 
|  | 
| -  // Treat all precompiled object files as explicit dependencies of all | 
| +  // Treat all pch output files as explicit dependencies of all | 
| // compiles. Some notes: | 
| // | 
| -  //  - Technically only the language-specific one is required for any specific | 
| -  //    compile, but that's more difficult to express and the additional logic | 
| -  //    doesn't buy much reduced parallelism. Just list them all (there's | 
| -  //    usually only one anyway). | 
| +  //  - Only the language-specific one is required for any specific compile, but | 
| +  //    that's more difficult to express and the additional logic doesn't buy | 
| +  //    much reduced parallelism. Just list them all (there's usually only one | 
| +  //    anyway). | 
| // | 
| -  //  - Technically the .pch file is the input to the compile, not the | 
| +  //  - On Windows, the .pch file is the input to the compile, not the | 
| //    precompiled header's corresponding object file that we're using here. | 
| //    But Ninja's depslog doesn't support multiple outputs from the | 
| //    precompiled header compile step (it outputs both the .pch file and a | 
| //    corresponding .obj file). So we consistently list the .obj file and the | 
| //    .pch file we really need comes along with it. | 
| +  // | 
| +  //  - GCC .gch files are not object files, therefore they are not added to the | 
| +  //    object file list. | 
| std::vector<OutputFile> obj_files; | 
| std::vector<SourceFile> other_files; | 
| -  WriteSources(pch_obj_files, order_only_dep, &obj_files, &other_files); | 
| +  WriteSources(*pch_files, order_only_dep, &obj_files, &other_files); | 
|  | 
| -  // Also link all pch object files. | 
| +  // Link all MSVC pch object files. The vector will be empty on GCC toolchains. | 
| obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end()); | 
| - | 
| if (!CheckForDuplicateObjectFiles(obj_files)) | 
| return; | 
|  | 
| @@ -343,11 +420,7 @@ void NinjaBinaryTargetWriter::WriteCompilerVars( | 
| bool has_precompiled_headers = | 
| target_->config_values().has_precompiled_headers(); | 
|  | 
| -  // Some toolchains pass cflags to the assembler since it's the same command, | 
| -  // and cflags_c might also be sent to the objective C compiler. | 
| -  // | 
| -  // TODO(brettw) remove the SOURCE_M from the CFLAGS_C writing once the Chrome | 
| -  // Mac build is updated not to pass cflags_c to .m files. | 
| +  // Some toolchains pass cflags to the assembler since it's the same command. | 
| EscapeOptions opts = GetFlagOptions(); | 
| if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_CPP) || | 
| used_types.Get(SOURCE_M) || used_types.Get(SOURCE_MM) || | 
| @@ -355,8 +428,8 @@ void NinjaBinaryTargetWriter::WriteCompilerVars( | 
| WriteOneFlag(SUBSTITUTION_CFLAGS, false, Toolchain::TYPE_NONE, | 
| &ConfigValues::cflags, opts); | 
| } | 
| -  if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_M) || | 
| -      used_types.Get(SOURCE_S) || used_types.Get(SOURCE_ASM)) { | 
| +  if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_S) || | 
| +      used_types.Get(SOURCE_ASM)) { | 
| WriteOneFlag(SUBSTITUTION_CFLAGS_C, has_precompiled_headers, | 
| Toolchain::TYPE_CC, &ConfigValues::cflags_c, opts); | 
| } | 
| @@ -397,49 +470,162 @@ void NinjaBinaryTargetWriter::WriteOneFlag( | 
| // Enables precompiled headers and names the .h file. It's a string | 
| // rather than a file name (so no need to rebase or use path_output_). | 
| out_ << " /Yu" << target_->config_values().precompiled_header(); | 
| +      RecursiveTargetConfigStringsToStream(target_, getter, | 
| +                                           flag_escape_options, out_); | 
| +    } else if (tool && tool->precompiled_header_type() == Tool::PCH_GCC) { | 
| +      // The targets to build the .gch files should omit the -include flag | 
| +      // below. To accomplish this, each substitution flag is overwritten in the | 
| +      // target rule and these values are repeated. The -include flag is omitted | 
| +      // in place of the required -x <header lang> flag for .gch targets. | 
| +      RecursiveTargetConfigStringsToStream(target_, getter, | 
| +                                           flag_escape_options, out_); | 
| + | 
| +      // Compute the gch file (it will be language-specific). | 
| +      std::vector<OutputFile> outputs; | 
| +      GetPCHOutputFiles(target_, tool_type, &outputs); | 
| +      if (!outputs.empty()) { | 
| +        // Trim the .gch suffix for the -include flag. | 
| +        // e.g. for gch file foo/bar/target.precompiled.h.gch: | 
| +        //          -include foo/bar/target.precompiled.h | 
| +        std::string pch_file = outputs[0].value(); | 
| +        pch_file.erase(pch_file.length() - 4); | 
| +        out_ << " -include " << pch_file; | 
| +      } | 
| } | 
| } | 
| - | 
| -  RecursiveTargetConfigStringsToStream(target_, getter, | 
| -                                       flag_escape_options, out_); | 
| out_ << std::endl; | 
| } | 
|  | 
| -void NinjaBinaryTargetWriter::WritePrecompiledHeaderCommands( | 
| +void NinjaBinaryTargetWriter::WritePCHCommands( | 
| const SourceFileTypeSet& used_types, | 
| const OutputFile& order_only_dep, | 
| -    std::vector<OutputFile>* object_files) { | 
| +    std::vector<OutputFile>* object_files, | 
| +    std::vector<OutputFile>* other_files) { | 
| if (!target_->config_values().has_precompiled_headers()) | 
| return; | 
|  | 
| const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC); | 
| if (tool_c && | 
| -      tool_c->precompiled_header_type() == Tool::PCH_MSVC && | 
| +      tool_c->precompiled_header_type() != Tool::PCH_NONE && | 
| used_types.Get(SOURCE_C)) { | 
| -    WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_C, | 
| -                           Toolchain::TYPE_CC, | 
| -                           order_only_dep, object_files); | 
| +    WritePCHCommand(SUBSTITUTION_CFLAGS_C, | 
| +                    Toolchain::TYPE_CC, | 
| +                    tool_c->precompiled_header_type(), | 
| +                    order_only_dep, object_files, other_files); | 
| } | 
| const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX); | 
| if (tool_cxx && | 
| -      tool_cxx->precompiled_header_type() == Tool::PCH_MSVC && | 
| +      tool_cxx->precompiled_header_type() != Tool::PCH_NONE && | 
| used_types.Get(SOURCE_CPP)) { | 
| -    WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_CC, | 
| -                           Toolchain::TYPE_CXX, | 
| -                           order_only_dep, object_files); | 
| +    WritePCHCommand(SUBSTITUTION_CFLAGS_CC, | 
| +                    Toolchain::TYPE_CXX, | 
| +                    tool_cxx->precompiled_header_type(), | 
| +                    order_only_dep, object_files, other_files); | 
| +  } | 
| + | 
| +  const Tool* tool_objc = target_->toolchain()->GetTool(Toolchain::TYPE_OBJC); | 
| +  if (tool_objc && | 
| +      tool_objc->precompiled_header_type() == Tool::PCH_GCC && | 
| +      used_types.Get(SOURCE_M)) { | 
| +    WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC, | 
| +                    Toolchain::TYPE_OBJC, | 
| +                    tool_objc->precompiled_header_type(), | 
| +                    order_only_dep, object_files, other_files); | 
| +  } | 
| + | 
| +  const Tool* tool_objcxx = | 
| +      target_->toolchain()->GetTool(Toolchain::TYPE_OBJCXX); | 
| +  if (tool_objcxx && | 
| +      tool_objcxx->precompiled_header_type() == Tool::PCH_GCC && | 
| +      used_types.Get(SOURCE_MM)) { | 
| +    WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC, | 
| +                    Toolchain::TYPE_OBJCXX, | 
| +                    tool_objcxx->precompiled_header_type(), | 
| +                    order_only_dep, object_files, other_files); | 
| } | 
| } | 
|  | 
| +void NinjaBinaryTargetWriter::WritePCHCommand( | 
| +    SubstitutionType flag_type, | 
| +    Toolchain::ToolType tool_type, | 
| +    Tool::PrecompiledHeaderType header_type, | 
| +    const OutputFile& order_only_dep, | 
| +    std::vector<OutputFile>* object_files, | 
| +    std::vector<OutputFile>* other_files) { | 
| +  switch (header_type) { | 
| +    case Tool::PCH_MSVC: | 
| +      WriteWindowsPCHCommand(flag_type, tool_type, order_only_dep, | 
| +                             object_files); | 
| +      break; | 
| +    case Tool::PCH_GCC: | 
| +      WriteGCCPCHCommand(flag_type, tool_type, order_only_dep, | 
| +                         other_files); | 
| +      break; | 
| +    case Tool::PCH_NONE: | 
| +      NOTREACHED() << "Cannot write a PCH command with no PCH header type"; | 
| +      break; | 
| +  } | 
| +} | 
| + | 
| +void NinjaBinaryTargetWriter::WriteGCCPCHCommand( | 
| +    SubstitutionType flag_type, | 
| +    Toolchain::ToolType tool_type, | 
| +    const OutputFile& order_only_dep, | 
| +    std::vector<OutputFile>* gch_files) { | 
| +  // Compute the pch output file (it will be language-specific). | 
| +  std::vector<OutputFile> outputs; | 
| +  GetPCHOutputFiles(target_, tool_type, &outputs); | 
| +  if (outputs.empty()) | 
| +    return; | 
| + | 
| +  gch_files->insert(gch_files->end(), outputs.begin(), outputs.end()); | 
| + | 
| +  // Build line to compile the file. | 
| +  WriteCompilerBuildLine(target_->config_values().precompiled_source(), | 
| +                         std::vector<OutputFile>(), order_only_dep, tool_type, | 
| +                         outputs); | 
| + | 
| +  // This build line needs a custom language-specific flags value. Rule-specific | 
| +  // variables are just indented underneath the rule line. | 
| +  out_ << "  " << kSubstitutionNinjaNames[flag_type] << " ="; | 
| + | 
| +  // Each substitution flag is overwritten in the target rule to replace the | 
| +  // implicitly generated -include flag with the -x <header lang> flag required | 
| +  // for .gch targets. | 
| +  EscapeOptions opts = GetFlagOptions(); | 
| +  if (tool_type == Toolchain::TYPE_CC) { | 
| +    RecursiveTargetConfigStringsToStream(target_, | 
| +        &ConfigValues::cflags_c, opts, out_); | 
| +  } else if (tool_type == Toolchain::TYPE_CXX) { | 
| +    RecursiveTargetConfigStringsToStream(target_, | 
| +        &ConfigValues::cflags_cc, opts, out_); | 
| +  } else if (tool_type == Toolchain::TYPE_OBJC) { | 
| +    RecursiveTargetConfigStringsToStream(target_, | 
| +        &ConfigValues::cflags_objc, opts, out_); | 
| +  } else if (tool_type == Toolchain::TYPE_OBJCXX) { | 
| +    RecursiveTargetConfigStringsToStream(target_, | 
| +        &ConfigValues::cflags_objcc, opts, out_); | 
| +  } | 
| + | 
| +  // Append the command to specify the language of the .gch file. | 
| +  out_ << " -x " << GetPCHLangForToolType(tool_type); | 
| + | 
| +  // Write two blank lines to help separate the PCH build lines from the | 
| +  // regular source build lines. | 
| +  out_ << std::endl << std::endl; | 
| +} | 
| + | 
| void NinjaBinaryTargetWriter::WriteWindowsPCHCommand( | 
| SubstitutionType flag_type, | 
| Toolchain::ToolType tool_type, | 
| const OutputFile& order_only_dep, | 
| std::vector<OutputFile>* object_files) { | 
| -  // Compute the object file (it will be language-specific). | 
| +  // Compute the pch output file (it will be language-specific). | 
| std::vector<OutputFile> outputs; | 
| -  GetWindowsPCHObjectFiles(target_, tool_type, &outputs); | 
| +  GetPCHOutputFiles(target_, tool_type, &outputs); | 
| if (outputs.empty()) | 
| return; | 
| + | 
| object_files->insert(object_files->end(), outputs.begin(), outputs.end()); | 
|  | 
| // Build line to compile the file. | 
| @@ -447,14 +633,13 @@ void NinjaBinaryTargetWriter::WriteWindowsPCHCommand( | 
| std::vector<OutputFile>(), order_only_dep, tool_type, | 
| outputs); | 
|  | 
| -  // This build line needs a custom language-specific flags value. It needs to | 
| -  // include the switch to generate the .pch file in addition to the normal | 
| -  // ones. Rule-specific variables are just indented underneath the rule line, | 
| -  // and this defines the new one in terms of the old value. | 
| +  // This build line needs a custom language-specific flags value. Rule-specific | 
| +  // variables are just indented underneath the rule line. | 
| out_ << "  " << kSubstitutionNinjaNames[flag_type] << " ="; | 
| -  out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}"; | 
|  | 
| // Append the command to generate the .pch file. | 
| +  // This adds the value to the existing flag instead of overwriting it. | 
| +  out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}"; | 
| out_ << " /Yc" << target_->config_values().precompiled_header(); | 
|  | 
| // Write two blank lines to help separate the PCH build lines from the | 
| @@ -463,14 +648,17 @@ void NinjaBinaryTargetWriter::WriteWindowsPCHCommand( | 
| } | 
|  | 
| void NinjaBinaryTargetWriter::WriteSources( | 
| -    const std::vector<OutputFile>& extra_deps, | 
| +    const std::vector<OutputFile>& pch_deps, | 
| const OutputFile& order_only_dep, | 
| std::vector<OutputFile>* object_files, | 
| std::vector<SourceFile>* other_files) { | 
| object_files->reserve(object_files->size() + target_->sources().size()); | 
|  | 
| std::vector<OutputFile> tool_outputs;  // Prevent reallocation in loop. | 
| +  std::vector<OutputFile> deps; | 
| for (const auto& source : target_->sources()) { | 
| +    // Clear the vector but maintain the max capacity to prevent reallocations. | 
| +    deps.resize(0); | 
| Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; | 
| if (!GetOutputFilesForSource(target_, source, &tool_type, &tool_outputs)) { | 
| if (GetSourceFileType(source) == SOURCE_DEF) | 
| @@ -479,7 +667,28 @@ void NinjaBinaryTargetWriter::WriteSources( | 
| } | 
|  | 
| if (tool_type != Toolchain::TYPE_NONE) { | 
| -      WriteCompilerBuildLine(source, extra_deps, order_only_dep, tool_type, | 
| +      // Only include PCH deps that correspond to the tool type, for instance, | 
| +      // do not specify target_name.precompile.cc.o (a CXX PCH file) as a dep | 
| +      // for the output of a C tool type. | 
| +      // | 
| +      // This makes the assumption that pch_deps only contains pch output files | 
| +      // with the naming scheme specified in GetWindowsPCHObjectExtension or | 
| +      // GetGCCPCHOutputExtension. | 
| +      const Tool* tool = target_->toolchain()->GetTool(tool_type); | 
| +      for (const auto& dep : pch_deps) { | 
| +        const std::string& output_value = dep.value(); | 
| +        std::string output_extension; | 
| +        if (tool->precompiled_header_type() == Tool::PCH_MSVC) { | 
| +          output_extension = GetWindowsPCHObjectExtension(tool_type); | 
| +        } else if (tool->precompiled_header_type() == Tool::PCH_GCC) { | 
| +          output_extension = GetGCCPCHOutputExtension(tool_type); | 
| +        } | 
| +        if (output_value.compare(output_value.size() - output_extension.size(), | 
| +            output_extension.size(), output_extension) == 0) { | 
| +          deps.push_back(dep); | 
| +        } | 
| +      } | 
| +      WriteCompilerBuildLine(source, deps, order_only_dep, tool_type, | 
| tool_outputs); | 
| } | 
|  | 
| @@ -788,11 +997,11 @@ void NinjaBinaryTargetWriter::WriteOrderOnlyDependencies( | 
| OutputFile NinjaBinaryTargetWriter::GetWindowsPCHFile( | 
| Toolchain::ToolType tool_type) const { | 
| // Use "obj/{dir}/{target_name}_{lang}.pch" which ends up | 
| -  // looking like "obj/chrome/browser/browser.cc.pch" | 
| +  // looking like "obj/chrome/browser/browser_cc.pch" | 
| OutputFile ret = GetTargetOutputDirAsOutputFile(target_); | 
| ret.value().append(target_->label().name()); | 
| ret.value().push_back('_'); | 
| -  ret.value().append(GetPCHLangForToolType(tool_type)); | 
| +  ret.value().append(GetPCHLangSuffixForToolType(tool_type)); | 
| ret.value().append(".pch"); | 
|  | 
| return ret; | 
|  |