aboutsummaryrefslogtreecommitdiff
path: root/libbuild2
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-02-08 11:02:25 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-02-08 11:02:25 +0200
commit435b3e43dd054a716b3fc67fc34b43267f8e9809 (patch)
tree8e11ad74f0397feee9ffce064d3c6812c740a832 /libbuild2
parent90d37f3fe126fa7b3d97fb071f537f910bd4a7fa (diff)
Enter scope src directories into scope map
Diffstat (limited to 'libbuild2')
-rw-r--r--libbuild2/cc/compile-rule.cxx20
-rw-r--r--libbuild2/config/operation.cxx2
-rw-r--r--libbuild2/context.cxx4
-rw-r--r--libbuild2/dist/operation.cxx2
-rw-r--r--libbuild2/dump.cxx17
-rw-r--r--libbuild2/file.cxx48
-rw-r--r--libbuild2/file.hxx2
-rw-r--r--libbuild2/parser.hxx2
-rw-r--r--libbuild2/scope.cxx59
-rw-r--r--libbuild2/scope.hxx57
-rw-r--r--libbuild2/search.cxx2
11 files changed, 148 insertions, 67 deletions
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index 8354bca..c9d2652 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -2151,8 +2151,7 @@ namespace build2
if (j != je)
{
- // The groups are ordered from the most to least
- // specific.
+ // The groups are ordered from the most to least specific.
//
for (const string& g: j->second)
if ((i = ths.find (g)) != ie)
@@ -2812,18 +2811,11 @@ namespace build2
if (!e.empty ())
n.resize (n.size () - e.size () - 1); // One for the dot.
- // See if this directory is part of any project out_root hierarchy and
- // if so determine the target type.
+ // See if this directory is part of any project and if so determine
+ // the target type.
//
- // Note that this will miss all the headers that come from src_root
- // (so they will be treated as generic C headers below). Generally, we
- // don't have the ability to determine that some file belongs to
- // src_root of some project. But that's not a problem for our
- // purposes: it is only important for us to accurately determine
- // target types for headers that could be auto-generated.
- //
- // While at it also try to determine if this target is from the src or
- // out tree of said project.
+ // While at it also determine if this target is from the src or out
+ // tree of said project.
//
dir_path out;
@@ -2839,7 +2831,7 @@ namespace build2
{
tts = map_extension (bs, n, e);
- if (bs.out_path () != bs.src_path () && d.sub (bs.src_path ()))
+ if (!bs.out_eq_src () && d.sub (bs.src_path ()))
out = out_src (d, *rs);
}
diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx
index f9d83da..7490bc3 100644
--- a/libbuild2/config/operation.cxx
+++ b/libbuild2/config/operation.cxx
@@ -720,7 +720,7 @@ namespace build2
//
create_bootstrap_inner (rs);
- if (rs.out_path () == rs.src_path ())
+ if (rs.out_eq_src ())
fail (l) << "forwarding to source directory " << rs.src_path ();
}
else
diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx
index 3224dc1..df06aa8 100644
--- a/libbuild2/context.cxx
+++ b/libbuild2/context.cxx
@@ -35,7 +35,7 @@ namespace build2
create_global_scope (scope_map& m)
{
auto i (m.insert (dir_path ()));
- scope& r (i->second);
+ scope& r (*i->second.scope);
r.out_path_ = &i->first;
return r;
};
@@ -488,7 +488,7 @@ namespace build2
//
if (c == '!' || (dir && dir->absolute ()))
{
- scope& s (c == '!' ? gs : sm.insert (*dir)->second);
+ scope& s (c == '!' ? gs : *sm.insert (*dir)->second.scope);
auto p (s.vars.insert (*o));
assert (p.second); // Variable name is unique.
diff --git a/libbuild2/dist/operation.cxx b/libbuild2/dist/operation.cxx
index 07f3b42..ac76a62 100644
--- a/libbuild2/dist/operation.cxx
+++ b/libbuild2/dist/operation.cxx
@@ -597,7 +597,7 @@ namespace build2
(rs->out_path () != t.dir && rs->src_path () != t.dir))
fail << "dist meta-operation target must be project root directory";
- if (rs->out_path () == rs->src_path ())
+ if (rs->out_eq_src ())
fail << "in-tree distribution of target " << t <<
info << "distribution requires out-of-tree build";
diff --git a/libbuild2/dump.cxx b/libbuild2/dump.cxx
index 95c7cae..7cd95dd 100644
--- a/libbuild2/dump.cxx
+++ b/libbuild2/dump.cxx
@@ -438,7 +438,7 @@ namespace build2
scope_map::const_iterator& i,
bool rel)
{
- const scope& p (i->second);
+ const scope& p (*i->second.scope);
const dir_path& d (i->first);
++i;
@@ -484,7 +484,8 @@ namespace build2
vb = true;
}
- // Nested scopes of which we are an immediate parent.
+ // Nested scopes of which we are an immediate parent. Only consider the
+ // out hierarchy.
//
// Note that because we use the logical (rather than physical) parent, we
// will be printing the logical scope hierarchy (i.e., a project with
@@ -492,7 +493,7 @@ namespace build2
// scope).
//
for (auto e (p.ctx.scopes.end ());
- i != e && i->second.parent_scope () == &p; )
+ i != e && i->second.out && i->second.scope->parent_scope () == &p; )
{
if (vb)
{
@@ -541,8 +542,8 @@ namespace build2
void
dump (const context& c, optional<action> a)
{
- auto i (c.scopes.cbegin ());
- assert (&i->second == &c.global_scope);
+ auto i (c.scopes.begin ());
+ assert (i->second.scope == &c.global_scope);
// We don't lock diag_stream here as dump() is supposed to be called from
// the main thread prior/after to any other threads being spawned.
@@ -556,9 +557,9 @@ namespace build2
void
dump (const scope& s, const char* cind)
{
- const scope_map_base& m (s.ctx.scopes); // Iterator interface.
- auto i (m.find (s.out_path ()));
- assert (i != m.end () && &i->second == &s);
+ const scope_map& m (s.ctx.scopes);
+ auto i (m.find_exact (s.out_path ()));
+ assert (i != m.end () && i->second.scope == &s);
string ind (cind);
ostream& os (*diag_stream);
diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx
index 5d1487f..87e21a6 100644
--- a/libbuild2/file.cxx
+++ b/libbuild2/file.cxx
@@ -399,7 +399,7 @@ namespace build2
const dir_path& src_root)
{
auto i (ctx.scopes.rw ().insert (out_root, true /* root */));
- scope& rs (i->second);
+ scope& rs (*i->second.scope);
// Set out_path. Note that src_path is set in setup_root() below.
//
@@ -457,9 +457,17 @@ namespace build2
const dir_path& d (cast<dir_path> (v));
if (s.src_path_ == nullptr)
- s.src_path_ = &d;
+ {
+ if (*s.out_path_ != d)
+ {
+ auto i (ctx.scopes.rw (s).insert (s, d));
+ s.src_path_ = &i->first;
+ }
+ else
+ s.src_path_ = s.out_path_;
+ }
else
- assert (s.src_path_ == &d);
+ assert (*s.src_path_ == d);
s.assign (ctx.var_forwarded) = forwarded;
}
@@ -469,7 +477,7 @@ namespace build2
const dir_path& out_base,
const dir_path& src_base)
{
- scope& s (i->second);
+ scope& s (*i->second.scope);
context& ctx (s.ctx);
// Set src/out_base variables.
@@ -496,7 +504,15 @@ namespace build2
assert (*s.out_path_ == out_base);
if (s.src_path_ == nullptr)
- s.src_path_ = &cast<dir_path> (sv);
+ {
+ if (out_base != src_base)
+ {
+ auto i (ctx.scopes.rw (s).insert (s, src_base));
+ s.src_path_ = &i->first;
+ }
+ else
+ s.src_path_ = s.out_path_;
+ }
else
assert (*s.src_path_ == src_base);
@@ -504,21 +520,22 @@ namespace build2
}
pair<scope&, scope*>
- switch_scope (scope& root, const dir_path& p, bool proj)
+ switch_scope (scope& root, const dir_path& out_base, bool proj)
{
// 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 (root.ctx.scopes.rw (root).insert (p));
- scope& base (i->second);
+ auto i (root.ctx.scopes.rw (root).insert (out_base));
+ scope& base (*i->second.scope);
scope* rs (nullptr);
if (proj && (rs = base.root_scope ()) != nullptr)
{
- // Path p can be src_base or out_base. Figure out which one it is.
+ // The path must be in the out (since we've inserted it as out into the
+ // scope map).
//
- dir_path out_base (p.sub (rs->out_path ()) ? p : out_src (p, *rs));
+ assert (out_base.sub (rs->out_path ()));
// Create and bootstrap root scope(s) of subproject(s) that this scope
// may belong to. If any were created, load them. Note that we need to
@@ -534,8 +551,7 @@ namespace build2
// Now we can figure out src_base and finish setting the scope.
//
- dir_path src_base (src_out (out_base, *rs));
- setup_base (i, move (out_base), move (src_base));
+ setup_base (i, out_base, src_out (out_base, *rs));
}
return pair<scope&, scope*> (base, rs);
@@ -1316,7 +1332,7 @@ namespace build2
// probably be tried first since that src_root was explicitly configured
// by the user. After that, #2 followed by #1 seems reasonable.
//
- scope& rs (create_root (ctx, out_root, dir_path ())->second);
+ scope& rs (*create_root (ctx, out_root, dir_path ())->second.scope);
bool bstrapped (bootstrapped (rs));
@@ -1383,7 +1399,7 @@ namespace build2
// The same logic to src_root as in create_bootstrap_outer().
//
- scope& rs (create_root (ctx, out_root, dir_path ())->second);
+ scope& rs (*create_root (ctx, out_root, dir_path ())->second.scope);
optional<bool> altn;
if (!bootstrapped (rs))
@@ -1618,7 +1634,7 @@ namespace build2
assert (!forwarded || out_root != src_root);
auto i (create_root (ctx, out_root, src_root));
- scope& rs (i->second);
+ scope& rs (*i->second.scope);
if (!bootstrapped (rs))
{
@@ -2327,7 +2343,7 @@ namespace build2
{
bool top (proot == nullptr);
- root = &create_root (ctx, out_root, src_root)->second;
+ root = create_root (ctx, out_root, src_root)->second.scope;
bool bstrapped (bootstrapped (*root));
diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx
index e0291fe..0c4ad62 100644
--- a/libbuild2/file.hxx
+++ b/libbuild2/file.hxx
@@ -146,7 +146,7 @@ namespace build2
// second.
//
LIBBUILD2_SYMEXPORT pair<scope&, scope*>
- switch_scope (scope& root, const dir_path&, bool project = true);
+ switch_scope (scope& root, const dir_path& out_base, bool project = true);
// Bootstrap and optionally load an ad hoc (sub)project (i.e., the kind that
// is not discovered and loaded automatically by bootstrap/load functions
diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx
index 1e924f0..3efb94a 100644
--- a/libbuild2/parser.hxx
+++ b/libbuild2/parser.hxx
@@ -531,7 +531,7 @@ namespace build2
// project. So both must be saved and restored.
//
void
- switch_scope (const dir_path&);
+ switch_scope (const dir_path& out_base);
void
process_default_target (token&);
diff --git a/libbuild2/scope.cxx b/libbuild2/scope.cxx
index 53c859f..29e0c55 100644
--- a/libbuild2/scope.cxx
+++ b/libbuild2/scope.cxx
@@ -944,10 +944,21 @@ namespace build2
auto scope_map::
insert (const dir_path& k, bool root) -> iterator
{
- scope_map_base& m (*this);
+ auto er (map_.emplace (k, true /* out */));
- auto er (m.emplace (k, scope (ctx, true /* global */)));
- scope& s (er.first->second);
+ if (er.second)
+ {
+ er.first->second.scope = new scope (ctx, true /* global */);
+ }
+ else if (!er.first->second.out)
+ {
+ // This can potentially be triggered if we use the same directory as one
+ // project's out and another's src.
+ //
+ fail << "directory " << k << " is used as both src and out scope";
+ }
+
+ scope& s (*er.first->second.scope);
// If this is a new scope, update the parent chain.
//
@@ -958,14 +969,14 @@ namespace build2
// Update scopes of which we are a new parent/root (unless this is the
// global scope). Also find our parent while at it.
//
- if (m.size () > 1)
+ if (map_.size () > 1)
{
// The first entry is ourselves.
//
- auto r (m.find_sub (k));
+ auto r (map_.find_sub (k));
for (++r.first; r.first != r.second; ++r.first)
{
- scope& c (r.first->second);
+ scope& c (*r.first->second.scope);
// The first scope of which we are a parent is the least (shortest)
// one which means there is no other scope between it and our
@@ -995,10 +1006,10 @@ namespace build2
{
// Upgrade to root scope.
//
- auto r (m.find_sub (k));
+ auto r (map_.find_sub (k));
for (++r.first; r.first != r.second; ++r.first)
{
- scope& c (r.first->second);
+ scope& c (*r.first->second.scope);
if (c.root_ == s.root_) // No intermediate root.
c.root_ = &s;
@@ -1010,14 +1021,36 @@ namespace build2
return er.first;
}
+ auto scope_map::
+ insert (scope& s, const dir_path& k) -> iterator
+ {
+ auto er (map_.emplace (k, false /* out */));
+
+ if (er.second)
+ {
+ er.first->second.scope = &s;
+ }
+ else if (!er.first->second.out)
+ {
+ assert (er.first->second.scope == &s);
+ }
+ else
+ {
+ // This can be triggered, for example, by specifying a variable override
+ // with src instead of out directory.
+ //
+ fail << "directory " << k << " is used as both src and out scope";
+ }
+
+ return er.first;
+ }
+
scope& scope_map::
find (const dir_path& k)
{
assert (k.normalized (false)); // Allow non-canonical dir separators.
-
- scope_map_base& m (*this);
- auto i (m.find_sup (k));
- assert (i != m.end ()); // Should have global scope.
- return i->second;
+ auto i (map_.find_sup (k));
+ assert (i != map_.end ()); // Should have global scope.
+ return *i->second.scope;
}
}
diff --git a/libbuild2/scope.hxx b/libbuild2/scope.hxx
index bc04bae..11fdfe4 100644
--- a/libbuild2/scope.hxx
+++ b/libbuild2/scope.hxx
@@ -43,8 +43,10 @@ namespace build2
const dir_path& out_path () const {return *out_path_;}
const dir_path& src_path () const {return *src_path_;}
- // The first is a pointer to the key in scope_map. The second is a pointer
- // to the src_root/base variable value, if any (i.e., it can be NULL).
+ bool out_eq_src () const {return out_path_ == src_path_;}
+
+ // These are pointers to the keys in scope_map. The second can be NULL
+ // during bootstrap until initialized.
//
const dir_path* out_path_ = nullptr;
const dir_path* src_path_ = nullptr;
@@ -627,21 +629,53 @@ namespace build2
}
};
- // Scope map.
+ // Scope map. Protected by the phase mutex.
//
- // Protected by the phase mutex. Note that the scope map is only for paths
- // from the out tree.
+ // While it contains both out and src paths, the latter is not available
+ // during bootstrap (see setup_root() and setup_base() for details).
//
- using scope_map_base = dir_path_map<scope>;
-
- class scope_map: public scope_map_base
+ class scope_map
{
public:
+ struct scope_ptr
+ {
+ using scope_type = build2::scope;
+
+ scope_type* scope;
+ bool out;
+
+ scope_ptr (bool o): scope (nullptr), out (o) {}
+ ~scope_ptr () {if (out) delete scope;}
+
+ scope_ptr (scope_ptr&& x) // For GCC 4.9
+ : scope (x.scope), out (x.out)
+ {
+ x.scope = nullptr;
+ }
+
+ scope_ptr& operator= (scope_ptr&&) = delete;
+
+ scope_ptr (const scope_ptr&) = delete;
+ scope_ptr& operator= (const scope_ptr&) = delete;
+ };
+
+ using map_type = dir_path_map<scope_ptr>;
+
+ using iterator = map_type::iterator;
+ using const_iterator = map_type::const_iterator;
+
+ // Insert a scope given its out path.
+ //
// Note that we assume the first insertion into the map is always the
// global scope with empty key.
//
LIBBUILD2_SYMEXPORT iterator
- insert (const dir_path&, bool root = false);
+ insert (const dir_path& our_path, bool root = false);
+
+ // Insert a shallow reference to the scope for its src path.
+ //
+ LIBBUILD2_SYMEXPORT iterator
+ insert (scope&, const dir_path& src_path);
// Find the most qualified scope that encompasses this path.
//
@@ -667,6 +701,10 @@ namespace build2
return find (path_cast<dir_path> (p));
}
+ const_iterator begin () const {return map_.begin ();}
+ const_iterator end () const {return map_.end ();}
+ const_iterator find_exact (const dir_path& d) const {return map_.find (d);}
+
// RW access.
//
public:
@@ -691,6 +729,7 @@ namespace build2
private:
context& ctx;
+ map_type map_;
};
}
diff --git a/libbuild2/search.cxx b/libbuild2/search.cxx
index 25a4199..fca19ea 100644
--- a/libbuild2/search.cxx
+++ b/libbuild2/search.cxx
@@ -175,7 +175,7 @@ namespace build2
if (tk.out->empty ())
{
- if (s->out_path () != s->src_path ())
+ if (!s->out_eq_src ())
out = out_src (d, *s->root_scope ());
}
else