aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/algorithm.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-06-21 10:04:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-06-21 10:04:07 +0200
commitbbe8cbd13c40a1309e0d7724319c5487a5df0879 (patch)
treebdd1e00d9605ec7d5d3d99f44f7eafaf7249a64c /libbuild2/algorithm.cxx
parent2f29c7fbe758ffb53e4de9983df8b1cc927dad05 (diff)
Add --trace-{match,execute} options
These options can be used to understand which dependency chain causes matching or execution of a particular target.
Diffstat (limited to 'libbuild2/algorithm.cxx')
-rw-r--r--libbuild2/algorithm.cxx96
1 files changed, 95 insertions, 1 deletions
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 355e633..564105c 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -357,6 +357,70 @@ namespace build2
return *m;
};
+ static bool
+ trace_target (const target& t, const vector<name>& ns)
+ {
+ for (const name& n: ns)
+ {
+ if (n.untyped () || n.qualified () || n.pattern)
+ fail << "unsupported trace target name '" << n << "'" <<
+ info << "unqualified, typed, non-pattern name expected";
+
+ if (!n.dir.empty ())
+ {
+ if (n.dir.relative () || !n.dir.normalized ())
+ fail << "absolute and normalized trace target directory expected";
+
+ if (t.dir != n.dir)
+ continue;
+ }
+
+ if (n.type == t.type ().name && n.value == t.name)
+ return true;
+ }
+
+ return false;
+ }
+
+ void
+ set_rule_trace (target_lock& l, const rule_match* rm)
+ {
+ action a (l.action);
+ target& t (*l.target);
+
+ // Note: see similar code in execute_impl() for execute.
+ //
+ if (trace_target (t, *t.ctx.trace_match))
+ {
+ diag_record dr (info);
+
+ dr << "matching to " << diag_do (a, t);
+
+ if (rm != nullptr)
+ {
+ const rule& r (rm->second);
+
+ if (const adhoc_rule* ar = dynamic_cast<const adhoc_rule*> (&r))
+ {
+ dr << info (ar->loc);
+
+ if (ar->pattern != nullptr)
+ dr << "using ad hoc pattern rule ";
+ else
+ dr << "using ad hoc recipe ";
+ }
+ else
+ dr << info << "using rule ";
+
+ dr << rm->first;
+ }
+ else
+ dr << info << "using directly-assigned recipe";
+ }
+
+ t[a].rule = rm;
+ }
+
// Return the matching rule or NULL if no match and try_match is true.
//
const rule_match*
@@ -837,7 +901,7 @@ namespace build2
return make_pair (false, target_state::unknown);
}
- s.rule = r;
+ set_rule (l, r);
l.offset = target::offset_matched;
if (step)
@@ -1899,6 +1963,36 @@ namespace build2
backlink_clean_pre (a, t, *blm);
}
+ // Note: see similar code in set_rule_trace() for match.
+ //
+ if (ctx.trace_execute != nullptr && trace_target (t, *ctx.trace_execute))
+ {
+ diag_record dr (info);
+
+ dr << diag_doing (a, t);
+
+ if (s.rule != nullptr)
+ {
+ const rule& r (s.rule->second);
+
+ if (const adhoc_rule* ar = dynamic_cast<const adhoc_rule*> (&r))
+ {
+ dr << info (ar->loc);
+
+ if (ar->pattern != nullptr)
+ dr << "using ad hoc pattern rule ";
+ else
+ dr << "using ad hoc recipe ";
+ }
+ else
+ dr << info << "using rule ";
+
+ dr << s.rule->first;
+ }
+ else
+ dr << info << "using directly-assigned recipe";
+ }
+
ts = execute_recipe (a, t, s.recipe);
if (blm)