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_target_writer.h" | 5 #include "tools/gn/ninja_target_writer.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 if (written_anything) | 140 if (written_anything) |
| 141 out_ << std::endl; | 141 out_ << std::endl; |
| 142 } | 142 } |
| 143 | 143 |
| 144 OutputFile NinjaTargetWriter::WriteInputDepsStampAndGetDep( | 144 OutputFile NinjaTargetWriter::WriteInputDepsStampAndGetDep( |
| 145 const std::vector<const Target*>& extra_hard_deps) const { | 145 const std::vector<const Target*>& extra_hard_deps) const { |
| 146 CHECK(target_->toolchain()) | 146 CHECK(target_->toolchain()) |
| 147 << "Toolchain not set on target " | 147 << "Toolchain not set on target " |
| 148 << target_->label().GetUserVisibleName(true); | 148 << target_->label().GetUserVisibleName(true); |
| 149 | 149 |
| 150 // For an action (where we run a script only once) the sources are the same | 150 // ---------- |
| 151 // as the source prereqs. | 151 // Collect all input files that are input deps of this target. Knowing the |
| 152 bool list_sources_as_input_deps = (target_->output_type() == Target::ACTION); | 152 // number before writing allows us to either skip writing the input deps |
| 153 // stamp or optimize it. Use pointers to avoid copies here. | |
| 154 std::vector<const SourceFile*> input_deps_sources; | |
| 155 input_deps_sources.reserve(32); | |
| 153 | 156 |
| 154 // Actions get implicit dependencies on the script itself. | 157 // Actions get implicit dependencies on the script itself. |
| 155 bool add_script_source_as_dep = | 158 if (target_->output_type() == Target::ACTION || |
| 156 (target_->output_type() == Target::ACTION) || | 159 target_->output_type() == Target::ACTION_FOREACH) |
| 157 (target_->output_type() == Target::ACTION_FOREACH); | 160 input_deps_sources.push_back(&target_->action_values().script()); |
| 158 | 161 |
| 159 if (!add_script_source_as_dep && | 162 // Input files. |
| 160 extra_hard_deps.empty() && | 163 for (const auto& input : target_->inputs()) |
| 161 target_->inputs().empty() && | 164 input_deps_sources.push_back(&input); |
| 162 target_->recursive_hard_deps().empty() && | |
| 163 (!list_sources_as_input_deps || target_->sources().empty()) && | |
| 164 target_->toolchain()->deps().empty()) | |
| 165 return OutputFile(); // No input/hard deps. | |
| 166 | 165 |
| 167 // One potential optimization is if there are few input dependencies (or | 166 // For an action (where we run a script only once) the sources are the same |
| 168 // potentially few sources that depend on these) it's better to just write | 167 // as the inputs. For action_foreach, the sources will be operated on |
| 169 // all hard deps on each sources line than have this intermediate stamp. We | 168 // separately so don't handle them here. |
| 170 // do the stamp file because duplicating all the order-only deps for each | 169 if (target_->output_type() == Target::ACTION) { |
| 171 // source file can really explode the ninja file but this won't be the most | 170 for (const auto& source : target_->sources()) |
| 172 // optimal thing in all cases. | 171 input_deps_sources.push_back(&source); |
| 173 | |
| 174 OutputFile input_stamp_file( | |
| 175 RebasePath(GetTargetOutputDir(target_).value(), | |
| 176 settings_->build_settings()->build_dir(), | |
| 177 settings_->build_settings()->root_path_utf8())); | |
| 178 input_stamp_file.value().append(target_->label().name()); | |
| 179 input_stamp_file.value().append(".inputdeps.stamp"); | |
| 180 | |
| 181 out_ << "build "; | |
| 182 path_output_.WriteFile(out_, input_stamp_file); | |
| 183 out_ << ": " | |
| 184 << GetNinjaRulePrefixForToolchain(settings_) | |
| 185 << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP); | |
| 186 | |
| 187 // Script file (if applicable). | |
| 188 if (add_script_source_as_dep) { | |
| 189 out_ << " "; | |
| 190 path_output_.WriteFile(out_, target_->action_values().script()); | |
| 191 } | 172 } |
| 192 | 173 |
| 193 // Input files are order-only deps. | 174 // ---------- |
| 194 for (const auto& input : target_->inputs()) { | 175 // Collect all target input dependencies of this target as was done for the |
| 195 out_ << " "; | 176 // files above. |
| 196 path_output_.WriteFile(out_, input); | 177 std::vector<const Target*> input_deps_targets; |
| 197 } | 178 input_deps_targets.reserve(32); |
| 198 if (list_sources_as_input_deps) { | |
| 199 for (const auto& source : target_->sources()) { | |
| 200 out_ << " "; | |
| 201 path_output_.WriteFile(out_, source); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 // The different souces of input deps may duplicate some targets, so uniquify | |
| 206 // them. These are sorted so the generated files are deterministic. | |
| 207 std::vector<const Target*> sorted_deps; | |
| 208 | 179 |
| 209 // Hard dependencies that are direct or indirect dependencies. | 180 // Hard dependencies that are direct or indirect dependencies. |
| 210 // These are large (up to 100s), hence why we check other | 181 // These are large (up to 100s), hence why we check other |
| 211 const std::set<const Target*>& hard_deps(target_->recursive_hard_deps()); | 182 const std::set<const Target*>& hard_deps(target_->recursive_hard_deps()); |
| 183 for (const Target* target : hard_deps) | |
| 184 input_deps_targets.push_back(target); | |
| 212 | 185 |
| 213 // Extra hard dependencies passed in. Note that these are usually empty/small. | 186 // Extra hard dependencies passed in. These are usually empty or small, and |
| 187 // we don't want to duplicate the explicit hard deps of the target. | |
| 214 for (const Target* target : extra_hard_deps) { | 188 for (const Target* target : extra_hard_deps) { |
| 215 if (!hard_deps.count(target)) | 189 if (!hard_deps.count(target)) |
| 216 sorted_deps.push_back(target); | 190 input_deps_targets.push_back(target); |
| 217 } | 191 } |
| 218 | 192 |
| 219 // Toolchain dependencies. These must be resolved before doing anything. | 193 // Toolchain dependencies. These must be resolved before doing anything. |
| 220 // This just writes all toolchain deps for simplicity. If we find that | 194 // This just writes all toolchain deps for simplicity. If we find that |
| 221 // toolchains often have more than one dependency, we could consider writing | 195 // toolchains often have more than one dependency, we could consider writing |
| 222 // a toolchain-specific stamp file and only include the stamp here. | 196 // a toolchain-specific stamp file and only include the stamp here. |
| 223 // Note that these are usually empty/small. | 197 // Note that these are usually empty/small. |
| 224 const LabelTargetVector& toolchain_deps = target_->toolchain()->deps(); | 198 const LabelTargetVector& toolchain_deps = target_->toolchain()->deps(); |
| 225 for (const auto& toolchain_dep : toolchain_deps) { | 199 for (const auto& toolchain_dep : toolchain_deps) { |
| 226 // This could theoretically duplicate dependencies already in the list, | 200 // This could theoretically duplicate dependencies already in the list, |
| 227 // but shouldn't happen in practice, is inconvenient to check for, | 201 // but it shouldn't happen in practice, is inconvenient to check for, |
| 228 // and only results in harmless redundant dependencies listed. | 202 // and only results in harmless redundant dependencies listed. |
| 229 if (!hard_deps.count(toolchain_dep.ptr)) | 203 input_deps_targets.push_back(toolchain_dep.ptr); |
| 230 sorted_deps.push_back(toolchain_dep.ptr); | |
| 231 } | 204 } |
| 232 | 205 |
| 233 for (const Target* target : hard_deps) { | 206 // --------- |
| 234 sorted_deps.push_back(target); | 207 // Write the outputs. |
| 208 | |
| 209 if (input_deps_sources.size() + input_deps_targets.size() == 0) | |
| 210 return OutputFile(); // No input dependencies. | |
| 211 | |
| 212 // If we're only generating one input dependency, return it directly instead | |
| 213 // of writing a stamp file for it. | |
| 214 if (input_deps_sources.size() == 1 && input_deps_targets.size() == 0) | |
|
scottmg
2016/02/03 22:41:18
Did you check if it's worth pushing multiple throu
brettw
2016/02/03 22:50:44
No, but doing this for 2 will definitely increase
| |
| 215 return OutputFile(settings_->build_settings(), *input_deps_sources[0]); | |
| 216 if (input_deps_sources.size() == 0 && input_deps_targets.size() == 1) { | |
| 217 const OutputFile& dep = input_deps_targets[0]->dependency_output_file(); | |
| 218 DCHECK(!dep.value().empty()); | |
| 219 return dep; | |
| 235 } | 220 } |
| 236 | 221 |
| 222 // Make a stamp file. | |
| 223 OutputFile input_stamp_file( | |
| 224 RebasePath(GetTargetOutputDir(target_).value(), | |
| 225 settings_->build_settings()->build_dir(), | |
| 226 settings_->build_settings()->root_path_utf8())); | |
| 227 input_stamp_file.value().append(target_->label().name()); | |
| 228 input_stamp_file.value().append(".inputdeps.stamp"); | |
| 229 | |
| 230 out_ << "build "; | |
| 231 path_output_.WriteFile(out_, input_stamp_file); | |
| 232 out_ << ": " | |
| 233 << GetNinjaRulePrefixForToolchain(settings_) | |
| 234 << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP); | |
| 235 | |
| 236 // File input deps. | |
| 237 for (const SourceFile* source : input_deps_sources) { | |
| 238 out_ << " "; | |
| 239 path_output_.WriteFile(out_, *source); | |
| 240 } | |
| 241 | |
| 242 // Target input deps. Sort by label so the output is deterministic (otherwise | |
| 243 // some of the targets will have gone through std::sets which will have | |
| 244 // sorted them by pointer). | |
| 237 std::sort( | 245 std::sort( |
| 238 sorted_deps.begin(), sorted_deps.end(), | 246 input_deps_targets.begin(), input_deps_targets.end(), |
| 239 [](const Target* a, const Target* b) { return a->label() < b->label(); }); | 247 [](const Target* a, const Target* b) { return a->label() < b->label(); }); |
| 240 | 248 for (const auto& dep : input_deps_targets) { |
| 241 for (const auto& dep : sorted_deps) { | |
| 242 DCHECK(!dep->dependency_output_file().value().empty()); | 249 DCHECK(!dep->dependency_output_file().value().empty()); |
| 243 out_ << " "; | 250 out_ << " "; |
| 244 path_output_.WriteFile(out_, dep->dependency_output_file()); | 251 path_output_.WriteFile(out_, dep->dependency_output_file()); |
| 245 } | 252 } |
| 246 | 253 |
| 247 out_ << "\n"; | 254 out_ << "\n"; |
| 248 return input_stamp_file; | 255 return input_stamp_file; |
| 249 } | 256 } |
| 250 | 257 |
| 251 void NinjaTargetWriter::WriteStampForTarget( | 258 void NinjaTargetWriter::WriteStampForTarget( |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 267 << GetNinjaRulePrefixForToolchain(settings_) | 274 << GetNinjaRulePrefixForToolchain(settings_) |
| 268 << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP); | 275 << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP); |
| 269 path_output_.WriteFiles(out_, files); | 276 path_output_.WriteFiles(out_, files); |
| 270 | 277 |
| 271 if (!order_only_deps.empty()) { | 278 if (!order_only_deps.empty()) { |
| 272 out_ << " ||"; | 279 out_ << " ||"; |
| 273 path_output_.WriteFiles(out_, order_only_deps); | 280 path_output_.WriteFiles(out_, order_only_deps); |
| 274 } | 281 } |
| 275 out_ << std::endl; | 282 out_ << std::endl; |
| 276 } | 283 } |
| OLD | NEW |