From 3bbbe09e8629ab5311a1bcbb9f56aa6a33e36f55 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 30 Nov 2022 09:08:53 +0200 Subject: Deal with order dependence in dist rule --- libbuild2/dist/rule.cxx | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'libbuild2/dist/rule.cxx') 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); + } + } } } -- cgit v1.1