aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-12 13:46:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-12 13:46:07 +0200
commitad4120afce8c7bc4001fc0173a0ff7611ec0198d (patch)
treeebbc31d03feda96560df437247b63206489a1139
parentdd4a389117812f0d3b45473d87214d67d0cb4a3a (diff)
Implement installation of prerequisite shared libraries
-rw-r--r--build/algorithm.cxx2
-rw-r--r--build/algorithm.ixx4
-rw-r--r--build/cxx/install2
-rw-r--r--build/cxx/install.cxx34
-rw-r--r--build/cxx/link22
-rw-r--r--build/cxx/link.cxx80
-rw-r--r--build/dist/operation.cxx2
-rw-r--r--build/file.cxx4
-rw-r--r--build/install/rule10
-rw-r--r--build/install/rule.cxx29
-rw-r--r--build/prerequisite7
-rw-r--r--build/prerequisite.cxx6
-rw-r--r--build/scope18
-rw-r--r--build/target8
-rw-r--r--build/target.txx5
15 files changed, 142 insertions, 91 deletions
diff --git a/build/algorithm.cxx b/build/algorithm.cxx
index 461d8d2..b296929 100644
--- a/build/algorithm.cxx
+++ b/build/algorithm.cxx
@@ -32,7 +32,7 @@ namespace build
// If this is a project-qualified prerequisite, then this
// is import's business.
//
- if (*pk.proj != nullptr)
+ if (pk.proj != nullptr)
return import (pk);
if (target* t = pk.tk.type->search (pk))
diff --git a/build/algorithm.ixx b/build/algorithm.ixx
index 72a04fe..309f99b 100644
--- a/build/algorithm.ixx
+++ b/build/algorithm.ixx
@@ -34,10 +34,8 @@ namespace build
const std::string* ext,
scope* scope)
{
- const std::string* proj (nullptr);
return search (
- prerequisite_key
- {&proj, {&type, &dir, &name, &ext}, scope});
+ prerequisite_key {nullptr, {&type, &dir, &name, &ext}, scope});
}
template <typename T>
diff --git a/build/cxx/install b/build/cxx/install
index 7117fb8..9df8408 100644
--- a/build/cxx/install
+++ b/build/cxx/install
@@ -15,7 +15,7 @@ namespace build
class install: public build::install::file_rule
{
public:
- virtual bool
+ virtual target*
filter (action, target&, prerequisite_member) const;
virtual match_result
diff --git a/build/cxx/install.cxx b/build/cxx/install.cxx
index e6417a6..f8c2c06 100644
--- a/build/cxx/install.cxx
+++ b/build/cxx/install.cxx
@@ -17,16 +17,35 @@ namespace build
{
using namespace bin;
- bool install::
- filter (action, target& t, prerequisite_member p) const
+ target* install::
+ filter (action a, target& t, prerequisite_member p) const
{
- // Don't install executable's prerequisite headers.
+ if (t.is_a<exe> ())
+ {
+ // Don't install executable's prerequisite headers.
+ //
+ if (p.is_a<hxx> () || p.is_a<ixx> () || p.is_a<txx> () || p.is_a<h> ())
+ return nullptr;
+ }
+
+ // If this is a shared library prerequisite, install it as long as it
+ // is in the same amalgamation as we are.
//
- if (t.is_a<exe> () &&
- (p.is_a<hxx> () || p.is_a<ixx> () || p.is_a<txx> () || p.is_a<h> ()))
- return false;
+ if ((t.is_a<exe> () || t.is_a<libso> ()) &&
+ (p.is_a<lib> () || p.is_a<libso> ()))
+ {
+ target* pt (&p.search ());
+
+ // If this is the lib{} group, pick a member which we would link.
+ //
+ if (lib* l = pt->is_a<lib> ())
+ pt = &link::link_member (*l, link::link_order (t));
- return true;
+ if (pt->is_a<libso> ()) // Can be liba{}.
+ return pt->in (t.weak_scope ()) ? pt : nullptr;
+ }
+
+ return file_rule::filter (a, t, p);
}
match_result install::
@@ -39,7 +58,6 @@ namespace build
// ones building this target. So first run link's match().
//
match_result r (link::instance.match (a, t, hint));
-
return r ? install::file_rule::match (a, t, "") : r;
}
diff --git a/build/cxx/link b/build/cxx/link
index 5d3d29e..5a5aafa 100644
--- a/build/cxx/link
+++ b/build/cxx/link
@@ -12,6 +12,8 @@
#include <build/types>
#include <build/rule>
+#include <build/bin/target>
+
namespace build
{
namespace cxx
@@ -30,6 +32,26 @@ namespace build
static link instance;
+ public:
+ enum class type {e, a, so};
+ enum class order {a, so, a_so, so_a};
+
+ static type
+ link_type (target& t)
+ {
+ return t.is_a<bin::exe> ()
+ ? type::e
+ : (t.is_a<bin::liba> () ? type::a : type::so);
+ }
+
+ static order
+ link_order (target&);
+
+ // Determine the library member (liba or libso) to link.
+ //
+ static target&
+ link_member (bin::lib&, order);
+
private:
friend class compile;
diff --git a/build/cxx/link.cxx b/build/cxx/link.cxx
index f5a2e3d..9296035 100644
--- a/build/cxx/link.cxx
+++ b/build/cxx/link.cxx
@@ -38,16 +38,7 @@ namespace build
{
using namespace bin;
- enum class type {e, a, so};
- enum class order {a, so, a_so, so_a};
-
- static inline type
- link_type (target& t)
- {
- return t.is_a<exe> () ? type::e : (t.is_a<liba> () ? type::a : type::so);
- }
-
- static order
+ link::order link::
link_order (target& t)
{
const char* var;
@@ -65,6 +56,40 @@ namespace build
: v.size () > 1 && v[1] == "shared" ? order::a_so : order::a;
}
+ target& link::
+ link_member (bin::lib& l, order lo)
+ {
+ bool lso (true);
+ const string& at (as<string> (*l["bin.lib"])); // Available types.
+
+ switch (lo)
+ {
+ case order::a:
+ case order::a_so:
+ lso = false; // Fall through.
+ case order::so:
+ case order::so_a:
+ {
+ if (lso ? at == "static" : at == "shared")
+ {
+ if (lo == order::a_so || lo == order::so_a)
+ lso = !lso;
+ else
+ fail << (lso ? "shared" : "static") << " build of " << l
+ << " is not available";
+ }
+ }
+ }
+
+ target* r (lso ? static_cast<target*> (l.so) : l.a);
+
+ if (r == nullptr)
+ r = &search (lso ? libso::static_type : liba::static_type,
+ prerequisite_key {nullptr, l.key (), nullptr});
+
+ return *r;
+ }
+
link::search_paths link::
extract_library_paths (scope& bs)
{
@@ -455,7 +480,7 @@ namespace build
type lt (link_type (t));
bool so (lt == type::so);
- optional<order> lo; // Link-order.
+ order lo (link_order (t));
// Derive file name from target name.
//
@@ -541,38 +566,7 @@ namespace build
}
else if (lib* l = pt->is_a<lib> ())
{
- // Determine the library type to link.
- //
- bool lso (true);
- const string& at (as<string> (*(*l)["bin.lib"]));
-
- if (!lo)
- lo = link_order (t);
-
- switch (*lo)
- {
- case order::a:
- case order::a_so:
- lso = false; // Fall through.
- case order::so:
- case order::so_a:
- {
- if (lso ? at == "static" : at == "shared")
- {
- if (*lo == order::a_so || *lo == order::so_a)
- lso = !lso;
- else
- fail << (lso ? "shared" : "static") << " build of " << *l
- << " is not available";
- }
- }
- }
-
- pt = lso ? static_cast<target*> (l->so) : l->a;
-
- if (pt == nullptr)
- pt = &search (lso ? libso::static_type : liba::static_type,
- p.key ());
+ pt = &link_member (*l, lo);
}
build::match (a, *pt);
diff --git a/build/dist/operation.cxx b/build/dist/operation.cxx
index 0069432..28a64fa 100644
--- a/build/dist/operation.cxx
+++ b/build/dist/operation.cxx
@@ -187,7 +187,7 @@ namespace build
const dir_path& src_nroot (nrs.src_path ());
- if (!src_nroot.sub (src_root)) // Not a source-level amalgamation.
+ if (!src_nroot.sub (src_root)) // Not a strong amalgamation.
continue;
add_adhoc (src_nroot, "build/export.build");
diff --git a/build/file.cxx b/build/file.cxx
index 59fe1b9..73ce7cb 100644
--- a/build/file.cxx
+++ b/build/file.cxx
@@ -957,8 +957,8 @@ namespace build
target&
import (const prerequisite_key& pk)
{
- assert (*pk.proj != nullptr);
- const string& p (**pk.proj);
+ assert (pk.proj != nullptr);
+ const string& p (*pk.proj);
// @@ We no longer have location. This is especially bad for the
// empty case, i.e., where do I need to specify the project
diff --git a/build/install/rule b/build/install/rule
index af38587..54014e1 100644
--- a/build/install/rule
+++ b/build/install/rule
@@ -27,12 +27,16 @@ namespace build
class file_rule: public rule
{
public:
- virtual bool
- filter (action, target&, prerequisite_member) const {return true;}
-
virtual match_result
match (action, target&, const std::string&) const;
+ // 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.
+ //
+ virtual target*
+ filter (action, target&, prerequisite_member) const;
+
virtual recipe
apply (action, target&, const match_result&) const;
diff --git a/build/install/rule.cxx b/build/install/rule.cxx
index bd538ed..3f8c16a 100644
--- a/build/install/rule.cxx
+++ b/build/install/rule.cxx
@@ -100,6 +100,13 @@ namespace build
return mr;
}
+ target* file_rule::
+ filter (action, target& t, prerequisite_member p) const
+ {
+ target& pt (p.search ());
+ return pt.in (t.root_scope ()) ? &pt : nullptr;
+ }
+
recipe file_rule::
apply (action a, target& t, const match_result& mr) const
{
@@ -121,8 +128,6 @@ namespace build
// run standard search_and_match()? Will need an indicator
// that it was forced (e.g., [install]) for filter() below.
//
- scope& rs (t.root_scope ());
-
for (prerequisite_member p: group_prerequisite_members (a, t))
{
// Ignore unresolved targets that are imported from other projects.
@@ -136,19 +141,13 @@ namespace build
// Let a customized rule have its say.
//
- // @@ This will be skipped if forced with [install].
+ // @@ This will be skipped if forced with [install]?
//
- if (!filter (a, t, p))
+ target* pt (filter (a, t, p));
+ if (pt == nullptr)
continue;
- target& pt (p.search ());
-
- // Ignore targets that are outside of our project.
- //
- if (!pt.in (rs))
- continue;
-
- build::match (a, pt);
+ build::match (a, *pt);
// If the matched rule returned noop_recipe, then the target
// state will be set to unchanged as an optimization. Use this
@@ -156,10 +155,10 @@ namespace build
// will help a lot in case of any static installable content
// (headers, documentation, etc).
//
- if (pt.state () != target_state::unchanged)
- t.prerequisite_targets.push_back (&pt);
+ if (pt->state () != target_state::unchanged)
+ t.prerequisite_targets.push_back (pt);
else
- unmatch (a, pt); // No intent to execute.
+ unmatch (a, *pt); // No intent to execute.
}
// This is where we diverge depending on the operation. In the
diff --git a/build/prerequisite b/build/prerequisite
index 3022e44..c435fd3 100644
--- a/build/prerequisite
+++ b/build/prerequisite
@@ -30,8 +30,7 @@ namespace build
public:
typedef build::scope scope_type;
- mutable const std::string* const* proj; // Only *proj can be NULL, points
- // to project_name_pool.
+ mutable const std::string* proj; // Can be NULL, from project_name_pool.
target_key tk;
mutable scope_type* scope; // Can be NULL if tk.dir is absolute.
};
@@ -43,7 +42,7 @@ namespace build
// Can compare project name pointers since they are from project_name_pool.
//
- return *x.proj < *y.proj || (*x.proj == *y.proj && x.tk < y.tk);
+ return x.proj < y.proj || (x.proj == y.proj && x.tk < y.tk);
}
std::ostream&
@@ -83,7 +82,7 @@ namespace build
prerequisite_key
key () const
{
- return prerequisite_key {&proj, {&type, &dir, &name, &ext}, &scope};
+ return prerequisite_key {proj, {&type, &dir, &name, &ext}, &scope};
}
public:
diff --git a/build/prerequisite.cxx b/build/prerequisite.cxx
index 89ac275..49cab89 100644
--- a/build/prerequisite.cxx
+++ b/build/prerequisite.cxx
@@ -20,9 +20,9 @@ namespace build
ostream&
operator<< (ostream& os, const prerequisite_key& pk)
{
- if (*pk.proj != nullptr)
- os << **pk.proj << '%';
- //
+ if (pk.proj != nullptr)
+ os << *pk.proj << '%';
+
// Don't print scope if we are project-qualified or the
// prerequisite's directory is absolute. In both these
// cases the scope is not used to resolve it to target.
diff --git a/build/scope b/build/scope
index 551ce9d..0cb319f 100644
--- a/build/scope
+++ b/build/scope
@@ -39,6 +39,9 @@ namespace build
const dir_path* out_path_ {nullptr};
const dir_path* src_path_ {nullptr};
+ bool
+ root () const {return root_ == this;}
+
scope*
parent_scope () const {return parent_;}
@@ -64,8 +67,19 @@ namespace build
: nullptr;
}
- bool
- root () const {return root_ == this;}
+ // Root scope of the outermost amalgamation or NULL if this scope is not
+ // (yet) in any (known) project. If there is no amalgamation, then this
+ // function returns the root scope of the project (in other words, in this
+ // case a project is treated as its own amalgamation).
+ //
+ scope*
+ weak_scope () const
+ {
+ scope* r (root_);
+ if (r != nullptr)
+ for (; r->parent_->root_ != nullptr; r = r->parent_->root_) ;
+ return r;
+ }
// Variables.
//
diff --git a/build/target b/build/target
index 69f8f4f..22b5e89 100644
--- a/build/target
+++ b/build/target
@@ -229,6 +229,12 @@ namespace build
scope&
strong_scope () const {return *root_scope ().strong_scope ();}
+ // Root scope of the outermost amalgamation that contains this target.
+ // The same notes as to root_scope() apply.
+ //
+ scope&
+ weak_scope () const {return *root_scope ().weak_scope ();}
+
bool
in (const scope& s) const
@@ -517,7 +523,7 @@ namespace build
key () const
{
return target != nullptr
- ? prerequisite_key {&prerequisite.get ().proj, target->key (), nullptr}
+ ? prerequisite_key {prerequisite.get ().proj, target->key (), nullptr}
: prerequisite.get ().key ();
}
diff --git a/build/target.txx b/build/target.txx
index a63994b..192cfbc 100644
--- a/build/target.txx
+++ b/build/target.txx
@@ -47,10 +47,7 @@ namespace build
if (tk.dir->absolute ())
dr << "target " << tk;
else
- {
- const string* proj (nullptr); // Used for local prerequisites.
- dr << "prerequisite " << prerequisite_key {&proj, tk, &s};
- }
+ dr << "prerequisite " << prerequisite_key {nullptr, tk, &s};
dr << info << "perhaps you forgot to add "
<< tk.type->name << "{*}: " << var << " = ...";