aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-07-29 10:32:36 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-07-29 10:32:36 +0200
commit682836daacdd3dc486187c9d60479b372895a470 (patch)
treea042ab0e46052436b08355f43fd54d9055ce9b82
parent2b922df93fcea9e3fad8e24b39c7fe579085d3ac (diff)
Implement "see through" installation semantics for utility libraries
-rw-r--r--build2/cc/install.cxx84
-rw-r--r--build2/cc/install.hxx23
-rw-r--r--build2/cc/link.hxx3
-rw-r--r--build2/cc/module.cxx28
-rw-r--r--build2/cc/module.hxx8
-rw-r--r--build2/install/init.cxx16
-rw-r--r--build2/install/rule.cxx27
-rw-r--r--build2/install/rule.hxx10
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<libu> () || p.is_a<libux> ())
- return nullptr;
+ // NOTE: see also alias_install::filter() below if changing anything
+ // here.
if (t.is_a<exe> ())
{
@@ -44,25 +44,32 @@ namespace build2
// @@ Shouldn't we also install a static library prerequisite of a
// static library?
//
- if ((t.is_a<exe> () || t.is_a<libs> ()) &&
- (p.is_a<lib> () || p.is_a<libs> ()))
+ if ((t.is_a<exe> () || t.is_a<libs> ()) &&
+ (p.is_a<libx> () || p.is_a<libs> ()))
{
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<lib> ())
+ if (const libx* l = pt->is_a<libx> ())
pt = &link_member (
*l, a, link_info (t.base_scope (), link_type (t).type));
if (pt->is_a<libs> ()) // 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<libux> ())
+ 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<libs> () && 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<libue> ())
+ {
+ if (x_header (p))
+ return nullptr;
+ }
+
+ if ((t.is_a<libue> () || t.is_a<libus> ()) &&
+ (p.is_a<libx> () || p.is_a<libs> ()))
+ {
+ const target* pt (&p.search (t));
+
+ if (const libx* l = pt->is_a<libx> ())
+ pt = &link_member (
+ *l, a, link_info (t.base_scope (), link_type (t).type));
+
+ if (pt->is_a<libs> ())
+ return pt->in (t.weak_scope ()) ? pt : nullptr;
+
+ if (pt->is_a<libux> ())
+ 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<libs> (perform_clean_id, x_link, lr);
r.insert<libs> (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<exe> (perform_install_id, x_install, ir);
- r.insert<exe> (perform_uninstall_id, x_uninstall, ir);
+ r.insert<exe> (perform_install_id, x_install, fr);
+ r.insert<exe> (perform_uninstall_id, x_uninstall, fr);
- r.insert<liba> (perform_install_id, x_install, ir);
- r.insert<liba> (perform_uninstall_id, x_uninstall, ir);
+ r.insert<liba> (perform_install_id, x_install, fr);
+ r.insert<liba> (perform_uninstall_id, x_uninstall, fr);
- r.insert<libs> (perform_install_id, x_install, ir);
- r.insert<libs> (perform_uninstall_id, x_uninstall, ir);
+ r.insert<libs> (perform_install_id, x_install, fr);
+ r.insert<libs> (perform_uninstall_id, x_uninstall, fr);
+
+ r.insert<libue> (perform_install_id, x_install, ar);
+ r.insert<libue> (perform_uninstall_id, x_uninstall, ar);
+
+ r.insert<libua> (perform_install_id, x_install, ar);
+ r.insert<libua> (perform_uninstall_id, x_uninstall, ar);
+
+ r.insert<libus> (perform_install_id, x_install, ar);
+ r.insert<libus> (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<bool> (string ("install.") + n + ".subdirs");
}
- static const alias_rule alias_;
- static const file_rule file_;
-
void
boot (scope& r, const location&, unique_ptr<module_base>&)
{
@@ -200,11 +197,16 @@ namespace build2
// Register our alias and file rules.
//
- bs.rules.insert<alias> (perform_install_id, "install.alias", alias_);
- bs.rules.insert<alias> (perform_uninstall_id, "uninstall.alias", alias_);
+ {
+ const auto& ar (alias_rule::instance);
+ const auto& fr (file_rule::instance);
- bs.rules.insert<file> (perform_install_id, "install.file", file_);
- bs.rules.insert<file> (perform_uninstall_id, "uinstall.file", file_);
+ bs.rules.insert<alias> (perform_install_id, "install.alias", ar);
+ bs.rules.insert<alias> (perform_uninstall_id, "uninstall.alias", ar);
+
+ bs.rules.insert<file> (perform_install_id, "install.file", fr);
+ bs.rules.insert<file> (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<path> (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