|
Ninja
|
00001 // Copyright 2011 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include "build.h" 00016 00017 #include <assert.h> 00018 #include <stdio.h> 00019 00020 #ifdef _WIN32 00021 #include <windows.h> 00022 #else 00023 #include <sys/ioctl.h> 00024 #include <sys/time.h> 00025 #include <sys/termios.h> 00026 #endif 00027 00028 #include "build_log.h" 00029 #include "disk_interface.h" 00030 #include "graph.h" 00031 #include "state.h" 00032 #include "subprocess.h" 00033 #include "util.h" 00034 00035 /// Tracks the status of a build: completion fraction, printing updates. 00036 struct BuildStatus { 00037 BuildStatus(const BuildConfig& config); 00038 void PlanHasTotalEdges(int total); 00039 void BuildEdgeStarted(Edge* edge); 00040 void BuildEdgeFinished(Edge* edge, bool success, const string& output, 00041 int* start_time, int* end_time); 00042 00043 private: 00044 void PrintStatus(Edge* edge); 00045 00046 const BuildConfig& config_; 00047 00048 /// Time the build started. 00049 int64_t start_time_millis_; 00050 /// Time we last printed an update. 00051 int64_t last_update_millis_; 00052 00053 int started_edges_, finished_edges_, total_edges_; 00054 00055 /// Map of running edge to time the edge started running. 00056 typedef map<Edge*, int> RunningEdgeMap; 00057 RunningEdgeMap running_edges_; 00058 00059 /// Whether we can do fancy terminal control codes. 00060 bool smart_terminal_; 00061 }; 00062 00063 BuildStatus::BuildStatus(const BuildConfig& config) 00064 : config_(config), 00065 start_time_millis_(GetTimeMillis()), 00066 last_update_millis_(start_time_millis_), 00067 started_edges_(0), finished_edges_(0), total_edges_(0) { 00068 #ifndef WIN32 00069 const char* term = getenv("TERM"); 00070 smart_terminal_ = isatty(1) && term && string(term) != "dumb"; 00071 #else 00072 smart_terminal_ = false; 00073 #endif 00074 00075 // Don't do anything fancy in verbose mode. 00076 if (config_.verbosity != BuildConfig::NORMAL) 00077 smart_terminal_ = false; 00078 } 00079 00080 void BuildStatus::PlanHasTotalEdges(int total) { 00081 total_edges_ = total; 00082 } 00083 00084 void BuildStatus::BuildEdgeStarted(Edge* edge) { 00085 int start_time = (int)(GetTimeMillis() - start_time_millis_); 00086 running_edges_.insert(make_pair(edge, start_time)); 00087 ++started_edges_; 00088 00089 PrintStatus(edge); 00090 } 00091 00092 void BuildStatus::BuildEdgeFinished(Edge* edge, 00093 bool success, 00094 const string& output, 00095 int* start_time, 00096 int* end_time) { 00097 int64_t now = GetTimeMillis(); 00098 ++finished_edges_; 00099 00100 RunningEdgeMap::iterator i = running_edges_.find(edge); 00101 *start_time = i->second; 00102 *end_time = (int)(now - start_time_millis_); 00103 int total_time = end_time - start_time; 00104 running_edges_.erase(i); 00105 00106 if (config_.verbosity == BuildConfig::QUIET) 00107 return; 00108 00109 if (smart_terminal_) 00110 PrintStatus(edge); 00111 00112 if (success && output.empty()) { 00113 if (smart_terminal_) { 00114 if (finished_edges_ == total_edges_) 00115 printf("\n"); 00116 } else { 00117 if (total_time > 5*1000) { 00118 printf("%.1f%% %d/%d\n", finished_edges_ * 100 / (float)total_edges_, 00119 finished_edges_, total_edges_); 00120 last_update_millis_ = now; 00121 } 00122 } 00123 } else { 00124 if (smart_terminal_) 00125 printf("\n"); 00126 00127 // Print the command that is spewing before printing its output. 00128 if (!success) 00129 printf("FAILED: %s\n", edge->EvaluateCommand().c_str()); 00130 00131 if (!output.empty()) 00132 printf("%s", output.c_str()); 00133 } 00134 } 00135 00136 void BuildStatus::PrintStatus(Edge* edge) { 00137 if (config_.verbosity == BuildConfig::QUIET) 00138 return; 00139 00140 bool force_full_command = config_.verbosity == BuildConfig::VERBOSE; 00141 00142 string to_print = edge->GetDescription(); 00143 if (to_print.empty() || force_full_command) 00144 to_print = edge->EvaluateCommand(); 00145 00146 if (smart_terminal_) 00147 printf("\r"); // Print over previous line, if any. 00148 00149 int progress_chars = printf("[%d/%d] ", started_edges_, total_edges_); 00150 00151 #ifndef WIN32 00152 if (smart_terminal_ && !force_full_command) { 00153 // Limit output to width of the terminal if provided so we don't cause 00154 // line-wrapping. 00155 winsize size; 00156 if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) { 00157 const int kMargin = progress_chars + 3; // Space for [xx/yy] and "...". 00158 if (to_print.size() + kMargin > size.ws_col) { 00159 int elide_size = (size.ws_col - kMargin) / 2; 00160 to_print = to_print.substr(0, elide_size) 00161 + "..." 00162 + to_print.substr(to_print.size() - elide_size, elide_size); 00163 } 00164 } 00165 } 00166 #endif 00167 00168 printf("%s", to_print.c_str()); 00169 00170 if (smart_terminal_ && !force_full_command) { 00171 printf("\e[K"); // Clear to end of line. 00172 fflush(stdout); 00173 } else { 00174 printf("\n"); 00175 } 00176 } 00177 00178 Plan::Plan() : command_edges_(0), wanted_edges_(0) {} 00179 00180 bool Plan::AddTarget(Node* node, string* err) { 00181 vector<Node*> stack; 00182 return AddSubTarget(node, &stack, err); 00183 } 00184 00185 bool Plan::AddSubTarget(Node* node, vector<Node*>* stack, string* err) { 00186 Edge* edge = node->in_edge_; 00187 if (!edge) { // Leaf node. 00188 if (node->dirty_) { 00189 string referenced; 00190 if (!stack->empty()) 00191 referenced = ", needed by '" + stack->back()->file_->path_ + "',"; 00192 *err = "'" + node->file_->path_ + "'" + referenced + " missing " 00193 "and no known rule to make it"; 00194 } 00195 return false; 00196 } 00197 assert(edge); 00198 00199 if (CheckDependencyCycle(node, stack, err)) 00200 return false; 00201 00202 if (edge->outputs_ready()) 00203 return false; // Don't need to do anything. 00204 00205 // If an entry in want_ does not already exist for edge, create an entry which 00206 // maps to false, indicating that we do not want to build this entry itself. 00207 pair<map<Edge*, bool>::iterator, bool> want_ins = 00208 want_.insert(make_pair(edge, false)); 00209 bool& want = want_ins.first->second; 00210 00211 // If we do need to build edge and we haven't already marked it as wanted, 00212 // mark it now. 00213 if (node->dirty() && !want) { 00214 want = true; 00215 ++wanted_edges_; 00216 if (find_if(edge->inputs_.begin(), edge->inputs_.end(), 00217 not1(mem_fun(&Node::ready))) == edge->inputs_.end()) 00218 ready_.insert(edge); 00219 if (!edge->is_phony()) 00220 ++command_edges_; 00221 } 00222 00223 if (!want_ins.second) 00224 return true; // We've already processed the inputs. 00225 00226 stack->push_back(node); 00227 for (vector<Node*>::iterator i = edge->inputs_.begin(); 00228 i != edge->inputs_.end(); ++i) { 00229 if (!AddSubTarget(*i, stack, err) && !err->empty()) 00230 return false; 00231 } 00232 assert(stack->back() == node); 00233 stack->pop_back(); 00234 00235 return true; 00236 } 00237 00238 bool Plan::CheckDependencyCycle(Node* node, vector<Node*>* stack, string* err) { 00239 vector<Node*>::reverse_iterator ri = 00240 find(stack->rbegin(), stack->rend(), node); 00241 if (ri == stack->rend()) 00242 return false; 00243 00244 // Add this node onto the stack to make it clearer where the loop 00245 // is. 00246 stack->push_back(node); 00247 00248 vector<Node*>::iterator start = find(stack->begin(), stack->end(), node); 00249 *err = "dependency cycle: "; 00250 for (vector<Node*>::iterator i = start; i != stack->end(); ++i) { 00251 if (i != start) 00252 err->append(" -> "); 00253 err->append((*i)->file_->path_); 00254 } 00255 return true; 00256 } 00257 00258 Edge* Plan::FindWork() { 00259 if (ready_.empty()) 00260 return NULL; 00261 set<Edge*>::iterator i = ready_.begin(); 00262 Edge* edge = *i; 00263 ready_.erase(i); 00264 return edge; 00265 } 00266 00267 void Plan::EdgeFinished(Edge* edge) { 00268 map<Edge*, bool>::iterator i = want_.find(edge); 00269 assert(i != want_.end()); 00270 if (i->second) 00271 --wanted_edges_; 00272 want_.erase(i); 00273 edge->outputs_ready_ = true; 00274 00275 // Check off any nodes we were waiting for with this edge. 00276 for (vector<Node*>::iterator i = edge->outputs_.begin(); 00277 i != edge->outputs_.end(); ++i) { 00278 NodeFinished(*i); 00279 } 00280 } 00281 00282 void Plan::NodeFinished(Node* node) { 00283 // See if we we want any edges from this node. 00284 for (vector<Edge*>::iterator i = node->out_edges_.begin(); 00285 i != node->out_edges_.end(); ++i) { 00286 map<Edge*, bool>::iterator want_i = want_.find(*i); 00287 if (want_i == want_.end()) 00288 continue; 00289 00290 // See if the edge is now ready. 00291 if (find_if((*i)->inputs_.begin(), (*i)->inputs_.end(), 00292 not1(mem_fun(&Node::ready))) == (*i)->inputs_.end()) { 00293 if (want_i->second) { 00294 ready_.insert(*i); 00295 } else { 00296 // We do not need to build this edge, but we might need to build one of 00297 // its dependents. 00298 EdgeFinished(*i); 00299 } 00300 } 00301 } 00302 } 00303 00304 void Plan::CleanNode(BuildLog* build_log, Node* node) { 00305 node->dirty_ = false; 00306 00307 for (vector<Edge*>::iterator ei = node->out_edges_.begin(); 00308 ei != node->out_edges_.end(); ++ei) { 00309 // Don't process edges that we don't actually want. 00310 map<Edge*, bool>::iterator want_i = want_.find(*ei); 00311 if (want_i == want_.end() || !want_i->second) 00312 continue; 00313 00314 // If all non-order-only inputs for this edge are now clean, 00315 // we might have changed the dirty state of the outputs. 00316 vector<Node*>::iterator begin = (*ei)->inputs_.begin(), 00317 end = (*ei)->inputs_.end() - (*ei)->order_only_deps_; 00318 if (find_if(begin, end, mem_fun(&Node::dirty)) == end) { 00319 // Recompute most_recent_input and command. 00320 time_t most_recent_input = 1; 00321 for (vector<Node*>::iterator ni = begin; ni != end; ++ni) 00322 if ((*ni)->file_->mtime_ > most_recent_input) 00323 most_recent_input = (*ni)->file_->mtime_; 00324 string command = (*ei)->EvaluateCommand(); 00325 00326 // Now, recompute the dirty state of each output. 00327 bool all_outputs_clean = true; 00328 for (vector<Node*>::iterator ni = (*ei)->outputs_.begin(); 00329 ni != (*ei)->outputs_.end(); ++ni) { 00330 if (!(*ni)->dirty_) 00331 continue; 00332 00333 // RecomputeOutputDirty will not modify dirty_ if the output is clean. 00334 (*ni)->dirty_ = false; 00335 00336 // Since we know that all non-order-only inputs are clean, we can pass 00337 // "false" as the "dirty" argument here. 00338 (*ei)->RecomputeOutputDirty(build_log, most_recent_input, false, 00339 command, *ni); 00340 if ((*ni)->dirty_) { 00341 all_outputs_clean = false; 00342 } else { 00343 CleanNode(build_log, *ni); 00344 } 00345 } 00346 00347 // If we cleaned all outputs, mark the node as not wanted. 00348 if (all_outputs_clean) { 00349 want_i->second = false; 00350 --wanted_edges_; 00351 if (!(*ei)->is_phony()) 00352 --command_edges_; 00353 } 00354 } 00355 } 00356 } 00357 00358 void Plan::Dump() { 00359 printf("pending: %d\n", (int)want_.size()); 00360 for (map<Edge*, bool>::iterator i = want_.begin(); i != want_.end(); ++i) { 00361 if (i->second) 00362 printf("want "); 00363 i->first->Dump(); 00364 } 00365 printf("ready: %d\n", (int)ready_.size()); 00366 } 00367 00368 struct RealCommandRunner : public CommandRunner { 00369 RealCommandRunner(const BuildConfig& config) : config_(config) {} 00370 virtual ~RealCommandRunner() {} 00371 virtual bool CanRunMore(); 00372 virtual bool StartCommand(Edge* edge); 00373 virtual Edge* WaitForCommand(bool* success, string* output); 00374 00375 const BuildConfig& config_; 00376 SubprocessSet subprocs_; 00377 map<Subprocess*, Edge*> subproc_to_edge_; 00378 }; 00379 00380 bool RealCommandRunner::CanRunMore() { 00381 return ((int)subprocs_.running_.size()) < config_.parallelism; 00382 } 00383 00384 bool RealCommandRunner::StartCommand(Edge* edge) { 00385 string command = edge->EvaluateCommand(); 00386 Subprocess* subproc = new Subprocess; 00387 subproc_to_edge_.insert(make_pair(subproc, edge)); 00388 if (!subproc->Start(&subprocs_, command)) 00389 return false; 00390 00391 subprocs_.Add(subproc); 00392 return true; 00393 } 00394 00395 Edge* RealCommandRunner::WaitForCommand(bool* success, string* output) { 00396 Subprocess* subproc; 00397 while ((subproc = subprocs_.NextFinished()) == NULL) { 00398 subprocs_.DoWork(); 00399 } 00400 00401 *success = subproc->Finish(); 00402 *output = subproc->GetOutput(); 00403 00404 map<Subprocess*, Edge*>::iterator i = subproc_to_edge_.find(subproc); 00405 Edge* edge = i->second; 00406 subproc_to_edge_.erase(i); 00407 00408 delete subproc; 00409 return edge; 00410 } 00411 00412 /// A CommandRunner that doesn't actually run the commands. 00413 struct DryRunCommandRunner : public CommandRunner { 00414 virtual ~DryRunCommandRunner() {} 00415 virtual bool CanRunMore() { 00416 return true; 00417 } 00418 virtual bool StartCommand(Edge* edge) { 00419 finished_.push(edge); 00420 return true; 00421 } 00422 virtual Edge* WaitForCommand(bool* success, string* output) { 00423 if (finished_.empty()) 00424 return NULL; 00425 *success = true; 00426 Edge* edge = finished_.front(); 00427 finished_.pop(); 00428 return edge; 00429 } 00430 00431 queue<Edge*> finished_; 00432 }; 00433 00434 Builder::Builder(State* state, const BuildConfig& config) 00435 : state_(state), config_(config) { 00436 disk_interface_ = new RealDiskInterface; 00437 if (config.dry_run) 00438 command_runner_ = new DryRunCommandRunner; 00439 else 00440 command_runner_ = new RealCommandRunner(config); 00441 status_ = new BuildStatus(config); 00442 log_ = state->build_log_; 00443 } 00444 00445 Node* Builder::AddTarget(const string& name, string* err) { 00446 Node* node = state_->LookupNode(name); 00447 if (!node) { 00448 *err = "unknown target: '" + name + "'"; 00449 return NULL; 00450 } 00451 if (!AddTarget(node, err)) 00452 return NULL; 00453 return node; 00454 } 00455 00456 bool Builder::AddTarget(Node* node, string* err) { 00457 node->file_->StatIfNecessary(disk_interface_); 00458 if (Edge* in_edge = node->in_edge_) { 00459 if (!in_edge->RecomputeDirty(state_, disk_interface_, err)) 00460 return false; 00461 if (in_edge->outputs_ready()) 00462 return true; // Nothing to do. 00463 } 00464 00465 if (!plan_.AddTarget(node, err)) 00466 return false; 00467 00468 return true; 00469 } 00470 00471 bool Builder::AlreadyUpToDate() const { 00472 return !plan_.more_to_do(); 00473 } 00474 00475 bool Builder::Build(string* err) { 00476 assert(!AlreadyUpToDate()); 00477 00478 status_->PlanHasTotalEdges(plan_.command_edge_count()); 00479 int pending_commands = 0; 00480 int failures_allowed = config_.swallow_failures; 00481 00482 // This main loop runs the entire build process. 00483 // It is structured like this: 00484 // First, we attempt to start as many commands as allowed by the 00485 // command runner. 00486 // Second, we attempt to wait for / reap the next finished command. 00487 // If we can do neither of those, the build is stuck, and we report 00488 // an error. 00489 while (plan_.more_to_do()) { 00490 // See if we can start any more commands. 00491 if (command_runner_->CanRunMore()) { 00492 if (Edge* edge = plan_.FindWork()) { 00493 if (!StartEdge(edge, err)) 00494 return false; 00495 00496 if (edge->is_phony()) 00497 FinishEdge(edge, true, ""); 00498 else 00499 ++pending_commands; 00500 00501 // We made some progress; go back to the main loop. 00502 continue; 00503 } 00504 } 00505 00506 // See if we can reap any finished commands. 00507 if (pending_commands) { 00508 bool success; 00509 string output; 00510 Edge* edge; 00511 if ((edge = command_runner_->WaitForCommand(&success, &output))) { 00512 --pending_commands; 00513 FinishEdge(edge, success, output); 00514 if (!success) { 00515 if (failures_allowed-- == 0) { 00516 if (config_.swallow_failures != 0) 00517 *err = "subcommands failed"; 00518 else 00519 *err = "subcommand failed"; 00520 return false; 00521 } 00522 } 00523 00524 // We made some progress; start the main loop over. 00525 continue; 00526 } 00527 } 00528 00529 // If we get here, we can neither enqueue new commands nor are any running. 00530 if (pending_commands) { 00531 *err = "stuck: pending commands but none to wait for? [this is a bug]"; 00532 return false; 00533 } 00534 00535 // If we get here, we cannot make any more progress. 00536 if (failures_allowed < config_.swallow_failures) { 00537 *err = "cannot make progress due to previous errors"; 00538 return false; 00539 } else { 00540 *err = "stuck [this is a bug]"; 00541 return false; 00542 } 00543 } 00544 00545 return true; 00546 } 00547 00548 bool Builder::StartEdge(Edge* edge, string* err) { 00549 if (edge->is_phony()) 00550 return true; 00551 00552 status_->BuildEdgeStarted(edge); 00553 00554 // Create directories necessary for outputs. 00555 // XXX: this will block; do we care? 00556 for (vector<Node*>::iterator i = edge->outputs_.begin(); 00557 i != edge->outputs_.end(); ++i) { 00558 if (!disk_interface_->MakeDirs((*i)->file_->path_)) 00559 return false; 00560 } 00561 00562 // Compute command and start it. 00563 string command = edge->EvaluateCommand(); 00564 if (!command_runner_->StartCommand(edge)) { 00565 err->assign("command '" + command + "' failed."); 00566 return false; 00567 } 00568 00569 return true; 00570 } 00571 00572 void Builder::FinishEdge(Edge* edge, bool success, const string& output) { 00573 time_t restat_mtime = 0; 00574 00575 if (success) { 00576 if (edge->rule_->restat_) { 00577 bool node_cleaned = false; 00578 00579 for (vector<Node*>::iterator i = edge->outputs_.begin(); 00580 i != edge->outputs_.end(); ++i) { 00581 if ((*i)->file_->exists()) { 00582 time_t new_mtime = disk_interface_->Stat((*i)->file_->path_); 00583 if ((*i)->file_->mtime_ == new_mtime) { 00584 // The rule command did not change the output. Propagate the clean 00585 // state through the build graph. 00586 plan_.CleanNode(log_, *i); 00587 node_cleaned = true; 00588 } 00589 } 00590 } 00591 00592 if (node_cleaned) { 00593 // If any output was cleaned, find the most recent mtime of any 00594 // (existing) non-order-only input. 00595 for (vector<Node*>::iterator i = edge->inputs_.begin(); 00596 i != edge->inputs_.end() - edge->order_only_deps_; ++i) { 00597 time_t input_mtime = disk_interface_->Stat((*i)->file_->path_); 00598 if (input_mtime == 0) { 00599 restat_mtime = 0; 00600 break; 00601 } 00602 if (input_mtime > restat_mtime) 00603 restat_mtime = input_mtime; 00604 } 00605 00606 // The total number of edges in the plan may have changed as a result 00607 // of a restat. 00608 status_->PlanHasTotalEdges(plan_.command_edge_count()); 00609 } 00610 } 00611 00612 plan_.EdgeFinished(edge); 00613 } 00614 00615 if (edge->is_phony()) 00616 return; 00617 00618 int start_time, end_time; 00619 status_->BuildEdgeFinished(edge, success, output, &start_time, &end_time); 00620 if (success && log_) 00621 log_->RecordCommand(edge, start_time, end_time, restat_mtime); 00622 }
1.7.5.1