aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/dist/rule.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/dist/rule.cxx')
-rw-r--r--libbuild2/dist/rule.cxx88
1 files changed, 75 insertions, 13 deletions
diff --git a/libbuild2/dist/rule.cxx b/libbuild2/dist/rule.cxx
index ac3d440..c63f7f3 100644
--- a/libbuild2/dist/rule.cxx
+++ b/libbuild2/dist/rule.cxx
@@ -8,6 +8,9 @@
#include <libbuild2/algorithm.hxx>
#include <libbuild2/diagnostics.hxx>
+#include <libbuild2/dist/types.hxx>
+#include <libbuild2/dist/module.hxx>
+
using namespace std;
namespace build2
@@ -27,17 +30,34 @@ namespace build2
const dir_path& src_root (rs.src_path ());
const dir_path& out_root (rs.out_path ());
- // If we can, go inside see-through groups.
+ // Note that we don't go inside see-through groups since the members for
+ // dist_* may be incomplete (or even bogus, e.g., the "representative
+ // sample"). Instead, for see-through groups our plan is as follows:
+ //
+ // 1. Here we match them as groups (so that we still match all their
+ // prerequisites).
+ //
+ // 2. In dist_project() we collect them along with files after dist_*
+ // but before perform_update. Here we also skip files that are
+ // members of see-through groups (which we may still get).
//
- for (prerequisite_member pm:
- group_prerequisite_members (a, t, members_mode::maybe))
+ // 3. During perform_update we collect all the see-through group
+ // members, similar to files on step (2).
+ //
+ for (const prerequisite& p: group_prerequisites (t))
{
// Note: no exclusion tests, we want all of them (and see also the
- // dist_include() override).
+ // dist_include() override). But if we don't ignore post hoc ones
+ // here, we will end up with a cycle (they will still be handled
+ // by the post-pass).
+ //
+ lookup l; // Ignore any operation-specific values.
+ if (include (a, t, p, &l) == include_type::posthoc)
+ continue;
// Skip prerequisites imported from other projects.
//
- if (pm.proj ())
+ if (p.proj)
continue;
// We used to always search and match but that resulted in the
@@ -56,18 +76,18 @@ namespace build2
// @@ Note that this is still an issue in a custom dist rule.
//
const target* pt (nullptr);
- if (pm.is_a<file> ())
+ if (p.is_a<file> ())
{
- pt = pm.load ();
+ pt = p.target.load ();
if (pt == nullptr)
{
- const prerequisite& p (pm.prerequisite);
-
// 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);
+ pt = k.tk.type->search (t.ctx, &t, k);
if (pt == nullptr)
{
@@ -79,15 +99,23 @@ namespace build2
!p.dir.sub (out_root))
continue;
- fail << "prerequisite " << k << " is not existing source file "
- << "nor known output target" << endf;
+ // 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()).
+ //
+ const module& mod (*rs.find_module<module> (module::name));
+
+ mlock l (mod.postponed.mutex);
+ mod.postponed.list.push_back (
+ postponed_prerequisite {a, t, p, t.state[a].rule->first});
+ continue;
}
search_custom (p, *pt); // Cache.
}
}
else
- pt = &pm.search (t);
+ pt = &search (t, p);
// Don't match targets that are outside of our project.
//
@@ -97,5 +125,39 @@ namespace build2
return noop_recipe; // We will never be executed.
}
+
+ void rule::
+ match_postponed (const postponed_prerequisite& pp)
+ {
+ action a (pp.action);
+ const target& t (pp.target);
+ const prerequisite& p (pp.prereq);
+
+ const prerequisite_key& k (p.key ());
+ const target* pt (k.tk.type->search (t.ctx, &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/rule manually.
+ //
+ fail << "prerequisite " << k << " is not existing source file nor "
+ << "known output target" <<
+ info << "while applying rule " << pp.rule << " 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);
+ }
+ }
}
}