From b2374e3174e13682fcfa3ffe3fc62f2fd161a7cc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 30 Nov 2015 14:31:40 +0200 Subject: Implement target type/pattern-specific variables For example: cxx{*-options}: dist = true 1. Only single '*' wildcard is supported, matches 0 or more characters. 2. If target type is not specified, it defaults to any target. 3. Appending (+=) is not allowed. 4. The value is expanded immediately in the context of the scope. 5. The more specific pattern (i.e., with the shortest "stem") is preferred. If the stem has the same length, then the last defined (but not redefined) pattern is used. This will probably have to change to become an error. See tests/variable/type-pattern for more examples. --- build/target.cxx | 56 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 10 deletions(-) (limited to 'build/target.cxx') diff --git a/build/target.cxx b/build/target.cxx index 9b20273..22c9ad4 100644 --- a/build/target.cxx +++ b/build/target.cxx @@ -137,7 +137,7 @@ namespace build { if (!s->target_vars.empty ()) { - auto find_specific = [&var, s] (const target& t) -> result + auto find_specific = [this, &var, s] (const target& t) -> result { // Search across target type hierarchy. // @@ -148,15 +148,51 @@ namespace build if (i == s->target_vars.end ()) continue; - //@@ TODO: match pattern. For now, we only handle '*'. - - auto j (i->second.find ("*")); - - if (j == i->second.end ()) - continue; - - if (auto p = j->second.find (var)) - return result (p, &j->second); + // 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 (); -- cgit v1.1