Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: tools/gn/target.cc

Issue 1126193005: Check for inputs not generated by deps (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@data
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/target.h ('k') | tools/gn/target_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « tools/gn/target.h ('k') | tools/gn/target_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698