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