From 1c7d67d9895c2bdbef13541b154ea17d25b8d515 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 23 Jan 2017 10:53:33 +0200 Subject: Go back to storing scope instead of target in prerequisite Turns out this was semantically the right way to do it. --- build2/cc/link.cxx | 8 ++++---- build2/cli/rule.cxx | 2 +- build2/parser.cxx | 18 ++++++++++-------- build2/prerequisite | 49 ++++++++++++++++++++++++++++++------------------- build2/prerequisite.cxx | 28 ++++++---------------------- build2/target | 7 ++----- build2/target.ixx | 6 +++--- 7 files changed, 56 insertions(+), 62 deletions(-) diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx index a8b7dcb..c94eb26 100644 --- a/build2/cc/link.cxx +++ b/build2/cc/link.cxx @@ -165,7 +165,7 @@ namespace build2 // If the prerequisite came from the lib{} group, then also // add it to lib's prerequisite_targets. // - if (p.prerequisite.owner != t) + if (!p.prerequisite.belongs (t)) t.group->prerequisite_targets.push_back (pt); t.prerequisite_targets.push_back (pt); @@ -487,7 +487,7 @@ namespace build2 // @@ Why are we creating the obj{} group if the source came from a // group? // - bool group (p.prerequisite.owner != t); // Group's prerequisite. + bool group (!p.prerequisite.belongs (t)); // Group's prerequisite. const prerequisite_key& cp (p.key ()); // C-source (X or C) key. const target_type& tt (group ? obj::static_type : ott); @@ -614,7 +614,7 @@ namespace build2 { // Note: add the source to the group, not the member. // - ot.prerequisites.push_back (p.as_prerequisite_for (ot)); + ot.prerequisites.push_back (p.as_prerequisite ()); // Add our lib*{} prerequisites to the object file (see the export.* // machinery for details). @@ -634,7 +634,7 @@ namespace build2 for (prerequisite& p: group_prerequisites (t)) { if (p.is_a () || p.is_a () || p.is_a ()) - ot.prerequisites.emplace_back (p, ot); + ot.prerequisites.emplace_back (p); } build2::match (a, *pt); diff --git a/build2/cli/rule.cxx b/build2/cli/rule.cxx index f5405a5..706830c 100644 --- a/build2/cli/rule.cxx +++ b/build2/cli/rule.cxx @@ -136,7 +136,7 @@ namespace build2 if (g == nullptr) g = &targets.insert (t.dir, t.out, t.name, trace); - g->prerequisites.push_back (p.as_prerequisite_for (*g)); + g->prerequisites.push_back (p.as_prerequisite ()); } else l4 ([&]{trace << ".cli file stem '" << p.name () << "' " diff --git a/build2/parser.cxx b/build2/parser.cxx index 9d118e8..ec9d9e4 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -693,14 +693,16 @@ namespace build2 dir_path (), move (pn.value), move (e), - tgs.back ()); + *scope_); - // Move last prerequisite (which will normally be the only one). - // - for (target& t: tgs) - t.prerequisites.push_back (&t == &p.owner - ? move (p) - : prerequisite (p, t)); + for (auto i (tgs.begin ()), e (tgs.end ()); i != e; ) + { + // Move last prerequisite (which will normally be the only + // one). + // + target& t (*i); + t.prerequisites.push_back (++i == e ? move (p) : p); + } } } @@ -3552,7 +3554,7 @@ namespace build2 false, // Enter as real (not implied). trace).first); - ct.prerequisites.emplace_back (dt, ct); + ct.prerequisites.emplace_back (prerequisite (dt)); } void parser:: diff --git a/build2/prerequisite b/build2/prerequisite index f951e0a..abfb2c1 100644 --- a/build2/prerequisite +++ b/build2/prerequisite @@ -48,20 +48,28 @@ namespace build2 class prerequisite { public: - typedef build2::target target_type; - typedef build2::target_type target_type_type; + using scope_type = build2::scope; + using target_type = build2::target; + using target_type_type = build2::target_type; // Note that unlike targets, for prerequisites an empty out directory // means undetermined rather than being definitely in the out tree. // + // It might seem natural to keep the reference to the owner target instead + // of to the scope. But that's not the semantics that we have, consider: + // + // foo/obj{x}: bar/cxx{y} + // + // bar/ here is relative to the scope, not to foo/. Plus, bar/ can resolve + // to either src or out. + // const optional proj; const target_type_type& type; const dir_path dir; // Normalized absolute or relative (to scope). const dir_path out; // Empty, normalized absolute, or relative. const string name; const optional ext; // Absent if unspecified. - - target_type& owner; // Target to which this prerequisite belongs. + scope_type& scope; target_type* target; // NULL if not yet resolved. Note that this // should always be the "primary target", not @@ -74,36 +82,39 @@ namespace build2 dir_path o, string n, optional e, - target_type& w) + scope_type& s) : proj (move (p)), type (t), dir (move (d)), out (move (o)), name (move (n)), ext (move (e)), - owner (w), + scope (s), target (nullptr) {} - // Make a copy for a new owner target. Note that both owner targets should - // be in the same scope. - // - prerequisite (const prerequisite&, target_type& owner); - // Make a prerequisite from a target. // - prerequisite (target_type&, target_type& owner); - - prerequisite (const prerequisite&) = delete; - prerequisite (prerequisite&&) = default; - - prerequisite& operator= (const prerequisite&) = delete; - prerequisite& operator= (prerequisite&&) = default; + explicit + prerequisite (target_type&); // Note that the returned key "tracks" the prerequisite; that is, any // updates to the prerequisite's members will be reflected in the key. // prerequisite_key - key () const; + key () const + { + return prerequisite_key {proj, {&type, &dir, &out, &name, ext}, &scope}; + } + + // Return true if this prerequisite instance (physically) belongs to the + // target's prerequisite list. Note that this test only works if you use + // references to the container elements and the container hasn't been + // resized since such a reference was obtained. Normally this function is + // used when iterating over a combined prerequisites range to detect if + // the prerequisite came from the group (see group_prerequisites). + // + bool + belongs (const target_type&) const; // Prerequisite (target) type. // diff --git a/build2/prerequisite.cxx b/build2/prerequisite.cxx index 469bdf9..3bffa3d 100644 --- a/build2/prerequisite.cxx +++ b/build2/prerequisite.cxx @@ -51,38 +51,22 @@ namespace build2 // prerequisite // prerequisite:: - prerequisite (const prerequisite& p, target_type& w) - : proj (p.proj), - type (p.type), - dir (p.dir), - out (p.out), - name (p.name), - ext (p.ext), - owner (w), - target (nullptr) - { - assert (&w.base_scope () == &p.owner.base_scope ()); - } - - // Make a prerequisite from a target. - // - prerequisite:: - prerequisite (target_type& t, target_type& w) + prerequisite (target_type& t) : proj (nullopt), type (t.type ()), dir (t.dir), out (t.out), // @@ If it's empty, then we treat as undetermined? name (t.name), ext (t.ext), - owner (w), + scope (t.base_scope ()), target (&t) { } - prerequisite_key prerequisite:: - key () const + bool prerequisite:: + belongs (const target_type& t) const { - return prerequisite_key { - proj, {&type, &dir, &out, &name, ext}, &owner.base_scope ()}; + const auto& p (t.prerequisites); + return !(p.empty () || this < &p.front () || this > &p.back ()); } } diff --git a/build2/target b/build2/target index 3bc9d5c..339ff90 100644 --- a/build2/target +++ b/build2/target @@ -763,13 +763,10 @@ namespace build2 return target != nullptr ? *target : build2::search (prerequisite); } - // Return as a new prerequisite instance for the specified owner target. - // Note that if this is a prerequisite, then both owners should be in the - // same scope (not a requirement if this is a target because then its path - // will be absolute). + // Return as a new prerequisite instance. // prerequisite_type - as_prerequisite_for (target_type& owner) const; + as_prerequisite () const; }; // It is often stored as the target's auxiliary data so make sure there is diff --git a/build2/target.ixx b/build2/target.ixx index 9c2c838..e2ac111 100644 --- a/build2/target.ixx +++ b/build2/target.ixx @@ -7,17 +7,17 @@ namespace build2 // prerequisite_member // inline prerequisite prerequisite_member:: - as_prerequisite_for (target_type& owner) const + as_prerequisite () const { if (target == nullptr) - return prerequisite_type (prerequisite, owner); + return prerequisite; // An ad hoc group member cannot be used as a prerequisite (use the whole // group instead). // assert (!target->adhoc_member ()); - return prerequisite_type (*target, owner); + return prerequisite_type (*target); } // prerequisite_members -- cgit v1.1