aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/scope.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/scope.cxx')
-rw-r--r--libbuild2/scope.cxx131
1 files changed, 102 insertions, 29 deletions
diff --git a/libbuild2/scope.cxx b/libbuild2/scope.cxx
index 814d876..23781a8 100644
--- a/libbuild2/scope.cxx
+++ b/libbuild2/scope.cxx
@@ -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)
{
}
@@ -685,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);
@@ -790,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;
@@ -806,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.
@@ -834,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);
}
}
@@ -849,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;
@@ -875,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);
}
}
@@ -910,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);
@@ -928,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
@@ -1010,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;
}
@@ -1028,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;
}
@@ -1132,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));
@@ -1142,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);