blob: ef74e35c423ebc847e901ca30b357a76edfaa60d [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 Hamajia09ed282015-07-31 12:21:54 +090024#include <algorithm>
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +090025#include <map>
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"
44#include "var.h"
Shinichiro Hamajid821f6d2015-07-14 04:03:27 +090045#include "version.h"
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +090046
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +090047static size_t FindCommandLineFlag(StringPiece cmd, StringPiece name) {
48 const size_t found = cmd.find(name);
49 if (found == string::npos || found == 0)
50 return string::npos;
51 return found;
52}
53
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +090054static StringPiece FindCommandLineFlagWithArg(StringPiece cmd,
55 StringPiece name) {
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +090056 size_t index = FindCommandLineFlag(cmd, name);
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +090057 if (index == string::npos)
58 return StringPiece();
59
60 StringPiece val = TrimLeftSpace(cmd.substr(index + name.size()));
61 index = val.find(name);
62 while (index != string::npos) {
63 val = TrimLeftSpace(val.substr(index + name.size()));
64 index = val.find(name);
65 }
66
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +090067 index = val.find_first_of(" \t");
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +090068 return val.substr(0, index);
69}
70
Shinichiro Hamaji9facae22015-07-03 17:16:36 +090071static bool StripPrefix(StringPiece p, StringPiece* s) {
72 if (!HasPrefix(*s, p))
73 return false;
74 *s = s->substr(p.size());
75 return true;
76}
77
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +090078size_t GetGomaccPosForAndroidCompileCommand(StringPiece cmdline) {
79 size_t index = cmdline.find(' ');
Shinichiro Hamaji9facae22015-07-03 17:16:36 +090080 if (index == string::npos)
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +090081 return string::npos;
82 StringPiece cmd = cmdline.substr(0, index);
83 if (HasSuffix(cmd, "ccache")) {
84 index++;
85 size_t pos = GetGomaccPosForAndroidCompileCommand(cmdline.substr(index));
86 return pos == string::npos ? string::npos : pos + index;
87 }
88 if (!StripPrefix("prebuilts/", &cmd))
89 return string::npos;
90 if (!StripPrefix("gcc/", &cmd) && !StripPrefix("clang/", &cmd))
91 return string::npos;
92 if (!HasSuffix(cmd, "gcc") && !HasSuffix(cmd, "g++") &&
93 !HasSuffix(cmd, "clang") && !HasSuffix(cmd, "clang++")) {
94 return string::npos;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +090095 }
96
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +090097 StringPiece rest = cmdline.substr(index);
98 return rest.find(" -c ") != string::npos ? 0 : string::npos;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +090099}
100
101static bool GetDepfileFromCommandImpl(StringPiece cmd, string* out) {
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +0900102 if ((FindCommandLineFlag(cmd, " -MD") == string::npos &&
103 FindCommandLineFlag(cmd, " -MMD") == string::npos) ||
104 FindCommandLineFlag(cmd, " -c") == string::npos) {
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900105 return false;
106 }
107
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +0900108 StringPiece mf = FindCommandLineFlagWithArg(cmd, " -MF");
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900109 if (!mf.empty()) {
110 mf.AppendToString(out);
111 return true;
112 }
113
Shinichiro Hamaji383cfe02015-07-27 16:12:45 +0900114 StringPiece o = FindCommandLineFlagWithArg(cmd, " -o");
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900115 if (o.empty()) {
116 ERROR("Cannot find the depfile in %s", cmd.as_string().c_str());
117 return false;
118 }
119
120 StripExt(o).AppendToString(out);
121 *out += ".d";
122 return true;
123}
124
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900125bool GetDepfileFromCommand(string* cmd, string* out) {
126 CHECK(!cmd->empty());
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900127 if (!GetDepfileFromCommandImpl(*cmd, out))
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900128 return false;
129
130 // A hack for Android - llvm-rs-cc seems not to emit a dep file.
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900131 if (cmd->find("bin/llvm-rs-cc ") != string::npos) {
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900132 return false;
133 }
134
135 // TODO: A hack for Makefiles generated by automake.
136
137 // A hack for Android to get .P files instead of .d.
138 string p;
139 StripExt(*out).AppendToString(&p);
140 p += ".P";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900141 if (cmd->find(p) != string::npos) {
142 const string rm_f = "; rm -f " + *out;
143 const size_t found = cmd->find(rm_f);
144 if (found == string::npos) {
145 ERROR("Cannot find removal of .d file: %s", cmd->c_str());
146 }
147 cmd->erase(found, rm_f.size());
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900148 return true;
149 }
150
151 // A hack for Android. For .s files, GCC does not use C
152 // preprocessor, so it ignores -MF flag.
153 string as = "/";
154 StripExt(Basename(*out)).AppendToString(&as);
155 as += ".s";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900156 if (cmd->find(as) != string::npos) {
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900157 return false;
158 }
159
Shinichiro Hamajid416e612015-07-18 12:43:34 +0900160 *cmd += "&& cp ";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900161 *cmd += *out;
162 *cmd += ' ';
163 *cmd += *out;
Shinichiro Hamajid416e612015-07-18 12:43:34 +0900164 *cmd += ".tmp ";
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900165 *out += ".tmp";
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900166 return true;
167}
168
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900169class NinjaGenerator {
170 public:
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900171 NinjaGenerator(const char* ninja_suffix, const char* ninja_dir, Evaluator* ev,
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900172 double start_time)
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900173 : ce_(ev), ev_(ev), fp_(NULL), rule_id_(0), start_time_(start_time) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900174 ev_->set_avoid_io(true);
Colin Crosse890a912015-07-20 13:28:00 -0700175 shell_ = ev->EvalVar(kShellSym);
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900176 if (g_flags.goma_dir)
177 gomacc_ = StringPrintf("%s/gomacc ", g_flags.goma_dir);
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900178 if (ninja_suffix) {
179 ninja_suffix_ = ninja_suffix;
180 }
Colin Crossbb2bba12015-07-20 16:31:18 -0700181 if (ninja_dir) {
182 ninja_dir_ = ninja_dir;
183 } else {
184 ninja_dir_ = ".";
185 }
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900186
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900187 GetExecutablePath(&kati_binary_);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900188 }
189
190 ~NinjaGenerator() {
191 ev_->set_avoid_io(false);
192 }
193
Shinichiro Hamaji998ccf72015-07-18 12:37:02 +0900194 void Generate(const vector<DepNode*>& nodes,
195 bool build_all_targets,
196 const string& orig_args) {
Shinichiro Hamaji998ccf72015-07-18 12:37:02 +0900197 GenerateNinja(nodes, build_all_targets, orig_args);
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900198 GenerateShell();
Dan Willemsen87417412015-08-24 17:57:12 -0700199 GenerateStamp(orig_args);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900200 }
201
202 static string GetStampFilename(const char* ninja_dir,
203 const char* ninja_suffix) {
204 return StringPrintf("%s/.kati_stamp%s",
205 ninja_dir ? ninja_dir : ".",
206 ninja_suffix ? ninja_suffix : "");
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900207 }
208
209 private:
210 string GenRuleName() {
211 return StringPrintf("rule%d", rule_id_++);
212 }
213
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900214 StringPiece TranslateCommand(const char* in, string* cmd_buf) {
215 const size_t orig_size = cmd_buf->size();
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900216 bool prev_backslash = false;
Shinichiro Hamaji53eaaf82015-07-15 06:09:43 +0900217 // Set space as an initial value so the leading comment will be
218 // stripped out.
219 char prev_char = ' ';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900220 char quote = 0;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +0900221 for (; *in; in++) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900222 switch (*in) {
223 case '#':
Shinichiro Hamaji53eaaf82015-07-15 06:09:43 +0900224 if (quote == 0 && isspace(prev_char)) {
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +0900225 while (in[1] && *in != '\n')
226 in++;
Colin Cross415e4a12015-07-15 18:21:38 -0700227 } else {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900228 *cmd_buf += *in;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900229 }
Colin Cross415e4a12015-07-15 18:21:38 -0700230 break;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900231
232 case '\'':
233 case '"':
234 case '`':
235 if (quote) {
236 if (quote == *in)
237 quote = 0;
238 } else if (!prev_backslash) {
239 quote = *in;
240 }
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900241 *cmd_buf += *in;
Shinichiro Hamaji4212e382015-06-29 17:21:04 +0900242 break;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900243
244 case '$':
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900245 *cmd_buf += "$$";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900246 break;
247
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900248 case '\n':
249 if (prev_backslash) {
Shinichiro Hamajia4dfe752015-07-28 15:54:36 +0900250 cmd_buf->resize(cmd_buf->size()-1);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900251 } else {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900252 *cmd_buf += ' ';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900253 }
Shinichiro Hamaji4d151832015-06-29 18:15:46 +0900254 break;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900255
256 case '\\':
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900257 *cmd_buf += '\\';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900258 break;
259
260 default:
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900261 *cmd_buf += *in;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900262 }
Colin Crossf6f1cf42015-07-15 15:25:30 -0700263
264 if (*in == '\\') {
265 prev_backslash = !prev_backslash;
266 } else {
267 prev_backslash = false;
268 }
269
Shinichiro Hamaji53eaaf82015-07-15 06:09:43 +0900270 prev_char = *in;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900271 }
272
Dan Willemsen45c49cc2015-08-21 12:39:34 -0700273 if (prev_backslash) {
274 cmd_buf->resize(cmd_buf->size()-1);
275 }
276
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900277 while (true) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900278 char c = (*cmd_buf)[cmd_buf->size()-1];
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900279 if (!isspace(c) && c != ';')
280 break;
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900281 cmd_buf->resize(cmd_buf->size() - 1);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900282 }
283
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900284 return StringPiece(cmd_buf->data() + orig_size,
285 cmd_buf->size() - orig_size);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900286 }
287
Colin Cross2e032ba2015-07-15 18:33:37 -0700288 bool GetDescriptionFromCommand(StringPiece cmd, string *out) {
Colin Cross2e032ba2015-07-15 18:33:37 -0700289 if (!HasPrefix(cmd, "echo ")) {
290 return false;
291 }
292 cmd = cmd.substr(5, cmd.size());
293
Colin Cross2e032ba2015-07-15 18:33:37 -0700294 bool prev_backslash = false;
295 char quote = 0;
296 string out_buf;
297
298 // Strip outer quotes, and fail if it is not a single echo command
299 for (StringPiece::iterator in = cmd.begin(); in != cmd.end(); in++) {
300 if (prev_backslash) {
301 prev_backslash = false;
302 out_buf += *in;
303 } else if (*in == '\\') {
304 prev_backslash = true;
305 out_buf += *in;
306 } else if (quote) {
307 if (*in == quote) {
308 quote = 0;
309 } else {
310 out_buf += *in;
311 }
312 } else {
313 switch (*in) {
314 case '\'':
315 case '"':
316 case '`':
317 quote = *in;
318 break;
319
320 case '<':
321 case '>':
322 case '&':
323 case '|':
324 case ';':
325 return false;
326
327 default:
328 out_buf += *in;
329 }
330 }
331 }
332
333 *out = out_buf;
334 return true;
335 }
336
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900337 bool GenShellScript(const vector<Command*>& commands,
338 string* cmd_buf,
339 string* description) {
Shinichiro Hamaji2ee6ca12015-07-18 03:37:21 +0900340 bool got_descritpion = false;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900341 bool use_gomacc = false;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900342 bool should_ignore_error = false;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900343 for (const Command* c : commands) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900344 if (!cmd_buf->empty()) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900345 if (should_ignore_error) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900346 *cmd_buf += " ; ";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900347 } else {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900348 *cmd_buf += " && ";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900349 }
350 }
351 should_ignore_error = c->ignore_error;
352
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900353 const char* in = c->cmd.c_str();
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900354 while (isspace(*in))
355 in++;
356
357 bool needs_subshell = commands.size() > 1;
358 if (*in == '(') {
359 needs_subshell = false;
360 }
361
362 if (needs_subshell)
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900363 *cmd_buf += '(';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900364
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900365 size_t cmd_start = cmd_buf->size();
366 StringPiece translated = TranslateCommand(in, cmd_buf);
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900367 if (g_flags.detect_android_echo && !got_descritpion && !c->echo &&
Shinichiro Hamaji2ee6ca12015-07-18 03:37:21 +0900368 GetDescriptionFromCommand(translated, description)) {
369 got_descritpion = true;
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900370 cmd_buf->resize(cmd_start);
Shinichiro Hamaji2ee6ca12015-07-18 03:37:21 +0900371 translated.clear();
372 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900373 if (translated.empty()) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900374 *cmd_buf += "true";
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900375 } else if (g_flags.goma_dir) {
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +0900376 size_t pos = GetGomaccPosForAndroidCompileCommand(translated);
377 if (pos != string::npos) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900378 cmd_buf->insert(cmd_start + pos, gomacc_);
Shinichiro Hamaji2c9fcbe2015-07-14 03:36:34 +0900379 use_gomacc = true;
380 }
Shinichiro Hamaji4cb8a6f2015-08-17 16:30:49 +0900381 } else if (translated.find("/gomacc") != string::npos) {
382 use_gomacc = true;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900383 }
384
385 if (c == commands.back() && c->ignore_error) {
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900386 *cmd_buf += " ; true";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900387 }
388
389 if (needs_subshell)
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900390 *cmd_buf += ')';
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900391 }
Shinichiro Hamaji5b69ad72015-09-11 04:19:09 +0900392 return (g_flags.remote_num_jobs || g_flags.goma_dir) && !use_gomacc;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900393 }
394
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900395 void EmitDepfile(string* cmd_buf) {
396 *cmd_buf += ' ';
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900397 string depfile;
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900398 bool result = GetDepfileFromCommand(cmd_buf, &depfile);
399 cmd_buf->resize(cmd_buf->size()-1);
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900400 if (!result)
401 return;
402 fprintf(fp_, " depfile = %s\n", depfile.c_str());
Shinichiro Hamaji71966412015-07-11 03:12:59 +0900403 fprintf(fp_, " deps = gcc\n");
Shinichiro Hamajie9f7e672015-07-03 15:57:45 +0900404 }
405
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900406 void EmitNode(DepNode* node) {
407 auto p = done_.insert(node->output);
408 if (!p.second)
409 return;
410
Shinichiro Hamaji346b20a2015-08-17 14:23:50 +0900411 // A hack to exclude out phony target in Android. If this exists,
412 // "ninja -t clean" tries to remove this directory and fails.
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900413 if (g_flags.detect_android_echo && node->output.str() == "out")
Shinichiro Hamaji346b20a2015-08-17 14:23:50 +0900414 return;
415
Dan Willemsenf3a4ced2015-08-25 14:22:35 -0700416 // This node is a leaf node
417 if (!node->has_rule && !node->is_phony) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900418 return;
Shinichiro Hamaji0f39c522015-07-07 13:14:02 +0900419 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900420
421 vector<Command*> commands;
422 ce_.Eval(node, &commands);
423
424 string rule_name = "phony";
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900425 bool use_local_pool = false;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900426 if (!commands.empty()) {
427 rule_name = GenRuleName();
428 fprintf(fp_, "rule %s\n", rule_name.c_str());
Colin Cross2e032ba2015-07-15 18:33:37 -0700429
430 string description = "build $out";
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900431 string cmd_buf;
432 use_local_pool |= GenShellScript(commands, &cmd_buf, &description);
Colin Cross2e032ba2015-07-15 18:33:37 -0700433 fprintf(fp_, " description = %s\n", description.c_str());
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900434 EmitDepfile(&cmd_buf);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900435
Shinichiro Hamajieb0e5f92015-07-17 03:38:23 +0900436 // It seems Linux is OK with ~130kB and Mac's limit is ~250kB.
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900437 // TODO: Find this number automatically.
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900438 if (cmd_buf.size() > 100 * 1000) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900439 fprintf(fp_, " rspfile = $out.rsp\n");
Shinichiro Hamajidbefa652015-07-27 14:08:42 +0900440 fprintf(fp_, " rspfile_content = %s\n", cmd_buf.c_str());
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900441 fprintf(fp_, " command = %s $out.rsp\n", shell_.c_str());
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900442 } else {
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900443 EscapeShell(&cmd_buf);
Shinichiro Hamaji2e04d302015-07-24 09:31:18 +0900444 fprintf(fp_, " command = %s -c \"%s\"\n",
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900445 shell_.c_str(), cmd_buf.c_str());
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900446 }
447 }
448
449 EmitBuild(node, rule_name);
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900450 if (use_local_pool)
451 fprintf(fp_, " pool = local_pool\n");
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900452
453 for (DepNode* d : node->deps) {
454 EmitNode(d);
455 }
Shinichiro Hamaji3f2cf1e2015-07-06 18:58:18 +0900456 for (DepNode* d : node->order_onlys) {
457 EmitNode(d);
458 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900459 }
460
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900461 string EscapeBuildTarget(Symbol s) const {
Shinichiro Hamaji753c8122015-07-18 17:16:24 +0900462 if (s.str().find_first_of("$: ") == string::npos)
463 return s.str();
464 string r;
465 for (char c : s.str()) {
466 switch (c) {
467 case '$':
468 case ':':
469 case ' ':
470 r += '$';
471 // fall through.
472 default:
473 r += c;
474 }
475 }
476 return r;
477 }
478
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900479 void EscapeShell(string* s) const {
480 if (s->find_first_of("$`!\\\"") == string::npos)
481 return;
Colin Crosse890a912015-07-20 13:28:00 -0700482 string r;
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900483 bool last_dollar = false;
484 for (char c : *s) {
Colin Crosse890a912015-07-20 13:28:00 -0700485 switch (c) {
486 case '$':
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900487 if (last_dollar) {
Colin Crosse890a912015-07-20 13:28:00 -0700488 r += c;
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900489 last_dollar = false;
Colin Crosse890a912015-07-20 13:28:00 -0700490 } else {
491 r += '\\';
492 r += c;
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900493 last_dollar = true;
Colin Crosse890a912015-07-20 13:28:00 -0700494 }
495 break;
496 case '`':
497 case '"':
498 case '!':
499 case '\\':
500 r += '\\';
501 // fall through.
502 default:
503 r += c;
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900504 last_dollar = false;
Colin Crosse890a912015-07-20 13:28:00 -0700505 }
506 }
Shinichiro Hamajidb559f52015-08-14 17:24:21 +0900507 s->swap(r);
Colin Crosse890a912015-07-20 13:28:00 -0700508 }
509
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900510 void EmitBuild(DepNode* node, const string& rule_name) {
Shinichiro Hamaji753c8122015-07-18 17:16:24 +0900511 fprintf(fp_, "build %s: %s",
512 EscapeBuildTarget(node->output).c_str(),
513 rule_name.c_str());
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900514 vector<Symbol> order_onlys;
Dan Willemsen3faa60f2015-08-21 13:24:39 -0700515 if (node->is_phony) {
516 fprintf(fp_, " _kati_always_build_");
517 }
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900518 for (DepNode* d : node->deps) {
Shinichiro Hamaji753c8122015-07-18 17:16:24 +0900519 fprintf(fp_, " %s", EscapeBuildTarget(d->output).c_str());
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900520 }
Shinichiro Hamaji183dbb92015-07-06 17:21:39 +0900521 if (!node->order_onlys.empty()) {
Shinichiro Hamajif4820de2015-06-29 17:03:17 +0900522 fprintf(fp_, " ||");
Shinichiro Hamaji183dbb92015-07-06 17:21:39 +0900523 for (DepNode* d : node->order_onlys) {
Shinichiro Hamaji753c8122015-07-18 17:16:24 +0900524 fprintf(fp_, " %s", EscapeBuildTarget(d->output).c_str());
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900525 }
526 }
527 fprintf(fp_, "\n");
528 }
529
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900530 void EmitRegenRules(const string& orig_args) {
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900531 if (!g_flags.gen_regen_rule)
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900532 return;
533
534 fprintf(fp_, "rule regen_ninja\n");
535 fprintf(fp_, " command = %s\n", orig_args.c_str());
536 fprintf(fp_, " generator = 1\n");
537 fprintf(fp_, " description = Regenerate ninja files due to dependency\n");
538 fprintf(fp_, "build %s: regen_ninja", GetNinjaFilename().c_str());
539 unordered_set<string> makefiles;
540 MakefileCacheManager::Get()->GetAllFilenames(&makefiles);
541 for (const string& makefile : makefiles) {
542 fprintf(fp_, " %.*s", SPF(makefile));
543 }
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900544 fprintf(fp_, " %s", kati_binary_.c_str());
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900545 fprintf(fp_, "\n\n");
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900546 }
547
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900548 string GetNinjaFilename() const {
Shinichiro Hamaji2e04d302015-07-24 09:31:18 +0900549 return StringPrintf("%s/build%s.ninja",
550 ninja_dir_.c_str(), ninja_suffix_.c_str());
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900551 }
552
553 string GetShellScriptFilename() const {
Shinichiro Hamaji2e04d302015-07-24 09:31:18 +0900554 return StringPrintf("%s/ninja%s.sh",
555 ninja_dir_.c_str(), ninja_suffix_.c_str());
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900556 }
557
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900558 string GetStampFilename() const {
559 return GetStampFilename(ninja_dir_.c_str(), ninja_suffix_.c_str());
560 }
561
Shinichiro Hamaji998ccf72015-07-18 12:37:02 +0900562 void GenerateNinja(const vector<DepNode*>& nodes,
563 bool build_all_targets,
564 const string& orig_args) {
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900565 fp_ = fopen(GetNinjaFilename().c_str(), "wb");
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900566 if (fp_ == NULL)
567 PERROR("fopen(build.ninja) failed");
568
Shinichiro Hamajid821f6d2015-07-14 04:03:27 +0900569 fprintf(fp_, "# Generated by kati %s\n", kGitVersion);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900570 fprintf(fp_, "\n");
571
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900572 if (!used_envs_.empty()) {
Shinichiro Hamaji5163e042015-07-14 03:51:44 +0900573 fprintf(fp_, "# Environment variables used:\n");
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900574 for (const auto& p : used_envs_) {
575 fprintf(fp_, "# %s=%s\n", p.first.c_str(), p.second.c_str());
Shinichiro Hamaji5163e042015-07-14 03:51:44 +0900576 }
577 fprintf(fp_, "\n");
578 }
579
Dan Willemsen2e762292015-08-19 20:39:41 -0700580 if (ninja_dir_ != ".") {
581 fprintf(fp_, "builddir = %s\n\n", ninja_dir_.c_str());
582 }
583
Shinichiro Hamaji4cb8a6f2015-08-17 16:30:49 +0900584 fprintf(fp_, "pool local_pool\n");
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900585 fprintf(fp_, " depth = %d\n\n", g_flags.num_jobs);
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900586
Dan Willemsen3faa60f2015-08-21 13:24:39 -0700587 fprintf(fp_, "build _kati_always_build_: phony\n\n");
588
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900589 EmitRegenRules(orig_args);
Shinichiro Hamaji998ccf72015-07-18 12:37:02 +0900590
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900591 for (DepNode* node : nodes) {
592 EmitNode(node);
593 }
594
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900595 for (Symbol e : Vars::used_env_vars()) {
Shinichiro Hamajied883ef2015-07-31 13:15:04 +0900596 StringPiece val(getenv(e.c_str()));
597 used_envs_.emplace(e.str(), val.as_string());
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900598 }
599
Shinichiro Hamaji43defe02015-07-11 07:06:43 +0900600 if (!build_all_targets) {
601 CHECK(!nodes.empty());
Shinichiro Hamaji865597b2015-07-28 16:16:58 +0900602 fprintf(fp_, "\ndefault %s\n",
603 EscapeBuildTarget(nodes.front()->output).c_str());
Shinichiro Hamaji43defe02015-07-11 07:06:43 +0900604 }
605
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900606 fclose(fp_);
607 }
608
609 void GenerateShell() {
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900610 FILE* fp = fopen(GetShellScriptFilename().c_str(), "wb");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900611 if (fp == NULL)
612 PERROR("fopen(ninja.sh) failed");
613
Shinichiro Hamaji4dd62de2015-07-28 16:06:52 +0900614 fprintf(fp, "#!/bin/sh\n");
Shinichiro Hamajiaf9887a2015-07-17 03:45:14 +0900615 fprintf(fp, "# Generated by kati %s\n", kGitVersion);
616 fprintf(fp, "\n");
Shinichiro Hamajic7629e02015-07-22 02:41:57 +0900617 if (ninja_dir_ == ".")
618 fprintf(fp, "cd $(dirname \"$0\")\n");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900619
620 for (const auto& p : ev_->exports()) {
621 if (p.second) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900622 const string val = ev_->EvalVar(p.first);
623 fprintf(fp, "export '%s'='%s'\n", p.first.c_str(), val.c_str());
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900624 } else {
Shinichiro Hamajif65e5722015-07-28 16:13:18 +0900625 fprintf(fp, "unset '%s'\n", p.first.c_str());
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900626 }
627 }
628
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900629 fprintf(fp, "exec ninja -f %s ", GetNinjaFilename().c_str());
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900630 if (g_flags.remote_num_jobs > 0) {
631 fprintf(fp, "-j%d ", g_flags.remote_num_jobs);
632 } else if (g_flags.goma_dir) {
Shinichiro Hamaji6d7c7b72015-07-18 16:51:39 +0900633 fprintf(fp, "-j500 ");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900634 }
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900635 fprintf(fp, "\"$@\"\n");
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900636
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900637 if (chmod(GetShellScriptFilename().c_str(), 0755) != 0)
Shinichiro Hamaji54b93ba2015-07-03 20:43:32 +0900638 PERROR("chmod ninja.sh failed");
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900639 }
640
Dan Willemsen87417412015-08-24 17:57:12 -0700641 void GenerateStamp(const string& orig_args) {
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900642 FILE* fp = fopen(GetStampFilename().c_str(), "wb");
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900643 CHECK(fp);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900644
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900645 size_t r = fwrite(&start_time_, sizeof(start_time_), 1, fp);
646 CHECK(r == 1);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900647
648 unordered_set<string> makefiles;
649 MakefileCacheManager::Get()->GetAllFilenames(&makefiles);
650 DumpInt(fp, makefiles.size() + 1);
651 DumpString(fp, kati_binary_);
652 for (const string& makefile : makefiles) {
653 DumpString(fp, makefile);
654 }
655
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900656 DumpInt(fp, Evaluator::used_undefined_vars().size());
657 for (Symbol v : Evaluator::used_undefined_vars()) {
658 DumpString(fp, v.str());
659 }
660
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900661 DumpInt(fp, used_envs_.size());
662 for (const auto& p : used_envs_) {
663 DumpString(fp, p.first);
664 DumpString(fp, p.second);
665 }
666
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900667 const unordered_map<string, vector<string>*>& globs = GetAllGlobCache();
668 DumpInt(fp, globs.size());
669 for (const auto& p : globs) {
670 DumpString(fp, p.first);
671 const vector<string>& files = *p.second;
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900672#if 0
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900673 unordered_set<string> dirs;
674 GetReadDirs(p.first, files, &dirs);
675 DumpInt(fp, dirs.size());
676 for (const string& dir : dirs) {
677 DumpString(fp, dir);
678 }
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900679#endif
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900680 DumpInt(fp, files.size());
681 for (const string& file : files) {
682 DumpString(fp, file);
683 }
684 }
685
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900686 const vector<CommandResult*>& crs = GetShellCommandResults();
687 DumpInt(fp, crs.size());
688 for (CommandResult* cr : crs) {
689 DumpString(fp, cr->cmd);
690 DumpString(fp, cr->result);
691 if (!cr->find.get()) {
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900692 // Always re-run this command.
693 DumpInt(fp, 0);
694 continue;
695 }
696
697 DumpInt(fp, 1);
698
699 vector<string> missing_dirs;
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900700 for (StringPiece fd : cr->find->finddirs) {
701 const string& d = ConcatDir(cr->find->chdir, fd);
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900702 if (!Exists(d))
703 missing_dirs.push_back(d);
704 }
705 DumpInt(fp, missing_dirs.size());
706 for (const string& d : missing_dirs) {
707 DumpString(fp, d);
708 }
709
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900710 DumpInt(fp, cr->find->read_dirs->size());
711 for (StringPiece s : *cr->find->read_dirs) {
712 DumpString(fp, ConcatDir(cr->find->chdir, s));
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900713 }
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900714 }
715
Dan Willemsen87417412015-08-24 17:57:12 -0700716 DumpString(fp, orig_args);
717
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900718 fclose(fp);
719 }
720
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900721 CommandEvaluator ce_;
722 Evaluator* ev_;
723 FILE* fp_;
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900724 unordered_set<Symbol> done_;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900725 int rule_id_;
Shinichiro Hamaji9facae22015-07-03 17:16:36 +0900726 string gomacc_;
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900727 string ninja_suffix_;
Colin Crossbb2bba12015-07-20 16:31:18 -0700728 string ninja_dir_;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900729 string shell_;
Shinichiro Hamajia6e06f82015-07-18 14:08:49 +0900730 map<string, string> used_envs_;
Shinichiro Hamajib58bb4b2015-07-30 18:02:51 +0900731 string kati_binary_;
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900732 double start_time_;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900733};
734
Shinichiro Hamaji8bddb462015-07-06 18:55:47 +0900735void GenerateNinja(const char* ninja_suffix,
Colin Crossbb2bba12015-07-20 16:31:18 -0700736 const char* ninja_dir,
Shinichiro Hamaji43defe02015-07-11 07:06:43 +0900737 const vector<DepNode*>& nodes,
738 Evaluator* ev,
Shinichiro Hamaji998ccf72015-07-18 12:37:02 +0900739 bool build_all_targets,
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900740 const string& orig_args,
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900741 double start_time) {
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900742 NinjaGenerator ng(ninja_suffix, ninja_dir, ev, start_time);
Shinichiro Hamaji998ccf72015-07-18 12:37:02 +0900743 ng.Generate(nodes, build_all_targets, orig_args);
Shinichiro Hamaji5f86e1a2015-06-29 14:25:39 +0900744}
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900745
Shinichiro Hamajie67d54e2015-08-13 14:39:11 +0900746static bool ShouldIgnoreDirty(StringPiece s) {
Shinichiro Hamaji003d06e2015-09-09 18:22:04 +0900747 return (g_flags.ignore_dirty_pattern &&
748 Pattern(g_flags.ignore_dirty_pattern).Match(s));
Shinichiro Hamajie67d54e2015-08-13 14:39:11 +0900749}
750
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900751bool NeedsRegen(const char* ninja_suffix,
Shinichiro Hamaji81958cb2015-08-06 19:36:55 +0900752 const char* ninja_dir,
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900753 bool ignore_kati_binary,
Shinichiro Hamaji90db5412015-08-13 15:03:52 +0900754 bool dump_kati_stamp,
Dan Willemsen87417412015-08-24 17:57:12 -0700755 double start_time,
756 const string& orig_args) {
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900757 bool retval = false;
758#define RETURN_TRUE do { \
759 if (dump_kati_stamp) \
760 retval = true; \
761 else \
762 return true; \
763 } while (0)
764
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900765#define LOAD_INT(fp) ({ \
766 int v = LoadInt(fp); \
767 if (v < 0) { \
768 fprintf(stderr, "incomplete kati_stamp, regenerating...\n"); \
769 RETURN_TRUE; \
770 } \
771 v; \
772 })
773
774#define LOAD_STRING(fp, s) ({ \
775 if (!LoadString(fp, s)) { \
776 fprintf(stderr, "incomplete kati_stamp, regenerating...\n"); \
777 RETURN_TRUE; \
778 } \
779 })
780
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900781 const string& stamp_filename =
Shinichiro Hamaji64eb42e2015-08-17 19:41:52 +0900782 NinjaGenerator::GetStampFilename(ninja_dir, ninja_suffix);
Shinichiro Hamaji90db5412015-08-13 15:03:52 +0900783 FILE* fp = fopen(stamp_filename.c_str(), "rb+");
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900784 if (!fp)
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900785 RETURN_TRUE;
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900786 ScopedFile sfp(fp);
787
Shinichiro Hamaji36eeb752015-07-31 15:12:04 +0900788 double gen_time;
789 size_t r = fread(&gen_time, sizeof(gen_time), 1, fp);
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900790 if (r != 1) {
791 fprintf(stderr, "incomplete kati_stamp, regenerating...\n");
792 RETURN_TRUE;
793 }
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900794 if (dump_kati_stamp)
795 printf("Generated time: %f\n", gen_time);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900796
797 string s, s2;
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900798 int num_files = LOAD_INT(fp);
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900799 for (int i = 0; i < num_files; i++) {
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900800 LOAD_STRING(fp, &s);
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900801 double ts = GetTimestamp(s);
802 if (gen_time < ts) {
Shinichiro Hamaji81958cb2015-08-06 19:36:55 +0900803 if (ignore_kati_binary) {
804 string kati_binary;
805 GetExecutablePath(&kati_binary);
806 if (s == kati_binary) {
807 fprintf(stderr, "%s was modified, ignored.\n", s.c_str());
808 continue;
809 }
810 }
Shinichiro Hamajie67d54e2015-08-13 14:39:11 +0900811 if (ShouldIgnoreDirty(s)) {
812 if (dump_kati_stamp)
813 printf("file %s: ignored (%f)\n", s.c_str(), ts);
814 continue;
815 }
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900816 if (dump_kati_stamp)
817 printf("file %s: dirty (%f)\n", s.c_str(), ts);
818 else
819 fprintf(stderr, "%s was modified, regenerating...\n", s.c_str());
820 RETURN_TRUE;
821 } else if (dump_kati_stamp) {
822 printf("file %s: clean (%f)\n", s.c_str(), ts);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900823 }
824 }
825
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900826 int num_undefineds = LOAD_INT(fp);
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900827 for (int i = 0; i < num_undefineds; i++) {
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900828 LOAD_STRING(fp, &s);
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900829 if (getenv(s.c_str())) {
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900830 if (dump_kati_stamp) {
831 printf("env %s: dirty (unset => %s)\n", s.c_str(), getenv(s.c_str()));
832 } else {
833 fprintf(stderr, "Environment variable %s was set, regenerating...\n",
834 s.c_str());
835 }
836 RETURN_TRUE;
837 } else if (dump_kati_stamp) {
838 printf("env %s: clean (unset)\n", s.c_str());
Shinichiro Hamaji7e708012015-07-31 13:07:34 +0900839 }
840 }
841
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900842 int num_envs = LOAD_INT(fp);
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900843 for (int i = 0; i < num_envs; i++) {
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900844 LOAD_STRING(fp, &s);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900845 StringPiece val(getenv(s.c_str()));
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900846 LOAD_STRING(fp, &s2);
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900847 if (val != s2) {
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900848 if (dump_kati_stamp) {
Shinichiro Hamajiad62e172015-08-13 13:54:24 +0900849 printf("env %s: dirty (%s => %.*s)\n",
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900850 s.c_str(), s2.c_str(), SPF(val));
851 } else {
852 fprintf(stderr, "Environment variable %s was modified (%s => %.*s), "
853 "regenerating...\n",
854 s.c_str(), s2.c_str(), SPF(val));
855 }
856 RETURN_TRUE;
857 } else if (dump_kati_stamp) {
858 printf("env %s: clean (%.*s)\n", s.c_str(), SPF(val));
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900859 }
860 }
861
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900862 {
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900863 int num_globs = LOAD_INT(fp);
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900864 string pat;
865 for (int i = 0; i < num_globs; i++) {
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900866 COLLECT_STATS("glob time (regen)");
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900867 LOAD_STRING(fp, &pat);
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900868#if 0
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900869 bool needs_reglob = false;
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900870 int num_dirs = LOAD_INT(fp);
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900871 for (int j = 0; j < num_dirs; j++) {
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900872 LOAD_STRING(fp, &s);
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900873 // TODO: Handle removed files properly.
874 needs_reglob |= gen_time < GetTimestamp(s);
875 }
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900876#endif
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900877 int num_files = LOAD_INT(fp);
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900878 vector<string>* files;
879 Glob(pat.c_str(), &files);
880 sort(files->begin(), files->end());
881 bool needs_regen = files->size() != static_cast<size_t>(num_files);
Colin Crosse5d75062015-08-31 17:15:02 -0700882 for (int j = 0; j < num_files; j++) {
883 LOAD_STRING(fp, &s);
884 if (!needs_regen) {
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900885 if ((*files)[j] != s) {
886 needs_regen = true;
887 break;
888 }
889 }
890 }
891 if (needs_regen) {
Shinichiro Hamajie67d54e2015-08-13 14:39:11 +0900892 if (ShouldIgnoreDirty(pat)) {
Shinichiro Hamajie3c43602015-08-13 13:47:27 +0900893 if (dump_kati_stamp) {
894 printf("wildcard %s: ignored\n", pat.c_str());
895 }
896 continue;
897 }
898 if (dump_kati_stamp) {
899 printf("wildcard %s: dirty\n", pat.c_str());
900 } else {
901 fprintf(stderr, "wildcard(%s) was changed, regenerating...\n",
902 pat.c_str());
903 }
904 RETURN_TRUE;
905 } else if (dump_kati_stamp) {
906 printf("wildcard %s: clean\n", pat.c_str());
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900907 }
Shinichiro Hamajia09ed282015-07-31 12:21:54 +0900908 }
909 }
910
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900911 int num_crs = LOAD_INT(fp);
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900912 for (int i = 0; i < num_crs; i++) {
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900913 string cmd, expected;
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900914 LOAD_STRING(fp, &cmd);
915 LOAD_STRING(fp, &expected);
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900916
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900917 {
918 COLLECT_STATS("stat time (regen)");
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900919 bool has_condition = LOAD_INT(fp);
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900920 if (has_condition) {
921 bool should_run_command = false;
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900922
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900923 int num_missing_dirs = LOAD_INT(fp);
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900924 for (int j = 0; j < num_missing_dirs; j++) {
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900925 LOAD_STRING(fp, &s);
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900926 should_run_command |= Exists(s);
927 }
928
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900929 int num_read_dirs = LOAD_INT(fp);
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900930 for (int j = 0; j < num_read_dirs; j++) {
Shinichiro Hamajiecababb2015-08-29 11:38:11 +0900931 LOAD_STRING(fp, &s);
Shinichiro Hamajif6671e42015-08-07 14:37:49 +0900932 // We assume we rarely do a significant change for the top
933 // directory which affects the results of find command.
Shinichiro Hamajie67d54e2015-08-13 14:39:11 +0900934 if (s == "" || s == "." || ShouldIgnoreDirty(s))
Shinichiro Hamajiede1f2f2015-08-07 14:24:44 +0900935 continue;
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900936 double ts = GetTimestamp(s);
937 should_run_command |= (ts < 0 || gen_time < ts);
938 }
939
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900940 if (!should_run_command) {
941 if (dump_kati_stamp)
942 printf("shell %s: clean (no rerun)\n", cmd.c_str());
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900943 continue;
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900944 }
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900945 }
Shinichiro Hamaji5a71a8b2015-08-06 19:23:18 +0900946 }
947
Shinichiro Hamajie67d54e2015-08-13 14:39:11 +0900948 FindCommand fc;
949 if (fc.Parse(cmd) && !fc.chdir.empty() && ShouldIgnoreDirty(fc.chdir)) {
950 if (dump_kati_stamp)
951 printf("shell %s: ignored\n", cmd.c_str());
952 continue;
953 }
954
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900955 {
956 COLLECT_STATS_WITH_SLOW_REPORT("shell time (regen)", cmd.c_str());
957 string result;
958 RunCommand("/bin/sh", cmd, RedirectStderr::DEV_NULL, &result);
959 FormatForCommandSubstitution(&result);
960 if (expected != result) {
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900961 if (dump_kati_stamp) {
962 printf("shell %s: dirty\n", cmd.c_str());
963 } else {
964 fprintf(stderr, "$(shell %s) was changed, regenerating...\n",
965 cmd.c_str());
966#if 0
967 fprintf(stderr, "%s => %s\n",
968 expected.c_str(), result.c_str());
969#endif
970 }
971 RETURN_TRUE;
972 } else if (dump_kati_stamp) {
973 printf("shell %s: clean (rerun)\n", cmd.c_str());
Shinichiro Hamajia8e903f2015-08-06 19:41:01 +0900974 }
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900975 }
976 }
977
Dan Willemsen87417412015-08-24 17:57:12 -0700978 LoadString(fp, &s);
979 if (orig_args != s) {
980 fprintf(stderr, "arguments changed, regenerating...\n");
981 RETURN_TRUE;
982 }
983
Shinichiro Hamaji90db5412015-08-13 15:03:52 +0900984 if (!retval) {
985 if (fseek(fp, 0, SEEK_SET) < 0)
986 PERROR("fseek");
987 size_t r = fwrite(&start_time, sizeof(start_time), 1, fp);
988 CHECK(r == 1);
989 }
990
Shinichiro Hamajif6df3342015-08-11 14:59:36 +0900991 return retval;
Shinichiro Hamajia4bb7742015-07-31 11:27:30 +0900992}