aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/context.cxx1
-rw-r--r--build2/target33
-rw-r--r--build2/target.cxx43
3 files changed, 77 insertions, 0 deletions
diff --git a/build2/context.cxx b/build2/context.cxx
index 40537b4..97a2995 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -345,6 +345,7 @@ namespace build2
t.insert<alias> ();
t.insert<dir> ();
t.insert<fsdir> ();
+ t.insert<in> ();
t.insert<exe> ();
t.insert<doc> ();
t.insert<man> ();
diff --git a/build2/target b/build2/target
index c672dc9..1a1fd8d 100644
--- a/build2/target
+++ b/build2/target
@@ -1428,6 +1428,12 @@ namespace build2
return const_cast<path_target*> (this)->derive_path (); // MT-aware.
}
+ const string&
+ derive_extension () const
+ {
+ return const_cast<path_target*> (this)->derive_extension (); // MT-aware.
+ }
+
public:
static const target_type static_type;
@@ -1526,6 +1532,33 @@ namespace build2
virtual const target_type& dynamic_type () const {return static_type;}
};
+ // This is the venerable .in ("input") file that needs some kind of
+ // preprocessing.
+ //
+ // One interesting aspect of this target type is that the prerequisite
+ // search is target-dependent. Consider:
+ //
+ // hxx{version}: in{version.hxx} // version.hxx.in -> version.hxx
+ //
+ // Having to specify the header extension explicitly is inelegant. Instead
+ // what we really want to write is this:
+ //
+ // hxx{version}: in{version}
+ //
+ // But how do we know that in{version} means version.hxx.in? That's where
+ // the target-dependent search comes in: we take into account the target
+ // we are a prerequisite of.
+ //
+ class in: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
// Common documentation file targets.
//
// @@ Maybe these should be in the built-in doc module?
diff --git a/build2/target.cxx b/build2/target.cxx
index e0f4e55..e1712b9 100644
--- a/build2/target.cxx
+++ b/build2/target.cxx
@@ -1008,6 +1008,49 @@ namespace build2
false
};
+ // in
+ //
+ static const target*
+ in_search (const target& xt, const prerequisite_key& cpk)
+ {
+ // If we have no extension then derive it from our target. The delegate
+ // to file_search().
+ //
+ prerequisite_key pk (cpk);
+ optional<string>& e (pk.tk.ext);
+
+ if (!e)
+ {
+ if (const file* t = xt.is_a<file> ())
+ {
+ const string& te (t->derive_extension ());
+ e = te + (te.empty () ? "" : ".") + "in";
+ }
+ else
+ fail << "prerequisite " << pk << " for a non-file target " << xt;
+ }
+
+ return file_search (xt, pk);
+ }
+
+ static bool
+ in_pattern (const target_type&, const scope&, string&, bool)
+ {
+ fail << "pattern in in{} prerequisite" << endf;
+ }
+
+ const target_type in::static_type
+ {
+ "in",
+ &file::static_type,
+ &file_factory<in, file_ext_def>, // No extension by default.
+ &target_extension_assert, // Should be taken care by search.
+ &in_pattern,
+ &target_print_1_ext_verb, // Same as file.
+ &in_search,
+ false
+ };
+
const target_type doc::static_type
{
"doc",