aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/b.cxx81
-rw-r--r--build2/context.cxx36
-rw-r--r--build2/file.cxx4
-rw-r--r--build2/operation.cxx4
-rw-r--r--build2/scope.hxx3
-rw-r--r--build2/variable.hxx7
-rwxr-xr-xold-tests/variable/override/test.sh30
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