From 05afdd8ca16c7066d12510a27e2fc08743bb2e95 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 29 Nov 2022 08:02:51 +0200 Subject: Fix backlink logic for target groups We used to backlink ad hoc group members both via the group and as individual members. And for explicit groups it was done only via individual members, which means it only works correctly if every member is individually updated. Now both types of groups are backlinked from the group target. --- libbuild2/diagnostics.cxx | 195 +++++++++++++++++++++++++++++++++------------- 1 file changed, 141 insertions(+), 54 deletions(-) (limited to 'libbuild2/diagnostics.cxx') diff --git a/libbuild2/diagnostics.cxx b/libbuild2/diagnostics.cxx index bc74db3..d91150b 100644 --- a/libbuild2/diagnostics.cxx +++ b/libbuild2/diagnostics.cxx @@ -82,39 +82,26 @@ namespace build2 dr << r; } - template // L can be target_key, path, or string. - static void - print_diag_impl (const char* p, - const L* l, bool lempty, - vector&& rs, - const char* c) - { - assert (rs.size () > 1); - // The overall plan is as follows: - // - // 1. Collect the printed names for all the group members. - // - // Note if the printed representation is irregular (see - // to_stream(target_key) for details). We will print such members each - // on a separate line. - // - // 2. Move the names so that we end up with contiguous partitions of - // targets with the same name. - // - // 3. Print the partitions, one per line. - // - vector, const target_key*>> ns; - ns.reserve (rs.size ()); + static inline bool + print_diag_cmp (const pair, const target_key*>& x, + const pair, const target_key*>& y) + { + return (x.second->dir->compare (*y.second->dir) == 0 && + x.first->compare (*y.first) == 0); + } - // Use the diag_record's ostringstream so that we get the appropriate - // stream verbosity, etc. - // - diag_record dr (text); - ostringstream& os (dr.os); - stream_verbosity sv (stream_verb (os)); + // Return true if we have multiple partitions (see below for details). + // + static bool + print_diag_collect (const vector& tks, + ostringstream& os, + stream_verbosity sv, + vector, const target_key*>>& ns) + { + ns.reserve (tks.size ()); - for (const target_key& k: rs) + for (const target_key& k: tks) { bool r; if (auto p = k.type->print) @@ -130,16 +117,9 @@ namespace build2 // Partition. // - auto cmp = [] (const pair, const target_key*>& x, - const pair, const target_key*>& y) - { - return (x.second->dir->compare (*y.second->dir) == 0 && - x.first->compare (*y.first) == 0); - }; - // While at it also determine whether we have multiple partitions. // - optional ml; + bool ml (false); for (auto b (ns.begin ()), e (ns.end ()); b != e; ) { const pair, const target_key*>& x (*b++); @@ -149,25 +129,24 @@ namespace build2 // b = stable_partition ( b, e, - [&cmp, &x] (const pair, const target_key*>& y) + [&x] (const pair, const target_key*>& y) { - return (x.first && y.first && cmp (x, y)); + return (x.first && y.first && print_diag_cmp (x, y)); }); if (!ml && b != e) - ml = string (); + ml = true; } - // Print. - // - os << p << ' '; - - if (l != nullptr) - os << *l << (lempty ? "" : " ") << (c == nullptr ? "->" : c) << ' '; - - if (ml) - ml = string (os.str ().size (), ' '); // Indentation. + return ml; + } + static void + print_diag_print (const vector, const target_key*>>& ns, + ostringstream& os, + stream_verbosity sv, + const optional& ml) + { for (auto b (ns.begin ()), i (b), e (ns.end ()); i != e; ) { if (i != b) @@ -185,7 +164,7 @@ namespace build2 // Calculate the number of members in this partition. // size_t n (1); - for (auto j (i + 1); j != e && j->first && cmp (*i, *j); ++j) + for (auto j (i + 1); j != e && j->first && print_diag_cmp (*i, *j); ++j) ++n; // Similar code to to_stream(target_key). @@ -232,6 +211,95 @@ namespace build2 } } + template // L can be target_key, path, or string. + static void + print_diag_impl (const char* p, + const L* l, bool lempty, + vector&& rs, + const char* c) + { + assert (rs.size () > 1); + + // The overall plan is as follows: + // + // 1. Collect the printed names for all the group members. + // + // Note if the printed representation is irregular (see + // to_stream(target_key) for details). We will print such members each + // on a separate line. + // + // 2. Move the names around so that we end up with contiguous partitions + // of targets with the same name. + // + // 3. Print the partitions, one per line. + // + // The steps 1-2 are performed by print_diag_impl_common() above. + // + vector, const target_key*>> ns; + + // Use the diag_record's ostringstream so that we get the appropriate + // stream verbosity, etc. + // + diag_record dr (text); + ostringstream& os (dr.os); + stream_verbosity sv (stream_verb (os)); + + optional ml; + if (print_diag_collect (rs, os, sv, ns)) + ml = string (); + + // Print. + // + os << p << ' '; + + if (l != nullptr) + os << *l << (lempty ? "" : " ") << (c == nullptr ? "->" : c) << ' '; + + if (ml) + ml = string (os.str ().size (), ' '); // Indentation. + + print_diag_print (ns, os, sv, ml); + } + + template // R can be target_key, path, or string. + static void + print_diag_impl (const char* p, + vector&& ls, const R& r, + const char* c) + { + assert (ls.size () > 1); + + // As above but for the group on the LHS. + // + vector, const target_key*>> ns; + + diag_record dr (text); + ostringstream& os (dr.os); + stream_verbosity sv (stream_verb (os)); + + optional ml; + if (print_diag_collect (ls, os, sv, ns)) + ml = string (); + + // Print. + // + os << p << ' '; + + if (ml) + ml = string (os.str ().size (), ' '); // Indentation. + + print_diag_print (ns, os, sv, ml); + + // @@ TODO: make sure `->` is aligned with longest line printed by + // print_diag_print(). Currently it can look like this: + // + // ln /tmp/hello-gcc/hello/hello/{hxx cxx}{hello-types} + // /tmp/hello-gcc/hello/hello/{hxx cxx}{hello-stubs} + // /tmp/hello-gcc/hello/hello/cxx{hello-ext} -> ./ + // + os << ' ' << (c == nullptr ? "->" : c) << ' ' << r; + } + void print_diag_impl (const char* p, target_key* l, vector&& rs, @@ -361,7 +429,9 @@ namespace build2 } void - print_diag (const char* p, const target& l, const dir_path& r, const char* c) + print_diag (const char* p, + const target& l, const path_name_view& r, + const char* c) { // @@ TODO: out qualification stripping: only do if p.out is subdir of t // (also below)? @@ -370,11 +440,28 @@ namespace build2 } void + print_diag (const char* p, const target& l, const dir_path& r, const char* c) + { + print_diag (p, l.key (), r, c); + } + + void + print_diag (const char* p, target_key&& l, const dir_path& r, const char* c) + { + text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r; + } + + void print_diag (const char* p, - const target& l, const path_name_view& r, + vector&& ls, const dir_path& r, const char* c) { - text << p << ' ' << l << ' ' << (c == nullptr ? "->" : c) << ' ' << r; + assert (!ls.empty ()); + + if (ls.size () == 1) + print_diag (p, move (ls.front ()), r, c); + else + print_diag_impl (p, move (ls), r, c); } void -- cgit v1.1