|
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 "graph.h" 00016 00017 #include <assert.h> 00018 #include <stdio.h> 00019 00020 #include "build_log.h" 00021 #include "disk_interface.h" 00022 #include "parsers.h" 00023 #include "state.h" 00024 #include "util.h" 00025 00026 bool FileStat::Stat(DiskInterface* disk_interface) { 00027 mtime_ = disk_interface->Stat(path_); 00028 return mtime_ > 0; 00029 } 00030 00031 bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface, 00032 string* err) { 00033 bool dirty = false; 00034 00035 if (!rule_->depfile_.empty()) { 00036 if (!LoadDepFile(state, disk_interface, err)) 00037 return false; 00038 } 00039 00040 outputs_ready_ = true; 00041 00042 time_t most_recent_input = 1; 00043 for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) { 00044 if ((*i)->file_->StatIfNecessary(disk_interface)) { 00045 if (Edge* edge = (*i)->in_edge_) { 00046 if (!edge->RecomputeDirty(state, disk_interface, err)) 00047 return false; 00048 } else { 00049 // This input has no in-edge; it is dirty if it is missing. 00050 (*i)->dirty_ = !(*i)->file_->exists(); 00051 } 00052 } 00053 00054 // If an input is not ready, neither are our outputs. 00055 if (Edge* edge = (*i)->in_edge_) 00056 if (!edge->outputs_ready_) 00057 outputs_ready_ = false; 00058 00059 if (!is_order_only(i - inputs_.begin())) { 00060 // If a regular input is dirty (or missing), we're dirty. 00061 // Otherwise consider mtime. 00062 if ((*i)->dirty_) { 00063 dirty = true; 00064 } else { 00065 if ((*i)->file_->mtime_ > most_recent_input) 00066 most_recent_input = (*i)->file_->mtime_; 00067 } 00068 } 00069 } 00070 00071 BuildLog* build_log = state ? state->build_log_ : 0; 00072 string command = EvaluateCommand(); 00073 00074 assert(!outputs_.empty()); 00075 for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) { 00076 // We may have other outputs that our input-recursive traversal hasn't hit 00077 // yet (or never will). Stat them if we haven't already to mark that we've 00078 // visited their dependents. 00079 (*i)->file_->StatIfNecessary(disk_interface); 00080 00081 RecomputeOutputDirty(build_log, most_recent_input, dirty, command, *i); 00082 if ((*i)->dirty_) 00083 outputs_ready_ = false; 00084 } 00085 00086 return true; 00087 } 00088 00089 void Edge::RecomputeOutputDirty(BuildLog* build_log, time_t most_recent_input, 00090 bool dirty, const string& command, 00091 Node* output) { 00092 if (is_phony()) { 00093 // Phony edges don't write any output. 00094 // They're only dirty if an input is dirty, or if there are no inputs 00095 // and we're missing the output. 00096 if (dirty) 00097 output->dirty_ = true; 00098 else if (inputs_.empty() && !output->file_->exists()) 00099 output->dirty_ = true; 00100 return; 00101 } 00102 00103 BuildLog::LogEntry* entry = 0; 00104 // Output is dirty if we're dirty, we're missing the output, 00105 // or if it's older than the most recent input mtime. 00106 if (dirty || !output->file_->exists()) { 00107 output->dirty_ = true; 00108 } else if (output->file_->mtime_ < most_recent_input) { 00109 // If this is a restat rule, we may have cleaned the output with a restat 00110 // rule in a previous run and stored the most recent input mtime in the 00111 // build log. Use that mtime instead, so that the file will only be 00112 // considered dirty if an input was modified since the previous run. 00113 if (rule_->restat_ && build_log && 00114 (entry = build_log->LookupByOutput(output->file_->path_))) { 00115 if (entry->restat_mtime < most_recent_input) 00116 output->dirty_ = true; 00117 } else { 00118 output->dirty_ = true; 00119 } 00120 } 00121 00122 if (!output->dirty_) { 00123 // May also be dirty due to the command changing since the last build. 00124 // But if this is a generator rule, the command changing does not make us 00125 // dirty. 00126 if (!rule_->generator_ && build_log && 00127 (entry || (entry = build_log->LookupByOutput(output->file_->path_)))) { 00128 if (command != entry->command) 00129 output->dirty_ = true; 00130 } 00131 } 00132 } 00133 00134 /// An Env for an Edge, providing $in and $out. 00135 struct EdgeEnv : public Env { 00136 EdgeEnv(Edge* edge) : edge_(edge) {} 00137 virtual string LookupVariable(const string& var) { 00138 string result; 00139 if (var == "in") { 00140 int explicit_deps = edge_->inputs_.size() - edge_->implicit_deps_ - 00141 edge_->order_only_deps_; 00142 for (vector<Node*>::iterator i = edge_->inputs_.begin(); 00143 i != edge_->inputs_.end() && explicit_deps; ++i, --explicit_deps) { 00144 if (!result.empty()) 00145 result.push_back(' '); 00146 result.append((*i)->file_->path_); 00147 } 00148 } else if (var == "out") { 00149 for (vector<Node*>::iterator i = edge_->outputs_.begin(); 00150 i != edge_->outputs_.end(); ++i) { 00151 if (!result.empty()) 00152 result.push_back(' '); 00153 result.append((*i)->file_->path_); 00154 } 00155 } else if (edge_->env_) { 00156 return edge_->env_->LookupVariable(var); 00157 } 00158 return result; 00159 } 00160 Edge* edge_; 00161 }; 00162 00163 string Edge::EvaluateCommand() { 00164 EdgeEnv env(this); 00165 return rule_->command_.Evaluate(&env); 00166 } 00167 00168 string Edge::GetDescription() { 00169 EdgeEnv env(this); 00170 return rule_->description_.Evaluate(&env); 00171 } 00172 00173 bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface, 00174 string* err) { 00175 EdgeEnv env(this); 00176 string path = rule_->depfile_.Evaluate(&env); 00177 00178 string content = disk_interface->ReadFile(path, err); 00179 if (!err->empty()) 00180 return false; 00181 if (content.empty()) 00182 return true; 00183 00184 MakefileParser makefile; 00185 string makefile_err; 00186 if (!makefile.Parse(content, &makefile_err)) { 00187 *err = path + ": " + makefile_err; 00188 return false; 00189 } 00190 00191 // Check that this depfile matches our output. 00192 StringPiece opath = StringPiece(outputs_[0]->file_->path_); 00193 if (opath != makefile.out_) { 00194 *err = "expected makefile to mention '" + outputs_[0]->file_->path_ + "', " 00195 "got '" + makefile.out_.AsString() + "'"; 00196 return false; 00197 } 00198 00199 inputs_.insert(inputs_.end() - order_only_deps_, makefile.ins_.size(), 0); 00200 implicit_deps_ += makefile.ins_.size(); 00201 vector<Node*>::iterator implicit_dep = 00202 inputs_.end() - order_only_deps_ - makefile.ins_.size(); 00203 00204 // Add all its in-edges. 00205 for (vector<StringPiece>::iterator i = makefile.ins_.begin(); 00206 i != makefile.ins_.end(); ++i, ++implicit_dep) { 00207 string path(i->str_, i->len_); 00208 if (!CanonicalizePath(&path, err)) 00209 return false; 00210 00211 Node* node = state->GetNode(path); 00212 *implicit_dep = node; 00213 node->out_edges_.push_back(this); 00214 00215 // If we don't have a edge that generates this input already, 00216 // create one; this makes us not abort if the input is missing, 00217 // but instead will rebuild in that circumstance. 00218 if (!node->in_edge_) { 00219 Edge* phony_edge = state->AddEdge(&State::kPhonyRule); 00220 node->in_edge_ = phony_edge; 00221 phony_edge->outputs_.push_back(node); 00222 00223 // RecomputeDirty might not be called for phony_edge if a previous call 00224 // to RecomputeDirty had caused the file to be stat'ed. Because previous 00225 // invocations of RecomputeDirty would have seen this node without an 00226 // input edge (and therefore ready), we have to set outputs_ready_ to true 00227 // to avoid a potential stuck build. If we do call RecomputeDirty for 00228 // this node, it will simply set outputs_ready_ to the correct value. 00229 phony_edge->outputs_ready_ = true; 00230 } 00231 } 00232 00233 return true; 00234 } 00235 00236 void Edge::Dump() { 00237 printf("[ "); 00238 for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) { 00239 printf("%s ", (*i)->file_->path_.c_str()); 00240 } 00241 printf("--%s-> ", rule_->name_.c_str()); 00242 for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) { 00243 printf("%s ", (*i)->file_->path_.c_str()); 00244 } 00245 printf("]\n"); 00246 } 00247 00248 bool Edge::is_phony() const { 00249 return rule_ == &State::kPhonyRule; 00250 }
1.7.5.1