Chromium Code Reviews| 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 <fstream> | 7 #include <fstream> |
| 8 #include <map> | 8 #include <map> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 13 #include "base/process/process_handle.h" | 13 #include "base/process/process_handle.h" |
| 14 #include "base/strings/string_util.h" | |
| 14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 15 #include "build/build_config.h" | 16 #include "build/build_config.h" |
| 16 #include "tools/gn/build_settings.h" | 17 #include "tools/gn/build_settings.h" |
| 17 #include "tools/gn/escape.h" | 18 #include "tools/gn/escape.h" |
| 18 #include "tools/gn/filesystem_utils.h" | 19 #include "tools/gn/filesystem_utils.h" |
| 19 #include "tools/gn/input_file_manager.h" | 20 #include "tools/gn/input_file_manager.h" |
| 20 #include "tools/gn/scheduler.h" | 21 #include "tools/gn/scheduler.h" |
| 21 #include "tools/gn/target.h" | 22 #include "tools/gn/target.h" |
| 22 #include "tools/gn/trace.h" | 23 #include "tools/gn/trace.h" |
| 23 | 24 |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 out_ << std::endl; | 173 out_ << std::endl; |
| 173 } | 174 } |
| 174 out_ << std::endl; | 175 out_ << std::endl; |
| 175 } | 176 } |
| 176 | 177 |
| 177 void NinjaBuildWriter::WritePhonyAndAllRules() { | 178 void NinjaBuildWriter::WritePhonyAndAllRules() { |
| 178 std::string all_rules; | 179 std::string all_rules; |
| 179 | 180 |
| 180 // Write phony rules for all uniquely-named targets in the default toolchain. | 181 // Write phony rules for all uniquely-named targets in the default toolchain. |
| 181 // Don't do other toolchains or we'll get naming conflicts, and if the name | 182 // Don't do other toolchains or we'll get naming conflicts, and if the name |
| 182 // isn't unique, also skip it. | 183 // isn't unique, also skip it. The exception is for the toplevel targets |
| 184 // which we also find. | |
| 183 std::map<std::string, int> small_name_count; | 185 std::map<std::string, int> small_name_count; |
| 184 for (size_t i = 0; i < default_toolchain_targets_.size(); i++) | 186 std::vector<const Target*> toplevel_targets; |
| 185 small_name_count[default_toolchain_targets_[i]->label().name()]++; | 187 for (size_t i = 0; i < default_toolchain_targets_.size(); i++) { |
| 188 const Target* target = default_toolchain_targets_[i]; | |
| 189 const Label& label = target->label(); | |
| 190 small_name_count[label.name()]++; | |
| 191 | |
| 192 // Look for targets with a name of the form | |
| 193 // dir = "//foo/", name = "foo" | |
| 194 // i.e. where the target name matches the top level directory. We will | |
| 195 // always write phony rules for these even if there is another target with | |
| 196 // the same short name. | |
| 197 const std::string& dir_string = label.dir().value(); | |
| 198 if (dir_string.size() == label.name().size() + 3 && // Size matches. | |
| 199 dir_string[0] == '/' && dir_string[1] == '/' && // "//" at beginning. | |
| 200 dir_string[dir_string.size() - 1] == '/' && // "/" at end. | |
| 201 dir_string.compare(2, label.name().size(), label.name()) == 0) | |
| 202 toplevel_targets.push_back(target); | |
| 203 } | |
| 186 | 204 |
| 187 for (size_t i = 0; i < default_toolchain_targets_.size(); i++) { | 205 for (size_t i = 0; i < default_toolchain_targets_.size(); i++) { |
| 188 const Target* target = default_toolchain_targets_[i]; | 206 const Target* target = default_toolchain_targets_[i]; |
| 207 const Label& label = target->label(); | |
| 208 OutputFile target_file = helper_.GetTargetOutputFile(target); | |
| 189 | 209 |
| 190 OutputFile target_file = helper_.GetTargetOutputFile(target); | 210 // Write the long name "foo/bar:baz" for the target "//foo/bar:baz". |
| 191 if (target_file.value() != target->label().name() && | 211 std::string long_name = label.GetUserVisibleName(false); |
| 192 small_name_count[default_toolchain_targets_[i]->label().name()] == 1) { | 212 base::TrimString(long_name, "/", &long_name); |
| 193 out_ << "build " << target->label().name() << ": phony "; | 213 WritePhonyRule(target, target_file, long_name); |
| 194 path_output_.WriteFile(out_, target_file); | 214 |
| 195 out_ << std::endl; | 215 // Write the directory name with no target name if they match |
| 216 // (e.g. "//foo/bar:bar" -> "foo/bar"). | |
| 217 if (FindLastDirComponent(label.dir()) == label.name()) { | |
| 218 std::string medium_name = DirectoryWithNoLastSlash(label.dir()); | |
| 219 base::TrimString(medium_name, "/", &medium_name); | |
| 220 WritePhonyRule(target, target_file, medium_name); | |
| 196 } | 221 } |
| 197 | 222 |
| 223 // Write short names for ones which are unique. | |
| 224 if (small_name_count[label.name()] == 1) | |
| 225 WritePhonyRule(target, target_file, label.name()); | |
| 226 | |
| 198 if (!all_rules.empty()) | 227 if (!all_rules.empty()) |
| 199 all_rules.append(" $\n "); | 228 all_rules.append(" $\n "); |
| 200 all_rules.append(target_file.value()); | 229 all_rules.append(target_file.value()); |
| 201 } | 230 } |
| 202 | 231 |
| 232 // Pick up phony rules for the toplevel targets with non-unique names (which | |
| 233 // would have been skipped in the above loop). | |
| 234 for (size_t i = 0; i < toplevel_targets.size(); i++) { | |
| 235 if (small_name_count[toplevel_targets[i]->label().name()] > 1) { | |
| 236 const Target* target = toplevel_targets[i]; | |
| 237 WritePhonyRule(target, helper_.GetTargetOutputFile(target), | |
| 238 target->label().name()); | |
| 239 } | |
| 240 } | |
| 241 | |
| 203 if (!all_rules.empty()) { | 242 if (!all_rules.empty()) { |
| 204 out_ << "\nbuild all: phony " << all_rules << std::endl; | 243 out_ << "\nbuild all: phony " << all_rules << std::endl; |
| 205 out_ << "default all" << std::endl; | 244 out_ << "default all" << std::endl; |
| 206 } | 245 } |
| 207 } | 246 } |
| 208 | 247 |
| 248 void NinjaBuildWriter::WritePhonyRule(const Target* target, | |
| 249 const OutputFile& target_file, | |
| 250 const std::string& phony_name) { | |
| 251 if (target_file.value() == phony_name) | |
| 252 return; // No need for a phony rule. | |
| 253 | |
| 254 EscapeOptions ninja_escape; | |
| 255 ninja_escape.mode = ESCAPE_NINJA; | |
| 256 | |
| 257 // Escape for special chars Ninja will handle. | |
| 258 std::string escaped = EscapeString(phony_name, ninja_escape, NULL); | |
| 259 | |
| 260 // Additionally escape colon which is meaningful in this context. | |
| 261 ReplaceSubstringsAfterOffset(&escaped, 0, ":", "$:"); | |
|
scottmg
2014/04/28 18:45:21
shouldn't escape_ninja be doing this?
| |
| 262 | |
| 263 out_ << "build " << escaped << ": phony "; | |
| 264 path_output_.WriteFile(out_, target_file); | |
| 265 out_ << std::endl; | |
| 266 } | |
| OLD | NEW |