aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/algorithm.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/algorithm.ixx')
-rw-r--r--libbuild2/algorithm.ixx279
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)