aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-08-10 08:57:59 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-08-10 08:57:59 +0200
commit67db22fcae32c8a8014866ef2ee55b6c7733c3f9 (patch)
treec5f9cee0c2c7b94e02cbb8d5efe3ed91872ec8f9 /libbuild2/cc
parent388b94567f3136d1370b37610081c5465a74bdb7 (diff)
Complete process_libraries() duplicate suppression work
Diffstat (limited to 'libbuild2/cc')
-rw-r--r--libbuild2/cc/compile-rule.cxx69
-rw-r--r--libbuild2/cc/compile-rule.hxx4
-rw-r--r--libbuild2/cc/link-rule.hxx9
-rw-r--r--libbuild2/cc/pkgconfig.cxx5
-rw-r--r--libbuild2/cc/windows-rpath.cxx96
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<file> ());
-
// 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<file> ());
+
// 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<libux> ();};
- 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<file> ());
+
+ // 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<const file*, 256>;
+ using appended_libraries = small_vector<const target*, 256>;
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<const string> dll;
+ string pdb; // Empty if none.
};
- using windows_dlls = set<windows_dll>;
+ using windows_dlls = vector<windows_dll>;
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<reference_wrapper<const string>, 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<libs> () && !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<reference_wrapper<const string>, 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<libs> () && !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<file> ().path ().string () : nullptr,
- string ()
+ pdb != nullptr ? pdb->as<file> ().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 ());
}
}