aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/scope.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/scope.cxx')
-rw-r--r--libbuild2/scope.cxx172
1 files changed, 133 insertions, 39 deletions
diff --git a/libbuild2/scope.cxx b/libbuild2/scope.cxx
index ad01aa7..23781a8 100644
--- a/libbuild2/scope.cxx
+++ b/libbuild2/scope.cxx
@@ -23,7 +23,7 @@ namespace build2
? empty_project_name
: i->first);
- os << (i != b ? " " : "") << n << '@' << i->second;
+ os << (i != b ? " " : "") << n << '@' << i->second.string ();
}
return os;
@@ -32,8 +32,8 @@ namespace build2
// scope
//
scope::
- scope (context& c, bool global)
- : ctx (c), vars (c, global), target_vars (c, global)
+ scope (context& c, bool shared)
+ : ctx (c), vars (*this, shared), target_vars (c, shared)
{
}
@@ -46,10 +46,12 @@ namespace build2
pair<lookup, size_t> scope::
lookup_original (const variable& var,
const target_key* tk,
- const target_key* gk,
+ const target_key* g1k,
+ const target_key* g2k,
size_t start_d) const
{
assert (tk != nullptr || var.visibility != variable_visibility::target);
+ assert (g2k == nullptr || g1k != nullptr);
size_t d (0);
@@ -61,7 +63,8 @@ namespace build2
auto pre_app = [&var, this] (lookup_type& l,
const scope* s,
const target_key* tk,
- const target_key* gk,
+ const target_key* g1k,
+ const target_key* g2k,
string n)
{
const value& v (*l);
@@ -76,7 +79,7 @@ namespace build2
// group, then we shouldn't be looking for stem in the target's
// variables. In other words, once we "jump" to group, we stay there.
//
- lookup_type stem (s->lookup_original (var, tk, gk, 2).first);
+ lookup_type stem (s->lookup_original (var, tk, g1k, g2k, 2).first);
// Check the cache.
//
@@ -140,7 +143,8 @@ namespace build2
// the copy.
//
optional<string> tn;
- optional<string> gn;
+ optional<string> g1n;
+ optional<string> g2n;
for (const scope* s (this); s != nullptr; )
{
@@ -159,7 +163,7 @@ namespace build2
if (l.defined ())
{
if (l->extra != 0) // Prepend/append?
- pre_app (l, s, tk, gk, move (*tn));
+ pre_app (l, s, tk, g1k, g2k, move (*tn));
return make_pair (move (l), d);
}
@@ -170,17 +174,30 @@ namespace build2
//
if (++d >= start_d)
{
- if (f && gk != nullptr)
+ if (f && g1k != nullptr)
{
- lookup_type l (s->target_vars.find (*gk, var, gn));
+ lookup_type l (s->target_vars.find (*g1k, var, g1n));
if (l.defined ())
{
if (l->extra != 0) // Prepend/append?
- pre_app (l, s, gk, nullptr, move (*gn));
+ pre_app (l, s, g1k, g2k, nullptr, move (*g1n));
return make_pair (move (l), d);
}
+
+ if (g2k != nullptr)
+ {
+ l = s->target_vars.find (*g2k, var, g2n);
+
+ if (l.defined ())
+ {
+ if (l->extra != 0) // Prepend/append?
+ pre_app (l, s, g2k, nullptr, nullptr, move (*g2n));
+
+ return make_pair (move (l), d);
+ }
+ }
}
}
}
@@ -319,8 +336,12 @@ namespace build2
return lookup_type ();
// Note: using the original as storage variable.
+ // Note: have to suppress aliases since used for something else.
//
- return lookup_type (s->vars.lookup (*o).first, &var, &s->vars);
+ return lookup_type (
+ s->vars.lookup (*o, true /* typed */, false /* aliased */).first,
+ &var,
+ &s->vars);
};
// Return true if a value is from this scope (either target type/pattern-
@@ -664,6 +685,8 @@ namespace build2
pair<const target_type*, optional<string>> scope::
find_target_type (name& n, const location& loc, const target_type* tt) const
{
+ // NOTE: see also functions-name.cxx:filter() if changing anything here.
+
optional<string> ext;
string& v (n.value);
@@ -769,9 +792,11 @@ namespace build2
}
pair<const target_type&, optional<string>> scope::
- find_target_type (name& n, name& o, const location& loc) const
+ find_target_type (name& n, name& o,
+ const location& loc,
+ const target_type* tt) const
{
- auto r (find_target_type (n, loc));
+ auto r (find_target_type (n, loc, tt));
if (r.first == nullptr)
fail (loc) << "unknown target type " << n.type << " in " << n;
@@ -785,26 +810,68 @@ namespace build2
fail (loc) << "expected directory after '@'";
}
- dir_path& d (n.dir);
+ dir_path& dir (n.dir);
const dir_path& sd (src_path ());
const dir_path& od (out_path ());
- if (d.empty ())
- d = src ? sd : od; // Already dormalized.
+ bool nabs (false);
+
+ if (dir.empty ())
+ dir = src ? sd : od; // Already normalized.
else
{
- if (d.relative ())
- d = (src ? sd : od) / d;
+ if (dir.relative ())
+ dir = (src ? sd : od) / dir;
+ else if (src)
+ nabs = true;
- d.normalize ();
+ dir.normalize ();
}
dir_path out;
- if (src && sd != od) // If in-source build, then out must be empty.
+ if (src)
{
- out = o.dir.relative () ? od / o.dir : move (o.dir);
+ bool oabs (o.dir.absolute ());
+
+ out = oabs ? move (o.dir) : od / o.dir;
out.normalize ();
+
+ // Make sure out and src are parallel unless both were specified as
+ // absolute. We make an exception for this case because out may be used
+ // to "tag" imported targets (see cc::search_library()). So it's sort of
+ // the "I know what I am doing" escape hatch (it would have been even
+ // better to verify such a target is outside any project but that won't
+ // be cheap).
+ //
+ // See similar code for prerequisites in parser::parse_dependency().
+ //
+ if (nabs && oabs)
+ ;
+ else if (root_->out_eq_src ()
+ ? out == dir
+ //
+ // @@ PERF: could just compare leafs in place.
+ //
+ : (out.sub (root_->out_path ()) &&
+ dir.sub (root_->src_path ()) &&
+ out.leaf (root_->out_path ()) == dir.leaf (root_->src_path ())))
+ ;
+ else
+ // @@ TMP change warn to fail after 0.16.0 release.
+ //
+ warn (loc) << "target output directory " << out
+ << " must be parallel to source directory " << dir;
+
+ // If this target is in this project, then out must be empty if this is
+ // in source build. We assume that if either src or out are relative,
+ // then it belongs to this project.
+ //
+ if (root_->out_eq_src ())
+ {
+ if (!nabs || !oabs || out.sub (root_->out_path ()))
+ out.clear ();
+ }
}
o.dir = move (out); // Result.
@@ -813,14 +880,16 @@ namespace build2
}
target_key scope::
- find_target_key (names& ns, const location& loc) const
+ find_target_key (names& ns,
+ const location& loc,
+ const target_type* tt) const
{
if (size_t n = ns.size ())
{
if (n == (ns[0].pair ? 2 : 1))
{
name dummy;
- return find_target_key (ns[0], n == 1 ? dummy : ns[1], loc);
+ return find_target_key (ns[0], n == 1 ? dummy : ns[1], loc, tt);
}
}
@@ -828,9 +897,11 @@ namespace build2
}
pair<const target_type&, optional<string>> scope::
- find_prerequisite_type (name& n, name& o, const location& loc) const
+ find_prerequisite_type (name& n, name& o,
+ const location& loc,
+ const target_type* tt) const
{
- auto r (find_target_type (n, loc));
+ auto r (find_target_type (n, loc, tt));
if (r.first == nullptr)
fail (loc) << "unknown target type " << n.type << " in " << n;
@@ -854,14 +925,16 @@ namespace build2
}
prerequisite_key scope::
- find_prerequisite_key (names& ns, const location& loc) const
+ find_prerequisite_key (names& ns,
+ const location& loc,
+ const target_type* tt) const
{
if (size_t n = ns.size ())
{
if (n == (ns[0].pair ? 2 : 1))
{
name dummy;
- return find_prerequisite_key (ns[0], n == 1 ? dummy : ns[1], loc);
+ return find_prerequisite_key (ns[0], n == 1 ? dummy : ns[1], loc, tt);
}
}
@@ -889,7 +962,9 @@ namespace build2
}
pair<reference_wrapper<const target_type>, bool> scope::
- derive_target_type (const string& name, const target_type& base)
+ derive_target_type (const string& name,
+ const target_type& base,
+ target_type::flag flags)
{
assert (root_scope () == this);
@@ -907,10 +982,20 @@ namespace build2
//
// Currently, if we define myfile{}: file{}, then myfile{foo} and
// myfile{foo.x} are the same target.
+
+ // Note: copies flags.
//
- unique_ptr<target_type> dt (new target_type (base));
- dt->base = &base;
- dt->factory = &derived_tt_factory;
+ unique_ptr<target_type> dt (
+ new target_type {
+ nullptr, // Will be patched in by insert() below.
+ &base,
+ &derived_tt_factory,
+ base.fixed_extension,
+ base.default_extension,
+ base.pattern,
+ base.print,
+ base.search,
+ base.flags | flags});
#if 0
// @@ We should probably inherit the fixed extension unless overriden with
@@ -989,8 +1074,17 @@ namespace build2
derive_target_type (const target_type& et)
{
assert (root_scope () == this);
- unique_ptr<target_type> dt (new target_type (et));
- dt->factory = &derived_tt_factory;
+ unique_ptr<target_type> dt (
+ new target_type {
+ nullptr, // Will be patched in by insert() below.
+ et.base,
+ &derived_tt_factory,
+ et.fixed_extension,
+ et.default_extension,
+ et.pattern,
+ et.print,
+ et.search,
+ et.flags});
return root_extra->target_types.insert (et.name, move (dt)).first;
}
@@ -1007,7 +1101,7 @@ namespace build2
if (er.first->second.front () == nullptr)
{
- er.first->second.front () = new scope (ctx, true /* global */);
+ er.first->second.front () = new scope (ctx, true /* shared */);
er.second = true;
}
@@ -1111,8 +1205,8 @@ namespace build2
}
auto scope_map::
- find (const dir_path& k) const -> pair<scopes::const_iterator,
- scopes::const_iterator>
+ find (const dir_path& k, bool sno) const -> pair<scopes::const_iterator,
+ scopes::const_iterator>
{
assert (k.normalized (false));
auto i (map_.find_sup (k));
@@ -1121,9 +1215,9 @@ namespace build2
auto b (i->second.begin ());
auto e (i->second.end ());
- // Skip NULL first element.
+ // Skip NULL first element if requested.
//
- if (*b == nullptr)
+ if (sno && *b == nullptr)
++b;
assert (b != e);