aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/dist/rule.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-11-30 09:08:53 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-11-30 09:08:53 +0200
commit3bbbe09e8629ab5311a1bcbb9f56aa6a33e36f55 (patch)
treef3f6ab4fc633d98ae5a215ba4529b07849ba6792 /libbuild2/dist/rule.cxx
parentd593b19735eec451b091fd46e4cb066e3478d6c9 (diff)
Deal with order dependence in dist rule
Diffstat (limited to 'libbuild2/dist/rule.cxx')
-rw-r--r--libbuild2/dist/rule.cxx43
1 files changed, 38 insertions, 5 deletions
diff --git a/libbuild2/dist/rule.cxx b/libbuild2/dist/rule.cxx
index 0c72ff5..7233eba 100644
--- a/libbuild2/dist/rule.cxx
+++ b/libbuild2/dist/rule.cxx
@@ -72,6 +72,8 @@ namespace build2
// Search for an existing target or existing file in src.
//
+ // Note: see also similar code in match_postponed() below.
+ //
const prerequisite_key& k (p.key ());
pt = k.tk.type->search (t, k);
@@ -85,12 +87,13 @@ namespace build2
!p.dir.sub (out_root))
continue;
- // @@ TODO: this can actually be order-dependent: for example
- // libs{} prerequisite may be unknown because we haven't
- // matched the lib{} group yet.
+ // This can be order-dependent: for example libs{} prerequisite
+ // may be unknown because we haven't matched the lib{} group
+ // yet. So we postpone this for later (see match_postponed()).
//
- fail << "prerequisite " << k << " is not existing source file "
- << "nor known output target" << endf;
+ mlock l (postponed_.mutex);
+ postponed_.list.push_back (postponed_prerequisite {a, t, p,});
+ continue;
}
search_custom (p, *pt); // Cache.
@@ -107,5 +110,35 @@ namespace build2
return noop_recipe; // We will never be executed.
}
+
+ void rule::
+ match_postponed (action a, const target& t, const prerequisite& p)
+ {
+ const prerequisite_key& k (p.key ());
+ const target* pt (k.tk.type->search (t, k));
+
+ if (pt == nullptr)
+ {
+ // Note that we do loose the diag frame that we normally get when
+ // failing during match. So let's mention the target manually.
+ //
+ fail << "prerequisite " << k << " is not existing source file nor "
+ << "known output target" <<
+ info << "while applying rule dist to " << diag_do (a, t);
+ }
+
+ search_custom (p, *pt); // Cache.
+
+ // It's theoretically possible that the target gets entered but nobody
+ // else depends on it but us. So we need to make sure it's matched
+ // (since it, in turns, can pull in other targets). Note that this could
+ // potentially add new postponed prerequisites to the list.
+ //
+ if (!pt->matched (a))
+ {
+ if (pt->dir.sub (t.root_scope ().out_path ()))
+ match_direct_sync (a, *pt);
+ }
+ }
}
}