aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-12-01 15:37:04 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-12-01 15:37:04 +0200
commit74212589a797ca75e55f92a522e198915c0dbaf6 (patch)
tree6e16ed2ed816c66a0c3edef74c1f1e050fa0e272
parent10fd2aface4486fc7f873dd2b54a1c2073c0b434 (diff)
Use 'extension' variable to resolve extension for file{}
We now also check target type/pattern-specific variables. So the new usage is: cli{*}: extension = cli
-rw-r--r--build/context.cxx2
-rw-r--r--build/scope15
-rw-r--r--build/scope.cxx24
-rw-r--r--build/target.cxx81
-rw-r--r--build/target.txx6
-rw-r--r--build/variable9
-rw-r--r--build/variable.cxx68
7 files changed, 127 insertions, 78 deletions
diff --git a/build/context.cxx b/build/context.cxx
index a20a7e2..699cc3c 100644
--- a/build/context.cxx
+++ b/build/context.cxx
@@ -74,6 +74,8 @@ namespace build
//
variable_pool.find ("subprojects", nullptr, '=');
+ variable_pool.find ("extension", string_type);
+
// Create global scope. For Win32 this is not a "real" root path.
// On POSIX, however, this is a real path. See the comment in
// <build/path-map> for details.
diff --git a/build/scope b/build/scope
index 8b0d0ad..1cfbc10 100644
--- a/build/scope
+++ b/build/scope
@@ -75,15 +75,26 @@ namespace build
// Lookup, including in outer scopes. If you only want to lookup
// in this scope, do it on the the variables map directly.
//
- lookup<const value>
+ build::lookup<const value>
operator[] (const variable&) const;
- lookup<const value>
+ build::lookup<const value>
operator[] (const std::string& name) const
{
return operator[] (variable_pool.find (name));
}
+ // As above, but includes target type/pattern-specific variables.
+ //
+ build::lookup<const value>
+ lookup (const target_type&, const string& name, const variable&) const;
+
+ build::lookup<const value>
+ lookup (const target_type& tt, const string& n, const string& var) const
+ {
+ return lookup (tt, n, variable_pool.find (var));
+ }
+
// Return a value suitable for assignment (or append if you only
// want to append to the value from this scope). If the variable
// does not exist in this scope's map, then a new one with the
diff --git a/build/scope.cxx b/build/scope.cxx
index d407ce0..305950b 100644
--- a/build/scope.cxx
+++ b/build/scope.cxx
@@ -15,6 +15,8 @@ namespace build
lookup<const value> scope::
operator[] (const variable& var) const
{
+ using result = build::lookup<const value>;
+
const value* r (nullptr);
const scope* s (this);
@@ -24,7 +26,27 @@ namespace build
break;
}
- return lookup<const value> (r, &s->vars);
+ return result (r, &s->vars);
+ }
+
+ lookup<const value> scope::
+ lookup (const target_type& tt, const string& name, const variable& var) const
+ {
+ using result = build::lookup<const value>;
+
+ for (const scope* s (this); s != nullptr; s = s->parent_scope ())
+ {
+ if (!s->target_vars.empty ())
+ {
+ if (auto l = s->target_vars.lookup (tt, name, var))
+ return l;
+ }
+
+ if (auto r = s->vars.find (var))
+ return result (r, &s->vars);
+ }
+
+ return result ();
}
value& scope::
diff --git a/build/target.cxx b/build/target.cxx
index 7c45e3e..85eec66 100644
--- a/build/target.cxx
+++ b/build/target.cxx
@@ -130,86 +130,25 @@ namespace build
return result (p, &group->vars);
}
- // Cannot simply delegate to scope's operator[] since we also
- // need to check target type/pattern-specific variables.
+ // We cannot simply delegate to scope's lookup() since we also need
+ // to check the group.
//
for (const scope* s (&base_scope ()); s != nullptr; s = s->parent_scope ())
{
if (!s->target_vars.empty ())
{
- auto find_specific = [this, &var, s] (const target& t) -> result
- {
- // Search across target type hierarchy.
- //
- for (auto tt (&t.type ()); tt != nullptr; tt = tt->base)
- {
- auto i (s->target_vars.find (*tt));
-
- if (i == s->target_vars.end ())
- continue;
-
- // Try to match the pattern, starting from the longest values
- // so that the more "specific" patterns (i.e., those that cover
- // fewer characters with the wildcard) take precedence. See
- // tests/variable/type-pattern.
- //
- const variable_pattern_map& m (i->second);
-
- for (auto j (m.rbegin ()); j != m.rend (); ++j)
- {
- const string& p (j->first);
-
- size_t nn (name.size ());
- size_t pn (p.size ());
-
- if (nn < pn - 1) // One for '*'.
- continue;
-
- size_t w (p.find ('*'));
- assert (w != string::npos);
-
- // Compare prefix.
- //
- if (w != 0 &&
- name.compare (0, w, p, 0, w) != 0)
- continue;
-
- ++w; // First suffix character.
- pn -= w; // Suffix length.
-
- // Compare suffix.
- //
- if (pn != 0 &&
- name.compare (nn - pn, pn, p, w, pn) != 0)
- continue;
-
- // Ok, this pattern matches. But is there a variable?
- //
- if (const value* v = j->second.find (var))
- {
- //@@ TODO: should we detect ambiguity? 'foo-*' '*-foo' and
- // 'foo-foo'? Right now the last defined will be used.
- //
- return result (v, &j->second);
- }
- }
- }
-
- return result ();
- };
-
- if (auto p = find_specific (*this))
- return p;
+ if (auto l = s->target_vars.lookup (type (), name, var))
+ return l;
if (group != nullptr)
{
- if (auto p = find_specific (*group))
- return p;
+ if (auto l = s->target_vars.lookup (group->type (), group->name, var))
+ return l;
}
}
- if (auto p = s->vars.find (var))
- return result (p, &s->vars);
+ if (auto r = s->vars.find (var))
+ return result (r, &s->vars);
}
return result ();
@@ -481,13 +420,13 @@ namespace build
(e != nullptr ? e : &extension_pool.find ("")));
}
- constexpr const char file_ext[] = "";
+ constexpr const char extension_var[] = "extension";
const target_type file::static_type
{
"file",
&path_target::static_type,
&file_factory<file>,
- &target_extension_fix<file_ext>,
+ &target_extension_var<extension_var>,
&search_file,
false
};
diff --git a/build/target.txx b/build/target.txx
index a293018..48bac21 100644
--- a/build/target.txx
+++ b/build/target.txx
@@ -20,12 +20,14 @@ namespace build
const std::string&
target_extension_var (const target_key& tk, scope& s)
{
- auto l (s[var]);
+ // Include target type/pattern-specific variables.
+ //
+ auto l (s.lookup (*tk.type, *tk.name, var));
if (!l)
{
diag_record dr;
- dr << fail << "no default extension in variable " << var
+ dr << fail << "no default extension in variable '" << var << "'"
<< info << "required to derive file name for ";
// This is a bit hacky: we may be dealing with a target (see
diff --git a/build/variable b/build/variable
index 2aec39d..7976ab9 100644
--- a/build/variable
+++ b/build/variable
@@ -768,8 +768,13 @@ namespace build
// consider its lifetime.
//
using variable_pattern_map = std::map<std::string, variable_map>;
- using variable_type_map = std::map<std::reference_wrapper<const target_type>,
- variable_pattern_map>;
+
+ struct variable_type_map: std::map<std::reference_wrapper<const target_type>,
+ variable_pattern_map>
+ {
+ build::lookup<const value>
+ lookup (const target_type&, const string& name, const variable&) const;
+ };
}
#include <build/variable.ixx>
diff --git a/build/variable.cxx b/build/variable.cxx
index 03c910d..753e3d3 100644
--- a/build/variable.cxx
+++ b/build/variable.cxx
@@ -342,4 +342,72 @@ namespace build
// variable_set
//
variable_set variable_pool;
+
+ // variable_type_map
+ //
+ lookup<const value> variable_type_map::
+ lookup (const target_type& type,
+ const string& name,
+ const variable& var) const
+ {
+ using result = build::lookup<const value>;
+
+ // Search across target type hierarchy.
+ //
+ for (auto tt (&type); tt != nullptr; tt = tt->base)
+ {
+ auto i (find (*tt));
+
+ if (i == end ())
+ continue;
+
+ // Try to match the pattern, starting from the longest values
+ // so that the more "specific" patterns (i.e., those that cover
+ // fewer characters with the wildcard) take precedence. See
+ // tests/variable/type-pattern.
+ //
+ const variable_pattern_map& m (i->second);
+
+ for (auto j (m.rbegin ()); j != m.rend (); ++j)
+ {
+ const string& p (j->first);
+
+ size_t nn (name.size ());
+ size_t pn (p.size ());
+
+ if (nn < pn - 1) // One for '*'.
+ continue;
+
+ size_t w (p.find ('*'));
+ assert (w != string::npos);
+
+ // Compare prefix.
+ //
+ if (w != 0 &&
+ name.compare (0, w, p, 0, w) != 0)
+ continue;
+
+ ++w; // First suffix character.
+ pn -= w; // Suffix length.
+
+ // Compare suffix.
+ //
+ if (pn != 0 &&
+ name.compare (nn - pn, pn, p, w, pn) != 0)
+ continue;
+
+ // Ok, this pattern matches. But is there a variable?
+ //
+ if (const value* v = j->second.find (var))
+ {
+ //@@ TODO: should we detect ambiguity? 'foo-*' '*-foo' and
+ // 'foo-foo'? Right now the last defined will be used.
+ //
+ return result (v, &j->second);
+ }
+ }
+ }
+
+ return result ();
+ }
}