1 // Copyright 2011 Google Inc. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "build_log.h"
23 // Canonicalize a path like "foo/../bar.h" into just "bar.h".
24 bool CanonicalizePath(string* path, string* err) {
25 // Try to fast-path out the common case.
26 if (path->find("/.") == string::npos &&
27 path->find("./") == string::npos) {
31 string inpath = *path;
32 vector<const char*> parts;
33 for (string::size_type start = 0; start < inpath.size(); ++start) {
34 string::size_type end = inpath.find('/', start);
35 if (end == string::npos)
39 parts.push_back(inpath.data() + start);
43 vector<const char*>::iterator i = parts.begin();
44 while (i != parts.end()) {
45 const char* part = *i;
51 } else if (part[1] == '.' && part[2] == 0) {
53 if (i == parts.begin()) {
54 *err = "can't canonicalize path '" + *path + "' that reaches "
55 "above its directory";
59 parts.erase(i, i + 2);
67 for (i = parts.begin(); i != parts.end(); ++i) {
76 bool FileStat::Stat(DiskInterface* disk_interface) {
77 mtime_ = disk_interface->Stat(path_);
81 bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
85 if (!rule_->depfile_.empty()) {
86 if (!LoadDepFile(state, disk_interface, err))
90 time_t most_recent_input = 1;
91 for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
92 if ((*i)->file_->StatIfNecessary(disk_interface)) {
93 if (Edge* edge = (*i)->in_edge_) {
94 if (!edge->RecomputeDirty(state, disk_interface, err))
97 // This input has no in-edge; it is dirty if it is missing.
98 // But it's ok for implicit deps to be missing.
99 if (!is_implicit(i - inputs_.begin()))
100 (*i)->dirty_ = !(*i)->file_->exists();
104 if (is_order_only(i - inputs_.begin())) {
105 // Order-only deps only make us dirty if they're missing.
106 if (!(*i)->file_->exists())
111 // If a regular input is dirty (or missing), we're dirty.
112 // Otherwise consider mtime.
116 if ((*i)->file_->mtime_ > most_recent_input)
117 most_recent_input = (*i)->file_->mtime_;
121 string command = EvaluateCommand();
123 assert(!outputs_.empty());
124 for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
125 // We may have other outputs, that our input-recursive traversal hasn't hit
126 // yet (or never will). Stat them if we haven't already.
127 (*i)->file_->StatIfNecessary(disk_interface);
129 // Output is dirty if we're dirty, we're missing the output,
130 // or if it's older than the most recent input mtime.
131 if (dirty || !(*i)->file_->exists() ||
132 (*i)->file_->mtime_ < most_recent_input) {
135 // May also be dirty due to the command changing since the last build.
136 BuildLog::LogEntry* entry;
137 if (state->build_log_ &&
138 (entry = state->build_log_->LookupByOutput((*i)->file_->path_))) {
139 if (command != entry->command)
147 struct EdgeEnv : public Env {
148 EdgeEnv(Edge* edge) : edge_(edge) {}
149 virtual string LookupVariable(const string& var) {
152 int explicit_deps = edge_->inputs_.size() - edge_->implicit_deps_ -
153 edge_->order_only_deps_;
154 for (vector<Node*>::iterator i = edge_->inputs_.begin();
155 i != edge_->inputs_.end() && explicit_deps; ++i, --explicit_deps) {
157 result.push_back(' ');
158 result.append((*i)->file_->path_);
160 } else if (var == "out") {
161 result = edge_->outputs_[0]->file_->path_;
162 } else if (edge_->env_) {
163 return edge_->env_->LookupVariable(var);
170 string Edge::EvaluateCommand() {
172 return rule_->command_.Evaluate(&env);
175 string Edge::GetDescription() {
177 return rule_->description_.Evaluate(&env);
180 bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface,
183 string path = rule_->depfile_.Evaluate(&env);
185 string content = disk_interface->ReadFile(path, err);
191 MakefileParser makefile;
193 if (!makefile.Parse(content, &makefile_err)) {
194 *err = path + ": " + makefile_err;
198 // Check that this depfile matches our output.
199 if (outputs_.size() != 1) {
200 *err = "expected only one output";
203 if (outputs_[0]->file_->path_ != makefile.out_) {
204 *err = "expected makefile to mention '" + outputs_[0]->file_->path_ + "', "
205 "got '" + makefile.out_ + "'";
209 // Add all its in-edges.
210 for (vector<string>::iterator i = makefile.ins_.begin();
211 i != makefile.ins_.end(); ++i) {
212 if (!CanonicalizePath(&*i, err))
215 Node* node = state->GetNode(*i);
216 inputs_.insert(inputs_.end() - order_only_deps_, node);
217 node->out_edges_.push_back(this);
226 for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
227 printf("%s ", (*i)->file_->path_.c_str());
229 printf("--%s-> ", rule_->name_.c_str());
230 for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
231 printf("%s ", (*i)->file_->path_.c_str());
236 bool Edge::is_phony() const {
237 return rule_ == &State::kPhonyRule;