aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/install
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-09-13 17:00:08 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-09-14 09:48:59 +0200
commitd552de5d028e1dfb108f343810604d0dfd74c2e6 (patch)
tree3ed1a320b0c3788001a1c61ff468f3392630f789 /libbuild2/install
parentb9ea935ac2e31144db8ebdc2a98ebfc3f94357cc (diff)
Consistently install prerequisites from any scope by default
It is also now possible to adjust this behavior with global config.install.scope override. Valid values for this variable are: project -- only from project strong -- from strong amalgamation weak -- from weak amalgamation global -- from all projects (default)
Diffstat (limited to 'libbuild2/install')
-rw-r--r--libbuild2/install/init.cxx31
-rw-r--r--libbuild2/install/rule.cxx43
-rw-r--r--libbuild2/install/rule.hxx21
-rw-r--r--libbuild2/install/utility.cxx32
-rw-r--r--libbuild2/install/utility.hxx8
5 files changed, 111 insertions, 24 deletions
diff --git a/libbuild2/install/init.cxx b/libbuild2/install/init.cxx
index 677ee07..5b5d1e2 100644
--- a/libbuild2/install/init.cxx
+++ b/libbuild2/install/init.cxx
@@ -392,6 +392,37 @@ namespace build2
// Configuration.
//
+
+ // config.install.scope
+ //
+ // We do not install prerequisites (for example, shared libraries) of
+ // targets (for example, executables) that belong to projects outside of
+ // this scope. Valid values are:
+ //
+ // project -- project scope
+ // strong -- strong amalgamation
+ // weak -- weak amalgamation
+ // global -- all projects (default)
+ //
+ // Note: can only be specified as a global override.
+ //
+ {
+ auto& v (vp.insert<string> ("config.install.scope"));
+
+ // If specified, verify it is a global override.
+ //
+ if (lookup l = rs[v])
+ {
+ if (!l.belongs (rs.global_scope ()))
+ fail << "config.install.scope must be a global override" <<
+ info << "specify !config.install.scope=...";
+ }
+
+ config::unsave_variable (rs, v);
+ }
+
+ // Installation directories.
+ //
// Note that we don't use any defaults for root -- the location
// must be explicitly specified or the installer will complain
// if and when we try to install.
diff --git a/libbuild2/install/rule.cxx b/libbuild2/install/rule.cxx
index 388400a..5092d42 100644
--- a/libbuild2/install/rule.cxx
+++ b/libbuild2/install/rule.cxx
@@ -54,16 +54,19 @@ namespace build2
}
const target* alias_rule::
- filter (action a, const target& t, prerequisite_iterator& i) const
+ filter (const scope* is,
+ action a, const target& t, prerequisite_iterator& i) const
{
assert (i->member == nullptr);
- return filter (a, t, i->prerequisite);
+ return filter (is, a, t, i->prerequisite);
}
const target* alias_rule::
- filter (action, const target& t, const prerequisite& p) const
+ filter (const scope* is,
+ action, const target& t, const prerequisite& p) const
{
- return &search (t, p);
+ const target& pt (search (t, p));
+ return is == nullptr || pt.in (*is) ? &pt : nullptr;
}
recipe alias_rule::
@@ -75,8 +78,9 @@ namespace build2
//
// @@ Shouldn't we do match in parallel (here and below)?
//
- auto& pts (t.prerequisite_targets[a]);
+ optional<const scope*> is; // Installation scope (resolve lazily).
+ auto& pts (t.prerequisite_targets[a]);
auto pms (group_prerequisite_members (a, t, members_mode::never));
for (auto i (pms.begin ()), e (pms.end ()); i != e; ++i)
{
@@ -100,7 +104,10 @@ namespace build2
// Note: we assume that if the filter enters the group, then it
// iterates over all its members.
//
- const target* pt (filter (a, t, i));
+ if (!is)
+ is = install_scope (t);
+
+ const target* pt (filter (*is, a, t, i));
if (pt == nullptr)
{
l5 ([&]{trace << "ignoring " << p << " (filtered out)";});
@@ -217,7 +224,6 @@ namespace build2
if (gv.members != nullptr)
{
auto& pts (t.prerequisite_targets[a]);
-
for (size_t i (0); i != gv.count; ++i)
{
const target* m (gv.members[i]);
@@ -271,17 +277,19 @@ namespace build2
}
const target* file_rule::
- filter (action a, const target& t, prerequisite_iterator& i) const
+ filter (const scope* is,
+ action a, const target& t, prerequisite_iterator& i) const
{
assert (i->member == nullptr);
- return filter (a, t, i->prerequisite);
+ return filter (is, a, t, i->prerequisite);
}
const target* file_rule::
- filter (action, const target& t, const prerequisite& p) const
+ filter (const scope* is,
+ action, const target& t, const prerequisite& p) const
{
const target& pt (search (t, p));
- return pt.in (t.root_scope ()) ? &pt : nullptr;
+ return is == nullptr || pt.in (*is) ? &pt : nullptr;
}
recipe file_rule::
@@ -314,8 +322,9 @@ namespace build2
if (a.operation () == update_id)
unchanged = match_inner (a, t, unmatch::unchanged).first;
- auto& pts (t.prerequisite_targets[a]);
+ optional<const scope*> is; // Installation scope (resolve lazily).
+ auto& pts (t.prerequisite_targets[a]);
auto pms (group_prerequisite_members (a, t, members_mode::never));
for (auto i (pms.begin ()), e (pms.end ()); i != e; ++i)
{
@@ -339,7 +348,11 @@ namespace build2
// Note: we assume that if the filter enters the group, then it
// iterates over all its members.
//
- const target* pt (filter (a, t, i));
+ if (!is)
+ is = install_scope (t);
+
+ const target* pt (filter (*is, a, t, i));
+
if (pt == nullptr)
{
l5 ([&]{trace << "ignoring " << p << " (filtered out)";});
@@ -541,7 +554,9 @@ namespace build2
{
if (fail_unknown)
fail << "unknown installation directory name '" << sn << "'" <<
- info << "did you forget to specify config." << var << "?";
+ info << "did you forget to specify config." << var << "?" <<
+ info << "specify !config." << var << "=... if installing "
+ << "from multiple projects";
return rs; // Empty.
}
diff --git a/libbuild2/install/rule.hxx b/libbuild2/install/rule.hxx
index 73f2486..ce60bb9 100644
--- a/libbuild2/install/rule.hxx
+++ b/libbuild2/install/rule.hxx
@@ -25,7 +25,9 @@ namespace build2
match (action, target&, const string&) const override;
// Return NULL if this prerequisite should be ignored and pointer to its
- // target otherwise. The default implementation allows all prerequsites.
+ // target otherwise. The default implementation ignores prerequsites
+ // that are outside of the installation scope (see install_scope() for
+ // details).
//
// The prerequisite is passed as an iterator allowing the filter to
// "see" inside groups.
@@ -34,10 +36,11 @@ namespace build2
prerequisite_members_range<group_prerequisites>::iterator;
virtual const target*
- filter (action, const target&, prerequisite_iterator&) const;
+ filter (const scope*,
+ action, const target&, prerequisite_iterator&) const;
virtual const target*
- filter (action, const target&, const prerequisite&) const;
+ filter (const scope*, action, const target&, const prerequisite&) const;
virtual recipe
apply (action, target&) const override;
@@ -103,11 +106,8 @@ namespace build2
// Return NULL if this prerequisite should be ignored and pointer to its
// target otherwise. The default implementation ignores prerequsites
- // that are outside of this target's project.
- //
- // @@ I wonder why we do weak amalgamation for alias but project for
- // file? And then override this for prerequisite libraries/modules
- // in cc::install_rule and bash::install_rule...
+ // that are outside of the installation scope (see install_scope() for
+ // details).
//
// The prerequisite is passed as an iterator allowing the filter to
// "see" inside groups.
@@ -116,10 +116,11 @@ namespace build2
prerequisite_members_range<group_prerequisites>::iterator;
virtual const target*
- filter (action, const target&, prerequisite_iterator&) const;
+ filter (const scope*,
+ action, const target&, prerequisite_iterator&) const;
virtual const target*
- filter (action, const target&, const prerequisite&) const;
+ filter (const scope*, action, const target&, const prerequisite&) const;
virtual recipe
apply (action, target&) const override;
diff --git a/libbuild2/install/utility.cxx b/libbuild2/install/utility.cxx
new file mode 100644
index 0000000..12215f8
--- /dev/null
+++ b/libbuild2/install/utility.cxx
@@ -0,0 +1,32 @@
+// file : libbuild2/install/utility.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <libbuild2/install/utility.hxx>
+
+namespace build2
+{
+ namespace install
+ {
+ const scope*
+ install_scope (const target& t)
+ {
+ context& ctx (t.ctx);
+
+ const variable& var (*ctx.var_pool.find ("config.install.scope"));
+
+ if (const string* s = cast_null<string> (ctx.global_scope[var]))
+ {
+ if (*s == "project")
+ return &t.root_scope ();
+ else if (*s == "strong")
+ return &t.strong_scope ();
+ else if (*s == "weak")
+ return &t.weak_scope ();
+ else if (*s != "global")
+ fail << "invalid " << var << " value '" << *s << "'";
+ }
+
+ return nullptr;
+ }
+ }
+}
diff --git a/libbuild2/install/utility.hxx b/libbuild2/install/utility.hxx
index 2c0ca56..cc5cd53 100644
--- a/libbuild2/install/utility.hxx
+++ b/libbuild2/install/utility.hxx
@@ -56,6 +56,14 @@ namespace build2
return install_mode (s, T::static_type, move (m));
}
+ // Return the "installation scope". We do not install prerequisites (for
+ // example, shared libraries) of targets (for example, executables) that
+ // belong to projects outside of this scope. If it's NULL, install
+ // prerequisites from all projects. See also config.install.scope.
+ //
+ LIBBUILD2_SYMEXPORT const scope*
+ install_scope (const target&);
+
// Resolve relative installation directory path (e.g., include/libfoo) to
// its absolute directory path (e.g., /usr/include/libfoo). If the
// resolution encountered an unknown directory, issue diagnostics and fail