Change next_proto member type.
[chromium-blink-merge.git] / tools / gn / ninja_target_writer.cc
blob8a5d0ee75c9f347fb08f43dceae5e184784c2fc7
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
3 // found in the LICENSE file.
5 #include "tools/gn/ninja_target_writer.h"
7 #include <fstream>
8 #include <sstream>
10 #include "base/files/file_util.h"
11 #include "base/strings/string_util.h"
12 #include "tools/gn/err.h"
13 #include "tools/gn/filesystem_utils.h"
14 #include "tools/gn/ninja_action_target_writer.h"
15 #include "tools/gn/ninja_binary_target_writer.h"
16 #include "tools/gn/ninja_copy_target_writer.h"
17 #include "tools/gn/ninja_group_target_writer.h"
18 #include "tools/gn/ninja_utils.h"
19 #include "tools/gn/output_file.h"
20 #include "tools/gn/scheduler.h"
21 #include "tools/gn/string_utils.h"
22 #include "tools/gn/substitution_writer.h"
23 #include "tools/gn/target.h"
24 #include "tools/gn/trace.h"
26 NinjaTargetWriter::NinjaTargetWriter(const Target* target,
27 std::ostream& out)
28 : settings_(target->settings()),
29 target_(target),
30 out_(out),
31 path_output_(settings_->build_settings()->build_dir(),
32 settings_->build_settings()->root_path_utf8(),
33 ESCAPE_NINJA) {
36 NinjaTargetWriter::~NinjaTargetWriter() {
39 // static
40 void NinjaTargetWriter::RunAndWriteFile(const Target* target) {
41 const Settings* settings = target->settings();
43 ScopedTrace trace(TraceItem::TRACE_FILE_WRITE,
44 target->label().GetUserVisibleName(false));
45 trace.SetToolchain(settings->toolchain_label());
47 base::FilePath ninja_file(settings->build_settings()->GetFullPath(
48 GetNinjaFileForTarget(target)));
50 if (g_scheduler->verbose_logging())
51 g_scheduler->Log("Writing", FilePathToUTF8(ninja_file));
53 base::CreateDirectory(ninja_file.DirName());
55 // It's rediculously faster to write to a string and then write that to
56 // disk in one operation than to use an fstream here.
57 std::stringstream file;
59 // Call out to the correct sub-type of writer.
60 if (target->output_type() == Target::COPY_FILES) {
61 NinjaCopyTargetWriter writer(target, file);
62 writer.Run();
63 } else if (target->output_type() == Target::ACTION ||
64 target->output_type() == Target::ACTION_FOREACH) {
65 NinjaActionTargetWriter writer(target, file);
66 writer.Run();
67 } else if (target->output_type() == Target::GROUP) {
68 NinjaGroupTargetWriter writer(target, file);
69 writer.Run();
70 } else if (target->output_type() == Target::EXECUTABLE ||
71 target->output_type() == Target::STATIC_LIBRARY ||
72 target->output_type() == Target::SHARED_LIBRARY ||
73 target->output_type() == Target::SOURCE_SET) {
74 NinjaBinaryTargetWriter writer(target, file);
75 writer.Run();
76 } else {
77 CHECK(0);
80 std::string contents = file.str();
81 base::WriteFile(ninja_file, contents.c_str(),
82 static_cast<int>(contents.size()));
85 void NinjaTargetWriter::WriteSharedVars(const SubstitutionBits& bits) {
86 bool written_anything = false;
88 // Target label.
89 if (bits.used[SUBSTITUTION_LABEL]) {
90 out_ << kSubstitutionNinjaNames[SUBSTITUTION_LABEL] << " = "
91 << SubstitutionWriter::GetTargetSubstitution(
92 target_, SUBSTITUTION_LABEL)
93 << std::endl;
94 written_anything = true;
97 // Root gen dir.
98 if (bits.used[SUBSTITUTION_ROOT_GEN_DIR]) {
99 out_ << kSubstitutionNinjaNames[SUBSTITUTION_ROOT_GEN_DIR] << " = "
100 << SubstitutionWriter::GetTargetSubstitution(
101 target_, SUBSTITUTION_ROOT_GEN_DIR)
102 << std::endl;
103 written_anything = true;
106 // Root out dir.
107 if (bits.used[SUBSTITUTION_ROOT_OUT_DIR]) {
108 out_ << kSubstitutionNinjaNames[SUBSTITUTION_ROOT_OUT_DIR] << " = "
109 << SubstitutionWriter::GetTargetSubstitution(
110 target_, SUBSTITUTION_ROOT_OUT_DIR)
111 << std::endl;
112 written_anything = true;
115 // Target gen dir.
116 if (bits.used[SUBSTITUTION_TARGET_GEN_DIR]) {
117 out_ << kSubstitutionNinjaNames[SUBSTITUTION_TARGET_GEN_DIR] << " = "
118 << SubstitutionWriter::GetTargetSubstitution(
119 target_, SUBSTITUTION_TARGET_GEN_DIR)
120 << std::endl;
121 written_anything = true;
124 // Target out dir.
125 if (bits.used[SUBSTITUTION_TARGET_OUT_DIR]) {
126 out_ << kSubstitutionNinjaNames[SUBSTITUTION_TARGET_OUT_DIR] << " = "
127 << SubstitutionWriter::GetTargetSubstitution(
128 target_, SUBSTITUTION_TARGET_OUT_DIR)
129 << std::endl;
130 written_anything = true;
133 // Target output name.
134 if (bits.used[SUBSTITUTION_TARGET_OUTPUT_NAME]) {
135 out_ << kSubstitutionNinjaNames[SUBSTITUTION_TARGET_OUTPUT_NAME] << " = "
136 << SubstitutionWriter::GetTargetSubstitution(
137 target_, SUBSTITUTION_TARGET_OUTPUT_NAME)
138 << std::endl;
139 written_anything = true;
142 // If we wrote any vars, separate them from the rest of the file that follows
143 // with a blank line.
144 if (written_anything)
145 out_ << std::endl;
148 OutputFile NinjaTargetWriter::WriteInputDepsStampAndGetDep(
149 const std::vector<const Target*>& extra_hard_deps) const {
150 CHECK(target_->toolchain())
151 << "Toolchain not set on target "
152 << target_->label().GetUserVisibleName(true);
154 // For an action (where we run a script only once) the sources are the same
155 // as the source prereqs.
156 bool list_sources_as_input_deps = (target_->output_type() == Target::ACTION);
158 // Actions get implicit dependencies on the script itself.
159 bool add_script_source_as_dep =
160 (target_->output_type() == Target::ACTION) ||
161 (target_->output_type() == Target::ACTION_FOREACH);
163 if (!add_script_source_as_dep &&
164 extra_hard_deps.empty() &&
165 target_->inputs().empty() &&
166 target_->recursive_hard_deps().empty() &&
167 (!list_sources_as_input_deps || target_->sources().empty()) &&
168 target_->toolchain()->deps().empty())
169 return OutputFile(); // No input/hard deps.
171 // One potential optimization is if there are few input dependencies (or
172 // potentially few sources that depend on these) it's better to just write
173 // all hard deps on each sources line than have this intermediate stamp. We
174 // do the stamp file because duplicating all the order-only deps for each
175 // source file can really explode the ninja file but this won't be the most
176 // optimal thing in all cases.
178 OutputFile input_stamp_file(
179 RebasePath(GetTargetOutputDir(target_).value(),
180 settings_->build_settings()->build_dir(),
181 settings_->build_settings()->root_path_utf8()));
182 input_stamp_file.value().append(target_->label().name());
183 input_stamp_file.value().append(".inputdeps.stamp");
185 out_ << "build ";
186 path_output_.WriteFile(out_, input_stamp_file);
187 out_ << ": "
188 << GetNinjaRulePrefixForToolchain(settings_)
189 << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
191 // Script file (if applicable).
192 if (add_script_source_as_dep) {
193 out_ << " ";
194 path_output_.WriteFile(out_, target_->action_values().script());
197 // Input files are order-only deps.
198 const Target::FileList& prereqs = target_->inputs();
199 for (size_t i = 0; i < prereqs.size(); i++) {
200 out_ << " ";
201 path_output_.WriteFile(out_, prereqs[i]);
203 if (list_sources_as_input_deps) {
204 const Target::FileList& sources = target_->sources();
205 for (size_t i = 0; i < sources.size(); i++) {
206 out_ << " ";
207 path_output_.WriteFile(out_, sources[i]);
211 // The different souces of input deps may duplicate some targets, so uniquify
212 // them (ordering doesn't matter for this case).
213 std::set<const Target*> unique_deps;
215 // Hard dependencies that are direct or indirect dependencies.
216 const std::set<const Target*>& hard_deps = target_->recursive_hard_deps();
217 for (std::set<const Target*>::const_iterator i = hard_deps.begin();
218 i != hard_deps.end(); ++i) {
219 unique_deps.insert(*i);
222 // Extra hard dependencies passed in.
223 unique_deps.insert(extra_hard_deps.begin(), extra_hard_deps.end());
225 // Toolchain dependencies. These must be resolved before doing anything.
226 // This just writs all toolchain deps for simplicity. If we find that
227 // toolchains often have more than one dependency, we could consider writing
228 // a toolchain-specific stamp file and only include the stamp here.
229 const LabelTargetVector& toolchain_deps = target_->toolchain()->deps();
230 for (size_t i = 0; i < toolchain_deps.size(); i++)
231 unique_deps.insert(toolchain_deps[i].ptr);
233 for (std::set<const Target*>::const_iterator i = unique_deps.begin();
234 i != unique_deps.end(); ++i) {
235 DCHECK(!(*i)->dependency_output_file().value().empty());
236 out_ << " ";
237 path_output_.WriteFile(out_, (*i)->dependency_output_file());
240 out_ << "\n";
241 return input_stamp_file;
244 void NinjaTargetWriter::WriteStampForTarget(
245 const std::vector<OutputFile>& files,
246 const std::vector<OutputFile>& order_only_deps) {
247 const OutputFile& stamp_file = target_->dependency_output_file();
249 // First validate that the target's dependency is a stamp file. Otherwise,
250 // we shouldn't have gotten here!
251 CHECK(EndsWith(stamp_file.value(), ".stamp", false))
252 << "Output should end in \".stamp\" for stamp file output. Instead got: "
253 << "\"" << stamp_file.value() << "\"";
255 out_ << "build ";
256 path_output_.WriteFile(out_, stamp_file);
258 out_ << ": "
259 << GetNinjaRulePrefixForToolchain(settings_)
260 << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
261 path_output_.WriteFiles(out_, files);
263 if (!order_only_deps.empty()) {
264 out_ << " ||";
265 path_output_.WriteFiles(out_, order_only_deps);
267 out_ << std::endl;