diff options
Diffstat (limited to 'libbuild2/algorithm.ixx')
-rw-r--r-- | libbuild2/algorithm.ixx | 279 |
1 files changed, 227 insertions, 52 deletions
diff --git a/libbuild2/algorithm.ixx b/libbuild2/algorithm.ixx index 2637349..836dbed 100644 --- a/libbuild2/algorithm.ixx +++ b/libbuild2/algorithm.ixx @@ -45,6 +45,17 @@ namespace build2 k.proj, {&tt, k.tk.dir, k.tk.out, k.tk.name, k.tk.ext}, k.scope}); } + inline const target* + search_existing (context& ctx, + const target_type& tt, + const prerequisite_key& k) + { + return search_existing ( + ctx, + prerequisite_key { + k.proj, {&tt, k.tk.dir, k.tk.out, k.tk.name, k.tk.ext}, k.scope}); + } + inline const target& search_new (context& ctx, const target_type& tt, @@ -187,15 +198,32 @@ namespace build2 t, T::static_type, dir, out, name, ext, scope).template as<T> (); } + template <typename T> + inline const T* + search_existing (context& ctx, + const dir_path& dir, + const dir_path& out, + const string& name, + const string* ext, + const scope* scope) + { + const target* r ( + search_existing ( + ctx, T::static_type, dir, out, name, ext, scope)); + return r != nullptr ? &r->template as<T> () : nullptr; + } + LIBBUILD2_SYMEXPORT target_lock - lock_impl (action, const target&, optional<scheduler::work_queue>); + lock_impl (action, const target&, + optional<scheduler::work_queue>, + uint64_t = 0); LIBBUILD2_SYMEXPORT void unlock_impl (action, target&, size_t); inline target_lock:: - target_lock (action_type a, target_type* t, size_t o) - : action (a), target (t), offset (o) + target_lock (action_type a, target_type* t, size_t o, bool f) + : action (a), target (t), offset (o), first (f) { if (target != nullptr) prev = stack (this); @@ -234,7 +262,7 @@ namespace build2 inline auto target_lock:: release () -> data { - data r {action, target, offset}; + data r {action, target, offset, first}; if (target != nullptr) { @@ -258,7 +286,7 @@ namespace build2 } inline target_lock:: - target_lock (target_lock&& x) + target_lock (target_lock&& x) noexcept : action (x.action), target (x.target), offset (x.offset) { if (target != nullptr) @@ -278,7 +306,7 @@ namespace build2 } inline target_lock& target_lock:: - operator= (target_lock&& x) + operator= (target_lock&& x) noexcept { if (this != &x) { @@ -346,7 +374,7 @@ namespace build2 n += e; } - return add_adhoc_member (t, tt, t.dir, t.out, move (n)); + return add_adhoc_member (t, tt, t.dir, t.out, move (n), nullopt /* ext */); } inline target* @@ -366,13 +394,18 @@ namespace build2 } LIBBUILD2_SYMEXPORT const rule_match* - match_rule (action, target&, const rule* skip, bool try_match = false); + match_rule_impl (action, target&, + uint64_t options, + const rule* skip, + bool try_match = false, + match_extra* = nullptr); LIBBUILD2_SYMEXPORT recipe apply_impl (action, target&, const rule_match&); LIBBUILD2_SYMEXPORT pair<bool, target_state> match_impl (action, const target&, + uint64_t options, size_t, atomic_count*, bool try_match = false); @@ -384,11 +417,11 @@ namespace build2 } inline target_state - match_sync (action a, const target& t, bool fail) + match_sync (action a, const target& t, uint64_t options, bool fail) { assert (t.ctx.phase == run_phase::match); - target_state r (match_impl (a, t, 0, nullptr).second); + target_state r (match_impl (a, t, options, 0, nullptr).second); if (r != target_state::failed) match_inc_dependents (a, t); @@ -399,12 +432,12 @@ namespace build2 } inline pair<bool, target_state> - try_match_sync (action a, const target& t, bool fail) + try_match_sync (action a, const target& t, uint64_t options, bool fail) { assert (t.ctx.phase == run_phase::match); pair<bool, target_state> r ( - match_impl (a, t, 0, nullptr, true /* try_match */)); + match_impl (a, t, options, 0, nullptr, true /* try_match */)); if (r.first) { @@ -418,11 +451,11 @@ namespace build2 } inline pair<bool, target_state> - match_sync (action a, const target& t, unmatch um) + match_sync (action a, const target& t, unmatch um, uint64_t options) { assert (t.ctx.phase == run_phase::match); - target_state s (match_impl (a, t, 0, nullptr).second); + target_state s (match_impl (a, t, options, 0, nullptr).second); if (s == target_state::failed) throw failed (); @@ -449,7 +482,7 @@ namespace build2 // cannot change their mind). // if ((s == target_state::unchanged && t.group == nullptr) || - t[a].dependents.load (memory_order_consume) != 0) + t[a].dependents.load (memory_order_relaxed) != 0) return make_pair (true, s); break; @@ -463,39 +496,76 @@ namespace build2 inline target_state match_async (action a, const target& t, size_t sc, atomic_count& tc, + uint64_t options, bool fail) { context& ctx (t.ctx); assert (ctx.phase == run_phase::match); - target_state r (match_impl (a, t, sc, &tc).second); + target_state r (match_impl (a, t, options, sc, &tc).second); - if (fail && !ctx.keep_going && r == target_state::failed) + if (r == target_state::failed && fail && !ctx.keep_going) throw failed (); return r; } inline target_state - match_complete (action a, const target& t, bool fail) + match_complete (action a, const target& t, uint64_t options, bool fail) { - return match_sync (a, t, fail); + return match_sync (a, t, options, fail); } inline pair<bool, target_state> - match_complete (action a, const target& t, unmatch um) + match_complete (action a, const target& t, unmatch um, uint64_t options) + { + return match_sync (a, t, um, options); + } + + inline target_state + match_direct_sync (action a, const target& t, uint64_t options, bool fail) + { + assert (t.ctx.phase == run_phase::match); + + target_state r (match_impl (a, t, options, 0, nullptr).second); + + if (r == target_state::failed && fail) + throw failed (); + + return r; + } + + inline target_state + match_direct_complete (action a, const target& t, + uint64_t options, + bool fail) { - return match_sync (a, t, um); + return match_direct_sync (a, t, options, fail); } - // Clear rule match-specific target data. + // Clear rule match-specific target data (except match_extra). // inline void clear_target (action a, target& t) { - t[a].vars.clear (); + target::opstate& s (t.state[a]); + s.recipe = nullptr; + s.recipe_keep = false; + s.resolve_counted = false; + s.vars.clear (); t.prerequisite_targets[a].clear (); - t.clear_data (a); + } + + LIBBUILD2_SYMEXPORT void + set_rule_trace (target_lock&, const rule_match*); + + inline void + set_rule (target_lock& l, const rule_match* r) + { + if (l.target->ctx.trace_match == nullptr) + (*l.target)[l.action].rule = r; + else + set_rule_trace (l, r); } inline void @@ -542,60 +612,101 @@ namespace build2 } inline void - match_recipe (target_lock& l, recipe r) + match_recipe (target_lock& l, recipe r, uint64_t options) { - assert (l.target != nullptr && - l.offset != target::offset_matched && + assert (options != 0 && + l.target != nullptr && + l.offset < target::offset_matched && l.target->ctx.phase == run_phase::match); + match_extra& me ((*l.target)[l.action].match_extra); + + me.reinit (false /* fallback */); + me.cur_options = options; // Already applied, so cur_, not new_options. + me.cur_options_.store (me.cur_options, memory_order_relaxed); clear_target (l.action, *l.target); - (*l.target)[l.action].rule = nullptr; // No rule. + set_rule (l, nullptr); // No rule. set_recipe (l, move (r)); l.offset = target::offset_applied; } inline void - match_rule (target_lock& l, const rule_match& r) + match_rule (target_lock& l, const rule_match& r, uint64_t options) { assert (l.target != nullptr && - l.offset != target::offset_matched && + l.offset < target::offset_matched && l.target->ctx.phase == run_phase::match); + match_extra& me ((*l.target)[l.action].match_extra); + + me.reinit (false /* fallback */); + me.new_options = options; clear_target (l.action, *l.target); - (*l.target)[l.action].rule = &r; + set_rule (l, &r); l.offset = target::offset_matched; } inline recipe - match_delegate (action a, target& t, const rule& dr, bool try_match) + match_delegate (action a, target& t, + const rule& dr, + uint64_t options, + bool try_match) { assert (t.ctx.phase == run_phase::match); // Note: we don't touch any of the t[a] state since that was/will be set // for the delegating rule. // - const rule_match* r (match_rule (a, t, &dr, try_match)); + const rule_match* r (match_rule_impl (a, t, options, &dr, try_match)); return r != nullptr ? apply_impl (a, t, *r) : empty_recipe; } inline target_state - match_inner (action a, const target& t) + match_inner (action a, const target& t, uint64_t options) { // In a sense this is like any other dependency. // assert (a.outer ()); - return match_sync (a.inner_action (), t); + return match_sync (a.inner_action (), t, options); } inline pair<bool, target_state> - match_inner (action a, const target& t, unmatch um) + match_inner (action a, const target& t, unmatch um, uint64_t options) { assert (a.outer ()); - return match_sync (a.inner_action (), t, um); + return match_sync (a.inner_action (), t, um, options); + } + + // Note: rematch is basically normal match but without the counts increment, + // so we just delegate to match_direct_*(). + // + inline target_state + rematch_sync (action a, const target& t, + uint64_t options, + bool fail) + { + return match_direct_sync (a, t, options, fail); + } + + inline target_state + rematch_async (action a, const target& t, + size_t start_count, atomic_count& task_count, + uint64_t options, + bool fail) + { + return match_async (a, t, start_count, task_count, options, fail); + } + + inline target_state + rematch_complete (action a, const target& t, + uint64_t options, + bool fail) + { + return match_direct_complete (a, t, options, fail); } LIBBUILD2_SYMEXPORT void - resolve_group_impl (action, const target&, target_lock); + resolve_group_impl (target_lock&&); inline const target* resolve_group (action a, const target& t) @@ -615,7 +726,7 @@ namespace build2 // then unlock and return. // if (t.group == nullptr && l.offset < target::offset_tried) - resolve_group_impl (a, t, move (l)); + resolve_group_impl (move (l)); break; } @@ -634,12 +745,16 @@ namespace build2 } LIBBUILD2_SYMEXPORT void - match_prerequisites (action, target&, const match_search&, const scope*); + match_prerequisites (action, target&, + const match_search&, + const scope*, + bool search_only); LIBBUILD2_SYMEXPORT void match_prerequisite_members (action, target&, const match_search_member&, - const scope*); + const scope*, + bool search_only); inline void match_prerequisites (action a, target& t, const match_search& ms) @@ -650,7 +765,21 @@ namespace build2 ms, (a.operation () != clean_id || t.is_a<alias> () ? nullptr - : &t.root_scope ())); + : &t.root_scope ()), + false); + } + + inline void + search_prerequisites (action a, target& t, const match_search& ms) + { + match_prerequisites ( + a, + t, + ms, + (a.operation () != clean_id || t.is_a<alias> () + ? nullptr + : &t.root_scope ()), + true); } inline void @@ -658,13 +787,16 @@ namespace build2 const match_search_member& msm) { if (a.operation () != clean_id || t.is_a<alias> ()) - match_prerequisite_members (a, t, msm, nullptr); + match_prerequisite_members (a, t, msm, nullptr, false); else { // Note that here we don't iterate over members even for see-through // groups since the group target should clean eveything up. A bit of an // optimization. // + // @@ TMP: I wonder if this still holds for the new group semantics + // we have in Qt automoc? Also below. + // match_search ms ( msm ? [&msm] (action a, @@ -676,20 +808,62 @@ namespace build2 } : match_search ()); - match_prerequisites (a, t, ms, &t.root_scope ()); + match_prerequisites (a, t, ms, &t.root_scope (), false); + } + } + + inline void + search_prerequisite_members (action a, target& t, + const match_search_member& msm) + { + if (a.operation () != clean_id || t.is_a<alias> ()) + match_prerequisite_members (a, t, msm, nullptr, true); + else + { + // Note that here we don't iterate over members even for see-through + // groups since the group target should clean eveything up. A bit of an + // optimization. + // + // @@ TMP: I wonder if this still holds for the new group semantics + // we have in Qt automoc? Also above. + // + match_search ms ( + msm + ? [&msm] (action a, + const target& t, + const prerequisite& p, + include_type i) + { + return msm (a, t, prerequisite_member {p, nullptr}, i); + } + : match_search ()); + + match_prerequisites (a, t, ms, &t.root_scope (), true); } } inline void match_prerequisites (action a, target& t, const scope& s) { - match_prerequisites (a, t, nullptr, &s); + match_prerequisites (a, t, nullptr, &s, false); + } + + inline void + search_prerequisites (action a, target& t, const scope& s) + { + match_prerequisites (a, t, nullptr, &s, true); } inline void match_prerequisite_members (action a, target& t, const scope& s) { - match_prerequisite_members (a, t, nullptr, &s); + match_prerequisite_members (a, t, nullptr, &s, false); + } + + inline void + search_prerequisite_members (action a, target& t, const scope& s) + { + match_prerequisite_members (a, t, nullptr, &s, true); } LIBBUILD2_SYMEXPORT target_state @@ -702,7 +876,7 @@ namespace build2 if (r == target_state::busy) { - t.ctx.sched.wait (t.ctx.count_executed (), + t.ctx.sched->wait (t.ctx.count_executed (), t[a].task_count, scheduler::work_none); @@ -738,7 +912,7 @@ namespace build2 // If the target is still busy, wait for its completion. // - ctx.sched.wait (ctx.count_executed (), + ctx.sched->wait (ctx.count_executed (), t[a].task_count, scheduler::work_none); @@ -749,20 +923,20 @@ namespace build2 execute_direct_impl (action, const target&, size_t, atomic_count*); inline target_state - execute_direct_sync (action a, const target& t) + execute_direct_sync (action a, const target& t, bool fail) { target_state r (execute_direct_impl (a, t, 0, nullptr)); if (r == target_state::busy) { - t.ctx.sched.wait (t.ctx.count_executed (), + t.ctx.sched->wait (t.ctx.count_executed (), t[a].task_count, scheduler::work_none); r = t.executed_state (a, false); } - if (r == target_state::failed) + if (r == target_state::failed && fail) throw failed (); return r; @@ -922,8 +1096,9 @@ namespace build2 p.first, static_cast<const T&> (p.second)); } + template <typename T> inline target_state - execute_members (action a, const target& t, const target* ts[], size_t n) + execute_members (action a, const target& t, T ts[], size_t n) { return t.ctx.current_mode == execution_mode::first ? straight_execute_members (a, t, ts, n, 0) |