aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-01 14:46:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-01 14:46:45 +0200
commit10fd2aface4486fc7f873dd2b54a1c2073c0b434 (patch)
tree5133810cf33b3e4ba4dfe78f659ee65599c31ffd
parent7996c2bfc2d7e998e2f9f1236d457ec7bea8ad8a (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.cxx2
-rw-r--r--build/bin/target.cxx28
-rw-r--r--build/cli/target.cxx8
-rw-r--r--build/cxx/target.cxx24
-rw-r--r--build/dump.cxx4
-rw-r--r--build/parser.cxx43
-rw-r--r--build/prerequisite1
-rw-r--r--build/rule-map5
-rw-r--r--build/target7
-rw-r--r--build/target-key5
-rw-r--r--build/target-type57
-rw-r--r--build/target.cxx48
-rw-r--r--tests/define/buildfile22
-rw-r--r--tests/define/buildfile.alias16
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"