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
25using namespace std;
26
28 const BuildConfig& config,
29 DiskInterface* disk_interface)
30 : state_(state),
31 config_(config),
32 dyndep_loader_(state, disk_interface),
34 disk_interface_(disk_interface),
35 status_(0) {
36}
37
38int Cleaner::RemoveFile(const string& path) {
39 return disk_interface_->RemoveFile(path);
40}
41
42bool Cleaner::FileExists(const string& path) {
43 string err;
44 TimeStamp mtime = disk_interface_->Stat(path, &err);
45 if (mtime == -1)
46 Error("%s", err.c_str());
47 return mtime > 0; // Treat Stat() errors as "file does not exist".
48}
49
50void Cleaner::Report(const string& path) {
52 if (IsVerbose())
53 printf("Remove %s\n", path.c_str());
54}
55
56void Cleaner::Remove(const string& path) {
57 if (!IsAlreadyRemoved(path)) {
58 removed_.insert(path);
59 if (config_.dry_run) {
60 if (FileExists(path))
61 Report(path);
62 } else {
63 int ret = RemoveFile(path);
64 if (ret == 0)
65 Report(path);
66 else if (ret == -1)
67 status_ = 1;
68 }
69 }
70}
71
72bool Cleaner::IsAlreadyRemoved(const string& path) {
73 set<string>::iterator i = removed_.find(path);
74 return (i != removed_.end());
75}
76
78 string depfile = edge->GetUnescapedDepfile();
79 if (!depfile.empty())
80 Remove(depfile);
81
82 string rspfile = edge->GetUnescapedRspfile();
83 if (!rspfile.empty())
84 Remove(rspfile);
85}
86
88 if (config_.verbosity == BuildConfig::QUIET)
89 return;
90 printf("Cleaning...");
91 if (IsVerbose())
92 printf("\n");
93 else
94 printf(" ");
95 fflush(stdout);
96}
97
99 if (config_.verbosity == BuildConfig::QUIET)
100 return;
101 printf("%d files.\n", cleaned_files_count_);
102}
103
104int Cleaner::CleanAll(bool generator) {
105 Reset();
106 PrintHeader();
107 LoadDyndeps();
108 for (vector<Edge*>::iterator e = state_->edges_.begin();
109 e != state_->edges_.end(); ++e) {
110 // Do not try to remove phony targets
111 if ((*e)->is_phony())
112 continue;
113 // Do not remove generator's files unless generator specified.
114 if (!generator && (*e)->GetBindingBool("generator"))
115 continue;
116 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
117 out_node != (*e)->outputs_.end(); ++out_node) {
118 Remove((*out_node)->path());
119 }
120
121 RemoveEdgeFiles(*e);
122 }
123 PrintFooter();
124 return status_;
125}
126
128 Reset();
129 PrintHeader();
130 LoadDyndeps();
131 for (BuildLog::Entries::const_iterator i = entries.begin(); i != entries.end(); ++i) {
132 Node* n = state_->LookupNode(i->first);
133 // Detecting stale outputs works as follows:
134 //
135 // - If it has no Node, it is not in the build graph, or the deps log
136 // anymore, hence is stale.
137 //
138 // - If it isn't an output or input for any edge, it comes from a stale
139 // entry in the deps log, but no longer referenced from the build
140 // graph.
141 //
142 if (!n || (!n->in_edge() && n->out_edges().empty())) {
143 Remove(i->first.AsString());
144 }
145 }
146 PrintFooter();
147 return status_;
148}
149
151 if (Edge* e = target->in_edge()) {
152 // Do not try to remove phony targets
153 if (!e->is_phony()) {
154 Remove(target->path());
156 }
157 for (vector<Node*>::iterator n = e->inputs_.begin(); n != e->inputs_.end();
158 ++n) {
159 Node* next = *n;
160 // call DoCleanTarget recursively if this node has not been visited
161 if (cleaned_.count(next) == 0) {
162 DoCleanTarget(next);
163 }
164 }
165 }
166
167 // mark this target to be cleaned already
168 cleaned_.insert(target);
169}
170
172 assert(target);
173
174 Reset();
175 PrintHeader();
176 LoadDyndeps();
177 DoCleanTarget(target);
178 PrintFooter();
179 return status_;
180}
181
182int Cleaner::CleanTarget(const char* target) {
183 assert(target);
184
185 Reset();
186 Node* node = state_->LookupNode(target);
187 if (node) {
188 CleanTarget(node);
189 } else {
190 Error("unknown target '%s'", target);
191 status_ = 1;
192 }
193 return status_;
194}
195
196int Cleaner::CleanTargets(int target_count, char* targets[]) {
197 Reset();
198 PrintHeader();
199 LoadDyndeps();
200 for (int i = 0; i < target_count; ++i) {
201 string target_name = targets[i];
202 if (target_name.empty()) {
203 Error("failed to canonicalize '': empty path");
204 status_ = 1;
205 continue;
206 }
207 uint64_t slash_bits;
208 CanonicalizePath(&target_name, &slash_bits);
209 Node* target = state_->LookupNode(target_name);
210 if (target) {
211 if (IsVerbose())
212 printf("Target %s\n", target_name.c_str());
213 DoCleanTarget(target);
214 } else {
215 Error("unknown target '%s'", target_name.c_str());
216 status_ = 1;
217 }
218 }
219 PrintFooter();
220 return status_;
221}
222
223void Cleaner::DoCleanRule(const Rule* rule) {
224 assert(rule);
225
226 for (vector<Edge*>::iterator e = state_->edges_.begin();
227 e != state_->edges_.end(); ++e) {
228 if ((*e)->rule().name() == rule->name()) {
229 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
230 out_node != (*e)->outputs_.end(); ++out_node) {
231 Remove((*out_node)->path());
232 RemoveEdgeFiles(*e);
233 }
234 }
235 }
236}
237
238int Cleaner::CleanRule(const Rule* rule) {
239 assert(rule);
240
241 Reset();
242 PrintHeader();
243 LoadDyndeps();
244 DoCleanRule(rule);
245 PrintFooter();
246 return status_;
247}
248
249int Cleaner::CleanRule(const char* rule) {
250 assert(rule);
251
252 Reset();
253 const Rule* r = state_->bindings_.LookupRule(rule);
254 if (r) {
255 CleanRule(r);
256 } else {
257 Error("unknown rule '%s'", rule);
258 status_ = 1;
259 }
260 return status_;
261}
262
263int Cleaner::CleanRules(int rule_count, char* rules[]) {
264 assert(rules);
265
266 Reset();
267 PrintHeader();
268 LoadDyndeps();
269 for (int i = 0; i < rule_count; ++i) {
270 const char* rule_name = rules[i];
271 const Rule* rule = state_->bindings_.LookupRule(rule_name);
272 if (rule) {
273 if (IsVerbose())
274 printf("Rule %s\n", rule_name);
275 DoCleanRule(rule);
276 } else {
277 Error("unknown rule '%s'", rule_name);
278 status_ = 1;
279 }
280 }
281 PrintFooter();
282 return status_;
283}
284
286 status_ = 0;
288 removed_.clear();
289 cleaned_.clear();
290}
291
293 // Load dyndep files that exist, before they are cleaned.
294 for (vector<Edge*>::iterator e = state_->edges_.begin();
295 e != state_->edges_.end(); ++e) {
296 Node* dyndep;
297 if ((dyndep = (*e)->dyndep_) && dyndep->dyndep_pending()) {
298 // Capture and ignore errors loading the dyndep file.
299 // We clean as much of the graph as we know.
300 std::string err;
301 dyndep_loader_.LoadDyndeps(dyndep, &err);
302 }
303 }
304}
Definition hash_map.h:26
Options (e.g. verbosity, parallelism) passed to a build.
Definition build.h:176
ExternalStringHashMap< std::unique_ptr< LogEntry > >::Type Entries
Definition build_log.h:95
const BuildConfig & config_
Definition clean.h:102
int CleanRule(const Rule *rule)
Clean all the file built with the given rule rule.
Definition clean.cc:238
int CleanTarget(Node *target)
Clean the given target and all the file built for it.
Definition clean.cc:171
void PrintFooter()
Definition clean.cc:98
void RemoveEdgeFiles(Edge *edge)
Remove the depfile and rspfile for an Edge.
Definition clean.cc:77
int cleaned_files_count_
Definition clean.h:106
void DoCleanTarget(Node *target)
Helper recursive method for CleanTarget().
Definition clean.cc:150
bool IsVerbose() const
Definition clean.h:71
bool IsAlreadyRemoved(const std::string &path)
Definition clean.cc:72
void Remove(const std::string &path)
Remove the given path file only if it has not been already removed.
Definition clean.cc:56
int CleanRules(int rule_count, char *rules[])
Clean the file produced by the given rules.
Definition clean.cc:263
void Report(const std::string &path)
Definition clean.cc:50
void Reset()
Definition clean.cc:285
DyndepLoader dyndep_loader_
Definition clean.h:103
void LoadDyndeps()
Load dependencies from dyndep bindings.
Definition clean.cc:292
bool FileExists(const std::string &path)
Definition clean.cc:42
Cleaner(State *state, const BuildConfig &config, DiskInterface *disk_interface)
Build a cleaner object with the given disk_interface.
Definition clean.cc:27
void DoCleanRule(const Rule *rule)
Definition clean.cc:223
std::set< std::string > removed_
Definition clean.h:104
std::set< Node * > cleaned_
Definition clean.h:105
int CleanTargets(int target_count, char *targets[])
Clean the given target targets.
Definition clean.cc:196
int CleanDead(const BuildLog::Entries &entries)
Clean the files produced by previous builds that are no longer in the manifest.
Definition clean.cc:127
int status_
Definition clean.h:108
int CleanAll(bool generator=false)
Clean all built files, except for files created by generator rules.
Definition clean.cc:104
int RemoveFile(const std::string &path)
Remove the file path.
Definition clean.cc:38
State * state_
Definition clean.h:101
DiskInterface * disk_interface_
Definition clean.h:107
void PrintHeader()
Definition clean.cc:87
Interface for accessing the disk.
An edge in the dependency graph; links between Nodes using Rules.
Definition graph.h:175
std::string GetUnescapedRspfile() const
Like GetBinding("rspfile"), but without shell escaping.
Definition graph.cc:530
std::string GetUnescapedDepfile() const
Like GetBinding("depfile"), but without shell escaping.
Definition graph.cc:520
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
Definition graph.h:42
const std::string & path() const
Definition graph.h:82
Edge * in_edge() const
Definition graph.h:100
bool dyndep_pending() const
Definition graph.h:97
const std::vector< Edge * > & out_edges() const
Definition graph.h:114
An invocable build command and associated metadata (description, etc.).
Definition eval_env.h:66
const std::string & name() const
Definition eval_env.h:73
Global state (file status) for a single run.
Definition state.h:95
int64_t TimeStamp
Definition timestamp.h:31
void Error(const char *msg, va_list ap)
Definition util.cc:98
void CanonicalizePath(string *path, uint64_t *slash_bits)
Definition util.cc:124
unsigned long long uint64_t
Definition win32port.h:29