OLD | NEW |
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/target.h" | 5 #include "tools/gn/target.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
| 9 #include <algorithm> |
| 10 |
9 #include "base/bind.h" | 11 #include "base/bind.h" |
10 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
11 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
12 #include "tools/gn/config_values_extractors.h" | 14 #include "tools/gn/config_values_extractors.h" |
13 #include "tools/gn/deps_iterator.h" | 15 #include "tools/gn/deps_iterator.h" |
14 #include "tools/gn/filesystem_utils.h" | 16 #include "tools/gn/filesystem_utils.h" |
15 #include "tools/gn/scheduler.h" | 17 #include "tools/gn/scheduler.h" |
| 18 #include "tools/gn/source_file_type.h" |
16 #include "tools/gn/substitution_writer.h" | 19 #include "tools/gn/substitution_writer.h" |
| 20 #include "tools/gn/tool.h" |
| 21 #include "tools/gn/toolchain.h" |
17 #include "tools/gn/trace.h" | 22 #include "tools/gn/trace.h" |
18 | 23 |
19 namespace { | 24 namespace { |
20 | 25 |
21 typedef std::set<const Config*> ConfigSet; | 26 typedef std::set<const Config*> ConfigSet; |
22 | 27 |
23 // Merges the public configs from the given target to the given config list. | 28 // Merges the public configs from the given target to the given config list. |
24 void MergePublicConfigsFrom(const Target* from_target, | 29 void MergePublicConfigsFrom(const Target* from_target, |
25 UniqueVector<LabelConfigPair>* dest) { | 30 UniqueVector<LabelConfigPair>* dest) { |
26 const UniqueVector<LabelConfigPair>& pub = from_target->public_configs(); | 31 const UniqueVector<LabelConfigPair>& pub = from_target->public_configs(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 "\n" | 67 "\n" |
63 "Use source sets for intermediate targets instead."); | 68 "Use source sets for intermediate targets instead."); |
64 } | 69 } |
65 | 70 |
66 // Set check_private_deps to true for the first invocation since a target | 71 // Set check_private_deps to true for the first invocation since a target |
67 // can see all of its dependencies. For recursive invocations this will be set | 72 // can see all of its dependencies. For recursive invocations this will be set |
68 // to false to follow only public dependency paths. | 73 // to false to follow only public dependency paths. |
69 // | 74 // |
70 // Pass a pointer to an empty set for the first invocation. This will be used | 75 // Pass a pointer to an empty set for the first invocation. This will be used |
71 // to avoid duplicate checking. | 76 // to avoid duplicate checking. |
| 77 // |
| 78 // Checking of object files is optional because it is much slower. This allows |
| 79 // us to check targets for normal outputs, and then as a second pass check |
| 80 // object files (since we know it will be an error otherwise). This allows |
| 81 // us to avoid computing all object file names in the common case. |
72 bool EnsureFileIsGeneratedByDependency(const Target* target, | 82 bool EnsureFileIsGeneratedByDependency(const Target* target, |
73 const OutputFile& file, | 83 const OutputFile& file, |
74 bool check_private_deps, | 84 bool check_private_deps, |
| 85 bool consider_object_files, |
75 std::set<const Target*>* seen_targets) { | 86 std::set<const Target*>* seen_targets) { |
76 if (seen_targets->find(target) != seen_targets->end()) | 87 if (seen_targets->find(target) != seen_targets->end()) |
77 return false; // Already checked this one and it's not found. | 88 return false; // Already checked this one and it's not found. |
78 seen_targets->insert(target); | 89 seen_targets->insert(target); |
79 | 90 |
80 // Assume that we have relatively few generated inputs so brute-force | 91 // Assume that we have relatively few generated inputs so brute-force |
81 // searching here is OK. If this becomes a bottleneck, consider storing | 92 // searching here is OK. If this becomes a bottleneck, consider storing |
82 // computed_outputs as a hash set. | 93 // computed_outputs as a hash set. |
83 for (const OutputFile& cur : target->computed_outputs()) { | 94 for (const OutputFile& cur : target->computed_outputs()) { |
84 if (file == cur) | 95 if (file == cur) |
85 return true; | 96 return true; |
86 } | 97 } |
87 | 98 |
| 99 // Check binary target intermediate files if requested. |
| 100 if (consider_object_files && target->IsBinary()) { |
| 101 std::vector<OutputFile> source_outputs; |
| 102 for (const SourceFile& source : target->sources()) { |
| 103 Toolchain::ToolType tool_type; |
| 104 if (!target->GetOutputFilesForSource(source, &tool_type, &source_outputs)) |
| 105 continue; |
| 106 if (std::find(source_outputs.begin(), source_outputs.end(), file) != |
| 107 source_outputs.end()) |
| 108 return true; |
| 109 } |
| 110 } |
| 111 |
88 // Check all public dependencies (don't do data ones since those are | 112 // Check all public dependencies (don't do data ones since those are |
89 // runtime-only). | 113 // runtime-only). |
90 for (const auto& pair : target->public_deps()) { | 114 for (const auto& pair : target->public_deps()) { |
91 if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, | 115 if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, |
92 seen_targets)) | 116 consider_object_files, seen_targets)) |
93 return true; // Found a path. | 117 return true; // Found a path. |
94 } | 118 } |
95 | 119 |
96 // Only check private deps if requested. | 120 // Only check private deps if requested. |
97 if (check_private_deps) { | 121 if (check_private_deps) { |
98 for (const auto& pair : target->private_deps()) { | 122 for (const auto& pair : target->private_deps()) { |
99 if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, | 123 if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, |
| 124 consider_object_files, |
100 seen_targets)) | 125 seen_targets)) |
101 return true; // Found a path. | 126 return true; // Found a path. |
102 } | 127 } |
103 } | 128 } |
104 return false; | 129 return false; |
105 } | 130 } |
106 | 131 |
107 } // namespace | 132 } // namespace |
108 | 133 |
109 Target::Target(const Settings* settings, const Label& label) | 134 Target::Target(const Settings* settings, const Label& label) |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 if (!CheckTestonly(err)) | 233 if (!CheckTestonly(err)) |
209 return false; | 234 return false; |
210 if (!CheckNoNestedStaticLibs(err)) | 235 if (!CheckNoNestedStaticLibs(err)) |
211 return false; | 236 return false; |
212 CheckSourcesGenerated(); | 237 CheckSourcesGenerated(); |
213 } | 238 } |
214 | 239 |
215 return true; | 240 return true; |
216 } | 241 } |
217 | 242 |
| 243 bool Target::IsBinary() const { |
| 244 return output_type_ == EXECUTABLE || |
| 245 output_type_ == SHARED_LIBRARY || |
| 246 output_type_ == LOADABLE_MODULE || |
| 247 output_type_ == STATIC_LIBRARY || |
| 248 output_type_ == SOURCE_SET; |
| 249 } |
| 250 |
218 bool Target::IsLinkable() const { | 251 bool Target::IsLinkable() const { |
219 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; | 252 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; |
220 } | 253 } |
221 | 254 |
222 bool Target::IsFinal() const { | 255 bool Target::IsFinal() const { |
223 return output_type_ == EXECUTABLE || | 256 return output_type_ == EXECUTABLE || |
224 output_type_ == SHARED_LIBRARY || | 257 output_type_ == SHARED_LIBRARY || |
225 output_type_ == LOADABLE_MODULE || | 258 output_type_ == LOADABLE_MODULE || |
226 output_type_ == ACTION || | 259 output_type_ == ACTION || |
227 output_type_ == ACTION_FOREACH || | 260 output_type_ == ACTION_FOREACH || |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 "Alas, I can not continue.", | 313 "Alas, I can not continue.", |
281 label().GetUserVisibleName(false).c_str(), | 314 label().GetUserVisibleName(false).c_str(), |
282 GetStringForOutputType(output_type_), | 315 GetStringForOutputType(output_type_), |
283 label().GetToolchainLabel().GetUserVisibleName(false).c_str(), | 316 label().GetToolchainLabel().GetUserVisibleName(false).c_str(), |
284 Toolchain::ToolTypeToName( | 317 Toolchain::ToolTypeToName( |
285 toolchain->GetToolTypeForTargetFinalOutput(this)).c_str())); | 318 toolchain->GetToolTypeForTargetFinalOutput(this)).c_str())); |
286 } | 319 } |
287 return false; | 320 return false; |
288 } | 321 } |
289 | 322 |
| 323 bool Target::GetOutputFilesForSource(const SourceFile& source, |
| 324 Toolchain::ToolType* computed_tool_type, |
| 325 std::vector<OutputFile>* outputs) const { |
| 326 outputs->clear(); |
| 327 *computed_tool_type = Toolchain::TYPE_NONE; |
| 328 |
| 329 SourceFileType file_type = GetSourceFileType(source); |
| 330 if (file_type == SOURCE_UNKNOWN) |
| 331 return false; |
| 332 if (file_type == SOURCE_O) { |
| 333 // Object files just get passed to the output and not compiled. |
| 334 outputs->push_back(OutputFile(settings()->build_settings(), source)); |
| 335 return true; |
| 336 } |
| 337 |
| 338 *computed_tool_type = toolchain_->GetToolTypeForSourceType(file_type); |
| 339 if (*computed_tool_type == Toolchain::TYPE_NONE) |
| 340 return false; // No tool for this file (it's a header file or something). |
| 341 const Tool* tool = toolchain_->GetTool(*computed_tool_type); |
| 342 if (!tool) |
| 343 return false; // Tool does not apply for this toolchain.file. |
| 344 |
| 345 // Figure out what output(s) this compiler produces. |
| 346 SubstitutionWriter::ApplyListToCompilerAsOutputFile( |
| 347 this, source, tool->outputs(), outputs); |
| 348 return !outputs->empty(); |
| 349 } |
| 350 |
290 void Target::PullDependentTargetConfigsFrom(const Target* dep) { | 351 void Target::PullDependentTargetConfigsFrom(const Target* dep) { |
291 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); | 352 MergeAllDependentConfigsFrom(dep, &configs_, &all_dependent_configs_); |
292 MergePublicConfigsFrom(dep, &configs_); | 353 MergePublicConfigsFrom(dep, &configs_); |
293 } | 354 } |
294 | 355 |
295 void Target::PullDependentTargetConfigs() { | 356 void Target::PullDependentTargetConfigs() { |
296 for (const auto& pair : GetDeps(DEPS_LINKED)) | 357 for (const auto& pair : GetDeps(DEPS_LINKED)) |
297 PullDependentTargetConfigsFrom(pair.ptr); | 358 PullDependentTargetConfigsFrom(pair.ptr); |
298 } | 359 } |
299 | 360 |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 void Target::CheckSourceGenerated(const SourceFile& source) const { | 622 void Target::CheckSourceGenerated(const SourceFile& source) const { |
562 if (!IsStringInOutputDir(settings()->build_settings()->build_dir(), | 623 if (!IsStringInOutputDir(settings()->build_settings()->build_dir(), |
563 source.value())) | 624 source.value())) |
564 return; // Not in output dir, this is OK. | 625 return; // Not in output dir, this is OK. |
565 | 626 |
566 // Tell the scheduler about unknown files. This will be noted for later so | 627 // Tell the scheduler about unknown files. This will be noted for later so |
567 // the list of files written by the GN build itself (often response files) | 628 // the list of files written by the GN build itself (often response files) |
568 // can be filtered out of this list. | 629 // can be filtered out of this list. |
569 OutputFile out_file(settings()->build_settings(), source); | 630 OutputFile out_file(settings()->build_settings(), source); |
570 std::set<const Target*> seen_targets; | 631 std::set<const Target*> seen_targets; |
571 if (!EnsureFileIsGeneratedByDependency(this, out_file, true, &seen_targets)) | 632 if (!EnsureFileIsGeneratedByDependency(this, out_file, true, false, |
572 g_scheduler->AddUnknownGeneratedInput(this, source); | 633 &seen_targets)) { |
| 634 // Check object files (much slower and very rare) only if the "normal" |
| 635 // output check failed. |
| 636 seen_targets.clear(); |
| 637 if (!EnsureFileIsGeneratedByDependency(this, out_file, true, true, |
| 638 &seen_targets)) |
| 639 g_scheduler->AddUnknownGeneratedInput(this, source); |
| 640 } |
573 } | 641 } |
OLD | NEW |