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

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

Issue 1123283003: GN: Don't generate phony rules called "all". (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 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/ninja_build_writer.h ('k') | no next file » | 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/ninja_build_writer.h" 5 #include "tools/gn/ninja_build_writer.h"
6 6
7 #include <fstream> 7 #include <fstream>
8 #include <map> 8 #include <map>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 out_ << "subninja "; 179 out_ << "subninja ";
180 path_output_.WriteFile(out_, GetNinjaFileForToolchain(elem)); 180 path_output_.WriteFile(out_, GetNinjaFileForToolchain(elem));
181 out_ << std::endl; 181 out_ << std::endl;
182 } 182 }
183 out_ << std::endl; 183 out_ << std::endl;
184 } 184 }
185 185
186 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) { 186 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
187 std::string all_rules; 187 std::string all_rules;
188 188
189 // Track rules as we generate them so we don't accidentally write a phony
190 // rule that collides with something else.
191 // GN internally generates an "all" target, so don't duplicate it.
192 std::set<std::string> written_rules;
193 written_rules.insert("all");
194
189 // Write phony rules for all uniquely-named targets in the default toolchain. 195 // Write phony rules for all uniquely-named targets in the default toolchain.
190 // Don't do other toolchains or we'll get naming conflicts, and if the name 196 // Don't do other toolchains or we'll get naming conflicts, and if the name
191 // isn't unique, also skip it. The exception is for the toplevel targets 197 // isn't unique, also skip it. The exception is for the toplevel targets
192 // which we also find. 198 // which we also find.
193 std::map<std::string, int> small_name_count; 199 std::map<std::string, int> small_name_count;
194 std::map<std::string, int> exe_count; 200 std::map<std::string, int> exe_count;
195 std::vector<const Target*> toplevel_targets; 201 std::vector<const Target*> toplevel_targets;
196 base::hash_set<std::string> target_files; 202 base::hash_set<std::string> target_files;
197 for (const auto& target : default_toolchain_targets_) { 203 for (const auto& target : default_toolchain_targets_) {
198 const Label& label = target->label(); 204 const Label& label = target->label();
199 small_name_count[label.name()]++; 205 small_name_count[label.name()]++;
200 206
201 // Look for targets with a name of the form 207 // Look for targets with a name of the form
202 // dir = "//foo/", name = "foo" 208 // dir = "//foo/", name = "foo"
203 // i.e. where the target name matches the top level directory. We will 209 // i.e. where the target name matches the top level directory. We will
204 // always write phony rules for these even if there is another target with 210 // always write phony rules for these even if there is another target with
205 // the same short name. 211 // the same short name.
206 const std::string& dir_string = label.dir().value(); 212 const std::string& dir_string = label.dir().value();
207 if (dir_string.size() == label.name().size() + 3 && // Size matches. 213 if (dir_string.size() == label.name().size() + 3 && // Size matches.
208 dir_string[0] == '/' && dir_string[1] == '/' && // "//" at beginning. 214 dir_string[0] == '/' && dir_string[1] == '/' && // "//" at beginning.
209 dir_string[dir_string.size() - 1] == '/' && // "/" at end. 215 dir_string[dir_string.size() - 1] == '/' && // "/" at end.
210 dir_string.compare(2, label.name().size(), label.name()) == 0) 216 dir_string.compare(2, label.name().size(), label.name()) == 0)
211 toplevel_targets.push_back(target); 217 toplevel_targets.push_back(target);
212 218
213 // Look for executables; later we will generate phony rules for them 219 // Look for executables; later we will generate phony rules for them
214 // even if there are non-executable targets with the same name. 220 // even if there are non-executable targets with the same name.
215 if (target->output_type() == Target::EXECUTABLE) 221 if (target->output_type() == Target::EXECUTABLE)
216 exe_count[label.name()]++; 222 exe_count[label.name()]++;
223
224 // Add the files to the list of generated targets so we don't write phony
225 // rules that collide.
226 std::string target_file(target->dependency_output_file().value());
227 NormalizePath(&target_file);
228 written_rules.insert(target_file);
217 } 229 }
218 230
219 for (const auto& target : default_toolchain_targets_) { 231 for (const auto& target : default_toolchain_targets_) {
220 const Label& label = target->label(); 232 const Label& label = target->label();
221 OutputFile target_file(target->dependency_output_file()); 233 OutputFile target_file(target->dependency_output_file());
222 // The output files may have leading "./" so normalize those away. 234 // The output files may have leading "./" so normalize those away.
223 NormalizePath(&target_file.value()); 235 NormalizePath(&target_file.value());
224 if (!target_files.insert(target_file.value()).second) { 236 if (!target_files.insert(target_file.value()).second) {
225 *err = Err(Location(), "Duplicate rules for " + target_file.value()); 237 *err = Err(Location(), "Duplicate rules for " + target_file.value());
226 return false; 238 return false;
227 } 239 }
228 240
229 // Write the long name "foo/bar:baz" for the target "//foo/bar:baz". 241 // Write the long name "foo/bar:baz" for the target "//foo/bar:baz".
230 std::string long_name = label.GetUserVisibleName(false); 242 std::string long_name = label.GetUserVisibleName(false);
231 base::TrimString(long_name, "/", &long_name); 243 base::TrimString(long_name, "/", &long_name);
232 WritePhonyRule(target, target_file, long_name); 244 WritePhonyRule(target, target_file, long_name, &written_rules);
233 245
234 // Write the directory name with no target name if they match 246 // Write the directory name with no target name if they match
235 // (e.g. "//foo/bar:bar" -> "foo/bar"). 247 // (e.g. "//foo/bar:bar" -> "foo/bar").
236 if (FindLastDirComponent(label.dir()) == label.name()) { 248 if (FindLastDirComponent(label.dir()) == label.name()) {
237 std::string medium_name = DirectoryWithNoLastSlash(label.dir()); 249 std::string medium_name = DirectoryWithNoLastSlash(label.dir());
238 base::TrimString(medium_name, "/", &medium_name); 250 base::TrimString(medium_name, "/", &medium_name);
239 // That may have generated a name the same as the short name of the 251 // That may have generated a name the same as the short name of the
240 // target which we already wrote. 252 // target which we already wrote.
241 if (medium_name != label.name()) 253 if (medium_name != label.name())
242 WritePhonyRule(target, target_file, medium_name); 254 WritePhonyRule(target, target_file, medium_name, &written_rules);
243 } 255 }
244 256
245 // Write short names for ones which are either completely unique or there 257 // Write short names for ones which are either completely unique or there
246 // at least only one of them in the default toolchain that is an exe. 258 // at least only one of them in the default toolchain that is an exe.
247 if (small_name_count[label.name()] == 1 || 259 if (small_name_count[label.name()] == 1 ||
248 (target->output_type() == Target::EXECUTABLE && 260 (target->output_type() == Target::EXECUTABLE &&
249 exe_count[label.name()] == 1)) { 261 exe_count[label.name()] == 1)) {
250 WritePhonyRule(target, target_file, label.name()); 262 WritePhonyRule(target, target_file, label.name(), &written_rules);
251 } 263 }
252 264
253 if (!all_rules.empty()) 265 if (!all_rules.empty())
254 all_rules.append(" $\n "); 266 all_rules.append(" $\n ");
255 all_rules.append(target_file.value()); 267 all_rules.append(target_file.value());
256 } 268 }
257 269
258 // Pick up phony rules for the toplevel targets with non-unique names (which 270 // Pick up phony rules for the toplevel targets with non-unique names (which
259 // would have been skipped in the above loop). 271 // would have been skipped in the above loop).
260 for (const auto& toplevel_target : toplevel_targets) { 272 for (const auto& toplevel_target : toplevel_targets) {
261 if (small_name_count[toplevel_target->label().name()] > 1) { 273 if (small_name_count[toplevel_target->label().name()] > 1) {
262 WritePhonyRule(toplevel_target, toplevel_target->dependency_output_file(), 274 WritePhonyRule(toplevel_target, toplevel_target->dependency_output_file(),
263 toplevel_target->label().name()); 275 toplevel_target->label().name(), &written_rules);
264 } 276 }
265 } 277 }
266 278
267 // Figure out if the BUILD file wants to declare a custom "default" 279 // Figure out if the BUILD file wants to declare a custom "default"
268 // target (rather than building 'all' by default). By convention 280 // target (rather than building 'all' by default). By convention
269 // we use group("default") but it doesn't have to be a group. 281 // we use group("default") but it doesn't have to be a group.
270 bool default_target_exists = false; 282 bool default_target_exists = false;
271 for (const auto& target : default_toolchain_targets_) { 283 for (const auto& target : default_toolchain_targets_) {
272 const Label& label = target->label(); 284 const Label& label = target->label();
273 if (label.dir().value() == "//" && label.name() == "default") 285 if (label.dir().value() == "//" && label.name() == "default")
274 default_target_exists = true; 286 default_target_exists = true;
275 } 287 }
276 288
277 if (!all_rules.empty()) { 289 if (!all_rules.empty()) {
278 out_ << "\nbuild all: phony " << all_rules << std::endl; 290 out_ << "\nbuild all: phony " << all_rules << std::endl;
279 } 291 }
280 292
281 if (default_target_exists) { 293 if (default_target_exists) {
282 out_ << "default default" << std::endl; 294 out_ << "default default" << std::endl;
283 } else if (!all_rules.empty()) { 295 } else if (!all_rules.empty()) {
284 out_ << "default all" << std::endl; 296 out_ << "default all" << std::endl;
285 } 297 }
286 298
287 return true; 299 return true;
288 } 300 }
289 301
290 void NinjaBuildWriter::WritePhonyRule(const Target* target, 302 void NinjaBuildWriter::WritePhonyRule(const Target* target,
291 const OutputFile& target_file, 303 const OutputFile& target_file,
292 const std::string& phony_name) { 304 const std::string& phony_name,
305 std::set<std::string>* written_rules) {
293 if (target_file.value() == phony_name) 306 if (target_file.value() == phony_name)
294 return; // No need for a phony rule. 307 return; // No need for a phony rule.
295 308
309 if (written_rules->find(phony_name) != written_rules->end())
310 return; // Already exists.
311 written_rules->insert(phony_name);
312
296 EscapeOptions ninja_escape; 313 EscapeOptions ninja_escape;
297 ninja_escape.mode = ESCAPE_NINJA; 314 ninja_escape.mode = ESCAPE_NINJA;
298 315
299 // Escape for special chars Ninja will handle. 316 // Escape for special chars Ninja will handle.
300 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); 317 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr);
301 318
302 out_ << "build " << escaped << ": phony "; 319 out_ << "build " << escaped << ": phony ";
303 path_output_.WriteFile(out_, target_file); 320 path_output_.WriteFile(out_, target_file);
304 out_ << std::endl; 321 out_ << std::endl;
305 } 322 }
OLDNEW
« no previous file with comments | « tools/gn/ninja_build_writer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698