aboutsummaryrefslogtreecommitdiff
path: root/build2/bin
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-02-15 03:55:15 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-03-02 14:03:34 +0200
commitb37f1aa6398065be806e6605a023189685669885 (patch)
treeb9b32091e3d70a31852302b24c99ecb62465464a /build2/bin
parenta64b2ae2099346471ead988d5f2d383d55a9bf89 (diff)
Implement parallel match
Diffstat (limited to 'build2/bin')
-rw-r--r--build2/bin/rule8
-rw-r--r--build2/bin/rule.cxx55
-rw-r--r--build2/bin/target32
-rw-r--r--build2/bin/target.cxx158
4 files changed, 95 insertions, 158 deletions
diff --git a/build2/bin/rule b/build2/bin/rule
index 5fe9069..95747c2 100644
--- a/build2/bin/rule
+++ b/build2/bin/rule
@@ -20,10 +20,10 @@ namespace build2
obj_rule () {}
virtual match_result
- match (slock&, action, target&, const string& hint) const override;
+ match (action, target&, const string&) const override;
virtual recipe
- apply (slock&, action, target&) const override;
+ apply (action, target&) const override;
};
class lib_rule: public rule
@@ -32,10 +32,10 @@ namespace build2
lib_rule () {}
virtual match_result
- match (slock&, action, target&, const string& hint) const override;
+ match (action, target&, const string&) const override;
virtual recipe
- apply (slock&, action, target&) const override;
+ apply (action, target&) const override;
static target_state
perform (action, const target&);
diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx
index 446f91b..3ea8e75 100644
--- a/build2/bin/rule.cxx
+++ b/build2/bin/rule.cxx
@@ -20,7 +20,7 @@ namespace build2
// obj
//
match_result obj_rule::
- match (slock&, action a, target& t, const string&) const
+ match (action a, target& t, const string&) const
{
fail << diag_doing (a, t) << " target group" <<
info << "explicitly select obje{}, obja{}, or objs{} member";
@@ -29,29 +29,20 @@ namespace build2
}
recipe obj_rule::
- apply (slock&, action, target&) const {return empty_recipe;}
+ apply (action, target&) const {return empty_recipe;}
// lib
//
// The whole logic is pretty much as if we had our two group members as
// our prerequisites.
//
-
- struct match_data
- {
- const string& type;
- };
-
- static_assert (sizeof (match_data) <= target::data_size,
- "insufficient space");
-
match_result lib_rule::
- match (slock&, action act, target& xt, const string&) const
+ match (action act, target& xt, const string&) const
{
lib& t (xt.as<lib> ());
- // Get the library type to build. If not set for a target, this
- // should be configured at the project scope by init().
+ // Get the library type to build. If not set for a target, this should
+ // be configured at the project scope by init().
//
const string& type (cast<string> (t["bin.lib"]));
@@ -62,7 +53,8 @@ namespace build2
fail << "unknown library type: " << type <<
info << "'static', 'shared', or 'both' expected";
- t.data (match_data {type}); // Save in the target's auxilary storage.
+ t.a = a ? &search<liba> (t.dir, t.out, t.name) : nullptr;
+ t.s = s ? &search<libs> (t.dir, t.out, t.name) : nullptr;
match_result mr (true);
@@ -76,31 +68,12 @@ namespace build2
}
recipe lib_rule::
- apply (slock& ml, action act, target& xt) const
+ apply (action act, target& xt) const
{
lib& t (xt.as<lib> ());
- const match_data& md (t.data<match_data> ());
- const string& type (md.type);
-
- bool a (type == "static" || type == "both");
- bool s (type == "shared" || type == "both");
-
- if (a)
- {
- if (t.a == nullptr)
- t.a = &search<liba> (t.dir, t.out, t.name, nullptr, nullptr);
-
- build2::match (ml, act, *t.a);
- }
-
- if (s)
- {
- if (t.s == nullptr)
- t.s = &search<libs> (t.dir, t.out, t.name, nullptr, nullptr);
-
- build2::match (ml, act, *t.s);
- }
+ const target* m[] = {t.a, t.s};
+ match_members (act, t, m);
return &perform;
}
@@ -110,13 +83,7 @@ namespace build2
{
const lib& t (xt.as<lib> ());
- const match_data& md (t.data<match_data> ());
- const string& type (md.type);
-
- bool a (type == "static" || type == "both");
- bool s (type == "shared" || type == "both");
-
- const target* m[] = {a ? t.a : nullptr, s ? t.s : nullptr};
+ const target* m[] = {t.a, t.s};
return execute_members (act, t, m);
}
}
diff --git a/build2/bin/target b/build2/bin/target
index 4157f67..35bde60 100644
--- a/build2/bin/target
+++ b/build2/bin/target
@@ -51,12 +51,6 @@ namespace build2
public:
using target::target;
- // Group members.
- //
- const_ptr<obje> e = nullptr;
- const_ptr<obja> a = nullptr;
- const_ptr<objs> s = nullptr;
-
public:
static const target_type static_type;
virtual const target_type& dynamic_type () const {return static_type;}
@@ -81,26 +75,32 @@ namespace build2
public:
static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
+
+ virtual const target_type&
+ dynamic_type () const override {return static_type;}
+ };
+
+ // Standard layout type compatible with group_view's const target*[2].
+ //
+ struct lib_members
+ {
+ const liba* a = nullptr;
+ const libs* s = nullptr;
};
- class lib: public target
+ class lib: public target, public lib_members
{
public:
using target::target;
- // Group members.
- //
- const_ptr<liba> a = nullptr;
- const_ptr<libs> s = nullptr;
+ virtual group_view
+ group_members (action_type) const override;
public:
static const target_type static_type;
- virtual const target_type& dynamic_type () const override
- {
- return static_type;
- }
+ virtual const target_type&
+ dynamic_type () const override {return static_type;}
};
// Windows import library.
diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx
index ea0a1ac..cf187fa 100644
--- a/build2/bin/target.cxx
+++ b/build2/bin/target.cxx
@@ -10,83 +10,58 @@ namespace build2
{
namespace bin
{
+ // Note that we link groups during the load phase since this is often
+ // relied upon when setting target-specific variables (e.g., we may set a
+ // common value for lib{} and then append liba/libs-specific values to
+ // it). While sure inelegant, this is MT-safe since during load we are
+ // running serial. For the members it is also safe to set the group during
+ // creation.
+
extern const char ext_var[] = "extension"; // VC14 rejects constexpr.
+ template <typename T>
static pair<target*, optional<string>>
- obje_factory (const target_type&,
+ objx_factory (const target_type&,
dir_path dir,
dir_path out,
string n,
optional<string> ext)
{
- obj* o (targets.find<obj> (dir, out, n));
- obje* e (new obje (move (dir), move (out), move (n)));
+ const obj* g (targets.find<obj> (dir, out, n));
- if ((e->group = o) != nullptr)
- o->e = e;
+ T* x (new T (move (dir), move (out), move (n)));
+ x->group = g;
- return make_pair (e, move (ext));
+ return make_pair (x, move (ext));
}
const target_type obje::static_type
{
"obje",
&file::static_type,
- &obje_factory,
+ &objx_factory<obje>,
&target_extension_var<ext_var, nullptr>,
nullptr,
&search_target, // Note: not _file(); don't look for an existing file.
false
};
- static pair<target*, optional<string>>
- obja_factory (const target_type&,
- dir_path dir,
- dir_path out,
- string n,
- optional<string> ext)
- {
- obj* o (targets.find<obj> (dir, out, n));
- obja* a (new obja (move (dir), move (out), move (n)));
-
- if ((a->group = o) != nullptr)
- o->a = a;
-
- return make_pair (a, move (ext));
- }
-
const target_type obja::static_type
{
"obja",
&file::static_type,
- &obja_factory,
+ &objx_factory<obja>,
&target_extension_var<ext_var, nullptr>,
nullptr,
&search_target, // Note: not _file(); don't look for an existing file.
false
};
- static pair<target*, optional<string>>
- objs_factory (const target_type&,
- dir_path dir,
- dir_path out,
- string n,
- optional<string> ext)
- {
- obj* o (targets.find<obj> (dir, out, n));
- objs* s (new objs (move (dir), move (out), move (n)));
-
- if ((s->group = o) != nullptr)
- o->s = s;
-
- return make_pair (s, move (ext));
- }
-
const target_type objs::static_type
{
"objs",
&file::static_type,
- &objs_factory,
+ &objx_factory<objs>,
&target_extension_var<ext_var, nullptr>,
nullptr,
&search_target, // Note: not _file(); don't look for an existing file.
@@ -100,20 +75,23 @@ namespace build2
string n,
optional<string> ext)
{
- obje* e (targets.find<obje> (dir, out, n));
- obja* a (targets.find<obja> (dir, out, n));
- objs* s (targets.find<objs> (dir, out, n));
+ // Casts are MT-aware (during serial load).
+ //
+ obje* e (phase == run_phase::load
+ ? const_cast<obje*> (targets.find<obje> (dir, out, n))
+ : nullptr);
+ obja* a (phase == run_phase::load
+ ? const_cast<obja*> (targets.find<obja> (dir, out, n))
+ : nullptr);
+ objs* s (phase == run_phase::load
+ ? const_cast<objs*> (targets.find<objs> (dir, out, n))
+ : nullptr);
obj* o (new obj (move (dir), move (out), move (n)));
- if ((o->e = e) != nullptr)
- e->group = o;
-
- if ((o->a = a)!= nullptr)
- a->group = o;
-
- if ((o->s = s)!= nullptr)
- s->group = o;
+ if (e != nullptr) e->group = o;
+ if (a != nullptr) a->group = o;
+ if (s != nullptr) s->group = o;
return make_pair (o, move (ext));
}
@@ -129,26 +107,22 @@ namespace build2
false
};
+ template <typename T>
static pair<target*, optional<string>>
- liba_factory (const target_type& t,
- dir_path d,
- dir_path o,
+ libx_factory (const target_type&,
+ dir_path dir,
+ dir_path out,
string n,
optional<string> ext)
{
- // Only link-up to the group if the types match exactly.
- //
- lib* l (t == liba::static_type ? targets.find<lib> (d, o, n) : nullptr);
- liba* a (new liba (move (d), move (o), move (n)));
+ const lib* g (targets.find<lib> (dir, out, n));
- if ((a->group = l) != nullptr)
- l->a = a;
+ T* x (new T (move (dir), move (out), move (n)));
+ x->group = g;
- return make_pair (a, move (ext));
+ return make_pair (x, move (ext));
}
- // @@
- //
// What extensions should we use? At the outset, this is platform-
// dependent. And if we consider cross-compilation, is it build or
// host-dependent? Feels like it should be host-dependent so that
@@ -163,36 +137,18 @@ namespace build2
{
"liba",
&file::static_type,
- &liba_factory,
+ &libx_factory<liba>,
&target_extension_var<ext_var, nullptr>,
nullptr,
&search_file,
false
};
- static pair<target*, optional<string>>
- libs_factory (const target_type& t,
- dir_path d,
- dir_path o,
- string n,
- optional<string> ext)
- {
- // Only link-up to the group if the types match exactly.
- //
- lib* l (t == libs::static_type ? targets.find<lib> (d, o, n) : nullptr);
- libs* s (new libs (move (d), move (o), move (n)));
-
- if ((s->group = l) != nullptr)
- l->s = s;
-
- return make_pair (s, move (ext));
- }
-
const target_type libs::static_type
{
"libs",
&file::static_type,
- &libs_factory,
+ &libx_factory<libs>,
&target_extension_var<ext_var, nullptr>,
nullptr,
&search_file,
@@ -201,23 +157,37 @@ namespace build2
// lib
//
+ group_view lib::
+ group_members (action_type) const
+ {
+ static_assert (sizeof (lib_members) == sizeof (const target*) * 2,
+ "member layout incompatible with array");
+
+ return a != nullptr || s != nullptr
+ ? group_view {reinterpret_cast<const target* const*> (&a), 2}
+ : group_view {nullptr, 0};
+ }
+
static pair<target*, optional<string>>
lib_factory (const target_type&,
- dir_path d,
- dir_path o,
+ dir_path dir,
+ dir_path out,
string n,
optional<string> ext)
{
- liba* a (targets.find<liba> (d, o, n));
- libs* s (targets.find<libs> (d, o, n));
-
- lib* l (new lib (move (d), move (o), move (n)));
+ // Casts are MT-aware (during serial load).
+ //
+ liba* a (phase == run_phase::load
+ ? const_cast<liba*> (targets.find<liba> (dir, out, n))
+ : nullptr);
+ libs* s (phase == run_phase::load
+ ? const_cast<libs*> (targets.find<libs> (dir, out, n))
+ : nullptr);
- if ((l->a = a) != nullptr)
- a->group = l;
+ lib* l (new lib (move (dir), move (out), move (n)));
- if ((l->s = s) != nullptr)
- s->group = l;
+ if (a != nullptr) a->group = l;
+ if (s != nullptr) s->group = l;
return make_pair (l, move (ext));
}