aboutsummaryrefslogtreecommitdiff
path: root/build2/version
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-11-10 20:41:51 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-11-10 20:41:51 +0200
commit99dfd1924b8a7bb5bdd0df132416ff8de6c382fa (patch)
treebfd6ed215d58064d03201315659bda0dbe49ac04 /build2/version
parentbecd974d4502f440c3071764c1d219c88caff286 (diff)
Relax substitution requirements, add alternative symbol in version .in support
Give this (legacy) version.h.in: Can now do: h{version}: in{version} file{$src_root/manifest} h{version}: in.symbol = '@' h{version}: FOO = $project.version
Diffstat (limited to 'build2/version')
-rw-r--r--build2/version/init.cxx10
-rw-r--r--build2/version/module.hxx2
-rw-r--r--build2/version/rule.cxx76
3 files changed, 70 insertions, 18 deletions
diff --git a/build2/version/init.cxx b/build2/version/init.cxx
index 7d08642..c0ce4cd 100644
--- a/build2/version/init.cxx
+++ b/build2/version/init.cxx
@@ -272,6 +272,16 @@ namespace build2
}
}
+ // Enter variables. Note: some overridable, some not.
+ //
+ auto& vp (var_pool.rw (rs));
+
+ // Alternative variable substitution symbols.
+ //
+ // @@ Note: should be moved to the 'in' module once we have it.
+ //
+ m.in_symbol = &vp.insert<string> ("in.symbol");
+
// Register rules.
//
{
diff --git a/build2/version/module.hxx b/build2/version/module.hxx
index 45b1a47..4f9f66d 100644
--- a/build2/version/module.hxx
+++ b/build2/version/module.hxx
@@ -27,6 +27,8 @@ namespace build2
butl::standard_version version;
dependency_constraints dependencies;
+ const variable* in_symbol = nullptr;
+
module (butl::standard_version v, dependency_constraints d)
: version (move (v)), dependencies (move (d)) {}
};
diff --git a/build2/version/rule.cxx b/build2/version/rule.cxx
index ceeb003..476f327 100644
--- a/build2/version/rule.cxx
+++ b/build2/version/rule.cxx
@@ -231,6 +231,18 @@ namespace build2
const scope& rs (t.root_scope ());
const module& m (*rs.modules.lookup<module> (module::name));
+ // The substitution symbol can be overridden with the in.symbol
+ // variable.
+ //
+ char sym ('$');
+ if (const string* s = cast_null<string> (t[m.in_symbol]))
+ {
+ if (s->size () == 1)
+ sym = s->front ();
+ else
+ fail << "invalid substitution symbol '" << *s << "'";
+ }
+
// Determine if anything needs to be updated.
//
timestamp mt (t.load_mtime ());
@@ -250,9 +262,15 @@ namespace build2
// First should come the rule name/version.
//
- if (dd.expect ("version.in 1") != nullptr)
+ if (dd.expect ("version.in 2") != nullptr)
l4 ([&]{trace << "rule mismatch forcing update of " << t;});
+ // Then the substitution symbol.
+ //
+ if (dd.expect (string (1, sym)) != nullptr)
+ l4 ([&]{trace << "substitution symbol mismatch forcing update of"
+ << t;});
+
// Then the .in file.
//
if (dd.expect (i.path ()) != nullptr)
@@ -268,6 +286,10 @@ namespace build2
if (dd.writing () || dd.mtime () > mt)
update = true;
+ //@@ TODO: what if one of the substituted non-version values is
+ // changes. See how we handle this in the .in module. In fact,
+ // it feels like this should be an extended version of in.
+
dd.close ();
}
@@ -279,19 +301,29 @@ namespace build2
const string& proj (cast<string> (rs.vars[var_project]));
// Perform substitutions for the project itself (normally the version.*
- // variables but we allow anything set on the root scope).
+ // variables but we allow anything set on the target and up).
//
- auto subst_self = [&rs, &t] (const location& l, const string& s)
+ auto subst_self = [&t] (const location& l, const string& s) -> string
{
- if (lookup x = rs.vars[s])
+ if (lookup x = t[s])
{
- // Call the string() function to convert the value.
- //
value v (*x);
- return convert<string> (
- functions.call (
- t.base_scope (), "string", vector_view<value> (&v, 1), l));
+ // For typed values call the string() function to convert it.
+ //
+ try
+ {
+ return convert<string> (
+ v.type == nullptr
+ ? move (v)
+ : functions.call (
+ t.base_scope (), "string", vector_view<value> (&v, 1), l));
+ }
+ catch (const invalid_argument& e)
+ {
+ fail (l) << e <<
+ info << "while substituting '" << s << "'" << endf;
+ }
}
else
fail (l) << "undefined project variable '" << s << "'" << endf;
@@ -505,7 +537,7 @@ namespace build2
{
d = 1;
- if (s[b] != '$')
+ if (s[b] != sym)
continue;
// Find the other end.
@@ -513,9 +545,9 @@ namespace build2
size_t e (b + 1);
for (; e != (n = s.size ()); ++e)
{
- if (s[e] == '$')
+ if (s[e] == sym)
{
- if (e + 1 != n && s[e + 1] == '$') // Escape.
+ if (e + 1 != n && s[e + 1] == sym) // Escape.
s.erase (e, 1); // Keep one, erase the other.
else
break;
@@ -523,7 +555,7 @@ namespace build2
}
if (e == n)
- fail (l) << "unterminated '$'";
+ fail (l) << "unterminated '" << sym << "'";
if (e - b == 1) // Escape.
{
@@ -534,14 +566,22 @@ namespace build2
// We have a substition with b pointing to the opening $ and e --
// to the closing. Split it into the package name and the trailer.
//
+ // We used to bail if there is no package component but now we
+ // treat it the same as project. This can be useful when trying
+ // to reuse existing .in files (e.g., from autoconf, etc).
+ //
+ string sn, st;
size_t p (s.find ('.', b + 1));
- if (p == string::npos || p > e)
- fail (l) << "invalid substitution: missing package name";
+ if (p != string::npos && p < e)
+ {
+ sn.assign (s, b + 1, p - b - 1);
+ st.assign (s, p + 1, e - p - 1);
+ }
+ else
+ st.assign (s, b + 1, e - b - 1);
- string sn (s, b + 1, p - b - 1);
- string st (s, p + 1, e - p - 1);
- string sr (sn == proj
+ string sr (sn.empty () || sn == proj
? subst_self (l, st)
: subst_dep (l, sn, st));