diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-12-01 14:46:45 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-12-01 14:46:45 +0200 |
commit | 10fd2aface4486fc7f873dd2b54a1c2073c0b434 (patch) | |
tree | 5133810cf33b3e4ba4dfe78f659ee65599c31ffd | |
parent | 7996c2bfc2d7e998e2f9f1236d457ec7bea8ad8a (diff) |
Reimplement define as dynamic derivation rather than alias
New syntax:
define cli: file
The rationale is we need to be able to assign the file extension (using
type/pattern-specific variables). And if it is an alias, we will assign
it to the original target type.
Note that we could still support aliases if we need to. Will need to
bring back the id member in target_type that would normally point to
itself but for an alias would point to the origin.
-rw-r--r-- | build/algorithm.cxx | 2 | ||||
-rw-r--r-- | build/bin/target.cxx | 28 | ||||
-rw-r--r-- | build/cli/target.cxx | 8 | ||||
-rw-r--r-- | build/cxx/target.cxx | 24 | ||||
-rw-r--r-- | build/dump.cxx | 4 | ||||
-rw-r--r-- | build/parser.cxx | 43 | ||||
-rw-r--r-- | build/prerequisite | 1 | ||||
-rw-r--r-- | build/rule-map | 5 | ||||
-rw-r--r-- | build/target | 7 | ||||
-rw-r--r-- | build/target-key | 5 | ||||
-rw-r--r-- | build/target-type | 57 | ||||
-rw-r--r-- | build/target.cxx | 48 | ||||
-rw-r--r-- | tests/define/buildfile | 22 | ||||
-rw-r--r-- | tests/define/buildfile.alias | 16 |
14 files changed, 109 insertions, 161 deletions
diff --git a/build/algorithm.cxx b/build/algorithm.cxx index 6c3374e..461d8d2 100644 --- a/build/algorithm.cxx +++ b/build/algorithm.cxx @@ -111,7 +111,7 @@ namespace build if (ttm->empty ()) continue; // Empty map for this operation id. - auto i (ttm->find (tt->id)); + auto i (ttm->find (tt)); if (i == ttm->end () || i->second.empty ()) continue; // No rules registered for this target type. diff --git a/build/bin/target.cxx b/build/bin/target.cxx index c2c5e05..6f2d7b5 100644 --- a/build/bin/target.cxx +++ b/build/bin/target.cxx @@ -24,14 +24,12 @@ namespace build const target_type obja::static_type { - typeid (obja), "obja", &file::static_type, &obja_factory, nullptr, &search_target, // Note: not _file(); don't look for an existing file. - false, - nullptr + false }; static target* @@ -48,14 +46,12 @@ namespace build const target_type objso::static_type { - typeid (objso), "objso", &file::static_type, &objso_factory, nullptr, &search_target, // Note: not _file(); don't look for an existing file. - false, - nullptr + false }; static target* @@ -76,26 +72,22 @@ namespace build const target_type obj::static_type { - typeid (obj), "obj", &target::static_type, &obj_factory, nullptr, &search_target, - false, - nullptr + false }; const target_type exe::static_type { - typeid (exe), "exe", &file::static_type, &target_factory<exe>, nullptr, &search_file, - false, - nullptr + false }; static target* @@ -125,14 +117,12 @@ namespace build constexpr const char a_ext[] = "a"; const target_type liba::static_type { - typeid (liba), "liba", &file::static_type, &liba_factory, &target_extension_fix<a_ext>, &search_file, - false, - nullptr + false }; static target* @@ -150,14 +140,12 @@ namespace build constexpr const char so_ext[] = "so"; const target_type libso::static_type { - typeid (libso), "libso", &file::static_type, &libso_factory, &target_extension_fix<so_ext>, &search_file, - false, - nullptr + false }; // lib @@ -187,14 +175,12 @@ namespace build const target_type lib::static_type { - typeid (lib), "lib", &target::static_type, &lib_factory, nullptr, &search_target, - false, - nullptr + false }; } } diff --git a/build/cli/target.cxx b/build/cli/target.cxx index 0666335..a480633 100644 --- a/build/cli/target.cxx +++ b/build/cli/target.cxx @@ -18,14 +18,12 @@ namespace build constexpr const char cli_ext[] = "cli"; const target_type cli::static_type { - typeid (cli), "cli", &file::static_type, &target_factory<cli>, &target_extension_fix<cli_ext>, &search_file, - false, - nullptr + false }; // cli.cxx @@ -66,14 +64,12 @@ namespace build const target_type cli_cxx::static_type { - typeid (cli_cxx), "cli.cxx", &mtime_target::static_type, &cli_cxx_factory, nullptr, &search_target, - true, // "See through" default iteration mode. - nullptr + true // "See through" default iteration mode. }; } } diff --git a/build/cxx/target.cxx b/build/cxx/target.cxx index e3d98e7..c8680b7 100644 --- a/build/cxx/target.cxx +++ b/build/cxx/target.cxx @@ -13,79 +13,67 @@ namespace build constexpr const char hxx_ext_var[] = "hxx.ext"; const target_type hxx::static_type { - typeid (hxx), "hxx", &file::static_type, &target_factory<hxx>, &target_extension_var<hxx_ext_var>, &search_file, - false, - nullptr + false }; constexpr const char ixx_ext_var[] = "ixx.ext"; const target_type ixx::static_type { - typeid (ixx), "ixx", &file::static_type, &target_factory<ixx>, &target_extension_var<ixx_ext_var>, &search_file, - false, - nullptr + false }; constexpr const char txx_ext_var[] = "txx.ext"; const target_type txx::static_type { - typeid (txx), "txx", &file::static_type, &target_factory<txx>, &target_extension_var<txx_ext_var>, &search_file, - false, - nullptr + false }; constexpr const char cxx_ext_var[] = "cxx.ext"; const target_type cxx::static_type { - typeid (cxx), "cxx", &file::static_type, &target_factory<cxx>, &target_extension_var<cxx_ext_var>, &search_file, - false, - nullptr + false }; constexpr const char h_ext_var[] = "h.ext"; const target_type h::static_type { - typeid (h), "h", &file::static_type, &target_factory<h>, &target_extension_var<h_ext_var>, &search_file, - false, - nullptr + false }; constexpr const char c_ext_var[] = "c.ext"; const target_type c::static_type { - typeid (c), "c", &file::static_type, &target_factory<c>, &target_extension_var<c_ext_var>, &search_file, - false, - nullptr + false }; } } diff --git a/build/dump.cxx b/build/dump.cxx index 7f4502e..62e032b 100644 --- a/build/dump.cxx +++ b/build/dump.cxx @@ -56,12 +56,12 @@ namespace build os << endl << ind; - if (t.id != target::static_type.id) + if (t != target::static_type) os << t.name << '{'; os << p; - if (t.id != target::static_type.id) + if (t != target::static_type) os << '}'; os << ':'; diff --git a/build/parser.cxx b/build/parser.cxx index 4981347..05c79db 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -808,58 +808,57 @@ namespace build } static target* - alias_factory (const target_type& tt, dir_path d, string n, const string* e) + derived_factory (const target_type& t, dir_path d, string n, const string* e) { - assert (tt.origin != nullptr); - target* r (tt.origin->factory (*tt.origin, move (d), move (n), e)); - r->alias_type = &tt; + target* r (t.base->factory (*t.base, move (d), move (n), e)); + r->derived_type = &t; return r; } void parser:: define (token& t, token_type& tt) { - // define <alias>=<name> + // define <derived>: <base> // - // See tests/define/buildfile. + // See tests/define. // if (next (t, tt) != type::name) fail (t) << "expected name instead of " << t << " in target type " << "definition"; - string a (move (t.value)); - const location al (get_location (t, &path_)); + string dn (move (t.value)); + const location dnl (get_location (t, &path_)); - if (next (t, tt) != type::equal) - fail (t) << "expected '=' instead of " << t << " in target type " + if (next (t, tt) != type::colon) + fail (t) << "expected ':' instead of " << t << " in target type " << "definition"; next (t, tt); if (tt == type::name) { - // Alias. + // Target. // - const string& n (t.value); - const target_type* ntt (scope_->find_target_type (n)); + const string& bn (t.value); + const target_type* bt (scope_->find_target_type (bn)); - if (ntt == nullptr) - fail (t) << "unknown target type " << n; + if (bt == nullptr) + fail (t) << "unknown target type " << bn; - unique_ptr<target_type> att (new target_type (*ntt)); - att->factory = &alias_factory; - att->origin = ntt->origin != nullptr ? ntt->origin : ntt; + unique_ptr<target_type> dt (new target_type (*bt)); + dt->base = bt; + dt->factory = &derived_factory; - target_type& ratt (*att); // Save non-const reference to the object. + target_type& rdt (*dt); // Save a non-const reference to the object. - auto pr (scope_->target_types.emplace (a, target_type_ref (move (att)))); + auto pr (scope_->target_types.emplace (dn, target_type_ref (move (dt)))); if (!pr.second) - fail (al) << "target type " << a << " already define in this scope"; + fail (dnl) << "target type " << dn << " already define in this scope"; // Patch the alias name to use the map's key storage. // - ratt.name = pr.first->first.c_str (); + rdt.name = pr.first->first.c_str (); next (t, tt); // Get newline. } diff --git a/build/prerequisite b/build/prerequisite index f91a199..3022e44 100644 --- a/build/prerequisite +++ b/build/prerequisite @@ -10,7 +10,6 @@ #include <iosfwd> #include <utility> // move #include <cassert> -#include <typeindex> #include <functional> // reference_wrapper #include <build/types> diff --git a/build/rule-map b/build/rule-map index 0ce49e7..d262ecd 100644 --- a/build/rule-map +++ b/build/rule-map @@ -9,7 +9,6 @@ #include <vector> #include <string> #include <memory> // unique_ptr -#include <typeindex> #include <functional> // reference_wrapper #include <butl/prefix-map> @@ -22,7 +21,7 @@ namespace build class rule; using target_type_rule_map = std::map< - std::type_index, // Target type. + const target_type*, butl::prefix_map<std::string, // Rule hint. std::reference_wrapper<rule>, '.'>>; @@ -41,7 +40,7 @@ namespace build if (oid >= map_.size ()) map_.resize ((oid < 3 ? 3 : oid) + 1); - map_[oid][typeid (T)].emplace (hint, r); + map_[oid][&T::static_type].emplace (hint, r); } // Return NULL if not found. diff --git a/build/target b/build/target index a1c7880..66daa66 100644 --- a/build/target +++ b/build/target @@ -354,15 +354,14 @@ namespace build const T* is_a () const {return dynamic_cast<const T*> (this);} - // An alias target type should be the same as its target type except - // for the name. + // Dynamic derivation to support define. // - const target_type* alias_type = nullptr; + const target_type* derived_type = nullptr; const target_type& type () const { - return alias_type != nullptr ? *alias_type : dynamic_type (); + return derived_type != nullptr ? *derived_type : dynamic_type (); } virtual const target_type& dynamic_type () const = 0; diff --git a/build/target-key b/build/target-key index f49efb2..526a33a 100644 --- a/build/target-key +++ b/build/target-key @@ -8,7 +8,6 @@ #include <map> #include <string> #include <ostream> -#include <typeindex> #include <functional> // reference_wrapper #include <butl/utility> // compare_c_string @@ -31,8 +30,8 @@ namespace build friend bool operator< (const target_key& x, const target_key& y) { - const std::type_index& xt (x.type->id); - const std::type_index& yt (y.type->id); + const target_type* xt (x.type); + const target_type* yt (y.type); //@@ TODO: use compare() to compare once. diff --git a/build/target-type b/build/target-type index 2c93455..e299fe2 100644 --- a/build/target-type +++ b/build/target-type @@ -8,9 +8,6 @@ #include <map> #include <string> #include <ostream> -#include <typeindex> - -#include <butl/utility> // compare_c_string #include <build/types> @@ -23,9 +20,13 @@ namespace build // Target type. // + // Note that we assume there is always a single instance of this class + // for any target type. As a result, we can use address comparison to + // determine if two target types are the same. + // + // struct target_type { - std::type_index id; const char* name; const target_type* base; target* (*factory) (const target_type&, dir_path, string, const string*); @@ -33,60 +34,50 @@ namespace build target* (*search) (const prerequisite_key&); bool see_through; // A group with the default "see through" semantics. - const target_type* origin; // Original target if this is an alias. - bool - is_a (const std::type_index&) const; // Defined in target.cxx + is_a (const target_type&) const; // Defined in target.cxx template <typename T> bool - is_a () const {return is_a (typeid (T));} + is_a () const {return is_a (T::static_type);} }; inline bool - operator< (const target_type& x, const target_type& y) - { - return x.id < y.id; - } + operator< (const target_type& x, const target_type& y) {return &x < &y;} + + inline bool + operator== (const target_type& x, const target_type& y) {return &x == &y;} + + inline bool + operator!= (const target_type& x, const target_type& y) {return &x != &y;} inline std::ostream& - operator<< (std::ostream& os, const target_type& tt) - { - return os << tt.name; - } + operator<< (std::ostream& os, const target_type& tt) {return os << tt.name;} // Target type map. // struct target_type_ref { - // Like reference_wrapper except it deletes the target type if it is - // an alias (aliases are always dynamically allocated). + // Like reference_wrapper except it sometimes deletes the target type. // explicit - target_type_ref (const target_type& r): p_ (&r) - { - assert (p_->origin == nullptr); - } + target_type_ref (const target_type& r): p_ (&r), d_ (false) {} explicit - target_type_ref (unique_ptr<target_type>&& p): p_ (p.release ()) - { - assert (p_->origin != nullptr); - } + target_type_ref (unique_ptr<target_type>&& p) + : p_ (p.release ()), d_ (true) {} + + target_type_ref (target_type_ref&& r) + : p_ (r.p_), d_ (r.d_) {r.p_ = nullptr;} - ~target_type_ref () - { - if (p_ != nullptr && p_->origin != nullptr) - delete p_; - } + ~target_type_ref () {if (p_ != nullptr && d_) delete p_;} explicit operator const target_type& () const {return *p_;} const target_type& get () const {return *p_;} - target_type_ref (target_type_ref&& r): p_ (r.p_) {r.p_ = nullptr;} - private: const target_type* p_; + bool d_; }; using target_type_map_base = std::map<string, target_type_ref>; diff --git a/build/target.cxx b/build/target.cxx index 649e570..7c45e3e 100644 --- a/build/target.cxx +++ b/build/target.cxx @@ -20,10 +20,10 @@ namespace build // target_type // bool target_type:: - is_a (const type_index& id) const + is_a (const target_type& tt) const { for (const target_type* p (this); p != nullptr; p = p->base) - if (p->id == id) + if (*p == tt) return true; return false; @@ -440,38 +440,32 @@ namespace build const target_type target::static_type { - typeid (target), "target", nullptr, nullptr, nullptr, &search_target, - false, - nullptr + false }; const target_type mtime_target::static_type { - typeid (mtime_target), "mtime_target", &target::static_type, nullptr, nullptr, &search_target, - false, - nullptr + false }; const target_type path_target::static_type { - typeid (path_target), "path_target", &mtime_target::static_type, nullptr, nullptr, &search_target, - false, - nullptr + false }; template <typename T> @@ -490,50 +484,42 @@ namespace build constexpr const char file_ext[] = ""; const target_type file::static_type { - typeid (file), "file", &path_target::static_type, &file_factory<file>, &target_extension_fix<file_ext>, &search_file, - false, - nullptr + false }; const target_type alias::static_type { - typeid (alias), "alias", &target::static_type, &target_factory<alias>, nullptr, // Should never need. &search_alias, - false, - nullptr + false }; const target_type dir::static_type { - typeid (dir), "dir", &alias::static_type, &target_factory<dir>, nullptr, // Should never need. &search_alias, - false, - nullptr + false }; const target_type fsdir::static_type { - typeid (fsdir), "fsdir", &target::static_type, &target_factory<fsdir>, nullptr, // Should never need. &search_target, - false, - nullptr + false }; static const std::string& @@ -547,27 +533,23 @@ namespace build const target_type buildfile::static_type { - typeid (buildfile), "buildfile", &file::static_type, &file_factory<buildfile>, &buildfile_target_extension, &search_file, - false, - nullptr + false }; constexpr const char doc_ext[] = ""; const target_type doc::static_type { - typeid (doc), "doc", &file::static_type, &file_factory<doc>, &target_extension_fix<doc_ext>, &search_file, - false, - nullptr + false }; static target* @@ -581,26 +563,22 @@ namespace build const target_type man::static_type { - typeid (man), "man", &doc::static_type, &man_factory, nullptr, // Should be specified explicitly. &search_file, - false, - nullptr + false }; constexpr const char man1_ext[] = "1"; const target_type man1::static_type { - typeid (man1), "man1", &man::static_type, &file_factory<man1>, &target_extension_fix<man1_ext>, &search_file, - false, - nullptr + false }; } diff --git a/tests/define/buildfile b/tests/define/buildfile index d3b9fc4..55b9e92 100644 --- a/tests/define/buildfile +++ b/tests/define/buildfile @@ -1,16 +1,14 @@ -#define # expected name -#define foo # expected = -#define foo= # expected name -#define foo=bar # unknown target type +#define # expected name +#define foo # expected : +#define foo: # expected name +#define foo: bar # unknown target type -define foo=file -foo{FOO}: # verify name is foo{FOO} and not file{FOO} with --verbose 6 +define foo: file +foo{FOO}: # verify name is foo{FOO} and not file{FOO} with --verbose 6 -#define foo=dir # already define in this scope +#define foo: dir # already define in this scope -define bar=foo -bar{FOO}: # verify name is foo{FOO} and not bar{FOO} with --verbose 6 -bar{BAR}: # verify name is bar{BAR} +define bar: foo +bar{BAR}: # verify name is bar{FOO} with --verbose 6 -define folder=dir -folder{./}: # verify prints "folder{} is up to date" +./: diff --git a/tests/define/buildfile.alias b/tests/define/buildfile.alias new file mode 100644 index 0000000..d3b9fc4 --- /dev/null +++ b/tests/define/buildfile.alias @@ -0,0 +1,16 @@ +#define # expected name +#define foo # expected = +#define foo= # expected name +#define foo=bar # unknown target type + +define foo=file +foo{FOO}: # verify name is foo{FOO} and not file{FOO} with --verbose 6 + +#define foo=dir # already define in this scope + +define bar=foo +bar{FOO}: # verify name is foo{FOO} and not bar{FOO} with --verbose 6 +bar{BAR}: # verify name is bar{BAR} + +define folder=dir +folder{./}: # verify prints "folder{} is up to date" |