diff options
Diffstat (limited to 'libbuild2/dist/rule.cxx')
-rw-r--r-- | libbuild2/dist/rule.cxx | 104 |
1 files changed, 90 insertions, 14 deletions
diff --git a/libbuild2/dist/rule.cxx b/libbuild2/dist/rule.cxx index 31f34e4..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 @@ -15,7 +18,7 @@ namespace build2 namespace dist { bool rule:: - match (action, target&, const string&) const + match (action, target&) const { return true; // We always match. } @@ -23,19 +26,38 @@ namespace build2 recipe rule:: apply (action a, target& t) const { - const dir_path& out_root (t.root_scope ().out_path ()); + const scope& rs (t.root_scope ()); + 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 p: - 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 (p.proj ()) + if (p.proj) continue; // We used to always search and match but that resulted in the @@ -56,32 +78,86 @@ namespace build2 const target* pt (nullptr); if (p.is_a<file> ()) { - pt = p.load (); + pt = p.target.load (); if (pt == nullptr) { // 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) - fail << "prerequisite " << k << " is not existing source file " - << "nor known output target" << endf; + { + // Skip it if it's outside of the project (e.g., an executable + // "imported" in an ad hoc way). + // + if (p.dir.absolute () && + !p.dir.sub (src_root) && + !p.dir.sub (out_root)) + continue; + + // 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.prerequisite, *pt); // Cache. + search_custom (p, *pt); // Cache. } } else - pt = &p.search (t); + pt = &search (t, p); // Don't match targets that are outside of our project. // if (pt->dir.sub (out_root)) - build2::match (a, *pt); + match_sync (a, *pt); } 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); + } + } } } |