From 67db22fcae32c8a8014866ef2ee55b6c7733c3f9 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 10 Aug 2021 08:57:59 +0200 Subject: Complete process_libraries() duplicate suppression work --- libbuild2/cc/compile-rule.cxx | 69 +++++++++++++++++++----------- libbuild2/cc/compile-rule.hxx | 4 +- libbuild2/cc/link-rule.hxx | 9 ++-- libbuild2/cc/pkgconfig.cxx | 5 ++- libbuild2/cc/windows-rpath.cxx | 96 +++++++++++++++++++++++++++--------------- 5 files changed, 114 insertions(+), 69 deletions(-) diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index 26ee566..df7be87 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -434,14 +434,14 @@ namespace build2 auto opt = [&d, this] (const target& lt, const string& t, bool com, bool exp) { - const file& l (lt.as ()); - // Note that in our model *.export.poptions are always "interface", // even if set on liba{}/libs{}, unlike loptions. // if (!exp) // Ignore libux. return true; + const file& l (lt.as ()); + // Suppress duplicates. // // Compilation is the simple case: we can add the options on the first @@ -519,23 +519,31 @@ namespace build2 // recursively, prerequisite libraries first. // void compile_rule:: - append_library_prefixes (prefix_map& m, + append_library_prefixes (appended_libraries& ls, prefix_map& pm, const scope& bs, - action a, - target& t, - linfo li) const + action a, target& t, linfo li) const { - //@@ TODO: implement duplicate suppression and prunning. Reuse above - // machinery. + struct data + { + appended_libraries& ls; + prefix_map& pm; + } d {ls, pm}; auto imp = [] (const target& l, bool la) {return la && l.is_a ();}; - auto opt = [&m, this] ( - const target& l, const string& t, bool com, bool exp) + auto opt = [&d, this] (const target& lt, + const string& t, bool com, bool exp) { if (!exp) return true; + const file& l (lt.as ()); + + // Suppress duplicates like in append_library_options(). + // + if (find (d.ls.begin (), d.ls.end (), &l) != d.ls.end ()) + return false; + const variable& var ( com ? c_export_poptions @@ -543,7 +551,11 @@ namespace build2 ? x_export_poptions : l.ctx.var_pool[t + ".export.poptions"])); - append_prefixes (m, l, var); + append_prefixes (d.pm, l, var); + + if (com) + d.ls.push_back (&l); + return true; }; @@ -1603,18 +1615,19 @@ namespace build2 target& t, linfo li) const -> prefix_map { - prefix_map m; + prefix_map pm; // First process our own. // - append_prefixes (m, t, x_poptions); - append_prefixes (m, t, c_poptions); + append_prefixes (pm, t, x_poptions); + append_prefixes (pm, t, c_poptions); // Then process the include directories from prerequisite libraries. // - append_library_prefixes (m, bs, a, t, li); + appended_libraries ls; + append_library_prefixes (ls, pm, bs, a, t, li); - return m; + return pm; } // Return the next make prerequisite starting from the specified @@ -6222,17 +6235,16 @@ namespace build2 // auto imp = [] (const target&, bool) { return false; }; - //@@ TODO: implement duplicate suppression and prunning? Reuse above - // machinery (do before is_a() call). - // The same logic as in append_libraries(). // + appended_libraries ls; struct data { - action a; - const file& ht; - const target*& lt; - } d {a, ht, lt}; + action a; + const file& ht; + const target*& lt; + appended_libraries& ls; + } d {a, ht, lt, ls}; auto lib = [&d] ( const target* const* lc, @@ -6250,6 +6262,11 @@ namespace build2 if (l == nullptr) return true; + // Suppress duplicates. + // + if (find (d.ls.begin (), d.ls.end (), l) != d.ls.end ()) + return false; + // Feels like we should only consider non-utility libraries with // utilities being treated as "direct" use. // @@ -6261,9 +6278,13 @@ namespace build2 // const auto& pts (l->prerequisite_targets[d.a]); if (find (pts.begin (), pts.end (), &d.ht) != pts.end ()) + { d.lt = l; + return false; + } - return d.lt == nullptr; + d.ls.push_back (l); + return true; }; library_cache lib_cache; diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx index d085c8e..d65089e 100644 --- a/libbuild2/cc/compile-rule.hxx +++ b/libbuild2/cc/compile-rule.hxx @@ -54,7 +54,7 @@ namespace build2 perform_clean (action, const target&) const; public: - using appended_libraries = small_vector; + using appended_libraries = small_vector; void append_library_options (appended_libraries&, strings&, @@ -114,7 +114,7 @@ namespace build2 append_prefixes (prefix_map&, const target&, const variable&) const; void - append_library_prefixes (prefix_map&, + append_library_prefixes (appended_libraries&, prefix_map&, const scope&, action, target&, linfo) const; diff --git a/libbuild2/cc/link-rule.hxx b/libbuild2/cc/link-rule.hxx index c20844d..23f7167 100644 --- a/libbuild2/cc/link-rule.hxx +++ b/libbuild2/cc/link-rule.hxx @@ -281,14 +281,11 @@ namespace build2 // struct windows_dll { - const string& dll; - const string* pdb; // NULL if none. - string pdb_storage; - - bool operator< (const windows_dll& y) const {return dll < y.dll;} + reference_wrapper dll; + string pdb; // Empty if none. }; - using windows_dlls = set; + using windows_dlls = vector; timestamp windows_rpath_timestamp (const file&, diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx index 17cc2dc..9177dbb 100644 --- a/libbuild2/cc/pkgconfig.cxx +++ b/libbuild2/cc/pkgconfig.cxx @@ -1710,9 +1710,10 @@ namespace build2 // linfo li {otype::e, la ? lorder::a_s : lorder::s_a}; + library_cache lib_cache; process_libraries (a, bs, li, sys_lib_dirs, l, la, 0, // Link flags. - imp, lib, opt, !binless); + imp, lib, opt, !binless /* self */, &lib_cache); for (const string& a: args) os << ' ' << a; @@ -1727,7 +1728,7 @@ namespace build2 priv = true; process_libraries (a, bs, li, sys_lib_dirs, l, la, 0, // Link flags. - imp, lib, opt, false); + imp, lib, opt, false /* self */, &lib_cache); for (const string& a: args) os << ' ' << a; diff --git a/libbuild2/cc/windows-rpath.cxx b/libbuild2/cc/windows-rpath.cxx index d4d2dc6..0fbc775 100644 --- a/libbuild2/cc/windows-rpath.cxx +++ b/libbuild2/cc/windows-rpath.cxx @@ -53,15 +53,16 @@ namespace build2 { timestamp r (timestamp_nonexistent); - //@@ TODO: implement duplicate suppression and prunning. Reuse - // rpath_libraries()'s machinery. + // Duplicate suppression similar to rpath_libraries(). + // + rpathed_libraries ls; // We need to collect all the DLLs, so go into implementation of both // shared and static (in case they depend on shared). // auto imp = [] (const target&, bool) {return true;}; - auto lib = [&r] ( + auto lib = [&r, &ls] ( const target* const* lc, const small_vector, 2>& ns, lflags, @@ -74,11 +75,15 @@ namespace build2 if (sys) return false; - // Ignore static libraries. - // if (l != nullptr) { - // This can be an "undiscovered" DLL (see search_library()). + // Suppress duplicates. + // + if (find (ls.begin (), ls.end (), l) != ls.end ()) + return false; + + // Ignore static libraries. Note that this can be an "undiscovered" + // DLL (see search_library()). // if (l->is_a () && !l->path ().empty ()) // Also covers binless. { @@ -87,6 +92,8 @@ namespace build2 if (t > r) r = t; } + + ls.push_back (l); } else { @@ -147,13 +154,21 @@ namespace build2 action a, linfo li) const -> windows_dlls { + // Note that we cannot reuse windows_dlls for duplicate suppression + // since it would only keep track of shared libraries. + // windows_dlls r; + rpathed_libraries ls; - //@@ TODO: implement duplicate suppression and prunning. + struct + { + const scope& bs; + rpathed_libraries& ls; + } d {bs, ls}; auto imp = [] (const target&, bool) {return true;}; - auto lib = [&r, &bs] ( + auto lib = [&d, &r] ( const target* const* lc, const small_vector, 2>& ns, lflags, @@ -166,55 +181,66 @@ namespace build2 if (l != nullptr) { + // Suppress duplicates. + // + if (find (d.ls.begin (), d.ls.end (), l) != d.ls.end ()) + return false; + if (l->is_a () && !l->path ().empty ()) // Also covers binless. { // Get .pdb if there is one. // - const target_type* tt (bs.find_target_type ("pdb")); + const target_type* tt (d.bs.find_target_type ("pdb")); const target* pdb (tt != nullptr ? find_adhoc_member (*l, *tt) : nullptr); - r.insert ( + + // Here we assume it's not a duplicate due to the check above. + // + r.push_back ( windows_dll { ns[0], - pdb != nullptr ? &pdb->as ().path ().string () : nullptr, - string () + pdb != nullptr ? pdb->as ().path ().string () : string (), }); } + + d.ls.push_back (l); } else { + string pdb; for (const string& f: ns) { size_t p (path::traits_type::find_extension (f)); if (p != string::npos && icasecmp (f.c_str () + p + 1, "dll") == 0) { - // See if we can find a corresponding .pdb. - // - windows_dll wd {f, nullptr, string ()}; - string& pdb (wd.pdb_storage); - - // First try "our" naming: foo.dll.pdb. - // - pdb = f; - pdb += ".pdb"; - - if (!exists (path (pdb))) + if (find_if (r.begin (), r.end (), + [&f] (const windows_dll& e) + { + return e.dll.get () == f; + }) == r.end ()) { - // Then try the usual naming: foo.pdb. + // See if we can find a corresponding .pdb. First try "our" + // naming: foo.dll.pdb. // - pdb.assign (f, 0, p); + pdb = f; pdb += ".pdb"; if (!exists (path (pdb))) - pdb.clear (); + { + // Then try the usual naming: foo.pdb. + // + pdb.assign (f, 0, p); + pdb += ".pdb"; + + if (!exists (path (pdb))) + pdb.clear (); + } + + r.push_back ( + windows_dll {f, pdb.empty () ? string () : move (pdb)}); } - - if (!pdb.empty ()) - wd.pdb = &pdb; - - r.insert (move (wd)); } } } @@ -365,16 +391,16 @@ namespace build2 //@@ Would be nice to avoid copying. Perhaps reuse buffers // by adding path::assign() and traits::leaf(). // - path dp (wd.dll); // DLL path. - path dn (dp.leaf ()); // DLL name. + path dp (wd.dll.get ()); // DLL path. + path dn (dp.leaf ()); // DLL name. link (dp, ad / dn); // Link .pdb if there is one. // - if (wd.pdb != nullptr) + if (!wd.pdb.empty ()) { - path pp (*wd.pdb); + path pp (wd.pdb); link (pp, ad / pp.leaf ()); } } -- cgit v1.1