aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--build/bin/target14
-rw-r--r--build/bin/target.cxx41
-rw-r--r--build/cli/target4
-rw-r--r--build/cli/target.cxx8
-rw-r--r--build/cxx/target12
-rw-r--r--build/cxx/target.cxx18
-rw-r--r--build/parser3
-rw-r--r--build/parser.cxx76
-rw-r--r--build/scope6
-rw-r--r--build/scope.cxx15
-rw-r--r--build/target35
-rw-r--r--build/target-type48
-rw-r--r--build/target.cxx39
-rw-r--r--build/types9
-rw-r--r--build/utility4
-rw-r--r--tests/define/buildfile16
16 files changed, 262 insertions, 86 deletions
diff --git a/build/bin/target b/build/bin/target
index 729f119..cbabcaf 100644
--- a/build/bin/target
+++ b/build/bin/target
@@ -19,8 +19,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class objso: public file
@@ -29,8 +29,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class obj: public target
@@ -42,8 +42,8 @@ namespace build
objso* so {nullptr};
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class exe: public file
@@ -52,8 +52,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
// The lib{} target group.
@@ -64,8 +64,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class libso: public file
@@ -74,8 +74,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class lib: public target
@@ -90,8 +90,8 @@ namespace build
reset (action_type);
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
}
}
diff --git a/build/bin/target.cxx b/build/bin/target.cxx
index 5a1bb92..c2c5e05 100644
--- a/build/bin/target.cxx
+++ b/build/bin/target.cxx
@@ -11,10 +11,10 @@ namespace build
namespace bin
{
static target*
- obja_factory (dir_path d, std::string n, const std::string* e)
+ obja_factory (const target_type&, dir_path d, string n, const string* e)
{
obj* o (targets.find<obj> (d, n));
- obja* a (new obja (std::move (d), std::move (n), e));
+ obja* a (new obja (move (d), move (n), e));
if ((a->group = o))
o->a = a;
@@ -30,14 +30,15 @@ namespace build
&obja_factory,
nullptr,
&search_target, // Note: not _file(); don't look for an existing file.
- false
+ false,
+ nullptr
};
static target*
- objso_factory (dir_path d, std::string n, const std::string* e)
+ objso_factory (const target_type&, dir_path d, string n, const string* e)
{
obj* o (targets.find<obj> (d, n));
- objso* so (new objso (std::move (d), std::move (n), e));
+ objso* so (new objso (move (d), move (n), e));
if ((so->group = o))
o->so = so;
@@ -53,11 +54,12 @@ namespace build
&objso_factory,
nullptr,
&search_target, // Note: not _file(); don't look for an existing file.
- false
+ false,
+ nullptr
};
static target*
- obj_factory (dir_path d, string n, const string* e)
+ obj_factory (const target_type&, dir_path d, string n, const string* e)
{
obja* a (targets.find<obja> (d, n));
objso* so (targets.find<objso> (d, n));
@@ -80,7 +82,8 @@ namespace build
&obj_factory,
nullptr,
&search_target,
- false
+ false,
+ nullptr
};
const target_type exe::static_type
@@ -91,14 +94,15 @@ namespace build
&target_factory<exe>,
nullptr,
&search_file,
- false
+ false,
+ nullptr
};
static target*
- liba_factory (dir_path d, std::string n, const std::string* e)
+ liba_factory (const target_type&, dir_path d, string n, const string* e)
{
lib* l (targets.find<lib> (d, n));
- liba* a (new liba (std::move (d), std::move (n), e));
+ liba* a (new liba (move (d), move (n), e));
if ((a->group = l))
l->a = a;
@@ -127,14 +131,15 @@ namespace build
&liba_factory,
&target_extension_fix<a_ext>,
&search_file,
- false
+ false,
+ nullptr
};
static target*
- libso_factory (dir_path d, std::string n, const std::string* e)
+ libso_factory (const target_type&, dir_path d, string n, const string* e)
{
lib* l (targets.find<lib> (d, n));
- libso* so (new libso (std::move (d), std::move (n), e));
+ libso* so (new libso (move (d), move (n), e));
if ((so->group = l))
l->so = so;
@@ -151,7 +156,8 @@ namespace build
&libso_factory,
&target_extension_fix<so_ext>,
&search_file,
- false
+ false,
+ nullptr
};
// lib
@@ -164,7 +170,7 @@ namespace build
}
static target*
- lib_factory (dir_path d, string n, const string* e)
+ lib_factory (const target_type&, dir_path d, string n, const string* e)
{
liba* a (targets.find<liba> (d, n));
libso* so (targets.find<libso> (d, n));
@@ -187,7 +193,8 @@ namespace build
&lib_factory,
nullptr,
&search_target,
- false
+ false,
+ nullptr
};
}
}
diff --git a/build/cli/target b/build/cli/target
index 7ee9a98..dbb05bd 100644
--- a/build/cli/target
+++ b/build/cli/target
@@ -19,8 +19,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class cli_cxx: public mtime_target
@@ -53,8 +53,8 @@ namespace build
load_mtime () const;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
}
}
diff --git a/build/cli/target.cxx b/build/cli/target.cxx
index e8ca1cf..0666335 100644
--- a/build/cli/target.cxx
+++ b/build/cli/target.cxx
@@ -24,7 +24,8 @@ namespace build
&target_factory<cli>,
&target_extension_fix<cli_ext>,
&search_file,
- false
+ false,
+ nullptr
};
// cli.cxx
@@ -47,7 +48,7 @@ namespace build
}
static target*
- cli_cxx_factory (dir_path d, string n, const string* e)
+ cli_cxx_factory (const target_type&, dir_path d, string n, const string* e)
{
tracer trace ("cli::cli_cxx_factory");
@@ -71,7 +72,8 @@ namespace build
&cli_cxx_factory,
nullptr,
&search_target,
- true // "See through" default iteration mode.
+ true, // "See through" default iteration mode.
+ nullptr
};
}
}
diff --git a/build/cxx/target b/build/cxx/target
index bcc5ff1..fe27c79 100644
--- a/build/cxx/target
+++ b/build/cxx/target
@@ -17,8 +17,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class ixx: public file
@@ -27,8 +27,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class txx: public file
@@ -37,8 +37,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class cxx: public file
@@ -47,8 +47,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
//@@ TMP
@@ -59,8 +59,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class c: public file
@@ -69,8 +69,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
}
}
diff --git a/build/cxx/target.cxx b/build/cxx/target.cxx
index c23fdd0..e3d98e7 100644
--- a/build/cxx/target.cxx
+++ b/build/cxx/target.cxx
@@ -19,7 +19,8 @@ namespace build
&target_factory<hxx>,
&target_extension_var<hxx_ext_var>,
&search_file,
- false
+ false,
+ nullptr
};
constexpr const char ixx_ext_var[] = "ixx.ext";
@@ -31,7 +32,8 @@ namespace build
&target_factory<ixx>,
&target_extension_var<ixx_ext_var>,
&search_file,
- false
+ false,
+ nullptr
};
constexpr const char txx_ext_var[] = "txx.ext";
@@ -43,7 +45,8 @@ namespace build
&target_factory<txx>,
&target_extension_var<txx_ext_var>,
&search_file,
- false
+ false,
+ nullptr
};
constexpr const char cxx_ext_var[] = "cxx.ext";
@@ -55,7 +58,8 @@ namespace build
&target_factory<cxx>,
&target_extension_var<cxx_ext_var>,
&search_file,
- false
+ false,
+ nullptr
};
constexpr const char h_ext_var[] = "h.ext";
@@ -67,7 +71,8 @@ namespace build
&target_factory<h>,
&target_extension_var<h_ext_var>,
&search_file,
- false
+ false,
+ nullptr
};
constexpr const char c_ext_var[] = "c.ext";
@@ -79,7 +84,8 @@ namespace build
&target_factory<c>,
&target_extension_var<c_ext_var>,
&search_file,
- false
+ false,
+ nullptr
};
}
}
diff --git a/build/parser b/build/parser
index e37e68a..4390c67 100644
--- a/build/parser
+++ b/build/parser
@@ -72,6 +72,9 @@ namespace build
using_ (token&, token_type&);
void
+ define (token&, token_type&);
+
+ void
variable (token&, token_type&, std::string name, token_type kind);
std::string
diff --git a/build/parser.cxx b/build/parser.cxx
index bc6caa9..4981347 100644
--- a/build/parser.cxx
+++ b/build/parser.cxx
@@ -12,6 +12,9 @@
#include <iterator> // make_move_iterator()
#include <iostream>
+#include <build/types>
+#include <build/utility>
+
#include <build/token>
#include <build/lexer>
@@ -130,6 +133,11 @@ namespace build
using_ (t, tt);
continue;
}
+ else if (n == "define")
+ {
+ define (t, tt);
+ continue;
+ }
}
// ': foo' is equvalent to '{}: foo' and to 'dir{}: foo'.
@@ -343,7 +351,7 @@ namespace build
const target_type* ti (
n.untyped ()
? &target::static_type
- : scope_->find_target_type (n.type.c_str ()));
+ : scope_->find_target_type (n.type));
if (ti == nullptr)
fail (nloc) << "unknown target type " << n.type;
@@ -799,6 +807,72 @@ namespace build
fail (t) << "expected newline instead of " << t;
}
+ static target*
+ alias_factory (const target_type& tt, 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;
+ return r;
+ }
+
+ void parser::
+ define (token& t, token_type& tt)
+ {
+ // define <alias>=<name>
+ //
+ // See tests/define/buildfile.
+ //
+ 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_));
+
+ if (next (t, tt) != type::equal)
+ fail (t) << "expected '=' instead of " << t << " in target type "
+ << "definition";
+
+ next (t, tt);
+
+ if (tt == type::name)
+ {
+ // Alias.
+ //
+ const string& n (t.value);
+ const target_type* ntt (scope_->find_target_type (n));
+
+ if (ntt == nullptr)
+ fail (t) << "unknown target type " << n;
+
+ unique_ptr<target_type> att (new target_type (*ntt));
+ att->factory = &alias_factory;
+ att->origin = ntt->origin != nullptr ? ntt->origin : ntt;
+
+ target_type& ratt (*att); // Save non-const reference to the object.
+
+ auto pr (scope_->target_types.emplace (a, target_type_ref (move (att))));
+
+ if (!pr.second)
+ fail (al) << "target type " << a << " already define in this scope";
+
+ // Patch the alias name to use the map's key storage.
+ //
+ ratt.name = pr.first->first.c_str ();
+
+ next (t, tt); // Get newline.
+ }
+ else
+ fail (t) << "expected name instead of " << t << " in target type "
+ << "definition";
+
+ if (tt == type::newline)
+ next (t, tt);
+ else if (tt != type::eos)
+ fail (t) << "expected newline instead of " << t;
+ }
+
void parser::
print (token& t, token_type& tt)
{
diff --git a/build/scope b/build/scope
index 2afc9f4..8b0d0ad 100644
--- a/build/scope
+++ b/build/scope
@@ -12,6 +12,8 @@
#include <butl/path-map>
#include <build/types>
+#include <build/utility>
+
#include <build/module>
#include <build/variable>
#include <build/prerequisite>
@@ -138,7 +140,7 @@ namespace build
target_type_map target_types;
const target_type*
- find_target_type (const char*, const scope** = nullptr) const;
+ find_target_type (const string&, const scope** = nullptr) const;
// Given a name, figure out its type, taking into account extensions,
// special names (e.g., '.' and '..'), or anything else that might be
@@ -147,7 +149,7 @@ namespace build
// necessarily normalized). Return NULL if not found.
//
const target_type*
- find_target_type (name&, const std::string*& ext) const;
+ find_target_type (name&, const string*& ext) const;
// Rules.
//
diff --git a/build/scope.cxx b/build/scope.cxx
index 53e3a53..d407ce0 100644
--- a/build/scope.cxx
+++ b/build/scope.cxx
@@ -44,7 +44,7 @@ namespace build
}
const target_type* scope::
- find_target_type (const char* tt, const scope** rs) const
+ find_target_type (const string& tt, const scope** rs) const
{
// Search scopes outwards, stopping at the project root.
//
@@ -69,6 +69,9 @@ namespace build
return nullptr;
}
+ static const string dir_tt ("dir");
+ static const string file_tt ("file");
+
const target_type* scope::
find_target_type (name& n, const string*& ext) const
{
@@ -78,22 +81,22 @@ namespace build
// First determine the target type.
//
- const char* tt;
+ const string* tt;
if (n.untyped ())
{
// Empty name or '.' and '..' signify a directory.
//
if (v.empty () || v == "." || v == "..")
- tt = "dir";
+ tt = &dir_tt;
else
//@@ TODO: derive type from extension.
//
- tt = "file";
+ tt = &file_tt;
}
else
- tt = n.type.c_str ();
+ tt = &n.type;
- const target_type* r (find_target_type (tt));
+ const target_type* r (find_target_type (*tt));
if (r == nullptr)
return r;
diff --git a/build/target b/build/target
index a866c98..a1c7880 100644
--- a/build/target
+++ b/build/target
@@ -22,6 +22,8 @@
#include <butl/multi-index> // map_iterator_adapter
#include <build/types>
+#include <build/utility>
+
#include <build/scope>
#include <build/variable>
#include <build/operation>
@@ -352,7 +354,18 @@ namespace build
const T*
is_a () const {return dynamic_cast<const T*> (this);}
- virtual const target_type& type () const = 0;
+ // An alias target type should be the same as its target type except
+ // for the name.
+ //
+ const target_type* alias_type = nullptr;
+
+ const target_type&
+ type () const
+ {
+ return alias_type != nullptr ? *alias_type : dynamic_type ();
+ }
+
+ virtual const target_type& dynamic_type () const = 0;
static const target_type static_type;
private:
@@ -897,8 +910,8 @@ namespace build
load_mtime () const final;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
// Alias target. It represents a list of targets (its prerequisites)
@@ -910,8 +923,8 @@ namespace build
using target::target;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
// Directory target. Note that this is not a filesystem directory
@@ -924,8 +937,8 @@ namespace build
using alias::alias;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
// While a filesystem directory is mtime-based, the semantics is
@@ -941,8 +954,8 @@ namespace build
using target::target;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class buildfile: public file
@@ -951,8 +964,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
// Common documentation file targets.
@@ -965,8 +978,8 @@ namespace build
using file::file;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
// The problem with man pages is this: different platforms have
@@ -1009,8 +1022,8 @@ namespace build
using doc::doc;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
class man1: public man
@@ -1019,8 +1032,8 @@ namespace build
using man::man;
public:
- virtual const target_type& type () const {return static_type;}
static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
};
// Common implementation of the target factory, extension, and
@@ -1028,9 +1041,9 @@ namespace build
//
template <typename T>
target*
- target_factory (dir_path d, std::string n, const std::string* e)
+ target_factory (const target_type&, dir_path d, string n, const string* e)
{
- return new T (std::move (d), std::move (n), e);
+ return new T (move (d), move (n), e);
}
// Return fixed target extension.
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
diff --git a/build/target.cxx b/build/target.cxx
index 22c9ad4..649e570 100644
--- a/build/target.cxx
+++ b/build/target.cxx
@@ -286,7 +286,7 @@ namespace build
if (r)
{
- unique_ptr<target> pt (tt.factory (move (dir), move (name), ext));
+ unique_ptr<target> pt (tt.factory (tt, move (dir), move (name), ext));
i = map_.emplace (
make_pair (target_key {&tt, &pt->dir, &pt->name, &pt->ext},
move (pt))).first;
@@ -446,7 +446,8 @@ namespace build
nullptr,
nullptr,
&search_target,
- false
+ false,
+ nullptr
};
const target_type mtime_target::static_type
@@ -457,7 +458,8 @@ namespace build
nullptr,
nullptr,
&search_target,
- false
+ false,
+ nullptr
};
const target_type path_target::static_type
@@ -468,12 +470,13 @@ namespace build
nullptr,
nullptr,
&search_target,
- false
+ false,
+ nullptr
};
template <typename T>
static target*
- file_factory (dir_path d, string n, const string* e)
+ file_factory (const target_type&, dir_path d, string n, const string* e)
{
// The file target type doesn't imply any extension. So if one
// wasn't specified, set it to empty rather than unspecified.
@@ -493,7 +496,8 @@ namespace build
&file_factory<file>,
&target_extension_fix<file_ext>,
&search_file,
- false
+ false,
+ nullptr
};
const target_type alias::static_type
@@ -504,7 +508,8 @@ namespace build
&target_factory<alias>,
nullptr, // Should never need.
&search_alias,
- false
+ false,
+ nullptr
};
const target_type dir::static_type
@@ -515,7 +520,8 @@ namespace build
&target_factory<dir>,
nullptr, // Should never need.
&search_alias,
- false
+ false,
+ nullptr
};
const target_type fsdir::static_type
@@ -526,7 +532,8 @@ namespace build
&target_factory<fsdir>,
nullptr, // Should never need.
&search_target,
- false
+ false,
+ nullptr
};
static const std::string&
@@ -546,7 +553,8 @@ namespace build
&file_factory<buildfile>,
&buildfile_target_extension,
&search_file,
- false
+ false,
+ nullptr
};
constexpr const char doc_ext[] = "";
@@ -558,11 +566,12 @@ namespace build
&file_factory<doc>,
&target_extension_fix<doc_ext>,
&search_file,
- false
+ false,
+ nullptr
};
static target*
- man_factory (dir_path d, string n, const string* e)
+ man_factory (const target_type&, dir_path d, string n, const string* e)
{
if (e == nullptr)
fail << "man target '" << n << "' must include extension (man section)";
@@ -578,7 +587,8 @@ namespace build
&man_factory,
nullptr, // Should be specified explicitly.
&search_file,
- false
+ false,
+ nullptr
};
constexpr const char man1_ext[] = "1";
@@ -590,6 +600,7 @@ namespace build
&file_factory<man1>,
&target_extension_fix<man1_ext>,
&search_file,
- false
+ false,
+ nullptr
};
}
diff --git a/build/types b/build/types
index 0a71252..c119839 100644
--- a/build/types
+++ b/build/types
@@ -7,6 +7,8 @@
#include <vector>
#include <string>
+#include <memory> // unique_ptr, shared_ptr
+#include <functional> // reference_wrapper
#include <butl/path>
#include <butl/timestamp>
@@ -17,7 +19,12 @@ namespace build
{
// Commonly-used types.
//
- using strings = std::vector<std::string>;
+ using std::string;
+ using std::unique_ptr;
+ using std::shared_ptr;
+ using std::reference_wrapper;
+
+ using strings = std::vector<string>;
using cstrings = std::vector<const char*>;
// <butl/path>
diff --git a/build/utility b/build/utility
index 42d7f0f..7e6b0df 100644
--- a/build/utility
+++ b/build/utility
@@ -7,7 +7,7 @@
#include <tuple>
#include <string>
-#include <utility>
+#include <utility> // move()
#include <exception>
#include <unordered_set>
@@ -15,6 +15,8 @@
namespace build
{
+ using std::move;
+
// Empty string and path.
//
extern const std::string empty_string;
diff --git a/tests/define/buildfile b/tests/define/buildfile
new file mode 100644
index 0000000..d3b9fc4
--- /dev/null
+++ b/tests/define/buildfile
@@ -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"