aboutsummaryrefslogtreecommitdiff
path: root/build/algorithm.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'build/algorithm.cxx')
-rw-r--r--build/algorithm.cxx203
1 files changed, 110 insertions, 93 deletions
diff --git a/build/algorithm.cxx b/build/algorithm.cxx
index bec51aa..488bbb7 100644
--- a/build/algorithm.cxx
+++ b/build/algorithm.cxx
@@ -45,131 +45,148 @@ namespace build
//
t.prerequisite_targets.clear ();
+ size_t oi (a.operation () - 1); // Operation index in rule_map.
+ scope& bs (t.base_scope ());
+
for (auto tt (&t.type ());
tt != nullptr && !t.recipe (a);
tt = tt->base)
{
- auto i (current_rules->find (tt->id));
+ // Search scopes outwards, stopping at the project root.
+ //
+ for (const scope* s (&bs);
+ s != nullptr;
+ s = s->root () ? global_scope : s->parent_scope ())
+ {
+ const rule_map& om (s->rules);
- if (i == current_rules->end () || i->second.empty ())
- continue; // No rules registered for this target type, try base.
+ if (om.size () <= oi)
+ continue; // No entry for this operation id.
- const auto& rules (i->second); // Hint map.
+ const target_type_rule_map& ttm (om[oi]);
- // @@ TODO
- //
- // Different rules can be used for different operations (update
- // vs test is a good example). So, at some point, we will probably
- // have to support a list of hints or even an operation-hint map
- // (e.g., 'hint=cxx test=foo' if cxx supports the test operation
- // but we want the foo rule instead). This is also the place where
- // the '{build clean}=cxx' construct (which we currently do not
- // support) can come handy.
- //
- // Also, ignore the hint (that is most likely ment for a different
- // operation) if this is a unique match.
- //
- string hint;
- auto rs (rules.size () == 1
- ? make_pair (rules.begin (), rules.end ())
- : rules.find_prefix (hint));
+ if (ttm.empty ())
+ continue; // Empty map for this operation id.
- for (auto i (rs.first); i != rs.second; ++i)
- {
- const string& n (i->first);
- const rule& ru (i->second);
+ auto i (ttm.find (tt->id));
- match_result m;
- {
- auto g (
- make_exception_guard (
- [](action a, target& t, const string& n)
- {
- info << "while matching rule " << n << " to "
- << diag_do (a, t);
- },
- a, t, n));
+ if (i == ttm.end () || i->second.empty ())
+ continue; // No rules registered for this target type.
- m = ru.match (a, t, hint);
- }
+ const auto& rules (i->second); // Hint map.
+
+ // @@ TODO
+ //
+ // Different rules can be used for different operations (update
+ // vs test is a good example). So, at some point, we will probably
+ // have to support a list of hints or even an operation-hint map
+ // (e.g., 'hint=cxx test=foo' if cxx supports the test operation
+ // but we want the foo rule instead). This is also the place where
+ // the '{build clean}=cxx' construct (which we currently do not
+ // support) can come handy.
+ //
+ // Also, ignore the hint (that is most likely ment for a different
+ // operation) if this is a unique match.
+ //
+ string hint;
+ auto rs (rules.size () == 1
+ ? make_pair (rules.begin (), rules.end ())
+ : rules.find_prefix (hint));
- if (m)
+ for (auto i (rs.first); i != rs.second; ++i)
{
- // Do the ambiguity test.
- //
- bool ambig (false);
+ const string& n (i->first);
+ const rule& ru (i->second);
- diag_record dr;
+ match_result m;
+ {
+ auto g (
+ make_exception_guard (
+ [](action a, target& t, const string& n)
+ {
+ info << "while matching rule " << n << " to "
+ << diag_do (a, t);
+ },
+ a, t, n));
+
+ m = ru.match (a, t, hint);
+ }
- for (++i; i != rs.second; ++i)
+ if (m)
{
- const string& n1 (i->first);
- const rule& ru1 (i->second);
+ // Do the ambiguity test.
+ //
+ bool ambig (false);
- match_result m1;
- {
- auto g (
- make_exception_guard (
- [](action a, target& t, const string& n1)
- {
- info << "while matching rule " << n1 << " to "
- << diag_do (a, t);
- },
- a, t, n1));
-
- m1 = ru1.match (a, t, hint);
- }
+ diag_record dr;
- if (m1)
+ for (++i; i != rs.second; ++i)
{
- if (!ambig)
+ const string& n1 (i->first);
+ const rule& ru1 (i->second);
+
+ match_result m1;
{
- dr << fail << "multiple rules matching " << diag_doing (a, t)
- << info << "rule " << n << " matches";
- ambig = true;
+ auto g (
+ make_exception_guard (
+ [](action a, target& t, const string& n1)
+ {
+ info << "while matching rule " << n1 << " to "
+ << diag_do (a, t);
+ },
+ a, t, n1));
+
+ m1 = ru1.match (a, t, hint);
}
- dr << info << "rule " << n1 << " also matches";
+ if (m1)
+ {
+ if (!ambig)
+ {
+ dr << fail << "multiple rules matching " << diag_doing (a, t)
+ << info << "rule " << n << " matches";
+ ambig = true;
+ }
+
+ dr << info << "rule " << n1 << " also matches";
+ }
}
- }
- if (!ambig)
- {
- if (apply)
- {
- auto g (
- make_exception_guard (
- [](action a, target& t, const string& n)
- {
- info << "while applying rule " << n << " to "
- << diag_do (a, t);
- },
- a, t, n));
-
- t.recipe (a, ru.apply (a, t, m));
- break;
- }
- else
+ if (!ambig)
{
- r.first = &ru;
- r.second = m;
+ if (apply)
+ {
+ auto g (
+ make_exception_guard (
+ [](action a, target& t, const string& n)
+ {
+ info << "while applying rule " << n << " to "
+ << diag_do (a, t);
+ },
+ a, t, n));
+
+ t.recipe (a, ru.apply (a, t, m));
+ }
+ else
+ {
+ r.first = &ru;
+ r.second = m;
+ }
+
return r;
}
+ else
+ dr << info << "use rule hint to disambiguate this match";
}
- else
- dr << info << "use rule hint to disambiguate this match";
}
}
}
- if (!t.recipe (a))
- {
- diag_record dr;
- dr << fail << "no rule to " << diag_do (a, t);
+ diag_record dr;
+ dr << fail << "no rule to " << diag_do (a, t);
- if (verb < 3)
- dr << info << "re-run with --verbose 3 for more information";
- }
+ if (verb < 3)
+ dr << info << "re-run with --verbose 3 for more information";
return r;
}