Ninja
clean.cc
Go to the documentation of this file.
1 // Copyright 2011 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 #include "clean.h"
16 
17 #include <assert.h>
18 #include <stdio.h>
19 
20 #include "disk_interface.h"
21 #include "graph.h"
22 #include "state.h"
23 #include "util.h"
24 
25 Cleaner::Cleaner(State* state, const BuildConfig& config)
26  : state_(state),
27  config_(config),
28  removed_(),
29  cleaned_(),
30  cleaned_files_count_(0),
31  disk_interface_(new RealDiskInterface),
32  status_(0) {
33 }
34 
36  const BuildConfig& config,
37  DiskInterface* disk_interface)
38  : state_(state),
39  config_(config),
40  removed_(),
41  cleaned_(),
42  cleaned_files_count_(0),
43  disk_interface_(disk_interface),
44  status_(0) {
45 }
46 
47 int Cleaner::RemoveFile(const string& path) {
48  return disk_interface_->RemoveFile(path);
49 }
50 
51 bool Cleaner::FileExists(const string& path) {
52  string err;
53  TimeStamp mtime = disk_interface_->Stat(path, &err);
54  if (mtime == -1)
55  Error("%s", err.c_str());
56  return mtime > 0; // Treat Stat() errors as "file does not exist".
57 }
58 
59 void Cleaner::Report(const string& path) {
61  if (IsVerbose())
62  printf("Remove %s\n", path.c_str());
63 }
64 
65 void Cleaner::Remove(const string& path) {
66  if (!IsAlreadyRemoved(path)) {
67  removed_.insert(path);
68  if (config_.dry_run) {
69  if (FileExists(path))
70  Report(path);
71  } else {
72  int ret = RemoveFile(path);
73  if (ret == 0)
74  Report(path);
75  else if (ret == -1)
76  status_ = 1;
77  }
78  }
79 }
80 
81 bool Cleaner::IsAlreadyRemoved(const string& path) {
82  set<string>::iterator i = removed_.find(path);
83  return (i != removed_.end());
84 }
85 
87  string depfile = edge->GetUnescapedDepfile();
88  if (!depfile.empty())
89  Remove(depfile);
90 
91  string rspfile = edge->GetUnescapedRspfile();
92  if (!rspfile.empty())
93  Remove(rspfile);
94 }
95 
98  return;
99  printf("Cleaning...");
100  if (IsVerbose())
101  printf("\n");
102  else
103  printf(" ");
104 }
105 
108  return;
109  printf("%d files.\n", cleaned_files_count_);
110 }
111 
112 int Cleaner::CleanAll(bool generator) {
113  Reset();
114  PrintHeader();
115  for (vector<Edge*>::iterator e = state_->edges_.begin();
116  e != state_->edges_.end(); ++e) {
117  // Do not try to remove phony targets
118  if ((*e)->is_phony())
119  continue;
120  // Do not remove generator's files unless generator specified.
121  if (!generator && (*e)->GetBindingBool("generator"))
122  continue;
123  for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
124  out_node != (*e)->outputs_.end(); ++out_node) {
125  Remove((*out_node)->path());
126  }
127 
128  RemoveEdgeFiles(*e);
129  }
130  PrintFooter();
131  return status_;
132 }
133 
135  if (Edge* e = target->in_edge()) {
136  // Do not try to remove phony targets
137  if (!e->is_phony()) {
138  Remove(target->path());
139  RemoveEdgeFiles(e);
140  }
141  for (vector<Node*>::iterator n = e->inputs_.begin(); n != e->inputs_.end();
142  ++n) {
143  Node* next = *n;
144  // call DoCleanTarget recursively if this node has not been visited
145  if (cleaned_.count(next) == 0) {
146  DoCleanTarget(next);
147  }
148  }
149  }
150 
151  // mark this target to be cleaned already
152  cleaned_.insert(target);
153 }
154 
156  assert(target);
157 
158  Reset();
159  PrintHeader();
160  DoCleanTarget(target);
161  PrintFooter();
162  return status_;
163 }
164 
165 int Cleaner::CleanTarget(const char* target) {
166  assert(target);
167 
168  Reset();
169  Node* node = state_->LookupNode(target);
170  if (node) {
171  CleanTarget(node);
172  } else {
173  Error("unknown target '%s'", target);
174  status_ = 1;
175  }
176  return status_;
177 }
178 
179 int Cleaner::CleanTargets(int target_count, char* targets[]) {
180  Reset();
181  PrintHeader();
182  for (int i = 0; i < target_count; ++i) {
183  const char* target_name = targets[i];
184  Node* target = state_->LookupNode(target_name);
185  if (target) {
186  if (IsVerbose())
187  printf("Target %s\n", target_name);
188  DoCleanTarget(target);
189  } else {
190  Error("unknown target '%s'", target_name);
191  status_ = 1;
192  }
193  }
194  PrintFooter();
195  return status_;
196 }
197 
198 void Cleaner::DoCleanRule(const Rule* rule) {
199  assert(rule);
200 
201  for (vector<Edge*>::iterator e = state_->edges_.begin();
202  e != state_->edges_.end(); ++e) {
203  if ((*e)->rule().name() == rule->name()) {
204  for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
205  out_node != (*e)->outputs_.end(); ++out_node) {
206  Remove((*out_node)->path());
207  RemoveEdgeFiles(*e);
208  }
209  }
210  }
211 }
212 
213 int Cleaner::CleanRule(const Rule* rule) {
214  assert(rule);
215 
216  Reset();
217  PrintHeader();
218  DoCleanRule(rule);
219  PrintFooter();
220  return status_;
221 }
222 
223 int Cleaner::CleanRule(const char* rule) {
224  assert(rule);
225 
226  Reset();
227  const Rule* r = state_->bindings_.LookupRule(rule);
228  if (r) {
229  CleanRule(r);
230  } else {
231  Error("unknown rule '%s'", rule);
232  status_ = 1;
233  }
234  return status_;
235 }
236 
237 int Cleaner::CleanRules(int rule_count, char* rules[]) {
238  assert(rules);
239 
240  Reset();
241  PrintHeader();
242  for (int i = 0; i < rule_count; ++i) {
243  const char* rule_name = rules[i];
244  const Rule* rule = state_->bindings_.LookupRule(rule_name);
245  if (rule) {
246  if (IsVerbose())
247  printf("Rule %s\n", rule_name);
248  DoCleanRule(rule);
249  } else {
250  Error("unknown rule '%s'", rule_name);
251  status_ = 1;
252  }
253  }
254  PrintFooter();
255  return status_;
256 }
257 
259  status_ = 0;
261  removed_.clear();
262  cleaned_.clear();
263 }
int status_
Definition: clean.h:104
const BuildConfig & config_
Definition: clean.h:99
void Report(const string &path)
Definition: clean.cc:59
Verbosity verbosity
Definition: build.h:130
vector< Edge * > edges_
All the edges of the graph.
Definition: state.h:124
int CleanTargets(int target_count, char *targets[])
Clean the given target targets.
Definition: clean.cc:179
const Rule * LookupRule(const string &rule_name)
Definition: eval_env.cc:44
Cleaner(State *state, const BuildConfig &config)
Build a cleaner object with a real disk interface.
Definition: clean.cc:25
string GetUnescapedRspfile()
Like GetBinding("rspfile"), but without shell escaping.
Definition: graph.cc:316
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
Definition: graph.h:35
void Remove(const string &path)
Remove the given path file only if it has not been already removed.
Definition: clean.cc:65
void Reset()
Definition: clean.cc:258
Interface for accessing the disk.
Edge * in_edge() const
Definition: graph.h:83
int TimeStamp
Definition: timestamp.h:22
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:124
DiskInterface * disk_interface_
Definition: clean.h:103
set< Node * > cleaned_
Definition: clean.h:101
int RemoveFile(const string &path)
Remove the file path.
Definition: clean.cc:47
int CleanAll(bool generator=false)
Clean all built files, except for files created by generator rules.
Definition: clean.cc:112
Implementation of DiskInterface that actually hits the disk.
void DoCleanTarget(Node *target)
Helper recursive method for CleanTarget().
Definition: clean.cc:134
int CleanRule(const Rule *rule)
Clean all the file built with the given rule rule.
Definition: clean.cc:213
An invokable build command and associated metadata (description, etc.).
Definition: eval_env.h:55
int CleanRules(int rule_count, char *rules[])
Clean the file produced by the given rules.
Definition: clean.cc:237
bool FileExists(const string &path)
Definition: clean.cc:51
virtual TimeStamp Stat(const string &path, string *err) const =0
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
BindingEnv bindings_
Definition: state.h:126
void PrintHeader()
Definition: clean.cc:96
const string & path() const
Definition: graph.h:73
State * state_
Definition: clean.h:98
void DoCleanRule(const Rule *rule)
Definition: clean.cc:198
int cleaned_files_count_
Definition: clean.h:102
void RemoveEdgeFiles(Edge *edge)
Remove the depfile and rspfile for an Edge.
Definition: clean.cc:86
virtual int RemoveFile(const string &path)=0
Remove the file named path.
Options (e.g. verbosity, parallelism) passed to a build.
Definition: build.h:121
Global state (file status) for a single run.
Definition: state.h:84
const string & name() const
Definition: eval_env.h:58
void PrintFooter()
Definition: clean.cc:106
bool IsVerbose() const
Definition: clean.h:71
string GetUnescapedDepfile()
Like GetBinding("depfile"), but without shell escaping.
Definition: graph.cc:311
int CleanTarget(Node *target)
Clean the given target and all the file built for it.
Definition: clean.cc:155
set< string > removed_
Definition: clean.h:100
bool IsAlreadyRemoved(const string &path)
Definition: clean.cc:81
bool dry_run
Definition: build.h:131
void Error(const char *msg,...)
Log an error message.
Definition: util.cc:82
Node * LookupNode(StringPiece path) const
Definition: state.cc:112