aboutsummaryrefslogtreecommitdiff
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
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)
-rw-r--r--libbuild2/bash/rule.cxx15
-rw-r--r--libbuild2/bash/rule.hxx11
-rw-r--r--libbuild2/cc/install-rule.cxx24
-rw-r--r--libbuild2/cc/install-rule.hxx6
-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
-rw-r--r--tests/function/install/testscript1
10 files changed, 132 insertions, 60 deletions
diff --git a/libbuild2/bash/rule.cxx b/libbuild2/bash/rule.cxx
index d378227..82c06c7 100644
--- a/libbuild2/bash/rule.cxx
+++ b/libbuild2/bash/rule.cxx
@@ -420,20 +420,5 @@ namespace build2
return r;
}
-
- const target* install_rule::
- filter (action a, const target& t, const prerequisite& p) const
- {
- // If this is a module prerequisite, install it as long as it is in the
- // same amalgamation as we are.
- //
- if (p.is_a<bash> ())
- {
- const target& pt (search (t, p));
- return pt.in (t.weak_scope ()) ? &pt : nullptr;
- }
- else
- return file_rule::filter (a, t, p);
- }
}
}
diff --git a/libbuild2/bash/rule.hxx b/libbuild2/bash/rule.hxx
index 81c4604..c54b07c 100644
--- a/libbuild2/bash/rule.hxx
+++ b/libbuild2/bash/rule.hxx
@@ -61,12 +61,8 @@ namespace build2
const string&) const;
};
- // Installation rule for bash scripts (exe{}) and modules (bash{}). Here
- // we do:
- //
- // 1. Signal to in_rule that this is update for install.
- //
- // 2. Custom filtering of prerequisites.
+ // Installation rule for bash scripts (exe{}) and modules (bash{}) that
+ // signals to in_rule that this is update for install.
//
class LIBBUILD2_BASH_SYMEXPORT install_rule: public install::file_rule
{
@@ -79,9 +75,6 @@ namespace build2
virtual recipe
apply (action, target&) const override;
- virtual const target*
- filter (action, const target&, const prerequisite&) const override;
-
protected:
const in_rule& in_;
};
diff --git a/libbuild2/cc/install-rule.cxx b/libbuild2/cc/install-rule.cxx
index dc10543..3e62d59 100644
--- a/libbuild2/cc/install-rule.cxx
+++ b/libbuild2/cc/install-rule.cxx
@@ -25,14 +25,15 @@ namespace build2
: common (move (d)), link_ (l) {}
const target* install_rule::
- filter (action a, const target& t, prerequisite_iterator& i) const
+ filter (const scope* is,
+ action a, const target& t, prerequisite_iterator& i) const
{
// NOTE: see libux_install_rule::filter() if changing anything here.
const prerequisite& p (i->prerequisite);
- // If this is a shared library prerequisite, install it as long as it
- // is in the same amalgamation as we are.
+ // If this is a shared library prerequisite, install it as long as it is
+ // in the installation scope.
//
// Less obvious: we also want to install a static library prerequisite
// of a library (since it could be referenced from its .pc file, etc).
@@ -61,7 +62,7 @@ namespace build2
// Note: not redundant since we are returning a member.
//
if ((st && pt->is_a<libs> ()) || (at && pt->is_a<liba> ()))
- return pt->in (t.weak_scope ()) ? pt : nullptr;
+ return is == nullptr || pt->in (*is) ? pt : nullptr;
// See through to libu*{} members. Note that we are always in the same
// project (and thus amalgamation).
@@ -72,7 +73,7 @@ namespace build2
// The rest of the tests only succeed if the base filter() succeeds.
//
- const target* pt (file_rule::filter (a, t, p));
+ const target* pt (file_rule::filter (is, a, t, p));
if (pt == nullptr)
return pt;
@@ -137,7 +138,7 @@ namespace build2
{
pt = t.is_a<exe> ()
? nullptr
- : file_rule::filter (a, *pt, pm.prerequisite);
+ : file_rule::filter (is, a, *pt, pm.prerequisite);
break;
}
}
@@ -279,8 +280,11 @@ namespace build2
: common (move (d)), link_ (l) {}
const target* libux_install_rule::
- filter (action a, const target& t, prerequisite_iterator& i) const
+ filter (const scope* is,
+ action a, const target& t, prerequisite_iterator& i) const
{
+ using file_rule = install::file_rule;
+
const prerequisite& p (i->prerequisite);
// The "see through" semantics that should be parallel to install_rule
@@ -301,13 +305,13 @@ namespace build2
pt = link_member (*l, a, link_info (t.base_scope (), ot));
if ((st && pt->is_a<libs> ()) || (at && pt->is_a<liba> ()))
- return pt->in (t.weak_scope ()) ? pt : nullptr;
+ return is == nullptr || pt->in (*is) ? pt : nullptr;
if (pt->is_a<libux> ())
return pt;
}
- const target* pt (install::file_rule::instance.filter (a, t, p));
+ const target* pt (file_rule::instance.filter (is, a, t, p));
if (pt == nullptr)
return pt;
@@ -349,7 +353,7 @@ namespace build2
{
pt = t.is_a<libue> ()
? nullptr
- : install::file_rule::instance.filter (a, *pt, pm.prerequisite);
+ : file_rule::instance.filter (is, a, *pt, pm.prerequisite);
break;
}
}
diff --git a/libbuild2/cc/install-rule.hxx b/libbuild2/cc/install-rule.hxx
index 5856352..acd1bd8 100644
--- a/libbuild2/cc/install-rule.hxx
+++ b/libbuild2/cc/install-rule.hxx
@@ -35,7 +35,8 @@ namespace build2
install_rule (data&&, const link_rule&);
virtual const target*
- filter (action, const target&, prerequisite_iterator&) const override;
+ filter (const scope*,
+ action, const target&, prerequisite_iterator&) const override;
virtual bool
match (action, target&, const string&) const override;
@@ -67,7 +68,8 @@ namespace build2
libux_install_rule (data&&, const link_rule&);
virtual const target*
- filter (action, const target&, prerequisite_iterator&) const override;
+ filter (const scope*,
+ action, const target&, prerequisite_iterator&) const override;
virtual bool
match (action, target&, const string&) const override;
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
diff --git a/tests/function/install/testscript b/tests/function/install/testscript
index 12cd506..2c70871 100644
--- a/tests/function/install/testscript
+++ b/tests/function/install/testscript
@@ -28,6 +28,7 @@ EOI
$* <'print $install.resolve([dir_path] foo/a)' 2>>EOE != 0
error: unknown installation directory name 'foo'
info: did you forget to specify config.install.foo?
+ info: specify !config.install.foo=... if installing from multiple projects
<stdin>:1:8: info: while calling install.resolve(dir_path)
EOE
}