| 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 |