From a49b6fff2ba25bf9150f89a4ecfc2c707ba633de Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 30 Oct 2023 10:38:53 +0200 Subject: WIP: install: complete reapply() for libu --- libbuild2/cc/install-rule.cxx | 16 +++--- libbuild2/install/rule.cxx | 119 ++++++++++++++++++++++++++++++++++++------ libbuild2/install/rule.hxx | 17 ++++++ 3 files changed, 127 insertions(+), 25 deletions(-) diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx index 0a5fb57..d3fa522 100644 --- a/libbuild2/cc/install-rule.cxx +++ b/libbuild2/cc/install-rule.cxx @@ -680,7 +680,8 @@ namespace build2 } } - return alias_rule::apply (a, t, me); + return alias_rule::apply_impl ( + a, t, me, me.cur_options != match_extra::all_options /* reapply */); } void libux_install_rule:: @@ -692,11 +693,8 @@ namespace build2 << ' ' << me.cur_options << ' ' << me.new_options; // @@ TMP - // If we are rematched with the buildtime option, propagate it to our - // prerequisite libraries. - // - // @@ Also libux? - // + me.cur_options |= me.new_options; + if ((me.new_options & lib::option_install_buildtime) != 0) { for (const target* pt: t.prerequisite_targets[a]) @@ -705,11 +703,9 @@ namespace build2 pt->is_a () || pt->is_a ())) rematch_sync (a, *pt, match_extra::all_options); } - } - - // @@ TODO: match additional prerequisites if required. - me.cur_options |= me.new_options; + alias_rule::reapply_impl (a, t, me); + } } } } diff --git a/libbuild2/install/rule.cxx b/libbuild2/install/rule.cxx index 63d58a7..29888ae 100644 --- a/libbuild2/install/rule.cxx +++ b/libbuild2/install/rule.cxx @@ -93,8 +93,23 @@ namespace build2 recipe alias_rule:: apply (action a, target& t, match_extra& me) const { + return apply_impl (a, t, me); + } + + recipe alias_rule:: + apply (action, target&) const + { + assert (false); // Never called. + return nullptr; + } + + recipe alias_rule:: + apply_impl (action a, target& t, match_extra& me, bool reapply) const + { tracer trace ("install::alias_rule::apply"); + assert (!reapply || a.operation () != update_id); + // Pass-through to our installable prerequisites. // // @@ Shouldn't we do match in parallel (here and below)? @@ -105,6 +120,8 @@ namespace build2 auto pms (group_prerequisite_members (a, t, members_mode::never)); for (auto i (pms.begin ()), e (pms.end ()); i != e; ++i) { + // NOTE: see essentially the same logic in reapply_impl() below. + // const prerequisite& p (i->prerequisite); // Ignore excluded. @@ -131,12 +148,14 @@ namespace build2 pair fr (filter (*is, a, t, i, me)); const target* pt (fr.first); + uint64_t options (fr.second); + + lookup l; + if (pt == nullptr) { l5 ([&]{trace << "ignoring " << p << " (filtered out)";}); - continue; } - // Check if this prerequisite is explicitly "not installable", that // is, there is the 'install' variable and its value is false. // @@ -148,38 +167,108 @@ namespace build2 // // Note: not the same as lookup_install() above. // - auto l ((*pt)[var_install (*p.scope.root_scope ())]); - if (l && cast (l).string () == "false") + else if ((l = (*pt)[var_install (*p.scope.root_scope ())]) && + cast (l).string () == "false") { l5 ([&]{trace << "ignoring " << *pt << " (not installable)";}); - continue; + pt = nullptr; } - - uint64_t options (fr.second); - // If this is not a file-based target (e.g., a target group such as // libu{}) then ignore it if there is no rule to install. // - if (pt->is_a ()) + else if (pt->is_a ()) + { match_sync (a, *pt, options); + } else if (!try_match_sync (a, *pt, options).first) { l5 ([&]{trace << "ignoring " << *pt << " (no rule)";}); pt = nullptr; } - if (pt != nullptr) - pts.push_back (prerequisite_target (pt, pi)); + if (pt != nullptr || reapply) + { + // Use auxiliary data for a NULL entry to distinguish between + // filtered out (1) and ignored for other reasons (0). + // + pts.push_back ( + prerequisite_target (pt, pi, fr.first == nullptr ? 1 : 0)); + } } return default_recipe; } - recipe alias_rule:: - apply (action, target&) const + void alias_rule:: + reapply_impl (action a, target& t, match_extra& me) const { - assert (false); // Never called. - return nullptr; + tracer trace ("install::alias_rule::reapply"); + + assert (a.operation () != update_id); + + optional is; + + // Iterate over prerequisites and prerequisite targets in parallel. + // + auto& pts (t.prerequisite_targets[a]); + size_t j (0), n (pts.size ()), en (0); + + auto pms (group_prerequisite_members (a, t, members_mode::never)); + for (auto i (pms.begin ()), e (pms.end ()); + i != e && j != n; + ++i, ++j, ++en) + { + // The same logic as in apply() above except that we skip + // prerequisites that were not filtered out. + // + const prerequisite& p (i->prerequisite); + + include_type pi (include (a, t, p)); + if (!pi) + continue; + + if (p.proj) + continue; + + prerequisite_target& pto (pts[j]); + + if (pto.target != nullptr || pto.data == 0) + continue; + + if (!is) + is = a.operation () != update_id ? install_scope (t) : nullptr; + + pair fr (filter (*is, a, t, i, me)); + + const target* pt (fr.first); + uint64_t options (fr.second); + + lookup l; + + if (pt == nullptr) + { + l5 ([&]{trace << "ignoring " << p << " (filtered out)";}); + } + else if ((l = (*pt)[var_install (*p.scope.root_scope ())]) && + cast (l).string () == "false") + { + l5 ([&]{trace << "ignoring " << *pt << " (not installable)";}); + pt = nullptr; + } + else if (pt->is_a ()) + { + match_sync (a, *pt, options); + } + else if (!try_match_sync (a, *pt, options).first) + { + l5 ([&]{trace << "ignoring " << *pt << " (no rule)";}); + pt = nullptr; + } + + pto = prerequisite_target (pt, pi, fr.first == nullptr ? 1 : 0); + } + + assert (en == n); // Did not call apply() with true for reapply? } // group_rule diff --git a/libbuild2/install/rule.hxx b/libbuild2/install/rule.hxx index 04ac9a7..b023af5 100644 --- a/libbuild2/install/rule.hxx +++ b/libbuild2/install/rule.hxx @@ -56,6 +56,23 @@ namespace build2 virtual recipe apply (action, target&, match_extra&) const override; + // Implementation of apply(). + // + // If the implementation may call reapply_impl(), then the reapply + // argument to apply_impl() must be true. Note that in this case, the + // *_impl() functions use the prerequisite_target::data member for own + // housekeeping. + // + recipe + apply_impl (action, target&, match_extra&, bool reapply = false) const; + + // Implementation of reapply() that re-tries prerequisites that have + // been filtered out during the reapply() call. Note that currently not + // supported for update, only for install/uninstall. + // + void + reapply_impl (action, target&, match_extra&) const; + alias_rule () {} static const alias_rule instance; -- cgit v1.1