aboutsummaryrefslogtreecommitdiff
path: root/build/target-type
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-01 13:39:09 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-01 13:42:10 +0200
commit7996c2bfc2d7e998e2f9f1236d457ec7bea8ad8a (patch)
treedca79d3657bec47d4cd5db85899a70d3d49c079e /build/target-type
parentf355a4379f035df61a7702f5ff805eefb004fb20 (diff)
Implement support for definition target type aliases
For example: define cli=file Currently, the semantics is that of a real alias with only name differences that are used for display. See tests/define/buildfile for more use cases.
Diffstat (limited to 'build/target-type')
-rw-r--r--build/target-type48
1 files changed, 39 insertions, 9 deletions
diff --git a/build/target-type b/build/target-type
index 154714c..2c93455 100644
--- a/build/target-type
+++ b/build/target-type
@@ -9,7 +9,6 @@
#include <string>
#include <ostream>
#include <typeindex>
-#include <functional> // reference_wrapper
#include <butl/utility> // compare_c_string
@@ -29,11 +28,13 @@ namespace build
std::type_index id;
const char* name;
const target_type* base;
- target* (*const factory) (dir_path, std::string, const std::string*);
- const std::string& (*const extension) (const target_key&, scope&);
- target* (*const search) (const prerequisite_key&);
+ target* (*factory) (const target_type&, dir_path, string, const string*);
+ const string& (*extension) (const target_key&, scope&);
+ 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
@@ -56,16 +57,45 @@ namespace build
// Target type map.
//
- using target_type_map_base = std::map<
- const char*,
- std::reference_wrapper<const target_type>,
- butl::compare_c_string>;
+ struct target_type_ref
+ {
+ // Like reference_wrapper except it deletes the target type if it is
+ // an alias (aliases are always dynamically allocated).
+ //
+ explicit
+ target_type_ref (const target_type& r): p_ (&r)
+ {
+ assert (p_->origin == nullptr);
+ }
+
+ explicit
+ target_type_ref (unique_ptr<target_type>&& p): p_ (p.release ())
+ {
+ assert (p_->origin != nullptr);
+ }
+
+ ~target_type_ref ()
+ {
+ if (p_ != nullptr && p_->origin != nullptr)
+ 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_;
+ };
+
+ using target_type_map_base = std::map<string, target_type_ref>;
class target_type_map: public target_type_map_base
{
public:
void
- insert (const target_type& tt) {emplace (tt.name, tt);}
+ insert (const target_type& tt) {emplace (tt.name, target_type_ref (tt));}
template <typename T>
void