[C++] Implement suffix rule
diff --git a/dep.cc b/dep.cc
index b0874c4..8dd851c 100644
--- a/dep.cc
+++ b/dep.cc
@@ -3,6 +3,7 @@
#include <algorithm>
#include <memory>
+#include "fileutil.h"
#include "log.h"
#include "rule.h"
#include "strutil.h"
@@ -10,6 +11,14 @@
static vector<DepNode*>* g_dep_node_pool;
+static StringPiece ReplaceSuffix(StringPiece s, StringPiece newsuf) {
+ string r;
+ AppendString(StripExt(s), &r);
+ r += '.';
+ AppendString(newsuf, &r);
+ return Intern(r);
+}
+
DepNode::DepNode(StringPiece o, bool p)
: output(o),
has_rule(false),
@@ -21,7 +30,7 @@
class DepBuilder {
public:
- DepBuilder(const vector<Rule*>& rules,
+ DepBuilder(const vector<shared_ptr<Rule>>& rules,
const Vars& vars,
const unordered_map<StringPiece, Vars*>& rule_vars)
: vars_(vars),
@@ -31,9 +40,6 @@
}
~DepBuilder() {
- for (Rule* r : implicit_rules_) {
- delete r;
- }
}
void Build(vector<StringPiece> targets,
@@ -56,8 +62,8 @@
}
private:
- void PopulateRules(const vector<Rule*>& rules) {
- for (Rule* rule : rules) {
+ void PopulateRules(const vector<shared_ptr<Rule>>& rules) {
+ for (shared_ptr<Rule> rule : rules) {
if (rule->outputs.empty()) {
PopulateImplicitRule(rule);
} else {
@@ -67,8 +73,32 @@
reverse(implicit_rules_.begin(), implicit_rules_.end());
}
- void PopulateExplicitRule(Rule* rule) {
+ bool PopulateSuffixRule(shared_ptr<Rule> rule, StringPiece output) {
+ if (output.empty() || output[0] != '.')
+ return false;
+
+ StringPiece rest = output.substr(1);
+ size_t dot_index = rest.find('.');
+ // If there is only a single dot or the third dot, this is not a
+ // suffix rule.
+ if (dot_index == string::npos ||
+ rest.substr(dot_index+1).find('.') != string::npos) {
+ return false;
+ }
+
+ StringPiece input_suffix = rest.substr(0, dot_index);
+ StringPiece output_suffix = rest.substr(dot_index+1);
+ shared_ptr<Rule> r = make_shared<Rule>(*rule);
+ r->inputs.clear();
+ r->inputs.push_back(input_suffix);
+ r->is_suffix_rule = true;
+ suffix_rules_[output_suffix].push_back(r);
+ return true;
+ }
+
+ void PopulateExplicitRule(shared_ptr<Rule> rule) {
for (StringPiece output : rule->outputs) {
+ const bool is_suffix_rule = PopulateSuffixRule(rule, output);
// isSuffixRule := db.populateSuffixRule(rule, output)
@@ -96,17 +126,16 @@
}
}
- void PopulateImplicitRule(Rule* rule) {
+ void PopulateImplicitRule(shared_ptr<Rule> rule) {
for (StringPiece output_pattern : rule->output_patterns) {
- Rule* r = new Rule(*rule);
- r->is_temporary = false;
+ shared_ptr<Rule> r = make_shared<Rule>(*rule);
r->output_patterns.clear();
r->output_patterns.push_back(output_pattern);
implicit_rules_.push_back(r);
}
}
- Rule* LookupRule(StringPiece o) {
+ shared_ptr<Rule> LookupRule(StringPiece o) {
auto found = rules_.find(o);
if (found != rules_.end())
return found->second;
@@ -120,8 +149,9 @@
return NULL;
}
- bool PickRule(StringPiece output, Rule** out_rule, Vars** out_var) {
- Rule* rule = LookupRule(output);
+ bool PickRule(StringPiece output,
+ shared_ptr<Rule>* out_rule, Vars** out_var) {
+ shared_ptr<Rule> rule = LookupRule(output);
Vars* vars = LookupRuleVars(output);
*out_rule = rule;
*out_var = vars;
@@ -131,13 +161,13 @@
}
}
- for (Rule* irule : implicit_rules_) {
+ for (shared_ptr<Rule> irule : implicit_rules_) {
CHECK(irule->output_patterns.size() == 1);
if (!Pattern(irule->output_patterns[0]).Match(output)) {
continue;
}
if (rule) {
- Rule* r = new Rule(*rule);
+ shared_ptr<Rule> r = make_shared<Rule>(*rule);
r->output_patterns = irule->output_patterns;
for (StringPiece input : irule->inputs)
r->inputs.push_back(input);
@@ -148,16 +178,43 @@
return true;
}
if (vars) {
- // Merge implicit rule variables...
+ // TODO: Merge implicit variables...
CHECK(false);
}
*out_rule = irule;
return true;
}
- // Suffix rule.
+ StringPiece output_suffix = GetExt(output);
+ if (output_suffix.get(0) != '.')
+ return rule.get();
- return rule;
+ SuffixRuleMap::const_iterator found = suffix_rules_.find(output_suffix);
+ if (found == suffix_rules_.end())
+ return rule.get();
+
+ for (shared_ptr<Rule> irule : found->second) {
+ CHECK(irule->inputs.size() != 1);
+ StringPiece input = ReplaceSuffix(output, irule->inputs[0]);
+ if (!Exists(input))
+ continue;
+
+ if (rule) {
+ shared_ptr<Rule> r = make_shared<Rule>(*rule);
+ r->inputs.insert(r->inputs.begin(), input);
+ r->cmds = irule->cmds;
+ r->loc = irule->loc;
+ r->cmd_lineno = irule->cmd_lineno;
+ *out_rule = r;
+ return true;
+ }
+ if (vars) {
+ // TODO: Merge implicit variables...
+ CHECK(false);
+ }
+ }
+
+ return rule.get();
}
DepNode* BuildPlan(StringPiece output, StringPiece needed_by, Vars* tsvs) {
@@ -173,7 +230,7 @@
DepNode* n = new DepNode(output, phony_[output]);
done_[output] = n;
- Rule* rule;
+ shared_ptr<Rule> rule;
Vars* vars;
if (!PickRule(output, &rule, &vars)) {
return n;
@@ -203,21 +260,22 @@
return n;
}
- unordered_map<StringPiece, Rule*> rules_;
+ unordered_map<StringPiece, shared_ptr<Rule>> rules_;
const Vars& vars_;
const unordered_map<StringPiece, Vars*>& rule_vars_;
- vector<Rule*> implicit_rules_; // pattern=%. no prefix,suffix.
+ vector<shared_ptr<Rule>> implicit_rules_; // pattern=%. no prefix,suffix.
//vector<Rule*> iprefix_rules_; // pattern=prefix%.. may have suffix
//vector<Rule*> isuffix_rules_; // pattern=%suffix no prefix
+ typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap;
+ SuffixRuleMap suffix_rules_;
- unordered_map<StringPiece, vector<Rule*>> suffix_rules_;
- Rule* first_rule_;
+ shared_ptr<Rule> first_rule_;
unordered_map<StringPiece, DepNode*> done_;
unordered_map<StringPiece, bool> phony_;
};
-void MakeDep(const vector<Rule*>& rules,
+void MakeDep(const vector<shared_ptr<Rule>>& rules,
const Vars& vars,
const unordered_map<StringPiece, Vars*>& rule_vars,
const vector<StringPiece>& targets,