diff options
-rw-r--r-- | build2/b.cxx | 81 | ||||
-rw-r--r-- | build2/context.cxx | 36 | ||||
-rw-r--r-- | build2/file.cxx | 4 | ||||
-rw-r--r-- | build2/operation.cxx | 4 | ||||
-rw-r--r-- | build2/scope.hxx | 3 | ||||
-rw-r--r-- | build2/variable.hxx | 7 | ||||
-rwxr-xr-x | old-tests/variable/override/test.sh | 30 |
7 files changed, 113 insertions, 52 deletions
diff --git a/build2/b.cxx b/build2/b.cxx index aedda7f..c1bf07d 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -1192,50 +1192,67 @@ main (int argc, char* argv[]) // // This is further complicated by the project vs amalgamation logic // (we may have already done the amalgamation but not the project). + // So we split it into two passes. // - bool first_a (true); - for (const variable_override& o: var_ovs) { - if (o.ovr.visibility != variable_visibility::normal) - continue; - - auto p (rs.weak_scope ()->vars.insert (o.ovr)); + auto& sm (scope_map::instance); - if (!p.second) + bool first_a (true); + for (const variable_override& o: var_ovs) { - if (first_a) - break; + if (o.ovr.visibility != variable_visibility::normal) + continue; - fail << "multiple amalgamation overrides of variable " - << o.var.name; - } + // If we have a directory, enter the scope, similar to how we do + // it in the context's reset(). + // + scope& s (o.dir + ? sm.insert ((out_base / *o.dir).normalize ())->second + : *rs.weak_scope ()); - value& v (p.first); - v = o.val; - first_a = false; - } + auto p (s.vars.insert (o.ovr)); - bool first_p (true); - for (const variable_override& o: var_ovs) - { - // Ours is either project (%foo) or scope (/foo). - // - if (o.ovr.visibility == variable_visibility::normal) - continue; + if (!p.second) + { + if (first_a) + break; + + fail << "multiple " << (o.dir ? "scope" : "amalgamation") + << " overrides of variable " << o.var.name; + } - auto p (rs.vars.insert (o.ovr)); + value& v (p.first); + v = o.val; + first_a = false; + } - if (!p.second) + bool first_p (true); + for (const variable_override& o: var_ovs) { - if (first_p) - break; + // Ours is either project (%foo) or scope (/foo). + // + if (o.ovr.visibility == variable_visibility::normal) + continue; - fail << "multiple project overrides of variable " << o.var.name; - } + scope& s (o.dir + ? sm.insert ((out_base / *o.dir).normalize ())->second + : rs); + + auto p (s.vars.insert (o.ovr)); - value& v (p.first); - v = o.val; - first_p = false; + if (!p.second) + { + if (first_p) + break; + + fail << "multiple " << (o.dir ? "scope" : "project") + << " overrides of variable " << o.var.name; + } + + value& v (p.first); + v = o.val; + first_p = false; + } } ts.root_scope = &rs; diff --git a/build2/context.cxx b/build2/context.cxx index 5741489..10995e6 100644 --- a/build2/context.cxx +++ b/build2/context.cxx @@ -412,7 +412,7 @@ namespace build2 // auto make_global_scope = [] () -> scope& { - auto i (scope_map::instance.insert (dir_path (), false)); + auto i (scope_map::instance.insert (dir_path ())); scope& r (i->second); r.out_path_ = &i->first; global_scope = scope::global_ = &r; @@ -602,7 +602,7 @@ namespace build2 // token t (l.next ()); - dir_path dir; + optional<dir_path> dir; if (t.type == token_type::word) { string& v (t.value); @@ -638,10 +638,20 @@ namespace build2 t.value.erase (0, p + 1); // Erase the separator. } - if (dir.relative ()) - dir.complete (); + if (dir->relative ()) + { + // Handle the special relative to base scope case (.../). + // + auto i (dir->begin ()); + + if (*i == "...") + dir = dir_path (++i, dir->end ()); // Note: can become empty. + else + dir->complete (); // Relative to CWD. + } - dir.normalize (); + if (dir->absolute ()) + dir->normalize (); } } @@ -668,7 +678,7 @@ namespace build2 string n (t.value, c == '!' || c == '%' || c == '/' ? 1 : 0); - if (c == '!' && !dir.empty ()) + if (c == '!' && dir) fail << "scope-qualified global override of variable " << n; variable_visibility v (c == '/' ? variable_visibility::scope : @@ -713,12 +723,13 @@ namespace build2 if (r.first.type != nullptr) fail << "typed override of variable " << n; - // Global and scope overrides we can enter directly. Project ones will - // be entered by the caller for each amalgamation/project. + // Global and absolute scope overrides we can enter directly. Project + // and relative scope ones will be entered by the caller for each + // amalgamation/project. // - if (c == '!' || !dir.empty ()) + if (c == '!' || (dir && dir->absolute ())) { - scope& s (c == '!' ? gs : sm.insert (dir, false)->second); + scope& s (c == '!' ? gs : sm.insert (*dir)->second); auto p (s.vars.insert (*o)); if (!p.second) @@ -727,14 +738,15 @@ namespace build2 fail << "multiple global overrides of variable " << n; else fail << "multiple overrides of variable " << n - << " in scope " << dir; + << " in scope " << *dir; } value& v (p.first); v = move (r.first); } else - vos.emplace_back (variable_override {var, *o, move (r.first)}); + vos.push_back ( + variable_override {var, *o, move (dir), move (r.first)}); } // Enter builtin variables and patterns. diff --git a/build2/file.cxx b/build2/file.cxx index 05527f3..3f0e7b7 100644 --- a/build2/file.cxx +++ b/build2/file.cxx @@ -221,7 +221,7 @@ namespace build2 scope_map::iterator create_root (scope& l, const dir_path& out_root, const dir_path& src_root) { - auto i (scopes.rw (l).insert (out_root, true)); + auto i (scopes.rw (l).insert (out_root, true /* root */)); scope& rs (i->second); // Set out_path. Note that src_path is set in setup_root() below. @@ -348,7 +348,7 @@ namespace build2 // First, enter the scope into the map and see if it is in any project. If // it is not, then there is nothing else to do. // - auto i (scopes.rw (root).insert (p, false)); + auto i (scopes.rw (root).insert (p)); scope& base (i->second); scope* rs (base.root_scope ()); diff --git a/build2/operation.cxx b/build2/operation.cxx index 229ea4e..aa92756 100644 --- a/build2/operation.cxx +++ b/build2/operation.cxx @@ -81,7 +81,7 @@ namespace build2 // Create the base scope. Note that its existence doesn't mean it was // already setup as a base scope; it can be the same as root. // - auto i (scopes.rw (root).insert (out_base, false)); + auto i (scopes.rw (root).insert (out_base)); scope& base (setup_base (i, out_base, src_base)); // Load the buildfile unless it is implied. @@ -456,7 +456,7 @@ namespace build2 if (rs.out_path () != out_base || rs.src_path () != src_base) fail (l) << "meta-operation info target must be project root directory"; - setup_base (scopes.rw (rs).insert (out_base, false), out_base, src_base); + setup_base (scopes.rw (rs).insert (out_base), out_base, src_base); } void diff --git a/build2/scope.hxx b/build2/scope.hxx index 7929bce..a0c96f0 100644 --- a/build2/scope.hxx +++ b/build2/scope.hxx @@ -352,7 +352,7 @@ namespace build2 // global scope with empty key. // iterator - insert (const dir_path&, bool root); + insert (const dir_path&, bool root = false); // Find the most qualified scope that encompasses this path. // @@ -396,6 +396,7 @@ namespace build2 // Entities that can access bypassing the lock proof. // + friend int main (int, char*[]); friend variable_overrides reset (const strings&); scope& diff --git a/build2/variable.hxx b/build2/variable.hxx index 7dc3d1a..246fdf3 100644 --- a/build2/variable.hxx +++ b/build2/variable.hxx @@ -927,9 +927,10 @@ namespace build2 // struct variable_override { - const variable& var; // Original variable. - const variable& ovr; // Override variable. - value val; + const variable& var; // Original variable. + const variable& ovr; // Override variable. + optional<dir_path> dir; // Scope directory relative to base. + value val; }; using variable_overrides = vector<variable_override>; diff --git a/old-tests/variable/override/test.sh b/old-tests/variable/override/test.sh index 76409d8..baef1ca 100755 --- a/old-tests/variable/override/test.sh +++ b/old-tests/variable/override/test.sh @@ -93,6 +93,16 @@ p/d : X p/d/t : X EOF +test .../v=X <<EOF +/ : +. : X +d : X +d/t : X +p : X +p/d : X +p/d/t : X +EOF + test ./p/v=X <<EOF / : . : @@ -103,6 +113,16 @@ p/d : X p/d/t : X EOF +test .../p/v=X <<EOF +/ : +. : +d : +d/t : +p : X +p/d : X +p/d/t : X +EOF + test v=X --buildfile loader ./p/ <<EOF / : . : X @@ -113,6 +133,16 @@ p/d : X p/d/t : X EOF +test .../v=X --buildfile loader ./p/ <<EOF +/ : +. : +d : +d/t : +p : X +p/d : X +p/d/t : X +EOF + test /v=X <<EOF / : . : X |