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 |