1 // 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 <limits.h> 18 #include <signal.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <time.h> 23 #include <unistd.h> 24 25 #include "affinity.h" 26 #include "dep.h" 27 #include "eval.h" 28 #include "exec.h" 29 #include "file.h" 30 #include "file_cache.h" 31 #include "fileutil.h" 32 #include "find.h" 33 #include "flags.h" 34 #include "func.h" 35 #include "log.h" 36 #include "ninja.h" 37 #include "parser.h" 38 #include "regen.h" 39 #include "stats.h" 40 #include "stmt.h" 41 #include "string_piece.h" 42 #include "stringprintf.h" 43 #include "strutil.h" 44 #include "symtab.h" 45 #include "timeutil.h" 46 #include "var.h" 47 48 // We know that there are leaks in Kati. Turn off LeakSanitizer by default. 49 extern "C" const char* __asan_default_options() { 50 return "detect_leaks=0:allow_user_segv_handler=1"; 51 } 52 53 static void Init() { 54 InitSymtab(); 55 InitFuncTable(); 56 InitDepNodePool(); 57 InitParser(); 58 } 59 60 static void Quit() { 61 ReportAllStats(); 62 63 QuitParser(); 64 QuitDepNodePool(); 65 QuitFuncTable(); 66 QuitSymtab(); 67 } 68 69 static void ReadBootstrapMakefile(const vector<Symbol>& targets, 70 vector<Stmt*>* stmts) { 71 string bootstrap = 72 ("CC?=cc\n" 73 #if defined(__APPLE__) 74 "CXX?=c++\n" 75 #else 76 "CXX?=g++\n" 77 #endif 78 "AR?=ar\n" 79 // Pretend to be GNU make 3.81, for compatibility. 80 "MAKE_VERSION?=3.81\n" 81 "KATI?=ckati\n" 82 // Overwrite $SHELL environment variable. 83 "SHELL=/bin/sh\n" 84 // TODO: Add more builtin vars. 85 86 // http://www.gnu.org/software/make/manual/make.html#Catalogue-of-Rules 87 // The document above is actually not correct. See default.c: 88 // http://git.savannah.gnu.org/cgit/make.git/tree/default.c?id=4.1 89 ".c.o:\n" 90 "\t$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<\n" 91 ".cc.o:\n" 92 "\t$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<\n" 93 // TODO: Add more builtin rules. 94 ); 95 if (g_flags.generate_ninja) { 96 bootstrap += StringPrintf("MAKE?=make -j%d\n", 97 g_flags.num_jobs <= 1 ? 1 : g_flags.num_jobs / 2); 98 } else { 99 bootstrap += StringPrintf("MAKE?=%s\n", 100 JoinStrings(g_flags.subkati_args, " ").c_str()); 101 } 102 bootstrap += 103 StringPrintf("MAKECMDGOALS?=%s\n", JoinSymbols(targets, " ").c_str()); 104 105 char cwd[PATH_MAX]; 106 if (!getcwd(cwd, PATH_MAX)) { 107 fprintf(stderr, "getcwd failed\n"); 108 CHECK(false); 109 } 110 bootstrap += StringPrintf("CURDIR:=%s\n", cwd); 111 Parse(Intern(bootstrap).str(), Loc("*bootstrap*", 0), stmts); 112 } 113 114 static void SetVar(StringPiece l, VarOrigin origin) { 115 size_t found = l.find('='); 116 CHECK(found != string::npos); 117 Symbol lhs = Intern(l.substr(0, found)); 118 StringPiece rhs = l.substr(found + 1); 119 lhs.SetGlobalVar( 120 new RecursiveVar(NewLiteral(rhs.data()), origin, rhs.data())); 121 } 122 123 extern "C" char** environ; 124 125 class SegfaultHandler { 126 public: 127 explicit SegfaultHandler(Evaluator* ev); 128 ~SegfaultHandler(); 129 130 void handle(int, siginfo_t*, void*); 131 132 private: 133 static SegfaultHandler* global_handler; 134 135 void dumpstr(const char* s) const { 136 (void)write(STDERR_FILENO, s, strlen(s)); 137 } 138 void dumpint(int i) const { 139 char buf[11]; 140 char* ptr = buf + sizeof(buf) - 1; 141 142 if (i < 0) { 143 i = -i; 144 dumpstr("-"); 145 } else if (i == 0) { 146 dumpstr("0"); 147 return; 148 } 149 150 *ptr = '\0'; 151 while (ptr > buf && i > 0) { 152 *--ptr = '0' + (i % 10); 153 i = i / 10; 154 } 155 156 dumpstr(ptr); 157 } 158 159 Evaluator* ev_; 160 161 struct sigaction orig_action_; 162 struct sigaction new_action_; 163 }; 164 165 SegfaultHandler* SegfaultHandler::global_handler = nullptr; 166 167 SegfaultHandler::SegfaultHandler(Evaluator* ev) : ev_(ev) { 168 CHECK(global_handler == nullptr); 169 global_handler = this; 170 171 // Construct an alternate stack, so that we can handle stack overflows. 172 stack_t ss; 173 ss.ss_sp = malloc(SIGSTKSZ * 2); 174 CHECK(ss.ss_sp != nullptr); 175 ss.ss_size = SIGSTKSZ * 2; 176 ss.ss_flags = 0; 177 if (sigaltstack(&ss, nullptr) == -1) { 178 PERROR("sigaltstack"); 179 } 180 181 // Register our segfault handler using the alternate stack, falling 182 // back to the default handler. 183 sigemptyset(&new_action_.sa_mask); 184 new_action_.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESETHAND; 185 new_action_.sa_sigaction = [](int sig, siginfo_t* info, void* context) { 186 if (global_handler != nullptr) { 187 global_handler->handle(sig, info, context); 188 } 189 190 raise(SIGSEGV); 191 }; 192 sigaction(SIGSEGV, &new_action_, &orig_action_); 193 } 194 195 void SegfaultHandler::handle(int sig, siginfo_t* info, void* context) { 196 // Avoid fprintf in case it allocates or tries to do anything else that may 197 // hang. 198 dumpstr("*kati*: Segmentation fault, last evaluated line was "); 199 dumpstr(ev_->loc().filename); 200 dumpstr(":"); 201 dumpint(ev_->loc().lineno); 202 dumpstr("\n"); 203 204 // Run the original handler, in case we've been preloaded with libSegFault 205 // or similar. 206 if (orig_action_.sa_sigaction != nullptr) { 207 orig_action_.sa_sigaction(sig, info, context); 208 } 209 } 210 211 SegfaultHandler::~SegfaultHandler() { 212 sigaction(SIGSEGV, &orig_action_, nullptr); 213 global_handler = nullptr; 214 } 215 216 static int Run(const vector<Symbol>& targets, 217 const vector<StringPiece>& cl_vars, 218 const string& orig_args) { 219 double start_time = GetTime(); 220 221 if (g_flags.generate_ninja && (g_flags.regen || g_flags.dump_kati_stamp)) { 222 ScopedTimeReporter tr("regen check time"); 223 if (!NeedsRegen(start_time, orig_args)) { 224 fprintf(stderr, "No need to regenerate ninja file\n"); 225 return 0; 226 } 227 if (g_flags.dump_kati_stamp) { 228 printf("Need to regenerate ninja file\n"); 229 return 0; 230 } 231 ClearGlobCache(); 232 } 233 234 SetAffinityForSingleThread(); 235 236 MakefileCacheManager* cache_mgr = NewMakefileCacheManager(); 237 238 Intern("MAKEFILE_LIST") 239 .SetGlobalVar(new SimpleVar(StringPrintf(" %s", g_flags.makefile), 240 VarOrigin::FILE)); 241 for (char** p = environ; *p; p++) { 242 SetVar(*p, VarOrigin::ENVIRONMENT); 243 } 244 unique_ptr<Evaluator> ev(new Evaluator()); 245 SegfaultHandler segfault(ev.get()); 246 247 vector<Stmt*> bootstrap_asts; 248 ReadBootstrapMakefile(targets, &bootstrap_asts); 249 ev->set_is_bootstrap(true); 250 for (Stmt* stmt : bootstrap_asts) { 251 LOG("%s", stmt->DebugString().c_str()); 252 stmt->Eval(ev.get()); 253 } 254 ev->set_is_bootstrap(false); 255 256 ev->set_is_commandline(true); 257 for (StringPiece l : cl_vars) { 258 vector<Stmt*> asts; 259 Parse(Intern(l).str(), Loc("*bootstrap*", 0), &asts); 260 CHECK(asts.size() == 1); 261 asts[0]->Eval(ev.get()); 262 } 263 ev->set_is_commandline(false); 264 265 { 266 ScopedTimeReporter tr("eval time"); 267 Makefile* mk = cache_mgr->ReadMakefile(g_flags.makefile); 268 for (Stmt* stmt : mk->stmts()) { 269 LOG("%s", stmt->DebugString().c_str()); 270 stmt->Eval(ev.get()); 271 } 272 } 273 274 for (ParseErrorStmt* err : GetParseErrors()) { 275 WARN_LOC(err->loc(), "warning for parse error in an unevaluated line: %s", 276 err->msg.c_str()); 277 } 278 279 vector<DepNode*> nodes; 280 { 281 ScopedTimeReporter tr("make dep time"); 282 MakeDep(ev.get(), ev->rules(), ev->rule_vars(), targets, &nodes); 283 } 284 285 if (g_flags.is_syntax_check_only) 286 return 0; 287 288 if (g_flags.generate_ninja) { 289 ScopedTimeReporter tr("generate ninja time"); 290 GenerateNinja(nodes, ev.get(), orig_args, start_time); 291 ev->DumpStackStats(); 292 return 0; 293 } 294 295 for (const auto& p : ev->exports()) { 296 const Symbol name = p.first; 297 if (p.second) { 298 Var* v = ev->LookupVar(name); 299 const string&& value = v->Eval(ev.get()); 300 LOG("setenv(%s, %s)", name.c_str(), value.c_str()); 301 setenv(name.c_str(), value.c_str(), 1); 302 } else { 303 LOG("unsetenv(%s)", name.c_str()); 304 unsetenv(name.c_str()); 305 } 306 } 307 308 { 309 ScopedTimeReporter tr("exec time"); 310 Exec(nodes, ev.get()); 311 } 312 313 ev->DumpStackStats(); 314 315 for (Stmt* stmt : bootstrap_asts) 316 delete stmt; 317 delete cache_mgr; 318 319 return 0; 320 } 321 322 static void FindFirstMakefie() { 323 if (g_flags.makefile != NULL) 324 return; 325 if (Exists("GNUmakefile")) { 326 g_flags.makefile = "GNUmakefile"; 327 #if !defined(__APPLE__) 328 } else if (Exists("makefile")) { 329 g_flags.makefile = "makefile"; 330 #endif 331 } else if (Exists("Makefile")) { 332 g_flags.makefile = "Makefile"; 333 } 334 } 335 336 static void HandleRealpath(int argc, char** argv) { 337 char buf[PATH_MAX]; 338 for (int i = 0; i < argc; i++) { 339 if (realpath(argv[i], buf)) 340 printf("%s\n", buf); 341 } 342 } 343 344 int main(int argc, char* argv[]) { 345 if (argc >= 2 && !strcmp(argv[1], "--realpath")) { 346 HandleRealpath(argc - 2, argv + 2); 347 return 0; 348 } 349 Init(); 350 string orig_args; 351 for (int i = 0; i < argc; i++) { 352 if (i) 353 orig_args += ' '; 354 orig_args += argv[i]; 355 } 356 g_flags.Parse(argc, argv); 357 FindFirstMakefie(); 358 if (g_flags.makefile == NULL) 359 ERROR("*** No targets specified and no makefile found."); 360 // This depends on command line flags. 361 if (g_flags.use_find_emulator) 362 InitFindEmulator(); 363 int r = Run(g_flags.targets, g_flags.cl_vars, orig_args); 364 Quit(); 365 return r; 366 } 367