Index: tools/gn/target.cc |
diff --git a/tools/gn/target.cc b/tools/gn/target.cc |
index 49a22fcbd8c4289e14623ebe2d39e8f68325f0a2..905ee4f3c65cc81eea8460543493a7b5011f605e 100644 |
--- a/tools/gn/target.cc |
+++ b/tools/gn/target.cc |
@@ -6,6 +6,8 @@ |
#include <stddef.h> |
+#include <algorithm> |
+ |
#include "base/bind.h" |
#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
@@ -13,7 +15,10 @@ |
#include "tools/gn/deps_iterator.h" |
#include "tools/gn/filesystem_utils.h" |
#include "tools/gn/scheduler.h" |
+#include "tools/gn/source_file_type.h" |
#include "tools/gn/substitution_writer.h" |
+#include "tools/gn/tool.h" |
+#include "tools/gn/toolchain.h" |
#include "tools/gn/trace.h" |
namespace { |
@@ -69,9 +74,15 @@ Err MakeStaticLibDepsError(const Target* from, const Target* to) { |
// |
// Pass a pointer to an empty set for the first invocation. This will be used |
// to avoid duplicate checking. |
+// |
+// Checking of object files is optional because it is much slower. This allows |
+// us to check targets for normal outputs, and then as a second pass check |
+// object files (since we know it will be an error otherwise). This allows |
+// us to avoid computing all object file names in the common case. |
bool EnsureFileIsGeneratedByDependency(const Target* target, |
const OutputFile& file, |
bool check_private_deps, |
+ bool consider_object_files, |
std::set<const Target*>* seen_targets) { |
if (seen_targets->find(target) != seen_targets->end()) |
return false; // Already checked this one and it's not found. |
@@ -85,11 +96,24 @@ bool EnsureFileIsGeneratedByDependency(const Target* target, |
return true; |
} |
+ // Check binary target intermediate files if requested. |
+ if (consider_object_files && target->IsBinary()) { |
+ std::vector<OutputFile> source_outputs; |
+ for (const SourceFile& source : target->sources()) { |
+ Toolchain::ToolType tool_type; |
+ if (!target->GetOutputFilesForSource(source, &tool_type, &source_outputs)) |
+ continue; |
+ if (std::find(source_outputs.begin(), source_outputs.end(), file) != |
+ source_outputs.end()) |
+ return true; |
+ } |
+ } |
+ |
// Check all public dependencies (don't do data ones since those are |
// runtime-only). |
for (const auto& pair : target->public_deps()) { |
if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, |
- seen_targets)) |
+ consider_object_files, seen_targets)) |
return true; // Found a path. |
} |
@@ -97,6 +121,7 @@ bool EnsureFileIsGeneratedByDependency(const Target* target, |
if (check_private_deps) { |
for (const auto& pair : target->private_deps()) { |
if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, |
+ consider_object_files, |
seen_targets)) |
return true; // Found a path. |
} |
@@ -215,6 +240,14 @@ bool Target::OnResolved(Err* err) { |
return true; |
} |
+bool Target::IsBinary() const { |
+ return output_type_ == EXECUTABLE || |
+ output_type_ == SHARED_LIBRARY || |
+ output_type_ == LOADABLE_MODULE || |
+ output_type_ == STATIC_LIBRARY || |
+ output_type_ == SOURCE_SET; |
+} |
+ |
bool Target::IsLinkable() const { |
return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; |
} |
@@ -287,6 +320,34 @@ bool Target::SetToolchain(const Toolchain* toolchain, Err* err) { |
return false; |
} |
+bool Target::GetOutputFilesForSource(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 = 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 = 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( |
+ this, source, tool->outputs(), outputs); |
+ return !outputs->empty(); |
+} |
+ |
void Target::PullDependentTargetConfigsFrom(const Target* dep) { |
MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); |
MergePublicConfigsFrom(dep, &configs_); |
@@ -568,6 +629,13 @@ void Target::CheckSourceGenerated(const SourceFile& source) const { |
// can be filtered out of this list. |
OutputFile out_file(settings()->build_settings(), source); |
std::set<const Target*> seen_targets; |
- if (!EnsureFileIsGeneratedByDependency(this, out_file, true, &seen_targets)) |
- g_scheduler->AddUnknownGeneratedInput(this, source); |
+ if (!EnsureFileIsGeneratedByDependency(this, out_file, true, false, |
+ &seen_targets)) { |
+ // Check object files (much slower and very rare) only if the "normal" |
+ // output check failed. |
+ seen_targets.clear(); |
+ if (!EnsureFileIsGeneratedByDependency(this, out_file, true, true, |
+ &seen_targets)) |
+ g_scheduler->AddUnknownGeneratedInput(this, source); |
+ } |
} |