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 680c0d9db459ac6366cfaef01448e0d2d106c992..7b81bfa517f91a8bbff08db1965302bc16b8449e 100644 |
--- a/tools/gn/ninja_binary_target_writer.cc |
+++ b/tools/gn/ninja_binary_target_writer.cc |
@@ -4,6 +4,7 @@ |
#include "tools/gn/ninja_binary_target_writer.h" |
+#include <cstring> |
#include <set> |
#include <sstream> |
@@ -12,12 +13,33 @@ |
#include "tools/gn/deps_iterator.h" |
#include "tools/gn/err.h" |
#include "tools/gn/escape.h" |
+#include "tools/gn/filesystem_utils.h" |
#include "tools/gn/ninja_utils.h" |
#include "tools/gn/settings.h" |
+#include "tools/gn/source_file_type.h" |
#include "tools/gn/string_utils.h" |
#include "tools/gn/substitution_writer.h" |
#include "tools/gn/target.h" |
+// Represents a set of tool types. Must be first since it is also shared by |
+// some helper functions in the anonymous namespace below. |
+class NinjaBinaryTargetWriter::SourceFileTypeSet { |
+ public: |
+ SourceFileTypeSet() { |
+ memset(flags_, 0, sizeof(bool) * static_cast<int>(SOURCE_NUMTYPES)); |
+ } |
+ |
+ void Set(SourceFileType type) { |
+ flags_[static_cast<int>(type)] = true; |
+ } |
+ bool Get(SourceFileType type) const { |
+ return flags_[static_cast<int>(type)]; |
+ } |
+ |
+ private: |
+ bool flags_[static_cast<int>(SOURCE_NUMTYPES)]; |
+}; |
+ |
namespace { |
// Returns the proper escape options for writing compiler and linker flags. |
@@ -65,31 +87,231 @@ struct IncludeWriter { |
PathOutput& path_output_; |
}; |
+// Computes the set of output files resulting from compiling the given source |
+// file. If the file can be compiled and the tool exists, fills the outputs in |
+// and writes the tool type to computed_tool_type. If the file is not |
+// compilable, returns false. |
+// |
+// The target that the source belongs to is passed as an argument. In the case |
+// of linking to source sets, this can be different than the target this class |
+// is currently writing. |
+// |
+// The function can succeed with a "NONE" tool type for object files which are |
+// just passed to the output. The output will always be overwritten, not |
+// appended to. |
+bool GetOutputFilesForSource(const Target* target, |
+ const SourceFile& source, |
+ Toolchain::ToolType* computed_tool_type, |
+ std::vector<OutputFile>* outputs) { |
+ outputs->clear(); |
+ *computed_tool_type = Toolchain::TYPE_NONE; |
+ |
+ SourceFileType file_type = GetSourceFileType(source); |
+ if (file_type == SOURCE_UNKNOWN) |
+ return false; |
+ if (file_type == SOURCE_O) { |
+ // Object files just get passed to the output and not compiled. |
+ outputs->push_back( |
+ OutputFile(target->settings()->build_settings(), source)); |
+ return true; |
+ } |
+ |
+ *computed_tool_type = |
+ target->toolchain()->GetToolTypeForSourceType(file_type); |
+ if (*computed_tool_type == Toolchain::TYPE_NONE) |
+ return false; // No tool for this file (it's a header file or something). |
+ const Tool* tool = target->toolchain()->GetTool(*computed_tool_type); |
+ if (!tool) |
+ return false; // Tool does not apply for this toolchain.file. |
+ |
+ // Figure out what output(s) this compiler produces. |
+ SubstitutionWriter::ApplyListToCompilerAsOutputFile( |
+ target, source, tool->outputs(), outputs); |
+ return !outputs->empty(); |
+} |
+ |
+// Returns the language-specific prefix/suffix for precomiled header files. |
+const char* GetPCHLangForToolType(Toolchain::ToolType type) { |
+ switch (type) { |
+ case Toolchain::TYPE_CC: |
+ return "c"; |
+ case Toolchain::TYPE_CXX: |
+ return "cc"; |
+ case Toolchain::TYPE_OBJC: |
+ return "m"; |
+ case Toolchain::TYPE_OBJCXX: |
+ return "mm"; |
+ 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) { |
+ outputs->clear(); |
+ |
+ // Compute the tool. This must use the tool type passed in rather than the |
+ // detected file type of the precompiled source file since the same |
+ // precompiled source file will be used for separate C/C++ compiles. |
+ const Tool* tool = target->toolchain()->GetTool(tool_type); |
+ if (!tool) |
+ return; |
+ SubstitutionWriter::ApplyListToCompilerAsOutputFile( |
+ target, target->config_values().precompiled_source(), |
+ tool->outputs(), outputs); |
+ |
+ if (outputs->empty()) |
+ return; |
+ 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); |
+ } |
+} |
+ |
+// Appends the object files generated by the given source set to the given |
+// output vector. |
+void AddSourceSetObjectFiles(const Target* source_set, |
+ UniqueVector<OutputFile>* obj_files) { |
+ std::vector<OutputFile> tool_outputs; // Prevent allocation in loop. |
+ NinjaBinaryTargetWriter::SourceFileTypeSet used_types; |
+ |
+ // Compute object files for all sources. Only link the first output from |
+ // the tool if there are more than one. |
+ for (const auto& source : source_set->sources()) { |
+ Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; |
+ if (GetOutputFilesForSource(source_set, source, &tool_type, &tool_outputs)) |
+ obj_files->push_back(tool_outputs[0]); |
+ |
+ used_types.Set(GetSourceFileType(source)); |
+ } |
+ |
+ // Precompiled header object files. |
+ 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()); |
+ } |
+ if (used_types.Get(SOURCE_CPP)) { |
+ GetWindowsPCHObjectFiles(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()); |
+ } |
+ if (used_types.Get(SOURCE_MM)) { |
+ GetWindowsPCHObjectFiles(source_set, Toolchain::TYPE_OBJCXX, |
+ &tool_outputs); |
+ obj_files->Append(tool_outputs.begin(), tool_outputs.end()); |
+ } |
+ } |
+} |
+ |
} // namespace |
NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target, |
std::ostream& out) |
: NinjaTargetWriter(target, out), |
- tool_(target->toolchain()->GetToolForTargetFinalOutput(target)) { |
+ tool_(target->toolchain()->GetToolForTargetFinalOutput(target)), |
+ rule_prefix_(GetNinjaRulePrefixForToolchain(settings_)) { |
} |
NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() { |
} |
void NinjaBinaryTargetWriter::Run() { |
- WriteCompilerVars(); |
+ // Figure out what source types are needed. |
+ SourceFileTypeSet used_types; |
+ for (const auto& source : target_->sources()) |
+ used_types.Set(GetSourceFileType(source)); |
+ |
+ WriteCompilerVars(used_types); |
+ |
+ // The input dependencies will be an order-only dependency. This will cause |
+ // Ninja to make sure the inputs are up-to-date before compiling this source, |
+ // 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 |
+ // |
+ // Why can we get away with this rather than using implicit deps ("|", which |
+ // 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. |
+ // |
+ // If a .cc file is generated by an input dependency, Ninja will see the |
+ // input to the build rule doesn't exist, and that it is an output from a |
+ // previous step, and build the previous step first. This is a "real" |
+ // dependency and doesn't need | or || to express. |
+ // |
+ // The only case where this rule matters is for the first build where no .d |
+ // files exist, and Ninja doesn't know what that source file depends on. In |
+ // this case it's sufficient to ensure that the upstream dependencies are |
+ // built first. This is exactly what Ninja's order-only dependencies |
+ // expresses. |
+ OutputFile order_only_dep = |
+ WriteInputDepsStampAndGetDep(std::vector<const Target*>()); |
+ |
+ std::vector<OutputFile> pch_obj_files; |
+ WritePrecompiledHeaderCommands(used_types, order_only_dep, &pch_obj_files); |
+ // Treat all precompiled object 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). |
+ // |
+ // - Technically 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. |
std::vector<OutputFile> obj_files; |
std::vector<SourceFile> other_files; |
- WriteSources(&obj_files, &other_files); |
+ WriteSources(pch_obj_files, order_only_dep, &obj_files, &other_files); |
- if (target_->output_type() == Target::SOURCE_SET) |
+ // Also link all pch object files. |
+ obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end()); |
+ |
+ if (target_->output_type() == Target::SOURCE_SET) { |
WriteSourceSetStamp(obj_files); |
- else |
+#ifndef NDEBUG |
+ // Verify that the function that separately computes a source set's object |
+ // files match the object files just computed. |
+ UniqueVector<OutputFile> computed_obj; |
+ AddSourceSetObjectFiles(target_, &computed_obj); |
+ DCHECK_EQ(obj_files.size(), computed_obj.size()); |
+ for (const auto& obj : obj_files) |
+ DCHECK_NE(static_cast<size_t>(-1), computed_obj.IndexOf(obj)); |
+#endif |
+ } else { |
WriteLinkerStuff(obj_files, other_files); |
+ } |
} |
-void NinjaBinaryTargetWriter::WriteCompilerVars() { |
+void NinjaBinaryTargetWriter::WriteCompilerVars( |
+ const SourceFileTypeSet& used_types) { |
const SubstitutionBits& subst = target_->toolchain()->substitution_bits(); |
// Defines. |
@@ -113,36 +335,134 @@ void NinjaBinaryTargetWriter::WriteCompilerVars() { |
out_ << std::endl; |
} |
- // C flags and friends. |
- EscapeOptions flag_escape_options = GetFlagOptions(); |
-#define WRITE_FLAGS(name, subst_enum) \ |
- if (subst.used[subst_enum]) { \ |
- out_ << kSubstitutionNinjaNames[subst_enum] << " ="; \ |
- RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \ |
- flag_escape_options, out_); \ |
- out_ << std::endl; \ |
+ 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. |
+ EscapeOptions opts = GetFlagOptions(); |
+ if (used_types.Get(SOURCE_C) || used_types.Get(SOURCE_CPP) || |
+ used_types.Get(SOURCE_M) || used_types.Get(SOURCE_MM) || |
+ used_types.Get(SOURCE_ASM)) { |
+ 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_ASM)) { |
+ WriteOneFlag(SUBSTITUTION_CFLAGS_C, has_precompiled_headers, |
+ Toolchain::TYPE_CC, &ConfigValues::cflags_c, opts); |
+ } |
+ if (used_types.Get(SOURCE_CPP)) { |
+ WriteOneFlag(SUBSTITUTION_CFLAGS_CC, has_precompiled_headers, |
+ Toolchain::TYPE_CXX, &ConfigValues::cflags_cc, opts); |
+ } |
+ if (used_types.Get(SOURCE_M)) { |
+ WriteOneFlag(SUBSTITUTION_CFLAGS_OBJC, has_precompiled_headers, |
+ Toolchain::TYPE_OBJC, &ConfigValues::cflags_objc, opts); |
+ } |
+ if (used_types.Get(SOURCE_MM)) { |
+ WriteOneFlag(SUBSTITUTION_CFLAGS_OBJCC, has_precompiled_headers, |
+ Toolchain::TYPE_OBJCXX, &ConfigValues::cflags_objcc, opts); |
+ } |
+ |
+ WriteSharedVars(subst); |
+} |
+ |
+void NinjaBinaryTargetWriter::WriteOneFlag( |
+ SubstitutionType subst_enum, |
+ bool has_precompiled_headers, |
+ Toolchain::ToolType tool_type, |
+ const std::vector<std::string>& (ConfigValues::* getter)() const, |
+ EscapeOptions flag_escape_options) { |
+ if (!target_->toolchain()->substitution_bits().used[subst_enum]) |
+ return; |
+ |
+ out_ << kSubstitutionNinjaNames[subst_enum] << " ="; |
+ |
+ if (has_precompiled_headers) { |
+ const Tool* tool = target_->toolchain()->GetTool(tool_type); |
+ if (tool && tool->precompiled_header_type() == Tool::PCH_MSVC) { |
+ // Name the .pch file. |
+ out_ << " /Fp"; |
+ path_output_.WriteFile(out_, GetWindowsPCHFile(tool_type)); |
+ |
+ // 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_); |
+ out_ << std::endl; |
+} |
- WRITE_FLAGS(cflags, SUBSTITUTION_CFLAGS) |
- WRITE_FLAGS(cflags_c, SUBSTITUTION_CFLAGS_C) |
- WRITE_FLAGS(cflags_cc, SUBSTITUTION_CFLAGS_CC) |
- WRITE_FLAGS(cflags_objc, SUBSTITUTION_CFLAGS_OBJC) |
- WRITE_FLAGS(cflags_objcc, SUBSTITUTION_CFLAGS_OBJCC) |
+void NinjaBinaryTargetWriter::WritePrecompiledHeaderCommands( |
+ const SourceFileTypeSet& used_types, |
+ const OutputFile& order_only_dep, |
+ std::vector<OutputFile>* object_files) { |
+ if (!target_->config_values().has_precompiled_headers()) |
+ return; |
-#undef WRITE_FLAGS |
+ const Tool* tool_c = target_->toolchain()->GetTool(Toolchain::TYPE_CC); |
+ if (tool_c && |
+ tool_c->precompiled_header_type() == Tool::PCH_MSVC && |
+ used_types.Get(SOURCE_C)) { |
+ WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_C, |
+ Toolchain::TYPE_CC, |
+ order_only_dep, object_files); |
+ } |
+ const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX); |
+ if (tool_cxx && |
+ tool_cxx->precompiled_header_type() == Tool::PCH_MSVC && |
+ used_types.Get(SOURCE_CPP)) { |
+ WriteWindowsPCHCommand(SUBSTITUTION_CFLAGS_CC, |
+ Toolchain::TYPE_CXX, |
+ order_only_dep, object_files); |
+ } |
+} |
- WriteSharedVars(subst); |
+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). |
+ std::vector<OutputFile> outputs; |
+ GetWindowsPCHObjectFiles(target_, tool_type, &outputs); |
+ if (outputs.empty()) |
+ return; |
+ object_files->insert(object_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. 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. |
+ out_ << " " << kSubstitutionNinjaNames[flag_type] << " ="; |
+ out_ << " ${" << kSubstitutionNinjaNames[flag_type] << "}"; |
+ |
+ // Append the command to generate the .pch file. |
+ out_ << " /Yc" << target_->config_values().precompiled_header(); |
+ |
+ // Write two blank lines to help separate the PCH build lines from the |
+ // regular source build lines. |
+ out_ << std::endl << std::endl; |
} |
void NinjaBinaryTargetWriter::WriteSources( |
+ const std::vector<OutputFile>& extra_deps, |
+ const OutputFile& order_only_dep, |
std::vector<OutputFile>* object_files, |
std::vector<SourceFile>* other_files) { |
- object_files->reserve(target_->sources().size()); |
- |
- OutputFile input_dep = |
- WriteInputDepsStampAndGetDep(std::vector<const Target*>()); |
- |
- std::string rule_prefix = GetNinjaRulePrefixForToolchain(settings_); |
+ object_files->reserve(object_files->size() + target_->sources().size()); |
std::vector<OutputFile> tool_outputs; // Prevent reallocation in loop. |
for (const auto& source : target_->sources()) { |
@@ -154,41 +474,8 @@ void NinjaBinaryTargetWriter::WriteSources( |
} |
if (tool_type != Toolchain::TYPE_NONE) { |
- out_ << "build"; |
- path_output_.WriteFiles(out_, tool_outputs); |
- |
- out_ << ": " << rule_prefix << Toolchain::ToolTypeToName(tool_type); |
- out_ << " "; |
- path_output_.WriteFile(out_, source); |
- if (!input_dep.value().empty()) { |
- // Write out the input dependencies as an order-only dependency. This |
- // will cause Ninja to make sure the inputs are up-to-date before |
- // compiling this source, 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. |
- // |
- // Why can we get away with this rather than using implicit deps ("|", |
- // which 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. |
- // |
- // If a .cc file is generated by an input dependency, Ninja will see |
- // the input to the build rule doesn't exist, and that it is an output |
- // from a previous step, and build the previous step first. This is a |
- // "real" dependency and doesn't need | or || to express. |
- // |
- // The only case where this rule matters is for the first build where |
- // no .d files exist, and Ninja doesn't know what that source file |
- // depends on. In this case it's sufficient to ensure that the upstream |
- // dependencies are built first. This is exactly what Ninja's order- |
- // only dependencies expresses. |
- out_ << " || "; |
- path_output_.WriteFile(out_, input_dep); |
- } |
- out_ << std::endl; |
+ WriteCompilerBuildLine(source, extra_deps, order_only_dep, tool_type, |
+ tool_outputs); |
} |
// It's theoretically possible for a compiler to produce more than one |
@@ -198,6 +485,34 @@ void NinjaBinaryTargetWriter::WriteSources( |
out_ << std::endl; |
} |
+void NinjaBinaryTargetWriter::WriteCompilerBuildLine( |
+ const SourceFile& source, |
+ const std::vector<OutputFile>& extra_deps, |
+ const OutputFile& order_only_dep, |
+ Toolchain::ToolType tool_type, |
+ const std::vector<OutputFile>& outputs) { |
+ out_ << "build"; |
+ path_output_.WriteFiles(out_, outputs); |
+ |
+ out_ << ": " << rule_prefix_ << Toolchain::ToolTypeToName(tool_type); |
+ out_ << " "; |
+ path_output_.WriteFile(out_, source); |
+ |
+ if (!extra_deps.empty()) { |
+ out_ << " |"; |
+ for (const OutputFile& dep : extra_deps) { |
+ out_ << " "; |
+ path_output_.WriteFile(out_, dep); |
+ } |
+ } |
+ |
+ if (!order_only_dep.value().empty()) { |
+ out_ << " || "; |
+ path_output_.WriteFile(out_, order_only_dep); |
+ } |
+ out_ << std::endl; |
+} |
+ |
void NinjaBinaryTargetWriter::WriteLinkerStuff( |
const std::vector<OutputFile>& object_files, |
const std::vector<SourceFile>& other_files) { |
@@ -208,8 +523,7 @@ void NinjaBinaryTargetWriter::WriteLinkerStuff( |
out_ << "build"; |
path_output_.WriteFiles(out_, output_files); |
- out_ << ": " |
- << GetNinjaRulePrefixForToolchain(settings_) |
+ out_ << ": " << rule_prefix_ |
<< Toolchain::ToolTypeToName( |
target_->toolchain()->GetToolTypeForTargetFinalOutput(target_)); |
@@ -219,18 +533,12 @@ void NinjaBinaryTargetWriter::WriteLinkerStuff( |
GetDeps(&extra_object_files, &linkable_deps, &non_linkable_deps); |
// Object files. |
- for (const auto& obj : object_files) { |
- out_ << " "; |
- path_output_.WriteFile(out_, obj); |
- } |
- for (const auto& obj : extra_object_files) { |
- out_ << " "; |
- path_output_.WriteFile(out_, obj); |
- } |
+ path_output_.WriteFiles(out_, object_files); |
+ path_output_.WriteFiles(out_, extra_object_files); |
+ // Dependencies. |
std::vector<OutputFile> implicit_deps; |
std::vector<OutputFile> solibs; |
- |
for (const Target* cur : linkable_deps) { |
// All linkable deps should have a link output file. |
DCHECK(!cur->link_output_file().value().empty()) |
@@ -442,18 +750,8 @@ void NinjaBinaryTargetWriter::ClassifyDependency( |
// just forward the dependency, otherwise the files in the source |
// set can easily get linked more than once which will cause |
// multiple definition errors. |
- if (can_link_libs) { |
- // Linking in a source set to an executable, shared library, or |
- // complete static library, so copy its object files. |
- std::vector<OutputFile> tool_outputs; // Prevent allocation in loop. |
- for (const auto& source : dep->sources()) { |
- Toolchain::ToolType tool_type = Toolchain::TYPE_NONE; |
- if (GetOutputFilesForSource(dep, source, &tool_type, &tool_outputs)) { |
- // Only link the first output if there are more than one. |
- extra_object_files->push_back(tool_outputs[0]); |
- } |
- } |
- } |
+ if (can_link_libs) |
+ AddSourceSetObjectFiles(dep, extra_object_files); |
// Add the source set itself as a non-linkable dependency on the current |
// target. This will make sure that anything the source set's stamp file |
@@ -481,33 +779,15 @@ void NinjaBinaryTargetWriter::WriteOrderOnlyDependencies( |
} |
} |
-bool NinjaBinaryTargetWriter::GetOutputFilesForSource( |
- const Target* target, |
- const SourceFile& source, |
- Toolchain::ToolType* computed_tool_type, |
- std::vector<OutputFile>* outputs) const { |
- outputs->clear(); |
- *computed_tool_type = Toolchain::TYPE_NONE; |
- |
- SourceFileType file_type = GetSourceFileType(source); |
- if (file_type == SOURCE_UNKNOWN) |
- return false; |
- if (file_type == SOURCE_O) { |
- // Object files just get passed to the output and not compiled. |
- outputs->push_back(OutputFile(settings_->build_settings(), source)); |
- return true; |
- } |
- |
- *computed_tool_type = |
- target->toolchain()->GetToolTypeForSourceType(file_type); |
- if (*computed_tool_type == Toolchain::TYPE_NONE) |
- return false; // No tool for this file (it's a header file or something). |
- const Tool* tool = target->toolchain()->GetTool(*computed_tool_type); |
- if (!tool) |
- return false; // Tool does not apply for this toolchain.file. |
- |
- // Figure out what output(s) this compiler produces. |
- SubstitutionWriter::ApplyListToCompilerAsOutputFile( |
- target, source, tool->outputs(), outputs); |
- return !outputs->empty(); |
+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" |
+ OutputFile ret = GetTargetOutputDirAsOutputFile(target_); |
+ ret.value().append(target_->label().name()); |
+ ret.value().push_back('_'); |
+ ret.value().append(GetPCHLangForToolType(tool_type)); |
+ ret.value().append(".pch"); |
+ |
+ return ret; |
} |