diff options
Diffstat (limited to 'build/algorithm.cxx')
-rw-r--r-- | build/algorithm.cxx | 203 |
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; } |