blob: 90e56c83031919d9301b7c50238e95a2ad9d82df [file] [log] [blame]
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// +build ignore
16
17#include "ninja.h"
18
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090019#include <stdio.h>
Shinichiro Hamajied883ef2015-07-31 13:15:04 +090020#include <stdlib.h>
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +090021#include <sys/stat.h>
22#include <unistd.h>
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +090023
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +090024#include <map>
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +090025#include <sstream>
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090026#include <string>
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +090027#include <unordered_map>
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090028#include <unordered_set>
29
30#include "command.h"
31#include "dep.h"
32#include "eval.h"
Shinichiro Hamaji998ccf72015-07-18 12:37:02 +090033#include "file_cache.h"
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +090034#include "fileutil.h"
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +090035#include "find.h"
Shinichiro Hamaji087cecd2015-07-06 19:51:58 +090036#include "flags.h"
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +090037#include "func.h"
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +090038#include "io.h"
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090039#include "log.h"
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +090040#include "stats.h"
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090041#include "string_piece.h"
42#include "stringprintf.h"
43#include "strutil.h"
Shinichiro Hamajia81301e2016-02-15 19:04:26 +090044#include "thread_pool.h"
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +090045#include "timeutil.h"
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090046#include "var.h"
Shinichiro Hamajid821f6d2015-07-14 04:03:27 +090047#include "version.h"
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090048
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +090049static size_t FindCommandLineFlag(StringPiece cmd, StringPiece name) {
50 const size_t found = cmd.find(name);
51 if (found == string::npos || found == 0)
52 return string::npos;
53 return found;
54}
55
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +090056static StringPiece FindCommandLineFlagWithArg(StringPiece cmd,
57 StringPiece name) {
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +090058 size_t index = FindCommandLineFlag(cmd, name);
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +090059 if (index == string::npos)
60 return StringPiece();
61
62 StringPiece val = TrimLeftSpace(cmd.substr(index + name.size()));
63 index = val.find(name);
64 while (index != string::npos) {
65 val = TrimLeftSpace(val.substr(index + name.size()));
66 index = val.find(name);
67 }
68
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +090069 index = val.find_first_of(" \t");
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +090070 return val.substr(0, index);
71}
72
Shinichiro Hamaji9facae22015-07-03 17:16:36 +090073static bool StripPrefix(StringPiece p, StringPiece* s) {
74 if (!HasPrefix(*s, p))
75 return false;
76 *s = s->substr(p.size());
77 return true;
78}
79
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +090080size_t GetGomaccPosForAndroidCompileCommand(StringPiece cmdline) {
81 size_t index = cmdline.find(' ');
Shinichiro Hamaji9facae22015-07-03 17:16:36 +090082 if (index == string::npos)
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +090083 return string::npos;
84 StringPiece cmd = cmdline.substr(0, index);
85 if (HasSuffix(cmd, "ccache")) {
86 index++;
87 size_t pos = GetGomaccPosForAndroidCompileCommand(cmdline.substr(index));
88 return pos == string::npos ? string::npos : pos + index;
89 }
90 if (!StripPrefix("prebuilts/", &cmd))
91 return string::npos;
92 if (!StripPrefix("gcc/", &cmd) && !StripPrefix("clang/", &cmd))
93 return string::npos;
94 if (!HasSuffix(cmd, "gcc") && !HasSuffix(cmd, "g++") &&
95 !HasSuffix(cmd, "clang") && !HasSuffix(cmd, "clang++")) {
96 return string::npos;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +090097 }
98
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +090099 StringPiece rest = cmdline.substr(index);
100 return rest.find(" -c ") != string::npos ? 0 : string::npos;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900101}
102
103static bool GetDepfileFromCommandImpl(StringPiece cmd, string* out) {
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +0900104 if ((FindCommandLineFlag(cmd, " -MD") == string::npos &&
105 FindCommandLineFlag(cmd, " -MMD") == string::npos) ||
106 FindCommandLineFlag(cmd, " -c") == string::npos) {
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900107 return false;
108 }
109
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +0900110 StringPiece mf = FindCommandLineFlagWithArg(cmd, " -MF");
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900111 if (!mf.empty()) {
112 mf.AppendToString(out);
113 return true;
114 }
115
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +0900116 StringPiece o = FindCommandLineFlagWithArg(cmd, " -o");
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900117 if (o.empty()) {
118 ERROR("Cannot find the depfile in %s", cmd.as_string().c_str());
119 return false;
120 }
121
122 StripExt(o).AppendToString(out);
123 *out += ".d";
124 return true;
125}
126
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900127bool GetDepfileFromCommand(string* cmd, string* out) {
128 CHECK(!cmd->empty());
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900129 if (!GetDepfileFromCommandImpl(*cmd, out))
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900130 return false;
131
132 // A hack for Android - llvm-rs-cc seems not to emit a dep file.
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900133 if (cmd->find("bin/llvm-rs-cc ") != string::npos) {
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900134 return false;
135 }
136
137 // TODO: A hack for Makefiles generated by automake.
138
139 // A hack for Android to get .P files instead of .d.
140 string p;
141 StripExt(*out).AppendToString(&p);
142 p += ".P";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900143 if (cmd->find(p) != string::npos) {
144 const string rm_f = "; rm -f " + *out;
145 const size_t found = cmd->find(rm_f);
146 if (found == string::npos) {
147 ERROR("Cannot find removal of .d file: %s", cmd->c_str());
148 }
149 cmd->erase(found, rm_f.size());
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900150 return true;
151 }
152
153 // A hack for Android. For .s files, GCC does not use C
154 // preprocessor, so it ignores -MF flag.
155 string as = "/";
156 StripExt(Basename(*out)).AppendToString(&as);
157 as += ".s";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900158 if (cmd->find(as) != string::npos) {
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900159 return false;
160 }
161
Shinichiro Hamajid416e612015-07-18 12:43:34 +0900162 *cmd += "&& cp ";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900163 *cmd += *out;
164 *cmd += ' ';
165 *cmd += *out;
Shinichiro Hamajid416e612015-07-18 12:43:34 +0900166 *cmd += ".tmp ";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900167 *out += ".tmp";
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900168 return true;
169}
170
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900171struct NinjaNode {
172 const DepNode* node;
173 vector<Command*> commands;
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900174 int rule_id;
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900175};
176
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900177class NinjaGenerator {
178 public:
Shinichiro Hamajif9869fc2015-09-28 17:18:59 +0900179 NinjaGenerator(Evaluator* ev, double start_time)
Shinichiro Hamaji85e5ed02016-01-20 16:25:32 +0900180 : ce_(ev),
181 ev_(ev),
182 fp_(NULL),
183 rule_id_(0),
184 start_time_(start_time),
Shinichiro Hamaji11347162016-01-20 16:23:22 +0900185 default_target_(NULL) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900186 ev_->set_avoid_io(true);
Shinichiro Hamaji2941ea02016-04-27 17:26:21 +0900187 shell_ = EscapeNinja(ev->GetShell());
188 shell_flags_ = EscapeNinja(ev->GetShellFlag());
Shinichiro Hamaji84ddbd22016-04-09 13:35:27 +0900189 const string use_goma_str = ev->EvalVar(Intern("USE_GOMA"));
190 use_goma_ = !(use_goma_str.empty() || use_goma_str == "false");
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900191 if (g_flags.goma_dir)
192 gomacc_ = StringPrintf("%s/gomacc ", g_flags.goma_dir);
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900193
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900194 GetExecutablePath(&kati_binary_);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900195 }
196
197 ~NinjaGenerator() {
198 ev_->set_avoid_io(false);
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900199 for (NinjaNode* nn : nodes_)
200 delete nn;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900201 }
202
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700203 void Generate(const vector<NamedDepNode>& nodes, const string& orig_args) {
Shinichiro Hamaji8ef0ce52016-01-19 18:07:43 +0900204 unlink(GetNinjaStampFilename().c_str());
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900205 PopulateNinjaNodes(nodes);
Shinichiro Hamaji94dc4c72016-02-19 13:45:29 +0900206 GenerateNinja();
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900207 GenerateShell();
Dan Willemsen87417412015-08-24 17:57:12 -0700208 GenerateStamp(orig_args);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900209 }
210
Shinichiro Hamajif9869fc2015-09-28 17:18:59 +0900211 static string GetStampTempFilename() {
212 return GetFilename(".kati_stamp%s.tmp");
Colin Cross0850f7d2015-09-14 15:11:45 -0700213 }
214
Shinichiro Hamaji8ef0ce52016-01-19 18:07:43 +0900215 static string GetFilename(const char* fmt) {
216 string r = g_flags.ninja_dir ? g_flags.ninja_dir : ".";
217 r += '/';
218 r += StringPrintf(fmt, g_flags.ninja_suffix ? g_flags.ninja_suffix : "");
219 return r;
220 }
221
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900222 private:
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700223 void PopulateNinjaNodes(const vector<NamedDepNode>& nodes) {
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900224 ScopedTimeReporter tr("ninja gen (eval)");
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700225 for (auto const& node : nodes) {
226 PopulateNinjaNode(node.second);
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900227 }
228 }
229
230 void PopulateNinjaNode(DepNode* node) {
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700231 if (done_.exists(node->output)) {
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900232 return;
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700233 }
234 done_.insert(node->output);
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900235
236 // A hack to exclude out phony target in Android. If this exists,
237 // "ninja -t clean" tries to remove this directory and fails.
238 if (g_flags.detect_android_echo && node->output.str() == "out")
239 return;
240
241 // This node is a leaf node
242 if (!node->has_rule && !node->is_phony) {
243 return;
244 }
245
246 NinjaNode* nn = new NinjaNode;
247 nn->node = node;
248 ce_.Eval(node, &nn->commands);
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900249 nn->rule_id = nn->commands.empty() ? -1 : rule_id_++;
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900250 nodes_.push_back(nn);
251
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700252 for (auto const& d : node->deps) {
253 PopulateNinjaNode(d.second);
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900254 }
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700255 for (auto const& d : node->order_onlys) {
256 PopulateNinjaNode(d.second);
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900257 }
258 }
259
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900260 StringPiece TranslateCommand(const char* in, string* cmd_buf) {
261 const size_t orig_size = cmd_buf->size();
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900262 bool prev_backslash = false;
Shinichiro Hamaji53eaaf82015-07-15 06:09:43 +0900263 // Set space as an initial value so the leading comment will be
264 // stripped out.
265 char prev_char = ' ';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900266 char quote = 0;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +0900267 for (; *in; in++) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900268 switch (*in) {
269 case '#':
Shinichiro Hamaji53eaaf82015-07-15 06:09:43 +0900270 if (quote == 0 && isspace(prev_char)) {
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +0900271 while (in[1] && *in != '\n')
272 in++;
Colin Cross415e4a12015-07-15 18:21:38 -0700273 } else {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900274 *cmd_buf += *in;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900275 }
Colin Cross415e4a12015-07-15 18:21:38 -0700276 break;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900277
278 case '\'':
279 case '"':
280 case '`':
281 if (quote) {
282 if (quote == *in)
283 quote = 0;
284 } else if (!prev_backslash) {
285 quote = *in;
286 }
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900287 *cmd_buf += *in;
Shinichiro Hamaji4212e382015-06-29 17:21:04 +0900288 break;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900289
290 case '$':
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900291 *cmd_buf += "$$";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900292 break;
293
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900294 case '\n':
295 if (prev_backslash) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700296 cmd_buf->resize(cmd_buf->size() - 1);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900297 } else {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900298 *cmd_buf += ' ';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900299 }
Shinichiro Hamaji4d151832015-06-29 18:15:46 +0900300 break;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900301
302 case '\\':
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900303 *cmd_buf += '\\';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900304 break;
305
306 default:
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900307 *cmd_buf += *in;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900308 }
Colin Crossf6f1cf42015-07-15 15:25:30 -0700309
310 if (*in == '\\') {
311 prev_backslash = !prev_backslash;
312 } else {
313 prev_backslash = false;
314 }
315
Shinichiro Hamaji53eaaf82015-07-15 06:09:43 +0900316 prev_char = *in;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900317 }
318
Dan Willemsen45c49cc2015-08-21 12:39:34 -0700319 if (prev_backslash) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700320 cmd_buf->resize(cmd_buf->size() - 1);
Dan Willemsen45c49cc2015-08-21 12:39:34 -0700321 }
322
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900323 while (true) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700324 char c = (*cmd_buf)[cmd_buf->size() - 1];
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900325 if (!isspace(c) && c != ';')
326 break;
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900327 cmd_buf->resize(cmd_buf->size() - 1);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900328 }
329
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900330 return StringPiece(cmd_buf->data() + orig_size,
331 cmd_buf->size() - orig_size);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900332 }
333
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700334 bool IsOutputMkdir(const char* name, StringPiece cmd) {
Dan Willemsen0b544c52015-08-24 15:36:38 -0700335 if (!HasPrefix(cmd, "mkdir -p ")) {
336 return false;
337 }
338 cmd = cmd.substr(9, cmd.size());
339 if (cmd.get(cmd.size() - 1) == '/') {
340 cmd = cmd.substr(0, cmd.size() - 1);
341 }
342
343 StringPiece dir = Dirname(name);
344 if (cmd == dir) {
345 return true;
346 }
347 return false;
348 }
349
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700350 bool GetDescriptionFromCommand(StringPiece cmd, string* out) {
Colin Cross2e032ba2015-07-15 18:33:37 -0700351 if (!HasPrefix(cmd, "echo ")) {
352 return false;
353 }
354 cmd = cmd.substr(5, cmd.size());
355
Colin Cross2e032ba2015-07-15 18:33:37 -0700356 bool prev_backslash = false;
357 char quote = 0;
358 string out_buf;
359
360 // Strip outer quotes, and fail if it is not a single echo command
361 for (StringPiece::iterator in = cmd.begin(); in != cmd.end(); in++) {
362 if (prev_backslash) {
363 prev_backslash = false;
364 out_buf += *in;
365 } else if (*in == '\\') {
366 prev_backslash = true;
367 out_buf += *in;
368 } else if (quote) {
369 if (*in == quote) {
370 quote = 0;
371 } else {
372 out_buf += *in;
373 }
374 } else {
375 switch (*in) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700376 case '\'':
377 case '"':
378 case '`':
379 quote = *in;
380 break;
Colin Cross2e032ba2015-07-15 18:33:37 -0700381
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700382 case '<':
383 case '>':
384 case '&':
385 case '|':
386 case ';':
387 return false;
Colin Cross2e032ba2015-07-15 18:33:37 -0700388
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700389 default:
390 out_buf += *in;
Colin Cross2e032ba2015-07-15 18:33:37 -0700391 }
392 }
393 }
394
395 *out = out_buf;
396 return true;
397 }
398
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700399 bool GenShellScript(const char* name,
Dan Willemsen0b544c52015-08-24 15:36:38 -0700400 const vector<Command*>& commands,
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900401 string* cmd_buf,
402 string* description) {
Shinichiro Hamaji2ee6ca12015-07-18 03:37:21 +0900403 bool got_descritpion = false;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900404 bool use_gomacc = false;
Dan Willemsen0b544c52015-08-24 15:36:38 -0700405 auto command_count = commands.size();
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900406 for (const Command* c : commands) {
Dan Willemsen0b544c52015-08-24 15:36:38 -0700407 size_t cmd_begin = cmd_buf->size();
408
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900409 if (!cmd_buf->empty()) {
Shinichiro Hamaji044a51d2016-03-15 08:31:29 +0900410 *cmd_buf += " && ";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900411 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900412
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900413 const char* in = c->cmd.c_str();
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900414 while (isspace(*in))
415 in++;
416
Shinichiro Hamaji044a51d2016-03-15 08:31:29 +0900417 bool needs_subshell = (command_count > 1 || c->ignore_error);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900418
419 if (needs_subshell)
Shinichiro Hamajif124de02016-03-17 06:18:32 +0900420 *cmd_buf += '(';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900421
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900422 size_t cmd_start = cmd_buf->size();
423 StringPiece translated = TranslateCommand(in, cmd_buf);
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900424 if (g_flags.detect_android_echo && !got_descritpion && !c->echo &&
Shinichiro Hamaji2ee6ca12015-07-18 03:37:21 +0900425 GetDescriptionFromCommand(translated, description)) {
426 got_descritpion = true;
Dan Willemsen0b544c52015-08-24 15:36:38 -0700427 translated.clear();
428 } else if (IsOutputMkdir(name, translated) && !c->echo &&
429 cmd_begin == 0) {
Shinichiro Hamaji2ee6ca12015-07-18 03:37:21 +0900430 translated.clear();
431 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900432 if (translated.empty()) {
Dan Willemsen0b544c52015-08-24 15:36:38 -0700433 cmd_buf->resize(cmd_begin);
434 command_count -= 1;
435 continue;
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900436 } else if (g_flags.goma_dir) {
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +0900437 size_t pos = GetGomaccPosForAndroidCompileCommand(translated);
438 if (pos != string::npos) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900439 cmd_buf->insert(cmd_start + pos, gomacc_);
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +0900440 use_gomacc = true;
441 }
Shinichiro Hamaji4cb8a6f2015-08-17 16:30:49 +0900442 } else if (translated.find("/gomacc") != string::npos) {
443 use_gomacc = true;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900444 }
445
Shinichiro Hamaji044a51d2016-03-15 08:31:29 +0900446 if (c->ignore_error) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900447 *cmd_buf += " ; true";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900448 }
449
450 if (needs_subshell)
Shinichiro Hamajif124de02016-03-17 06:18:32 +0900451 *cmd_buf += " )";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900452 }
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700453 return (use_goma_ || g_flags.remote_num_jobs || g_flags.goma_dir) &&
454 !use_gomacc;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900455 }
456
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900457 bool GetDepfile(const DepNode* node, string* cmd_buf, string* depfile) {
Shinichiro Hamaji85e5ed02016-01-20 16:25:32 +0900458 if (node->depfile_var) {
459 node->depfile_var->Eval(ev_, depfile);
460 return true;
461 }
Shinichiro Hamajif3ad9e02016-03-03 18:26:17 +0900462 if (!g_flags.detect_depfiles)
463 return false;
Shinichiro Hamaji85e5ed02016-01-20 16:25:32 +0900464
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900465 *cmd_buf += ' ';
Shinichiro Hamaji85e5ed02016-01-20 16:25:32 +0900466 bool result = GetDepfileFromCommand(cmd_buf, depfile);
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700467 cmd_buf->resize(cmd_buf->size() - 1);
Shinichiro Hamaji85e5ed02016-01-20 16:25:32 +0900468 return result;
469 }
470
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900471 void EmitDepfile(NinjaNode* nn, string* cmd_buf, ostringstream* o) {
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900472 const DepNode* node = nn->node;
Shinichiro Hamaji85e5ed02016-01-20 16:25:32 +0900473 string depfile;
474 if (!GetDepfile(node, cmd_buf, &depfile))
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900475 return;
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900476 *o << " depfile = " << depfile << "\n";
477 *o << " deps = gcc\n";
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900478 }
479
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900480 void EmitNode(NinjaNode* nn, ostringstream* o) {
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900481 const DepNode* node = nn->node;
482 const vector<Command*>& commands = nn->commands;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900483
484 string rule_name = "phony";
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900485 bool use_local_pool = false;
Dan Willemsencac3d5a2016-09-16 23:51:12 -0700486 if (node->output.get(0) == '.') {
487 return;
488 }
Shinichiro Hamajiac6f1692016-05-18 14:35:40 +0900489 if (g_flags.enable_debug) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700490 *o << "# " << (node->loc.filename ? node->loc.filename : "(null)") << ':'
491 << node->loc.lineno << "\n";
Shinichiro Hamajiac6f1692016-05-18 14:35:40 +0900492 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900493 if (!commands.empty()) {
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900494 rule_name = StringPrintf("rule%d", nn->rule_id);
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900495 *o << "rule " << rule_name << "\n";
Colin Cross2e032ba2015-07-15 18:33:37 -0700496
497 string description = "build $out";
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900498 string cmd_buf;
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700499 use_local_pool |= GenShellScript(node->output.c_str(), commands, &cmd_buf,
500 &description);
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900501 *o << " description = " << description << "\n";
Shinichiro Hamaji7373ee22016-02-15 20:26:38 +0900502 EmitDepfile(nn, &cmd_buf, o);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900503
Shinichiro Hamajieb0e5f92015-07-17 03:38:23 +0900504 // It seems Linux is OK with ~130kB and Mac's limit is ~250kB.
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900505 // TODO: Find this number automatically.
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900506 if (cmd_buf.size() > 100 * 1000) {
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900507 *o << " rspfile = $out.rsp\n";
508 *o << " rspfile_content = " << cmd_buf << "\n";
509 *o << " command = " << shell_ << " $out.rsp\n";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900510 } else {
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900511 EscapeShell(&cmd_buf);
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700512 *o << " command = " << shell_ << ' ' << shell_flags_ << " \"" << cmd_buf
513 << "\"\n";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900514 }
Shinichiro Hamaji3ac2a092015-10-01 18:38:02 +0900515 if (node->is_restat) {
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900516 *o << " restat = 1\n";
Shinichiro Hamaji3ac2a092015-10-01 18:38:02 +0900517 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900518 }
519
Shinichiro Hamaji7373ee22016-02-15 20:26:38 +0900520 EmitBuild(nn, rule_name, use_local_pool, o);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900521 }
522
Shinichiro Hamaji422179d2016-02-19 13:26:31 +0900523 string EscapeNinja(const string& s) const {
524 if (s.find_first_of("$: ") == string::npos)
525 return s;
Shinichiro Hamaji753c8122015-07-18 17:16:24 +0900526 string r;
Shinichiro Hamaji422179d2016-02-19 13:26:31 +0900527 for (char c : s) {
Shinichiro Hamaji753c8122015-07-18 17:16:24 +0900528 switch (c) {
529 case '$':
530 case ':':
531 case ' ':
532 r += '$';
Dan Willemsen72887f22018-10-09 18:04:38 -0700533#if defined(__has_cpp_attribute) && __has_cpp_attribute(clang::fallthrough)
534 [[clang::fallthrough]];
535#endif
Shinichiro Hamaji753c8122015-07-18 17:16:24 +0900536 default:
537 r += c;
538 }
539 }
540 return r;
541 }
542
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700543 string EscapeBuildTarget(Symbol s) const { return EscapeNinja(s.str()); }
Shinichiro Hamaji422179d2016-02-19 13:26:31 +0900544
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700545 void EmitBuild(NinjaNode* nn,
546 const string& rule_name,
547 bool use_local_pool,
548 ostringstream* o) {
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900549 const DepNode* node = nn->node;
Colin Cross5b26db32015-09-29 16:51:02 -0700550 string target = EscapeBuildTarget(node->output);
Dan Willemsenb78d16f2017-08-09 16:51:34 -0700551 *o << "build " << target;
Dan Willemsen72a8e012017-08-13 22:06:47 -0700552 if (!node->implicit_outputs.empty()) {
553 *o << " |";
554 for (Symbol output : node->implicit_outputs) {
555 *o << " " << EscapeBuildTarget(output);
Dan Willemsenb78d16f2017-08-09 16:51:34 -0700556 }
557 }
558 *o << ": " << rule_name;
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900559 vector<Symbol> order_onlys;
Dan Willemsen3faa60f2015-08-21 13:24:39 -0700560 if (node->is_phony) {
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900561 *o << " _kati_always_build_";
Dan Willemsen3faa60f2015-08-21 13:24:39 -0700562 }
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700563 for (auto const& d : node->deps) {
564 *o << " " << EscapeBuildTarget(d.first).c_str();
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900565 }
Shinichiro Hamaji183dbb92015-07-06 17:21:39 +0900566 if (!node->order_onlys.empty()) {
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900567 *o << " ||";
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700568 for (auto const& d : node->order_onlys) {
569 *o << " " << EscapeBuildTarget(d.first).c_str();
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900570 }
571 }
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900572 *o << "\n";
Dan Willemsen2f75ffa2016-11-04 16:57:57 -0700573 if (node->ninja_pool_var) {
574 string pool;
575 node->ninja_pool_var->Eval(ev_, &pool);
576 *o << " pool = " << pool << "\n";
577 } else if (use_local_pool) {
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900578 *o << " pool = local_pool\n";
Dan Willemsen2f75ffa2016-11-04 16:57:57 -0700579 }
Colin Cross5b26db32015-09-29 16:51:02 -0700580 if (node->is_default_target) {
Shinichiro Hamaji8380fb82016-02-26 16:51:50 +0900581 unique_lock<mutex> lock(mu_);
Shinichiro Hamajia62b02a2015-10-01 14:21:40 +0900582 default_target_ = node;
Colin Cross5b26db32015-09-29 16:51:02 -0700583 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900584 }
585
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700586 static string GetEnvScriptFilename() { return GetFilename("env%s.sh"); }
Colin Cross27df5312015-11-09 13:39:14 -0800587
Shinichiro Hamaji94dc4c72016-02-19 13:45:29 +0900588 void GenerateNinja() {
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900589 ScopedTimeReporter tr("ninja gen (emit)");
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900590 fp_ = fopen(GetNinjaFilename().c_str(), "wb");
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900591 if (fp_ == NULL)
592 PERROR("fopen(build.ninja) failed");
593
Shinichiro Hamajid821f6d2015-07-14 04:03:27 +0900594 fprintf(fp_, "# Generated by kati %s\n", kGitVersion);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900595 fprintf(fp_, "\n");
596
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900597 if (!used_envs_.empty()) {
Shinichiro Hamaji5163e042015-07-14 03:51:44 +0900598 fprintf(fp_, "# Environment variables used:\n");
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900599 for (const auto& p : used_envs_) {
600 fprintf(fp_, "# %s=%s\n", p.first.c_str(), p.second.c_str());
Shinichiro Hamaji5163e042015-07-14 03:51:44 +0900601 }
602 fprintf(fp_, "\n");
603 }
604
Dan Willemsen64c31bd2018-09-26 14:10:40 -0700605 if (!g_flags.no_ninja_prelude) {
606 if (g_flags.ninja_dir) {
607 fprintf(fp_, "builddir = %s\n\n", g_flags.ninja_dir);
608 }
609
610 fprintf(fp_, "pool local_pool\n");
611 fprintf(fp_, " depth = %d\n\n", g_flags.num_jobs);
612
613 fprintf(fp_, "build _kati_always_build_: phony\n\n");
Dan Willemsen2e762292015-08-19 20:39:41 -0700614 }
615
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900616 unique_ptr<ThreadPool> tp(NewThreadPool(g_flags.num_jobs));
617 CHECK(g_flags.num_jobs);
618 int num_nodes_per_task = nodes_.size() / (g_flags.num_jobs * 10) + 1;
619 int num_tasks = nodes_.size() / num_nodes_per_task + 1;
Shinichiro Hamaji1a444a82016-02-16 13:49:49 +0900620 vector<ostringstream> bufs(num_tasks);
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900621 for (int i = 0; i < num_tasks; i++) {
Shinichiro Hamaji7373ee22016-02-15 20:26:38 +0900622 tp->Submit([this, i, num_nodes_per_task, &bufs]() {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700623 int l =
624 min(num_nodes_per_task * (i + 1), static_cast<int>(nodes_.size()));
625 for (int j = num_nodes_per_task * i; j < l; j++) {
626 EmitNode(nodes_[j], &bufs[i]);
627 }
628 });
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900629 }
630 tp->Wait();
631
Dan Willemsen87b8da72018-10-26 09:21:23 -0700632 if (!g_flags.generate_empty_ninja) {
633 for (const ostringstream& buf : bufs) {
634 fprintf(fp_, "%s", buf.str().c_str());
635 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900636 }
637
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700638 SymbolSet used_env_vars(Vars::used_env_vars());
Shinichiro Hamaji29e45702015-12-09 15:44:51 +0900639 // PATH changes $(shell).
640 used_env_vars.insert(Intern("PATH"));
641 for (Symbol e : used_env_vars) {
Shinichiro Hamajied883ef2015-07-31 13:15:04 +0900642 StringPiece val(getenv(e.c_str()));
643 used_envs_.emplace(e.str(), val.as_string());
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900644 }
645
Shinichiro Hamaji9c5e60c2015-09-29 13:26:45 +0900646 string default_targets;
Shinichiro Hamaji4e3b4212015-11-09 17:08:32 +0900647 if (g_flags.targets.empty() || g_flags.gen_all_targets) {
Shinichiro Hamajia62b02a2015-10-01 14:21:40 +0900648 CHECK(default_target_);
649 default_targets = EscapeBuildTarget(default_target_->output);
Shinichiro Hamaji9c5e60c2015-09-29 13:26:45 +0900650 } else {
651 for (Symbol s : g_flags.targets) {
652 if (!default_targets.empty())
653 default_targets += ' ';
654 default_targets += EscapeBuildTarget(s);
655 }
Shinichiro Hamaji43defe02015-07-11 07:06:43 +0900656 }
Dan Willemsen87b8da72018-10-26 09:21:23 -0700657 if (!g_flags.generate_empty_ninja) {
658 fprintf(fp_, "\n");
659 fprintf(fp_, "default %s\n", default_targets.c_str());
660 }
Shinichiro Hamaji43defe02015-07-11 07:06:43 +0900661
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900662 fclose(fp_);
663 }
664
665 void GenerateShell() {
Colin Cross27df5312015-11-09 13:39:14 -0800666 FILE* fp = fopen(GetEnvScriptFilename().c_str(), "wb");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900667 if (fp == NULL)
Colin Cross27df5312015-11-09 13:39:14 -0800668 PERROR("fopen(env.sh) failed");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900669
Shinichiro Hamaji4dd62de2015-07-28 16:06:52 +0900670 fprintf(fp, "#!/bin/sh\n");
Shinichiro Hamajiaf9887a2015-07-17 03:45:14 +0900671 fprintf(fp, "# Generated by kati %s\n", kGitVersion);
672 fprintf(fp, "\n");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900673
674 for (const auto& p : ev_->exports()) {
675 if (p.second) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900676 const string val = ev_->EvalVar(p.first);
677 fprintf(fp, "export '%s'='%s'\n", p.first.c_str(), val.c_str());
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900678 } else {
Shinichiro Hamajif65e5722015-07-28 16:13:18 +0900679 fprintf(fp, "unset '%s'\n", p.first.c_str());
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900680 }
681 }
682
Colin Cross27df5312015-11-09 13:39:14 -0800683 fclose(fp);
684
Shinichiro Hamaji8ef0ce52016-01-19 18:07:43 +0900685 fp = fopen(GetNinjaShellScriptFilename().c_str(), "wb");
Colin Cross27df5312015-11-09 13:39:14 -0800686 if (fp == NULL)
687 PERROR("fopen(ninja.sh) failed");
688
689 fprintf(fp, "#!/bin/sh\n");
690 fprintf(fp, "# Generated by kati %s\n", kGitVersion);
691 fprintf(fp, "\n");
692
693 fprintf(fp, ". %s\n", GetEnvScriptFilename().c_str());
694
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900695 fprintf(fp, "exec ninja -f %s ", GetNinjaFilename().c_str());
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900696 if (g_flags.remote_num_jobs > 0) {
697 fprintf(fp, "-j%d ", g_flags.remote_num_jobs);
698 } else if (g_flags.goma_dir) {
Shinichiro Hamaji6d7c7b72015-07-18 16:51:39 +0900699 fprintf(fp, "-j500 ");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900700 }
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900701 fprintf(fp, "\"$@\"\n");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900702
Colin Cross27df5312015-11-09 13:39:14 -0800703 fclose(fp);
704
Shinichiro Hamaji8ef0ce52016-01-19 18:07:43 +0900705 if (chmod(GetNinjaShellScriptFilename().c_str(), 0755) != 0)
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900706 PERROR("chmod ninja.sh failed");
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900707 }
708
Dan Willemsen87417412015-08-24 17:57:12 -0700709 void GenerateStamp(const string& orig_args) {
Colin Cross0850f7d2015-09-14 15:11:45 -0700710 FILE* fp = fopen(GetStampTempFilename().c_str(), "wb");
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900711 CHECK(fp);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900712
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900713 size_t r = fwrite(&start_time_, sizeof(start_time_), 1, fp);
714 CHECK(r == 1);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900715
716 unordered_set<string> makefiles;
717 MakefileCacheManager::Get()->GetAllFilenames(&makefiles);
718 DumpInt(fp, makefiles.size() + 1);
719 DumpString(fp, kati_binary_);
720 for (const string& makefile : makefiles) {
721 DumpString(fp, makefile);
722 }
723
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900724 DumpInt(fp, Evaluator::used_undefined_vars().size());
725 for (Symbol v : Evaluator::used_undefined_vars()) {
726 DumpString(fp, v.str());
727 }
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900728 DumpInt(fp, used_envs_.size());
729 for (const auto& p : used_envs_) {
730 DumpString(fp, p.first);
731 DumpString(fp, p.second);
732 }
733
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900734 const unordered_map<string, vector<string>*>& globs = GetAllGlobCache();
735 DumpInt(fp, globs.size());
736 for (const auto& p : globs) {
737 DumpString(fp, p.first);
738 const vector<string>& files = *p.second;
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900739#if 0
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900740 unordered_set<string> dirs;
741 GetReadDirs(p.first, files, &dirs);
742 DumpInt(fp, dirs.size());
743 for (const string& dir : dirs) {
744 DumpString(fp, dir);
745 }
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900746#endif
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900747 DumpInt(fp, files.size());
748 for (const string& file : files) {
749 DumpString(fp, file);
750 }
751 }
752
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900753 const vector<CommandResult*>& crs = GetShellCommandResults();
754 DumpInt(fp, crs.size());
755 for (CommandResult* cr : crs) {
Dan Willemsenf06d8012016-10-03 00:16:07 -0700756 DumpInt(fp, static_cast<int>(cr->op));
Stefan Beckerd4f28712016-04-07 13:29:36 +0300757 DumpString(fp, cr->shell);
Dan Willemsen064be222016-09-30 20:17:14 -0700758 DumpString(fp, cr->shellflag);
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900759 DumpString(fp, cr->cmd);
760 DumpString(fp, cr->result);
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900761
Dan Willemsenf06d8012016-10-03 00:16:07 -0700762 if (cr->op == CommandOp::FIND) {
763 vector<string> missing_dirs;
764 for (StringPiece fd : cr->find->finddirs) {
765 const string& d = ConcatDir(cr->find->chdir, fd);
766 if (!Exists(d))
767 missing_dirs.push_back(d);
768 }
769 DumpInt(fp, missing_dirs.size());
770 for (const string& d : missing_dirs) {
771 DumpString(fp, d);
772 }
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900773
Dan Willemsen439f6f12016-10-19 01:13:54 -0700774 DumpInt(fp, cr->find->found_files->size());
775 for (StringPiece s : *cr->find->found_files) {
776 DumpString(fp, ConcatDir(cr->find->chdir, s));
777 }
778
Dan Willemsenf06d8012016-10-03 00:16:07 -0700779 DumpInt(fp, cr->find->read_dirs->size());
780 for (StringPiece s : *cr->find->read_dirs) {
781 DumpString(fp, ConcatDir(cr->find->chdir, s));
782 }
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900783 }
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900784 }
785
Dan Willemsen87417412015-08-24 17:57:12 -0700786 DumpString(fp, orig_args);
787
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900788 fclose(fp);
Colin Cross0850f7d2015-09-14 15:11:45 -0700789
Shinichiro Hamaji8ef0ce52016-01-19 18:07:43 +0900790 rename(GetStampTempFilename().c_str(), GetNinjaStampFilename().c_str());
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900791 }
792
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900793 CommandEvaluator ce_;
794 Evaluator* ev_;
795 FILE* fp_;
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700796 SymbolSet done_;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900797 int rule_id_;
Shinichiro Hamaji84ddbd22016-04-09 13:35:27 +0900798 bool use_goma_;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900799 string gomacc_;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900800 string shell_;
Stefan Becker187bf082016-04-07 13:28:42 +0300801 string shell_flags_;
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900802 map<string, string> used_envs_;
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900803 string kati_binary_;
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900804 const double start_time_;
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900805 vector<NinjaNode*> nodes_;
Shinichiro Hamajia81301e2016-02-15 19:04:26 +0900806
Shinichiro Hamaji8380fb82016-02-26 16:51:50 +0900807 mutex mu_;
Shinichiro Hamajif9350dd2016-02-09 17:52:40 +0900808 const DepNode* default_target_;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900809};
810
Shinichiro Hamaji8ef0ce52016-01-19 18:07:43 +0900811string GetNinjaFilename() {
812 return NinjaGenerator::GetFilename("build%s.ninja");
813}
814
815string GetNinjaShellScriptFilename() {
816 return NinjaGenerator::GetFilename("ninja%s.sh");
817}
818
819string GetNinjaStampFilename() {
820 return NinjaGenerator::GetFilename(".kati_stamp%s");
821}
822
Sasha Smundake8f4d6d2018-07-27 10:34:04 -0700823void GenerateNinja(const vector<NamedDepNode>& nodes,
Shinichiro Hamaji43defe02015-07-11 07:06:43 +0900824 Evaluator* ev,
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900825 const string& orig_args,
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900826 double start_time) {
Shinichiro Hamajif9869fc2015-09-28 17:18:59 +0900827 NinjaGenerator ng(ev, start_time);
Shinichiro Hamaji9c5e60c2015-09-29 13:26:45 +0900828 ng.Generate(nodes, orig_args);
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900829}