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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "tools/gn/config_values_extractors.h" | 10 #include "tools/gn/config_values_extractors.h" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 from->label().GetUserVisibleName(false) + | 53 from->label().GetUserVisibleName(false) + |
54 "\n" | 54 "\n" |
55 "which is a complete static library can't depend on\n" + | 55 "which is a complete static library can't depend on\n" + |
56 to->label().GetUserVisibleName(false) + | 56 to->label().GetUserVisibleName(false) + |
57 "\n" | 57 "\n" |
58 "which is a static library.\n" | 58 "which is a static library.\n" |
59 "\n" | 59 "\n" |
60 "Use source sets for intermediate targets instead."); | 60 "Use source sets for intermediate targets instead."); |
61 } | 61 } |
62 | 62 |
| 63 // Set check_private_deps to true for the first invocation since a target |
| 64 // can see all of its dependencies. For recursive invocations this will be set |
| 65 // to false to follow only public dependency paths. |
| 66 // |
| 67 // Pass a pointer to an empty set for the first invocation. This will be used |
| 68 // to avoid duplicate checking. |
| 69 bool EnsureFileIsGeneratedByDependency(const Target* target, |
| 70 const OutputFile& file, |
| 71 bool check_private_deps, |
| 72 std::set<const Target*>* seen_targets) { |
| 73 if (seen_targets->find(target) != seen_targets->end()) |
| 74 return false; // Already checked this one and it's not found. |
| 75 seen_targets->insert(target); |
| 76 |
| 77 // Assume that we have relatively few generated inputs so brute-force |
| 78 // searching here is OK. If this becomes a bottleneck, consider storing |
| 79 // computed_outputs as a hash set. |
| 80 for (const OutputFile& cur : target->computed_outputs()) { |
| 81 if (file == cur) |
| 82 return true; |
| 83 } |
| 84 |
| 85 // Check all public dependencies (don't do data ones since those are |
| 86 // runtime-only). |
| 87 for (const auto& pair : target->public_deps()) { |
| 88 if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, |
| 89 seen_targets)) |
| 90 return true; // Found a path. |
| 91 } |
| 92 |
| 93 // Only check private deps if requested. |
| 94 if (check_private_deps) { |
| 95 for (const auto& pair : target->private_deps()) { |
| 96 if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false, |
| 97 seen_targets)) |
| 98 return true; // Found a path. |
| 99 } |
| 100 } |
| 101 return false; |
| 102 } |
| 103 |
63 } // namespace | 104 } // namespace |
64 | 105 |
65 Target::Target(const Settings* settings, const Label& label) | 106 Target::Target(const Settings* settings, const Label& label) |
66 : Item(settings, label), | 107 : Item(settings, label), |
67 output_type_(UNKNOWN), | 108 output_type_(UNKNOWN), |
68 all_headers_public_(true), | 109 all_headers_public_(true), |
69 check_includes_(true), | 110 check_includes_(true), |
70 complete_static_lib_(false), | 111 complete_static_lib_(false), |
71 testonly_(false), | 112 testonly_(false), |
72 toolchain_(nullptr) { | 113 toolchain_(nullptr) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end()); | 166 all_lib_dirs_.append(cur.lib_dirs().begin(), cur.lib_dirs().end()); |
126 all_libs_.append(cur.libs().begin(), cur.libs().end()); | 167 all_libs_.append(cur.libs().begin(), cur.libs().end()); |
127 } | 168 } |
128 | 169 |
129 PullDependentTargets(); | 170 PullDependentTargets(); |
130 PullForwardedDependentConfigs(); | 171 PullForwardedDependentConfigs(); |
131 PullRecursiveHardDeps(); | 172 PullRecursiveHardDeps(); |
132 | 173 |
133 FillOutputFiles(); | 174 FillOutputFiles(); |
134 | 175 |
135 if (!CheckVisibility(err)) | 176 if (settings()->build_settings()->check_for_bad_items()) { |
136 return false; | 177 if (!CheckVisibility(err)) |
137 if (!CheckTestonly(err)) | 178 return false; |
138 return false; | 179 if (!CheckTestonly(err)) |
139 if (!CheckNoNestedStaticLibs(err)) | 180 return false; |
140 return false; | 181 if (!CheckNoNestedStaticLibs(err)) |
| 182 return false; |
| 183 CheckSourcesGenerated(); |
| 184 } |
141 | 185 |
142 return true; | 186 return true; |
143 } | 187 } |
144 | 188 |
145 bool Target::IsLinkable() const { | 189 bool Target::IsLinkable() const { |
146 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; | 190 return output_type_ == STATIC_LIBRARY || output_type_ == SHARED_LIBRARY; |
147 } | 191 } |
148 | 192 |
149 bool Target::IsFinal() const { | 193 bool Target::IsFinal() const { |
150 return output_type_ == EXECUTABLE || output_type_ == SHARED_LIBRARY || | 194 return output_type_ == EXECUTABLE || output_type_ == SHARED_LIBRARY || |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 // when Android uses a better STL. | 341 // when Android uses a better STL. |
298 for (std::set<const Target*>::const_iterator cur = | 342 for (std::set<const Target*>::const_iterator cur = |
299 pair.ptr->recursive_hard_deps().begin(); | 343 pair.ptr->recursive_hard_deps().begin(); |
300 cur != pair.ptr->recursive_hard_deps().end(); ++cur) | 344 cur != pair.ptr->recursive_hard_deps().end(); ++cur) |
301 recursive_hard_deps_.insert(*cur); | 345 recursive_hard_deps_.insert(*cur); |
302 } | 346 } |
303 } | 347 } |
304 | 348 |
305 void Target::FillOutputFiles() { | 349 void Target::FillOutputFiles() { |
306 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); | 350 const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this); |
| 351 bool check_tool_outputs = false; |
307 switch (output_type_) { | 352 switch (output_type_) { |
308 case GROUP: | 353 case GROUP: |
309 case SOURCE_SET: | 354 case SOURCE_SET: |
310 case COPY_FILES: | 355 case COPY_FILES: |
311 case ACTION: | 356 case ACTION: |
312 case ACTION_FOREACH: { | 357 case ACTION_FOREACH: { |
313 // These don't get linked to and use stamps which should be the first | 358 // These don't get linked to and use stamps which should be the first |
314 // entry in the outputs. These stamps are named | 359 // entry in the outputs. These stamps are named |
315 // "<target_out_dir>/<targetname>.stamp". | 360 // "<target_out_dir>/<targetname>.stamp". |
316 dependency_output_file_ = GetTargetOutputDirAsOutputFile(this); | 361 dependency_output_file_ = GetTargetOutputDirAsOutputFile(this); |
317 dependency_output_file_.value().append(GetComputedOutputName(true)); | 362 dependency_output_file_.value().append(GetComputedOutputName(true)); |
318 dependency_output_file_.value().append(".stamp"); | 363 dependency_output_file_.value().append(".stamp"); |
319 break; | 364 break; |
320 } | 365 } |
321 case EXECUTABLE: | 366 case EXECUTABLE: |
322 // Executables don't get linked to, but the first output is used for | 367 // Executables don't get linked to, but the first output is used for |
323 // dependency management. | 368 // dependency management. |
324 CHECK_GE(tool->outputs().list().size(), 1u); | 369 CHECK_GE(tool->outputs().list().size(), 1u); |
| 370 check_tool_outputs = true; |
325 dependency_output_file_ = | 371 dependency_output_file_ = |
326 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | 372 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
327 this, tool, tool->outputs().list()[0]); | 373 this, tool, tool->outputs().list()[0]); |
328 break; | 374 break; |
329 case STATIC_LIBRARY: | 375 case STATIC_LIBRARY: |
330 // Static libraries both have dependencies and linking going off of the | 376 // Static libraries both have dependencies and linking going off of the |
331 // first output. | 377 // first output. |
332 CHECK(tool->outputs().list().size() >= 1); | 378 CHECK(tool->outputs().list().size() >= 1); |
| 379 check_tool_outputs = true; |
333 link_output_file_ = dependency_output_file_ = | 380 link_output_file_ = dependency_output_file_ = |
334 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | 381 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
335 this, tool, tool->outputs().list()[0]); | 382 this, tool, tool->outputs().list()[0]); |
336 break; | 383 break; |
337 case SHARED_LIBRARY: | 384 case SHARED_LIBRARY: |
338 CHECK(tool->outputs().list().size() >= 1); | 385 CHECK(tool->outputs().list().size() >= 1); |
| 386 check_tool_outputs = true; |
339 if (tool->link_output().empty() && tool->depend_output().empty()) { | 387 if (tool->link_output().empty() && tool->depend_output().empty()) { |
340 // Default behavior, use the first output file for both. | 388 // Default behavior, use the first output file for both. |
341 link_output_file_ = dependency_output_file_ = | 389 link_output_file_ = dependency_output_file_ = |
342 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | 390 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
343 this, tool, tool->outputs().list()[0]); | 391 this, tool, tool->outputs().list()[0]); |
344 } else { | 392 } else { |
345 // Use the tool-specified ones. | 393 // Use the tool-specified ones. |
346 if (!tool->link_output().empty()) { | 394 if (!tool->link_output().empty()) { |
347 link_output_file_ = | 395 link_output_file_ = |
348 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | 396 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
349 this, tool, tool->link_output()); | 397 this, tool, tool->link_output()); |
350 } | 398 } |
351 if (!tool->depend_output().empty()) { | 399 if (!tool->depend_output().empty()) { |
352 dependency_output_file_ = | 400 dependency_output_file_ = |
353 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( | 401 SubstitutionWriter::ApplyPatternToLinkerAsOutputFile( |
354 this, tool, tool->depend_output()); | 402 this, tool, tool->depend_output()); |
355 } | 403 } |
356 } | 404 } |
357 break; | 405 break; |
358 case UNKNOWN: | 406 case UNKNOWN: |
359 default: | 407 default: |
360 NOTREACHED(); | 408 NOTREACHED(); |
361 } | 409 } |
| 410 |
| 411 // Count all outputs from this tool as something generated by this target. |
| 412 if (check_tool_outputs) { |
| 413 SubstitutionWriter::ApplyListToLinkerAsOutputFile( |
| 414 this, tool, tool->outputs(), &computed_outputs_); |
| 415 |
| 416 // Output names aren't canonicalized in the same way that source files |
| 417 // are. For example, the tool outputs often use |
| 418 // {{some_var}}/{{output_name}} which expands to "./foo", but this won't |
| 419 // match "foo" which is what we'll compute when converting a SourceFile to |
| 420 // an OutputFile. |
| 421 for (auto& out : computed_outputs_) |
| 422 NormalizePath(&out.value()); |
| 423 } |
| 424 |
| 425 // Also count anything the target has declared to be an output. |
| 426 std::vector<SourceFile> outputs_as_sources; |
| 427 action_values_.GetOutputsAsSourceFiles(this, &outputs_as_sources); |
| 428 for (const SourceFile& out : outputs_as_sources) |
| 429 computed_outputs_.push_back(OutputFile(settings()->build_settings(), out)); |
362 } | 430 } |
363 | 431 |
364 bool Target::CheckVisibility(Err* err) const { | 432 bool Target::CheckVisibility(Err* err) const { |
365 for (const auto& pair : GetDeps(DEPS_ALL)) { | 433 for (const auto& pair : GetDeps(DEPS_ALL)) { |
366 if (!Visibility::CheckItemVisibility(this, pair.ptr, err)) | 434 if (!Visibility::CheckItemVisibility(this, pair.ptr, err)) |
367 return false; | 435 return false; |
368 } | 436 } |
369 return true; | 437 return true; |
370 } | 438 } |
371 | 439 |
(...skipping 30 matching lines...) Expand all Loading... |
402 | 470 |
403 // Verify no inherited libraries are static libraries. | 471 // Verify no inherited libraries are static libraries. |
404 for (const auto& lib : inherited_libraries().GetOrdered()) { | 472 for (const auto& lib : inherited_libraries().GetOrdered()) { |
405 if (lib->output_type() == Target::STATIC_LIBRARY) { | 473 if (lib->output_type() == Target::STATIC_LIBRARY) { |
406 *err = MakeStaticLibDepsError(this, lib); | 474 *err = MakeStaticLibDepsError(this, lib); |
407 return false; | 475 return false; |
408 } | 476 } |
409 } | 477 } |
410 return true; | 478 return true; |
411 } | 479 } |
| 480 |
| 481 void Target::CheckSourcesGenerated() const { |
| 482 // Checks that any inputs or sources to this target that are in the build |
| 483 // directory are generated by a target that this one transitively depends on |
| 484 // in some way. We already guarantee that all generated files are written |
| 485 // to the build dir. |
| 486 // |
| 487 // See Scheduler::AddUnknownGeneratedInput's declaration for more. |
| 488 for (const SourceFile& file : sources_) |
| 489 CheckSourceGenerated(file); |
| 490 for (const SourceFile& file : inputs_) |
| 491 CheckSourceGenerated(file); |
| 492 } |
| 493 |
| 494 void Target::CheckSourceGenerated(const SourceFile& source) const { |
| 495 if (!IsStringInOutputDir(settings()->build_settings()->build_dir(), |
| 496 source.value())) |
| 497 return; // Not in output dir, this is OK. |
| 498 |
| 499 // Tell the scheduler about unknown files. This will be noted for later so |
| 500 // the list of files written by the GN build itself (often response files) |
| 501 // can be filtered out of this list. |
| 502 OutputFile out_file(settings()->build_settings(), source); |
| 503 std::set<const Target*> seen_targets; |
| 504 if (!EnsureFileIsGeneratedByDependency(this, out_file, true, &seen_targets)) |
| 505 g_scheduler->AddUnknownGeneratedInput(this, source); |
| 506 } |
OLD | NEW |