aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/build/script/parser.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-12-03 09:47:05 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-12-03 09:47:05 +0200
commit82e9227262a41bfa740952659b3b91d2d99e984e (patch)
treeb0ee458f8cb0fb28ac0aae9b1927331a1d80a94c /libbuild2/build/script/parser.cxx
parentd9745e79083e12a2c3eb129a20fc20be3607a4c3 (diff)
Add depdb-dyndep --drop-cycles option
Diffstat (limited to 'libbuild2/build/script/parser.cxx')
-rw-r--r--libbuild2/build/script/parser.cxx72
1 files changed, 46 insertions, 26 deletions
diff --git a/libbuild2/build/script/parser.cxx b/libbuild2/build/script/parser.cxx
index 15545cf..2210cc8 100644
--- a/libbuild2/build/script/parser.cxx
+++ b/libbuild2/build/script/parser.cxx
@@ -1442,7 +1442,8 @@ namespace build2
move (cwd),
move (*file),
ops.what_specified () ? move (ops.what ()) : string (what),
- def_pt};
+ def_pt,
+ ops.drop_cycles ()};
return;
}
@@ -1600,13 +1601,15 @@ namespace build2
auto add = [this, &trace, what,
a, &bs, &t, &pts, pts_n = pts.size (),
- &map_ext, def_pt, &pfx_map, &so_map,
+ &ops, &map_ext, def_pt, &pfx_map, &so_map,
&dd, &skip_count] (path fp,
- bool cache,
+ size_t* skip,
timestamp mt) -> optional<bool>
{
context& ctx (t.ctx);
+ bool cache (skip == nullptr);
+
// We can only defer the failure if we will be running the recipe
// body.
//
@@ -1636,26 +1639,51 @@ namespace build2
fp, cache, cache /* normalized */,
map_ext, *def_pt, pfx_map, so_map).first)
{
- // Skip if this is one of the static prerequisites.
+ // We don't need to do these tests for the cached case since such
+ // prerequisites would have been skipped (and we won't get here if
+ // the target/prerequisite set changes since we hash them).
//
- for (size_t i (0); i != pts_n; ++i)
+ if (!cache)
{
- const prerequisite_target& p (pts[i]);
+ // Skip if this is one of the static prerequisites.
+ //
+ for (size_t i (0); i != pts_n; ++i)
+ {
+ const prerequisite_target& p (pts[i]);
- if (const target* pt =
- (p.target != nullptr ? p.target :
- p.data != 0 ? reinterpret_cast<target*> (p.data) :
- nullptr))
+ if (const target* pt =
+ (p.target != nullptr ? p.target :
+ p.data != 0 ? reinterpret_cast<target*> (p.data) :
+ nullptr))
+ {
+ if (ft == pt)
+ return false;
+ }
+ }
+
+ // Skip if this is one of the targets.
+ //
+ if (ops.drop_cycles ())
{
- if (pt == ft)
+ for (const target* m (&t); m != nullptr; m = m->adhoc_member)
{
- // Note that we have to increment the skip count since we
- // skip before performing this test.
- //
- skip_count++;
- return false;
+ if (ft == m)
+ return false;
}
}
+
+ // Skip until where we left off.
+ //
+ // Note that we used to do this outside of this lambda and
+ // before calling enter_file() but due to the above skips we can
+ // only do it here if we want to have a consistent view of the
+ // prerequisite lists between the cached and non-cached cases.
+ //
+ if (*skip != 0)
+ {
+ --(*skip);
+ return false;
+ }
}
if (optional<bool> u = dyndep::inject_file (
@@ -1724,7 +1752,7 @@ namespace build2
if (l->empty ()) // Done, nothing changed.
return;
- if (optional<bool> r = add (path (move (*l)), true /*cache*/, mt))
+ if (optional<bool> r = add (path (move (*l)), nullptr, mt))
{
restart = *r;
@@ -1880,16 +1908,8 @@ namespace build2
if (r.first == make_type::target)
continue;
- // Skip until where we left off.
- //
- if (skip != 0)
- {
- skip--;
- continue;
- }
-
if (optional<bool> u = add (path (move (r.second)),
- false /* cache */,
+ &skip,
rmt))
{
restart = *u;