Index: tools/gn/ninja_build_writer.cc |
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc |
index 1436af6da7e2ff0ce77e18f967b9b177c3d98f64..fa83874b2e8a5efbf29472e4a3f5b1814939a259 100644 |
--- a/tools/gn/ninja_build_writer.cc |
+++ b/tools/gn/ninja_build_writer.cc |
@@ -15,6 +15,7 @@ |
#include "base/strings/utf_string_conversions.h" |
#include "build/build_config.h" |
#include "tools/gn/build_settings.h" |
+#include "tools/gn/err.h" |
#include "tools/gn/escape.h" |
#include "tools/gn/filesystem_utils.h" |
#include "tools/gn/input_file_manager.h" |
@@ -91,11 +92,11 @@ NinjaBuildWriter::NinjaBuildWriter( |
NinjaBuildWriter::~NinjaBuildWriter() { |
} |
-void NinjaBuildWriter::Run() { |
+bool NinjaBuildWriter::Run(Err* err) { |
WriteNinjaRules(); |
WriteLinkPool(); |
WriteSubninjas(); |
- WritePhonyAndAllRules(); |
+ return WritePhonyAndAllRules(err); |
} |
// static |
@@ -103,7 +104,8 @@ bool NinjaBuildWriter::RunAndWriteFile( |
const BuildSettings* build_settings, |
const std::vector<const Settings*>& all_settings, |
const Toolchain* default_toolchain, |
- const std::vector<const Target*>& default_toolchain_targets) { |
+ const std::vector<const Target*>& default_toolchain_targets, |
+ Err* err) { |
ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja"); |
base::FilePath ninja_file(build_settings->GetFullPath( |
@@ -113,19 +115,22 @@ bool NinjaBuildWriter::RunAndWriteFile( |
std::ofstream file; |
file.open(FilePathToUTF8(ninja_file).c_str(), |
std::ios_base::out | std::ios_base::binary); |
- if (file.fail()) |
+ if (file.fail()) { |
+ *err = Err(Location(), "Couldn't open build.ninja for writing"); |
return false; |
+ } |
std::ofstream depfile; |
depfile.open((FilePathToUTF8(ninja_file) + ".d").c_str(), |
std::ios_base::out | std::ios_base::binary); |
- if (depfile.fail()) |
+ if (depfile.fail()) { |
+ *err = Err(Location(), "Couldn't open depfile for writing"); |
return false; |
+ } |
NinjaBuildWriter gen(build_settings, all_settings, default_toolchain, |
default_toolchain_targets, file, depfile); |
- gen.Run(); |
- return true; |
+ return gen.Run(err); |
} |
void NinjaBuildWriter::WriteNinjaRules() { |
@@ -171,7 +176,7 @@ void NinjaBuildWriter::WriteSubninjas() { |
out_ << std::endl; |
} |
-void NinjaBuildWriter::WritePhonyAndAllRules() { |
+bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) { |
std::string all_rules; |
// Write phony rules for all uniquely-named targets in the default toolchain. |
@@ -180,6 +185,7 @@ void NinjaBuildWriter::WritePhonyAndAllRules() { |
// which we also find. |
std::map<std::string, int> small_name_count; |
std::vector<const Target*> toplevel_targets; |
+ base::hash_set<std::string> target_files; |
for (size_t i = 0; i < default_toolchain_targets_.size(); i++) { |
const Target* target = default_toolchain_targets_[i]; |
const Label& label = target->label(); |
@@ -204,6 +210,10 @@ void NinjaBuildWriter::WritePhonyAndAllRules() { |
OutputFile target_file(target->dependency_output_file()); |
// The output files may have leading "./" so normalize those away. |
NormalizePath(&target_file.value()); |
+ if (!target_files.insert(target_file.value()).second) { |
+ *err = Err(Location(), "Duplicate rules for " + target_file.value()); |
+ return false; |
+ } |
// Write the long name "foo/bar:baz" for the target "//foo/bar:baz". |
std::string long_name = label.GetUserVisibleName(false); |
@@ -244,6 +254,7 @@ void NinjaBuildWriter::WritePhonyAndAllRules() { |
out_ << "\nbuild all: phony " << all_rules << std::endl; |
out_ << "default all" << std::endl; |
} |
+ return true; |
} |
void NinjaBuildWriter::WritePhonyRule(const Target* target, |