From 682836daacdd3dc486187c9d60479b372895a470 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 29 Jul 2017 10:32:36 +0200 Subject: Implement "see through" installation semantics for utility libraries --- build2/cc/install.cxx | 84 ++++++++++++++++++++++++++++++++++++++++--------- build2/cc/install.hxx | 23 ++++++++++++-- build2/cc/link.hxx | 3 +- build2/cc/module.cxx | 28 ++++++++++++----- build2/cc/module.hxx | 8 +++-- build2/install/init.cxx | 16 +++++----- build2/install/rule.cxx | 27 +++++++++++----- build2/install/rule.hxx | 10 ++++++ 8 files changed, 157 insertions(+), 42 deletions(-) diff --git a/build2/cc/install.cxx b/build2/cc/install.cxx index 75f6b8a..a0dc9b8 100644 --- a/build2/cc/install.cxx +++ b/build2/cc/install.cxx @@ -19,16 +19,16 @@ namespace build2 { using namespace bin; - install:: - install (data&& d, const link& l): common (move (d)), link_ (l) {} + // file_install + // + file_install:: + file_install (data&& d, const link& l): common (move (d)), link_ (l) {} - const target* install:: + const target* file_install:: filter (action a, const target& t, prerequisite_member p) const { - // Skip utility libraries. - // - if (p.is_a () || p.is_a ()) - return nullptr; + // NOTE: see also alias_install::filter() below if changing anything + // here. if (t.is_a ()) { @@ -44,25 +44,32 @@ namespace build2 // @@ Shouldn't we also install a static library prerequisite of a // static library? // - if ((t.is_a () || t.is_a ()) && - (p.is_a () || p.is_a ())) + if ((t.is_a () || t.is_a ()) && + (p.is_a () || p.is_a ())) { const target* pt (&p.search (t)); - // If this is the lib{} group, pick a member which we would link. + // If this is the lib{}/libu{} group, pick a member which we would + // link. For libu{} we want to the "see through" logic. // - if (const lib* l = pt->is_a ()) + if (const libx* l = pt->is_a ()) pt = &link_member ( *l, a, link_info (t.base_scope (), link_type (t).type)); if (pt->is_a ()) // Can be liba{}. return pt->in (t.weak_scope ()) ? pt : nullptr; + + // See through libux{}. Note that we are always in the same project + // (and thus amalgamation). + // + if (pt->is_a ()) + return pt; } return file_rule::filter (a, t, p); } - match_result install:: + match_result file_install:: match (action a, target& t, const string& hint) const { // @@ How do we split the hint between the two? @@ -75,7 +82,7 @@ namespace build2 return r ? file_rule::match (a, t, "") : r; } - recipe install:: + recipe file_install:: apply (action a, target& t) const { recipe r (file_rule::apply (a, t)); @@ -93,7 +100,7 @@ namespace build2 return r; } - void install:: + void file_install:: install_extra (const file& t, const install_dir& id) const { if (t.is_a () && tclass != "windows") @@ -119,7 +126,7 @@ namespace build2 } } - bool install:: + bool file_install:: uninstall_extra (const file& t, const install_dir& id) const { bool r (false); @@ -146,5 +153,52 @@ namespace build2 return r; } + + // alias_install + // + alias_install:: + alias_install (data&& d, const link& l): common (move (d)), link_ (l) {} + + const target* alias_install:: + filter (action a, const target& t, prerequisite_member p) const + { + // The "see through" semantics that should be parallel to file_install + // above. In particular, here we use libue/libua/libus{} as proxies for + // exe/liba/libs{} there. + // + if (t.is_a ()) + { + if (x_header (p)) + return nullptr; + } + + if ((t.is_a () || t.is_a ()) && + (p.is_a () || p.is_a ())) + { + const target* pt (&p.search (t)); + + if (const libx* l = pt->is_a ()) + pt = &link_member ( + *l, a, link_info (t.base_scope (), link_type (t).type)); + + if (pt->is_a ()) + return pt->in (t.weak_scope ()) ? pt : nullptr; + + if (pt->is_a ()) + return pt; + } + + return alias_rule::filter (a, t, p); + } + + match_result alias_install:: + match (action a, target& t, const string& hint) const + { + // We only want to handle installation if we are also the ones building + // this target. So first run link's match(). + // + match_result r (link_.match (a, t, hint)); + return r ? alias_rule::match (a, t, "") : r; + } } } diff --git a/build2/cc/install.hxx b/build2/cc/install.hxx index b7d92fb..a846fc8 100644 --- a/build2/cc/install.hxx +++ b/build2/cc/install.hxx @@ -19,10 +19,12 @@ namespace build2 { class link; - class install: public build2::install::file_rule, virtual common + // Installation rule for exe, liba{}, and libs{}. + // + class file_install: public install::file_rule, virtual common { public: - install (data&&, const link&); + file_install (data&&, const link&); virtual const target* filter (action, const target&, prerequisite_member) const override; @@ -42,6 +44,23 @@ namespace build2 private: const link& link_; }; + + // Installation rule for libux{}. + // + class alias_install: public install::alias_rule, virtual common + { + public: + alias_install (data&&, const link&); + + virtual const target* + filter (action, const target&, prerequisite_member) const override; + + virtual match_result + match (action, target&, const string&) const override; + + private: + const link& link_; + }; } } diff --git a/build2/cc/link.hxx b/build2/cc/link.hxx index ed28eca..c4c9c9e 100644 --- a/build2/cc/link.hxx +++ b/build2/cc/link.hxx @@ -37,7 +37,8 @@ namespace build2 perform_clean (action, const target&) const; private: - friend class install; + friend class file_install; + friend class alias_install; // Shared library paths. // diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx index 2b19e70..56b74e9 100644 --- a/build2/cc/module.cxx +++ b/build2/cc/module.cxx @@ -425,20 +425,32 @@ namespace build2 r.insert (perform_clean_id, x_link, lr); r.insert (configure_update_id, x_link, lr); - // Note that libu*{} are not installable. + // Note that while libu*{} are not installable, we need to see through + // them in case they depend on stuff that we need to install (see the + // install rule implementations for details). // if (install_loaded) { - const install& ir (*this); + const file_install& fr (*this); + const alias_install& ar (*this); - r.insert (perform_install_id, x_install, ir); - r.insert (perform_uninstall_id, x_uninstall, ir); + r.insert (perform_install_id, x_install, fr); + r.insert (perform_uninstall_id, x_uninstall, fr); - r.insert (perform_install_id, x_install, ir); - r.insert (perform_uninstall_id, x_uninstall, ir); + r.insert (perform_install_id, x_install, fr); + r.insert (perform_uninstall_id, x_uninstall, fr); - r.insert (perform_install_id, x_install, ir); - r.insert (perform_uninstall_id, x_uninstall, ir); + r.insert (perform_install_id, x_install, fr); + r.insert (perform_uninstall_id, x_uninstall, fr); + + r.insert (perform_install_id, x_install, ar); + r.insert (perform_uninstall_id, x_uninstall, ar); + + r.insert (perform_install_id, x_install, ar); + r.insert (perform_uninstall_id, x_uninstall, ar); + + r.insert (perform_install_id, x_install, ar); + r.insert (perform_uninstall_id, x_uninstall, ar); } } } diff --git a/build2/cc/module.hxx b/build2/cc/module.hxx index db17998..a6a1115 100644 --- a/build2/cc/module.hxx +++ b/build2/cc/module.hxx @@ -52,7 +52,10 @@ namespace build2 }; class module: public module_base, protected virtual common, - link, compile, install + link, + compile, + file_install, + alias_install { public: explicit @@ -60,7 +63,8 @@ namespace build2 : common (move (d)), link (move (d)), compile (move (d)), - install (move (d), *this) {} + file_install (move (d), *this), + alias_install (move (d), *this) {} void init (scope&, const location&, const variable_map&); diff --git a/build2/install/init.cxx b/build2/install/init.cxx index 6a5114d..1d51be2 100644 --- a/build2/install/init.cxx +++ b/build2/install/init.cxx @@ -124,9 +124,6 @@ namespace build2 var_pool.rw (r).insert (string ("install.") + n + ".subdirs"); } - static const alias_rule alias_; - static const file_rule file_; - void boot (scope& r, const location&, unique_ptr&) { @@ -200,11 +197,16 @@ namespace build2 // Register our alias and file rules. // - bs.rules.insert (perform_install_id, "install.alias", alias_); - bs.rules.insert (perform_uninstall_id, "uninstall.alias", alias_); + { + const auto& ar (alias_rule::instance); + const auto& fr (file_rule::instance); - bs.rules.insert (perform_install_id, "install.file", file_); - bs.rules.insert (perform_uninstall_id, "uinstall.file", file_); + bs.rules.insert (perform_install_id, "install.alias", ar); + bs.rules.insert (perform_uninstall_id, "uninstall.alias", ar); + + bs.rules.insert (perform_install_id, "install.file", fr); + bs.rules.insert (perform_uninstall_id, "uinstall.file", fr); + } // Configuration. // diff --git a/build2/install/rule.cxx b/build2/install/rule.cxx index 8611247..f2fc233 100644 --- a/build2/install/rule.cxx +++ b/build2/install/rule.cxx @@ -38,20 +38,32 @@ namespace build2 // alias_rule // + const alias_rule alias_rule::instance; + match_result alias_rule:: match (action, target&, const string&) const { return true; } + const target* alias_rule:: + filter (action, const target& t, prerequisite_member p) const + { + return &p.search (t); + } + recipe alias_rule:: apply (action a, target& t) const { tracer trace ("install::alias_rule::apply"); - for (const prerequisite& p: group_prerequisites (t)) + for (prerequisite_member p: group_prerequisite_members (a, t)) { - const target& pt (search (t, p)); + // Let a customized rule have its say. + // + const target* pt (filter (a, t, p)); + if (pt == nullptr) + continue; // Check if this prerequisite is explicitly "not installable", // that is, there is the 'install' variable and its value is @@ -65,16 +77,15 @@ namespace build2 // // Note: not the same as lookup() above. // - auto l (pt["install"]); - + auto l ((*pt)["install"]); if (l && cast (l).string () == "false") { - l5 ([&]{trace << "ignoring " << pt;}); + l5 ([&]{trace << "ignoring " << *pt;}); continue; } - build2::match (a, pt); - t.prerequisite_targets.push_back (&pt); + build2::match (a, *pt); + t.prerequisite_targets.push_back (pt); } return default_recipe; @@ -82,6 +93,8 @@ namespace build2 // file_rule // + const file_rule file_rule::instance; + struct match_data { bool install; diff --git a/build2/install/rule.hxx b/build2/install/rule.hxx index 76259c9..ad0d8ec 100644 --- a/build2/install/rule.hxx +++ b/build2/install/rule.hxx @@ -19,6 +19,8 @@ namespace build2 class alias_rule: public rule { public: + static const alias_rule instance; + alias_rule () {} virtual match_result @@ -26,6 +28,12 @@ namespace build2 virtual recipe apply (action, target&) const override; + + // Return NULL if this prerequisite should be ignored and pointer to its + // target otherwise. The default implementation accepts all prerequsites. + // + virtual const target* + filter (action, const target&, prerequisite_member) const; }; struct install_dir; @@ -33,6 +41,8 @@ namespace build2 class file_rule: public rule { public: + static const file_rule instance; + file_rule () {} virtual match_result -- cgit v1.1