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/ninja_build_writer.h" | 5 #include "tools/gn/ninja_build_writer.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <fstream> | 9 #include <fstream> |
10 #include <map> | 10 #include <map> |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 "Two or more targets generate the same output:\n " + | 123 "Two or more targets generate the same output:\n " + |
124 bad_output.value() + "\n\n" | 124 bad_output.value() + "\n\n" |
125 "This is can often be fixed by changing one of the target names, or by \n" | 125 "This is can often be fixed by changing one of the target names, or by \n" |
126 "setting an output_name on one of them.\n" | 126 "setting an output_name on one of them.\n" |
127 "\nCollisions:\n" + matches_string); | 127 "\nCollisions:\n" + matches_string); |
128 for (size_t i = 1; i < matches.size(); i++) | 128 for (size_t i = 1; i < matches.size(); i++) |
129 result.AppendSubErr(Err(matches[i]->defined_from(), "Collision.")); | 129 result.AppendSubErr(Err(matches[i]->defined_from(), "Collision.")); |
130 return result; | 130 return result; |
131 } | 131 } |
132 | 132 |
| 133 // Given two toolchains with the same name, generates an error message |
| 134 // that describes the problem. |
| 135 Err GetDuplicateToolchainError(const SourceFile& source_file, |
| 136 const Toolchain* previous_toolchain, |
| 137 const Toolchain* toolchain) { |
| 138 Err result(toolchain->defined_from(), "Duplicate toolchain.", |
| 139 "Two or more toolchains write to the same directory:\n " + |
| 140 source_file.GetDir().value() + "\n\n" |
| 141 "This can be fixed by making sure that distinct toolchains have\n" |
| 142 "distinct names.\n"); |
| 143 result.AppendSubErr( |
| 144 Err(previous_toolchain->defined_from(), "Previous toolchain.")); |
| 145 return result; |
| 146 } |
| 147 |
133 } // namespace | 148 } // namespace |
134 | 149 |
135 NinjaBuildWriter::NinjaBuildWriter( | 150 NinjaBuildWriter::NinjaBuildWriter( |
136 const BuildSettings* build_settings, | 151 const BuildSettings* build_settings, |
137 const std::unordered_map<const Settings*, const Toolchain*>& | 152 const std::unordered_map<const Settings*, const Toolchain*>& |
138 used_toolchains, | 153 used_toolchains, |
139 const Toolchain* default_toolchain, | 154 const Toolchain* default_toolchain, |
140 const std::vector<const Target*>& default_toolchain_targets, | 155 const std::vector<const Target*>& default_toolchain_targets, |
141 std::ostream& out, | 156 std::ostream& out, |
142 std::ostream& dep_out) | 157 std::ostream& dep_out) |
143 : build_settings_(build_settings), | 158 : build_settings_(build_settings), |
144 used_toolchains_(used_toolchains), | 159 used_toolchains_(used_toolchains), |
145 default_toolchain_(default_toolchain), | 160 default_toolchain_(default_toolchain), |
146 default_toolchain_targets_(default_toolchain_targets), | 161 default_toolchain_targets_(default_toolchain_targets), |
147 out_(out), | 162 out_(out), |
148 dep_out_(dep_out), | 163 dep_out_(dep_out), |
149 path_output_(build_settings->build_dir(), | 164 path_output_(build_settings->build_dir(), |
150 build_settings->root_path_utf8(), | 165 build_settings->root_path_utf8(), |
151 ESCAPE_NINJA) {} | 166 ESCAPE_NINJA) {} |
152 | 167 |
153 NinjaBuildWriter::~NinjaBuildWriter() { | 168 NinjaBuildWriter::~NinjaBuildWriter() { |
154 } | 169 } |
155 | 170 |
156 bool NinjaBuildWriter::Run(Err* err) { | 171 bool NinjaBuildWriter::Run(Err* err) { |
157 WriteNinjaRules(); | 172 WriteNinjaRules(); |
158 WriteAllPools(); | 173 WriteAllPools(); |
159 WriteSubninjas(); | 174 return WriteSubninjas(err) && WritePhonyAndAllRules(err); |
160 return WritePhonyAndAllRules(err); | |
161 } | 175 } |
162 | 176 |
163 // static | 177 // static |
164 bool NinjaBuildWriter::RunAndWriteFile( | 178 bool NinjaBuildWriter::RunAndWriteFile( |
165 const BuildSettings* build_settings, | 179 const BuildSettings* build_settings, |
166 const Builder& builder, | 180 const Builder& builder, |
167 Err* err) { | 181 Err* err) { |
168 ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja"); | 182 ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja"); |
169 | 183 |
170 std::vector<const Target*> all_targets = builder.GetAllResolvedTargets(); | 184 std::vector<const Target*> all_targets = builder.GetAllResolvedTargets(); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 [&pool_name](const Pool* a, const Pool* b) { | 294 [&pool_name](const Pool* a, const Pool* b) { |
281 return pool_name(a) < pool_name(b); | 295 return pool_name(a) < pool_name(b); |
282 }); | 296 }); |
283 for (const Pool* pool : sorted_pools) { | 297 for (const Pool* pool : sorted_pools) { |
284 out_ << "pool " << pool_name(pool) << std::endl | 298 out_ << "pool " << pool_name(pool) << std::endl |
285 << " depth = " << pool->depth() << std::endl | 299 << " depth = " << pool->depth() << std::endl |
286 << std::endl; | 300 << std::endl; |
287 } | 301 } |
288 } | 302 } |
289 | 303 |
290 void NinjaBuildWriter::WriteSubninjas() { | 304 bool NinjaBuildWriter::WriteSubninjas(Err* err) { |
291 // Write toolchains sorted by their name, to make output deterministic. | 305 // Write toolchains sorted by their name, to make output deterministic. |
292 std::vector<std::pair<const Settings*, const Toolchain*>> sorted_settings( | 306 std::vector<std::pair<const Settings*, const Toolchain*>> sorted_settings( |
293 used_toolchains_.begin(), used_toolchains_.end()); | 307 used_toolchains_.begin(), used_toolchains_.end()); |
294 std::sort(sorted_settings.begin(), sorted_settings.end(), | 308 std::sort(sorted_settings.begin(), sorted_settings.end(), |
295 [this](const std::pair<const Settings*, const Toolchain*>& a, | 309 [this](const std::pair<const Settings*, const Toolchain*>& a, |
296 const std::pair<const Settings*, const Toolchain*>& b) { | 310 const std::pair<const Settings*, const Toolchain*>& b) { |
297 // Always put the default toolchain first. | 311 // Always put the default toolchain first. |
298 if (b.second == default_toolchain_) | 312 if (b.second == default_toolchain_) |
299 return false; | 313 return false; |
300 if (a.second == default_toolchain_) | 314 if (a.second == default_toolchain_) |
301 return true; | 315 return true; |
302 return GetNinjaFileForToolchain(a.first) < | 316 return GetNinjaFileForToolchain(a.first) < |
303 GetNinjaFileForToolchain(b.first); | 317 GetNinjaFileForToolchain(b.first); |
304 }); | 318 }); |
| 319 |
| 320 SourceFile previous_subninja; |
| 321 const Toolchain* previous_toolchain = nullptr; |
| 322 |
305 for (const auto& pair : sorted_settings) { | 323 for (const auto& pair : sorted_settings) { |
| 324 SourceFile subninja = GetNinjaFileForToolchain(pair.first); |
| 325 |
| 326 // Since the toolchains are sorted, comparing to the previous subninja is |
| 327 // enough to find duplicates. |
| 328 if (subninja == previous_subninja) { |
| 329 *err = |
| 330 GetDuplicateToolchainError(subninja, previous_toolchain, pair.second); |
| 331 return false; |
| 332 } |
| 333 |
306 out_ << "subninja "; | 334 out_ << "subninja "; |
307 path_output_.WriteFile(out_, GetNinjaFileForToolchain(pair.first)); | 335 path_output_.WriteFile(out_, subninja); |
308 out_ << std::endl; | 336 out_ << std::endl; |
| 337 previous_subninja = subninja; |
| 338 previous_toolchain = pair.second; |
309 } | 339 } |
310 out_ << std::endl; | 340 out_ << std::endl; |
| 341 return true; |
311 } | 342 } |
312 | 343 |
313 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) { | 344 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) { |
314 // Track rules as we generate them so we don't accidentally write a phony | 345 // Track rules as we generate them so we don't accidentally write a phony |
315 // rule that collides with something else. | 346 // rule that collides with something else. |
316 // GN internally generates an "all" target, so don't duplicate it. | 347 // GN internally generates an "all" target, so don't duplicate it. |
317 base::hash_set<std::string> written_rules; | 348 base::hash_set<std::string> written_rules; |
318 written_rules.insert("all"); | 349 written_rules.insert("all"); |
319 | 350 |
320 // Set if we encounter a target named "//:default". | 351 // Set if we encounter a target named "//:default". |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 EscapeOptions ninja_escape; | 505 EscapeOptions ninja_escape; |
475 ninja_escape.mode = ESCAPE_NINJA; | 506 ninja_escape.mode = ESCAPE_NINJA; |
476 | 507 |
477 // Escape for special chars Ninja will handle. | 508 // Escape for special chars Ninja will handle. |
478 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); | 509 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); |
479 | 510 |
480 out_ << "build " << escaped << ": phony "; | 511 out_ << "build " << escaped << ": phony "; |
481 path_output_.WriteFile(out_, target->dependency_output_file()); | 512 path_output_.WriteFile(out_, target->dependency_output_file()); |
482 out_ << std::endl; | 513 out_ << std::endl; |
483 } | 514 } |
OLD | NEW |