From 74212589a797ca75e55f92a522e198915c0dbaf6 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 1 Dec 2015 15:37:04 +0200 Subject: 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 --- build/context.cxx | 2 ++ build/scope | 15 ++++++++-- build/scope.cxx | 24 +++++++++++++++- build/target.cxx | 81 +++++++----------------------------------------------- build/target.txx | 6 ++-- build/variable | 9 ++++-- build/variable.cxx | 68 +++++++++++++++++++++++++++++++++++++++++++++ 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 // 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 + build::lookup operator[] (const variable&) const; - lookup + build::lookup operator[] (const std::string& name) const { return operator[] (variable_pool.find (name)); } + // As above, but includes target type/pattern-specific variables. + // + build::lookup + lookup (const target_type&, const string& name, const variable&) const; + + build::lookup + 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 scope:: operator[] (const variable& var) const { + using result = build::lookup; + const value* r (nullptr); const scope* s (this); @@ -24,7 +26,27 @@ namespace build break; } - return lookup (r, &s->vars); + return result (r, &s->vars); + } + + lookup scope:: + lookup (const target_type& tt, const string& name, const variable& var) const + { + using result = build::lookup; + + 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, - &target_extension_fix, + &target_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; - using variable_type_map = std::map, - variable_pattern_map>; + + struct variable_type_map: std::map, + variable_pattern_map> + { + build::lookup + lookup (const target_type&, const string& name, const variable&) const; + }; } #include 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 variable_type_map:: + lookup (const target_type& type, + const string& name, + const variable& var) const + { + using result = build::lookup; + + // 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 (); + } } -- cgit v1.1