From b37f1aa6398065be806e6605a023189685669885 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 15 Feb 2017 03:55:15 +0200 Subject: Implement parallel match --- build2/bin/rule | 8 +-- build2/bin/rule.cxx | 55 ++++-------------- build2/bin/target | 32 +++++----- build2/bin/target.cxx | 158 ++++++++++++++++++++------------------------------ 4 files changed, 95 insertions(+), 158 deletions(-) (limited to 'build2/bin') 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 ()); - // 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 (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 (t.dir, t.out, t.name) : nullptr; + t.s = s ? &search (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 ()); - const match_data& md (t.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 (t.dir, t.out, t.name, nullptr, nullptr); - - build2::match (ml, act, *t.a); - } - - if (s) - { - if (t.s == nullptr) - t.s = &search (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 ()); - const match_data& md (t.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 e = nullptr; - const_ptr a = nullptr; - const_ptr 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 a = nullptr; - const_ptr 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 static pair> - obje_factory (const target_type&, + objx_factory (const target_type&, dir_path dir, dir_path out, string n, optional ext) { - obj* o (targets.find (dir, out, n)); - obje* e (new obje (move (dir), move (out), move (n))); + const obj* g (targets.find (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, &target_extension_var, nullptr, &search_target, // Note: not _file(); don't look for an existing file. false }; - static pair> - obja_factory (const target_type&, - dir_path dir, - dir_path out, - string n, - optional ext) - { - obj* o (targets.find (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, &target_extension_var, nullptr, &search_target, // Note: not _file(); don't look for an existing file. false }; - static pair> - objs_factory (const target_type&, - dir_path dir, - dir_path out, - string n, - optional ext) - { - obj* o (targets.find (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, &target_extension_var, nullptr, &search_target, // Note: not _file(); don't look for an existing file. @@ -100,20 +75,23 @@ namespace build2 string n, optional ext) { - obje* e (targets.find (dir, out, n)); - obja* a (targets.find (dir, out, n)); - objs* s (targets.find (dir, out, n)); + // Casts are MT-aware (during serial load). + // + obje* e (phase == run_phase::load + ? const_cast (targets.find (dir, out, n)) + : nullptr); + obja* a (phase == run_phase::load + ? const_cast (targets.find (dir, out, n)) + : nullptr); + objs* s (phase == run_phase::load + ? const_cast (targets.find (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 static pair> - 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 ext) { - // Only link-up to the group if the types match exactly. - // - lib* l (t == liba::static_type ? targets.find (d, o, n) : nullptr); - liba* a (new liba (move (d), move (o), move (n))); + const lib* g (targets.find (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, &target_extension_var, nullptr, &search_file, false }; - static pair> - libs_factory (const target_type& t, - dir_path d, - dir_path o, - string n, - optional ext) - { - // Only link-up to the group if the types match exactly. - // - lib* l (t == libs::static_type ? targets.find (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, &target_extension_var, 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 (&a), 2} + : group_view {nullptr, 0}; + } + static pair> lib_factory (const target_type&, - dir_path d, - dir_path o, + dir_path dir, + dir_path out, string n, optional ext) { - liba* a (targets.find (d, o, n)); - libs* s (targets.find (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 (targets.find (dir, out, n)) + : nullptr); + libs* s (phase == run_phase::load + ? const_cast (targets.find (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)); } -- cgit v1.1