diff options
Diffstat (limited to 'libbuild2/adhoc-rule-regex-pattern.cxx')
-rw-r--r-- | libbuild2/adhoc-rule-regex-pattern.cxx | 135 |
1 files changed, 121 insertions, 14 deletions
diff --git a/libbuild2/adhoc-rule-regex-pattern.cxx b/libbuild2/adhoc-rule-regex-pattern.cxx index 59a63bc..2d60520 100644 --- a/libbuild2/adhoc-rule-regex-pattern.cxx +++ b/libbuild2/adhoc-rule-regex-pattern.cxx @@ -86,7 +86,9 @@ namespace build2 tt = n.untyped () ? &file::static_type : s.find_target_type (n.type); if (tt == nullptr) - fail (loc) << "unknown target type " << n.type; + fail (loc) << "unknown target type " << n.type << + info << "perhaps the module that defines this target type is " + << "not loaded by project " << *s.root_scope (); } bool e (n.pattern && @@ -126,10 +128,13 @@ namespace build2 } bool adhoc_rule_regex_pattern:: - match (action a, target& t, const string&, match_extra& me) const + match (action a, const target& t, const string&, match_extra& me) const { tracer trace ("adhoc_rule_regex_pattern::match"); + // Note: target may not be locked in which case we should not modify + // target or match_extra (see adhoc_rule::match() for background). + // The plan is as follows: First check the "type signature" of the target // and its prerequisites (the primary target type has already been matched // by the rule matching machinery). If there is a match, then concatenate @@ -161,12 +166,17 @@ namespace build2 // implementation. Except we support the unmatch and match values in // the update variable. // + // Note: assuming group prerequisites are immutable (not locked). + // for (prerequisite_member p: group_prerequisite_members (a, t)) { // Note that here we don't validate the update operation override // value (since we may not match). Instead the rule does this in // apply(). // + // Note: assuming include()'s use of target only relied on immutable + // data (not locked). + // lookup l; if (include (a, t, p, a.operation () == update_id ? &l : nullptr) == include_type::normal && p.is_a (tt)) @@ -205,10 +215,13 @@ namespace build2 // So the plan is to store the string in match_extra::data() and // regex_match_results (which we can move) in the auxiliary data storage. // + // Note: only cache if locked. + // static_assert (sizeof (string) <= match_extra::data_size, "match data too large"); - string& ns (me.data (string ())); + string tmp; + string& ns (me.locked ? me.data (string ()) : tmp); auto append_name = [&ns, first = true, @@ -226,10 +239,12 @@ namespace build2 // Primary target (always a pattern). // auto te (targets_.end ()), ti (targets_.begin ()); - append_name (t.key (), *ti); + append_name (t.key (), *ti); // Immutable (not locked). // Match ad hoc group members. // + // Note: shouldn't be in effect for an explicit group (not locked). + // while ((ti = find_if (ti + 1, te, pattern)) != te) { const target* at (find_adhoc_member (t, ti->type)); @@ -279,7 +294,9 @@ namespace build2 return false; } - t.data (a, move (mr)); + if (me.locked) + t.data (a, move (mr)); + return true; } @@ -304,8 +321,14 @@ namespace build2 } void adhoc_rule_regex_pattern:: - apply_adhoc_members (action a, target& t, const scope&, match_extra&) const + apply_group_members (action a, target& t, const scope& bs, + match_extra&) const { + if (targets_.size () == 1) // The group/primary target is always present. + return; + + group* g (t.is_a<group> ()); + const auto& mr (t.data<regex_match_results> (a)); for (auto i (targets_.begin () + 1); i != targets_.end (); ++i) @@ -333,14 +356,86 @@ namespace build2 d.normalize (); } - // @@ TODO: currently this uses type as the ad hoc member identity. + string n (substitute ( + t, + mr, + e.name.value, + (g != nullptr + ? "explicit target group member" + : "ad hoc target group member"))); + + // @@ TODO: save location in constructor? // - add_adhoc_member ( - t, - e.type, - move (d), - dir_path () /* out */, - substitute (t, mr, e.name.value, "ad hoc target group member")); + location loc; + + optional<string> ext (target::split_name (n, loc)); + + if (g != nullptr) + { + auto& ms (g->members); + + // These are conceptually static but they behave more like dynamic in + // that we likely need to insert the target, set its group, etc. In a + // sense, they are rule-static, but group-dynamic. + // + // Note: a custom version of the dyndep_rule::inject_group_member() + // logic. + // + auto l (search_new_locked ( + bs.ctx, + e.type, + move (d), + dir_path (), // Always in out. + move (n), + ext ? &*ext : nullptr, + &bs)); + + const target& t (l.first); // Note: non-const only if have lock. + + if (l.second) + { + l.first.group = g; + l.second.unlock (); + } + else + { + if (find (ms.begin (), ms.end (), &t) != ms.end ()) + continue; + + if (t.group != g) // Note: atomic. + { + // We can only update the group under lock. + // + target_lock tl (lock (a, t)); + + if (!tl) + fail << "group " << *g << " member " << t << " is already matched" << + info << "static group members specified by pattern rules cannot " + << "be used as prerequisites directly, only via group"; + + if (t.group == nullptr) + tl.target->group = g; + else if (t.group != g) + { + fail << "group " << *g << " member " << t + << " is already member of group " << *t.group; + } + } + } + + ms.push_back (&t); + } + else + { + add_adhoc_member_identity ( + t, + e.type, + move (d), + dir_path (), // Always in out. + move (n), + move (ext), + loc); + } } } @@ -357,6 +452,18 @@ namespace build2 auto& pts (t.prerequisite_targets[a]); + // Avoid duplicating fsdir{} that may have already been injected by + // inject_fsdir() (in which case it is expected to be first). + // + const target* dir (nullptr); + if (!pts.empty ()) + { + const prerequisite_target& pt (pts.front ()); + + if (pt.target != nullptr && pt.adhoc () && pt.target->is_a<fsdir> ()) + dir = pt.target; + } + for (const element& e: prereqs_) { // While it would be nice to avoid copying here, the semantics of @@ -393,7 +500,7 @@ namespace build2 const target& pt (search (t, move (n), *s, &e.type)); - if (clean && !pt.in (*bs.root_scope ())) + if (&pt == dir || (clean && !pt.in (*bs.root_scope ()))) continue; // @@ TODO: it could be handy to mark a prerequisite (e.g., a tool) |