| Index: tools/gn/command_gen.cc
|
| diff --git a/tools/gn/command_gen.cc b/tools/gn/command_gen.cc
|
| index 76f1f36f7c4ee841a692db6f812416025bb9a7c7..eceb8df09f867c28ed8a45733e8a01b418ee016a 100644
|
| --- a/tools/gn/command_gen.cc
|
| +++ b/tools/gn/command_gen.cc
|
| @@ -6,6 +6,7 @@
|
| #include "base/bind.h"
|
| #include "base/command_line.h"
|
| #include "base/strings/string_number_conversions.h"
|
| +#include "base/strings/stringprintf.h"
|
| #include "base/timer/elapsed_timer.h"
|
| #include "tools/gn/build_settings.h"
|
| #include "tools/gn/commands.h"
|
| @@ -44,6 +45,89 @@ void ItemResolvedCallback(base::subtle::Atomic32* write_counter,
|
| }
|
| }
|
|
|
| +// Returns a pointer to the target with the given file as an output, or null
|
| +// if no targets generate the file. This is brute force since this is an
|
| +// error condition and performance shouldn't matter.
|
| +const Target* FindTargetThatGeneratesFile(const Builder* builder,
|
| + const SourceFile& file) {
|
| + std::vector<const Target*> targets = builder->GetAllResolvedTargets();
|
| + if (targets.empty())
|
| + return nullptr;
|
| +
|
| + OutputFile output_file(targets[0]->settings()->build_settings(), file);
|
| + for (const Target* target : targets) {
|
| + for (const auto& cur_output : target->computed_outputs()) {
|
| + if (cur_output == output_file)
|
| + return target;
|
| + }
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +// Prints an error that the given file was present as a source or input in
|
| +// the given target(s) but was not generated by any of its dependencies.
|
| +void PrintInvalidGeneratedInput(const Builder* builder,
|
| + const SourceFile& file,
|
| + const std::vector<const Target*>& targets) {
|
| + std::string err;
|
| +
|
| + const std::string target_str = targets.size() > 1 ? "targets" : "target";
|
| + err += "The file:\n";
|
| + err += " " + file.value() + "\n";
|
| + err += "is listed as an input or source for the " + target_str + ":\n";
|
| + for (const Target* target : targets)
|
| + err += " " + target->label().GetUserVisibleName(false) + "\n";
|
| +
|
| + const Target* generator = FindTargetThatGeneratesFile(builder, file);
|
| + if (generator) {
|
| + err += "but this file was not generated by any dependencies of the " +
|
| + target_str + ". The target\nthat generates the file is:\n ";
|
| + err += generator->label().GetUserVisibleName(false);
|
| + } else {
|
| + err += "but no targets in the build generate that file.";
|
| + }
|
| +
|
| + Err(Location(), "Input to " + target_str + " not generated by a dependency.",
|
| + err).PrintToStdout();
|
| +}
|
| +
|
| +bool CheckForInvalidGeneratedInputs(Setup* setup) {
|
| + std::multimap<SourceFile, const Target*> unknown_inputs =
|
| + g_scheduler->GetUnknownGeneratedInputs();
|
| + if (unknown_inputs.empty())
|
| + return true; // No bad files.
|
| +
|
| + int errors_found = 0;
|
| + auto cur = unknown_inputs.begin();
|
| + while (cur != unknown_inputs.end()) {
|
| + errors_found++;
|
| + auto end_of_range = unknown_inputs.upper_bound(cur->first);
|
| +
|
| + // Package the values more conveniently for printing.
|
| + SourceFile bad_input = cur->first;
|
| + std::vector<const Target*> targets;
|
| + while (cur != end_of_range)
|
| + targets.push_back((cur++)->second);
|
| +
|
| + PrintInvalidGeneratedInput(setup->builder(), bad_input, targets);
|
| + OutputString("\n");
|
| + }
|
| +
|
| + OutputString(
|
| + "If you have generated inputs, there needs to be a dependency path "
|
| + "between the\ntwo targets in addition to just listing the files. For "
|
| + "indirect dependencies,\nthe intermediate ones must be public_deps. "
|
| + "data_deps don't count since they're\nonly runtime dependencies. If "
|
| + "you think a dependency chain exists, it might be\nbecause the chain "
|
| + "is private. Try \"gn path\" to analyze.\n");
|
| +
|
| + if (errors_found > 1) {
|
| + OutputString(base::StringPrintf("\n%d generated input errors found.\n",
|
| + errors_found), DECORATION_YELLOW);
|
| + }
|
| + return false;
|
| +}
|
| +
|
| } // namespace
|
|
|
| const char kGen[] = "gen";
|
| @@ -107,6 +191,9 @@ int RunGen(const std::vector<std::string>& args) {
|
| return 1;
|
| }
|
|
|
| + if (!CheckForInvalidGeneratedInputs(setup))
|
| + return 1;
|
| +
|
| base::TimeDelta elapsed_time = timer.Elapsed();
|
|
|
| if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kQuiet)) {
|
|
|