blob: 4325925d2c35e160aaa2612cad740736736651a6 [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "dep.h"
2
Shinichiro Hamaji4a711312015-06-19 14:44:20 +09003#include <algorithm>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09004#include <memory>
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +09005#include <unordered_map>
6#include <unordered_set>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09007
Shinichiro Hamaji0562c302015-06-19 15:30:49 +09008#include "fileutil.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09009#include "log.h"
10#include "rule.h"
Shinichiro Hamaji4a711312015-06-19 14:44:20 +090011#include "strutil.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090012#include "var.h"
13
14static vector<DepNode*>* g_dep_node_pool;
15
Shinichiro Hamaji0562c302015-06-19 15:30:49 +090016static StringPiece ReplaceSuffix(StringPiece s, StringPiece newsuf) {
17 string r;
18 AppendString(StripExt(s), &r);
19 r += '.';
20 AppendString(newsuf, &r);
21 return Intern(r);
22}
23
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090024DepNode::DepNode(StringPiece o, bool p)
25 : output(o),
26 has_rule(false),
27 is_order_only(false),
28 is_phony(p),
29 target_specific_vars(NULL) {
30 g_dep_node_pool->push_back(this);
31}
32
33class DepBuilder {
34 public:
Shinichiro Hamaji0562c302015-06-19 15:30:49 +090035 DepBuilder(const vector<shared_ptr<Rule>>& rules,
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090036 const Vars& vars,
37 const unordered_map<StringPiece, Vars*>& rule_vars)
38 : vars_(vars),
39 rule_vars_(rule_vars),
40 first_rule_(NULL) {
41 PopulateRules(rules);
42 }
43
Shinichiro Hamaji4a711312015-06-19 14:44:20 +090044 ~DepBuilder() {
Shinichiro Hamaji4a711312015-06-19 14:44:20 +090045 }
46
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090047 void Build(vector<StringPiece> targets,
48 vector<DepNode*>* nodes) {
49 if (targets.empty()) {
50 if (!first_rule_) {
51 ERROR("*** No targets.");
52 }
53 CHECK(!first_rule_->outputs.empty());
54 targets.push_back(first_rule_->outputs[0]);
55 }
56
57 // TODO: LogStats?
58
59 for (StringPiece target : targets) {
60 unique_ptr<Vars> tsvs(new Vars);
61 DepNode* n = BuildPlan(target, "", tsvs.get());
62 nodes->push_back(n);
63 }
64 }
65
66 private:
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +090067 bool Exists(StringPiece target) {
68 auto found = rules_.find(target);
69 if (found != rules_.end())
70 return true;
71 if (phony_.count(target))
72 return true;
73 return ::Exists(target);
74 }
75
Shinichiro Hamaji0562c302015-06-19 15:30:49 +090076 void PopulateRules(const vector<shared_ptr<Rule>>& rules) {
77 for (shared_ptr<Rule> rule : rules) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090078 if (rule->outputs.empty()) {
79 PopulateImplicitRule(rule);
80 } else {
81 PopulateExplicitRule(rule);
82 }
83 }
Shinichiro Hamaji4a711312015-06-19 14:44:20 +090084 reverse(implicit_rules_.begin(), implicit_rules_.end());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090085 }
86
Shinichiro Hamaji0562c302015-06-19 15:30:49 +090087 bool PopulateSuffixRule(shared_ptr<Rule> rule, StringPiece output) {
88 if (output.empty() || output[0] != '.')
89 return false;
90
91 StringPiece rest = output.substr(1);
92 size_t dot_index = rest.find('.');
93 // If there is only a single dot or the third dot, this is not a
94 // suffix rule.
95 if (dot_index == string::npos ||
96 rest.substr(dot_index+1).find('.') != string::npos) {
97 return false;
98 }
99
100 StringPiece input_suffix = rest.substr(0, dot_index);
101 StringPiece output_suffix = rest.substr(dot_index+1);
102 shared_ptr<Rule> r = make_shared<Rule>(*rule);
103 r->inputs.clear();
104 r->inputs.push_back(input_suffix);
105 r->is_suffix_rule = true;
106 suffix_rules_[output_suffix].push_back(r);
107 return true;
108 }
109
110 void PopulateExplicitRule(shared_ptr<Rule> rule) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900111 for (StringPiece output : rule->outputs) {
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900112 const bool is_suffix_rule = PopulateSuffixRule(rule, output);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900113 // isSuffixRule := db.populateSuffixRule(rule, output)
114
115
116 /*
117 if oldRule, present := db.rules[output]; present {
118 r := mergeRules(oldRule, rule, output, isSuffixRule)
119 db.rules[output] = r
120 } else {
121 db.rules[output] = rule
122 if db.firstRule == nil && !strings.HasPrefix(output, ".") {
123 db.firstRule = rule
124 }
125 }
126 */
127
128 auto p = rules_.insert(make_pair(output, rule));
129 if (p.second) {
130 if (!first_rule_ && output.get(0) != '.') {
131 first_rule_ = rule;
132 }
133 } else {
134 // TODO: merge
135 CHECK(false);
136 }
137 }
138 }
139
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900140 void PopulateImplicitRule(shared_ptr<Rule> rule) {
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900141 for (StringPiece output_pattern : rule->output_patterns) {
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900142 shared_ptr<Rule> r = make_shared<Rule>(*rule);
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900143 r->output_patterns.clear();
144 r->output_patterns.push_back(output_pattern);
145 implicit_rules_.push_back(r);
146 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900147 }
148
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900149 shared_ptr<Rule> LookupRule(StringPiece o) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900150 auto found = rules_.find(o);
151 if (found != rules_.end())
152 return found->second;
153 return NULL;
154 }
155
156 Vars* LookupRuleVars(StringPiece o) {
157 auto found = rule_vars_.find(o);
158 if (found != rule_vars_.end())
159 return found->second;
160 return NULL;
161 }
162
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900163 bool CanPickImplicitRule(shared_ptr<Rule> rule, StringPiece output) {
164 CHECK(rule->output_patterns.size() == 1);
165 Pattern pat(rule->output_patterns[0]);
166 if (!pat.Match(output)) {
167 return false;
168 }
169 for (StringPiece input : rule->inputs) {
170 string buf;
171 pat.AppendSubst(output, input, &buf);
172 if (!Exists(buf))
173 return false;
174 }
175 return true;
176 }
177
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900178 bool PickRule(StringPiece output,
179 shared_ptr<Rule>* out_rule, Vars** out_var) {
180 shared_ptr<Rule> rule = LookupRule(output);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900181 Vars* vars = LookupRuleVars(output);
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900182 *out_rule = rule;
183 *out_var = vars;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900184 if (rule) {
185 if (!rule->cmds.empty()) {
186 return true;
187 }
188 }
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900189
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900190 for (shared_ptr<Rule> irule : implicit_rules_) {
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900191 if (!CanPickImplicitRule(irule, output))
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900192 continue;
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900193 if (rule) {
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900194 shared_ptr<Rule> r = make_shared<Rule>(*rule);
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900195 r->output_patterns = irule->output_patterns;
196 for (StringPiece input : irule->inputs)
197 r->inputs.push_back(input);
198 r->cmds = irule->cmds;
199 r->loc = irule->loc;
200 r->cmd_lineno = irule->cmd_lineno;
201 *out_rule = r;
202 return true;
203 }
204 if (vars) {
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900205 // TODO: Merge implicit variables...
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900206 CHECK(false);
207 }
208 *out_rule = irule;
209 return true;
210 }
211
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900212 StringPiece output_suffix = GetExt(output);
213 if (output_suffix.get(0) != '.')
214 return rule.get();
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900215 output_suffix = output_suffix.substr(1);
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900216
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900217 SuffixRuleMap::const_iterator found = suffix_rules_.find(output_suffix);
218 if (found == suffix_rules_.end())
219 return rule.get();
220
221 for (shared_ptr<Rule> irule : found->second) {
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900222 CHECK(irule->inputs.size() == 1);
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900223 StringPiece input = ReplaceSuffix(output, irule->inputs[0]);
224 if (!Exists(input))
225 continue;
226
227 if (rule) {
228 shared_ptr<Rule> r = make_shared<Rule>(*rule);
229 r->inputs.insert(r->inputs.begin(), input);
230 r->cmds = irule->cmds;
231 r->loc = irule->loc;
232 r->cmd_lineno = irule->cmd_lineno;
233 *out_rule = r;
234 return true;
235 }
236 if (vars) {
237 // TODO: Merge implicit variables...
238 CHECK(false);
239 }
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900240 *out_rule = irule;
241 return true;
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900242 }
243
244 return rule.get();
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900245 }
246
247 DepNode* BuildPlan(StringPiece output, StringPiece needed_by, Vars* tsvs) {
248 LOG("BuildPlan: %s for %s",
249 output.as_string().c_str(),
250 needed_by.as_string().c_str());
251
252 auto found = done_.find(output);
253 if (found != done_.end()) {
254 return found->second;
255 }
256
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900257 DepNode* n = new DepNode(output, phony_.count(output));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900258 done_[output] = n;
259
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900260 shared_ptr<Rule> rule;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900261 Vars* vars;
262 if (!PickRule(output, &rule, &vars)) {
263 return n;
264 }
265
266 // TODO: Handle TSVs
267
268 for (StringPiece input : rule->inputs) {
269 if (rule->output_patterns.size() > 0) {
270 if (rule->output_patterns.size() > 1) {
271 ERROR("TODO: multiple output pattern is not supported yet");
272 }
Shinichiro Hamaji4a711312015-06-19 14:44:20 +0900273 string o;
274 Pattern(rule->output_patterns[0]).AppendSubst(input, output, &o);
275 input = Intern(o);
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900276 } else if (rule->is_suffix_rule) {
277 input = Intern(ReplaceSuffix(output, input));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900278 }
279
280 n->actual_inputs.push_back(input);
281 DepNode* c = BuildPlan(input, output, tsvs);
282 n->deps.push_back(c);
283 }
284
285 // TODO: order only
286 n->has_rule = true;
287 n->cmds = rule->cmds;
288
289 return n;
290 }
291
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900292 unordered_map<StringPiece, shared_ptr<Rule>> rules_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900293 const Vars& vars_;
294 const unordered_map<StringPiece, Vars*>& rule_vars_;
295
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900296 vector<shared_ptr<Rule>> implicit_rules_; // pattern=%. no prefix,suffix.
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900297 //vector<Rule*> iprefix_rules_; // pattern=prefix%.. may have suffix
298 //vector<Rule*> isuffix_rules_; // pattern=%suffix no prefix
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900299 typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap;
300 SuffixRuleMap suffix_rules_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900301
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900302 shared_ptr<Rule> first_rule_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900303 unordered_map<StringPiece, DepNode*> done_;
Shinichiro Hamaji52dbb602015-06-19 15:57:07 +0900304 unordered_set<StringPiece> phony_;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900305};
306
Shinichiro Hamaji0562c302015-06-19 15:30:49 +0900307void MakeDep(const vector<shared_ptr<Rule>>& rules,
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900308 const Vars& vars,
309 const unordered_map<StringPiece, Vars*>& rule_vars,
310 const vector<StringPiece>& targets,
311 vector<DepNode*>* nodes) {
312 DepBuilder db(rules, vars, rule_vars);
313 db.Build(targets, nodes);
314}
315
316void InitDepNodePool() {
317 g_dep_node_pool = new vector<DepNode*>;
318}
319
320void QuitDepNodePool() {
321 for (DepNode* n : *g_dep_node_pool)
322 delete n;
323 delete g_dep_node_pool;
324}