aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc/windows-rpath.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/cc/windows-rpath.cxx')
-rw-r--r--libbuild2/cc/windows-rpath.cxx222
1 files changed, 149 insertions, 73 deletions
diff --git a/libbuild2/cc/windows-rpath.cxx b/libbuild2/cc/windows-rpath.cxx
index eddb9c4..eb62ad1 100644
--- a/libbuild2/cc/windows-rpath.cxx
+++ b/libbuild2/cc/windows-rpath.cxx
@@ -45,6 +45,8 @@ namespace build2
// Return the greatest (newest) timestamp of all the DLLs that we will be
// adding to the assembly or timestamp_nonexistent if there aren't any.
//
+ // Note: called during the execute phase.
+ //
timestamp link_rule::
windows_rpath_timestamp (const file& t,
const scope& bs,
@@ -53,31 +55,59 @@ namespace build2
{
timestamp r (timestamp_nonexistent);
+ // 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 file&, bool) {return true;};
-
- auto lib = [&r] (const file* const* lc,
- const string& f,
- lflags,
- bool sys)
+ auto imp = [] (const target&, bool) {return true;};
+
+ auto lib = [&r, &ls] (
+ const target* const* lc,
+ const small_vector<reference_wrapper<const string>, 2>& ns,
+ lflags,
+ const string*,
+ bool sys)
{
- const file* l (lc != nullptr ? *lc : nullptr);
+ const file* l (lc != nullptr ? &(*lc)->as<file> () : nullptr);
// We don't rpath system libraries.
//
if (sys)
- return;
+ return false;
- // Skip static libraries.
- //
if (l != nullptr)
{
- // This can be an "undiscovered" DLL (see search_library()).
+ // Suppress duplicates.
//
- if (!l->is_a<libs> () || l->path ().empty ()) // Also covers binless.
- return;
+ 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.
+ {
+ // Handle the case where the library is a member of a group (for
+ // example, people are trying to hack something up with pre-built
+ // libraries; see GH issue #366).
+ //
+ timestamp t;
+ if (l->group_state (action () /* inner */))
+ {
+ t = l->group->is_a<mtime_target> ()->mtime ();
+ assert (t != timestamp_unknown);
+ }
+ else
+ t = l->load_mtime ();
+
+ if (t > r)
+ r = t;
+ }
+
+ ls.push_back (l);
}
else
{
@@ -91,25 +121,29 @@ namespace build2
//
// Though this can happen on MinGW with direct DLL link...
//
- size_t p (path::traits_type::find_extension (f));
+ 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)
- return;
- }
+ if (p != string::npos && icasecmp (f.c_str () + p + 1, "dll") == 0)
+ {
+ timestamp t (mtime (f.c_str ()));
- // Ok, this is a DLL.
- //
- timestamp t (l != nullptr
- ? l->load_mtime ()
- : mtime (f.c_str ()));
+ if (t > r)
+ r = t;
+ }
+ }
+ }
- if (t > r)
- r = t;
+ return true;
};
+ library_cache lib_cache;
for (const prerequisite_target& pt: t.prerequisite_targets[a])
{
- if (pt.adhoc || pt == nullptr)
+ // Note: during execute so check for ad hoc first to avoid data races.
+ //
+ if (pt.adhoc () || pt == nullptr)
continue;
bool la;
@@ -120,7 +154,10 @@ namespace build2
( f = pt->is_a<libs> ()))
process_libraries (a, bs, li, sys_lib_dirs,
*f, la, pt.data,
- imp, lib, nullptr, true);
+ imp, lib, nullptr,
+ true /* self */,
+ false /* proc_opt_group */,
+ &lib_cache);
}
return r;
@@ -135,76 +172,107 @@ 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;
- auto imp = [] (const file&, bool) {return true;};
-
- auto lib = [&r, &bs] (const file* const* lc,
- const string& f,
- lflags,
- bool sys)
+ struct
+ {
+ const scope& bs;
+ rpathed_libraries& ls;
+ } d {bs, ls};
+
+ auto imp = [] (const target&, bool) {return true;};
+
+ auto lib = [&d, &r] (
+ const target* const* lc,
+ const small_vector<reference_wrapper<const string>, 2>& ns,
+ lflags,
+ const string*,
+ bool sys)
{
- const file* l (lc != nullptr ? *lc : nullptr);
+ const file* l (lc != nullptr ? &(*lc)->as<file> () : nullptr);
if (sys)
- return;
+ return false;
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 {
- f,
- pdb != nullptr ? &pdb->as<file> ().path ().string () : nullptr,
- string ()
+ ns[0],
+ pdb != nullptr ? pdb->as<file> ().path ().string () : string (),
});
}
+
+ d.ls.push_back (l);
}
else
{
- size_t p (path::traits_type::find_extension (f));
-
- if (p != string::npos && icasecmp (f.c_str () + p + 1, "dll") == 0)
+ string pdb;
+ for (const string& f: ns)
{
- // See if we can find a corresponding .pdb.
- //
- windows_dll wd {f, nullptr, string ()};
- string& pdb (wd.pdb_storage);
+ size_t p (path::traits_type::find_extension (f));
- // First try "our" naming: foo.dll.pdb.
- //
- pdb = f;
- pdb += ".pdb";
-
- if (!exists (path (pdb)))
+ if (p != string::npos && icasecmp (f.c_str () + p + 1, "dll") == 0)
{
- // Then try the usual naming: foo.pdb.
- //
- pdb.assign (f, 0, p);
- pdb += ".pdb";
-
- if (!exists (path (pdb)))
- pdb.clear ();
+ if (find_if (r.begin (), r.end (),
+ [&f] (const windows_dll& e)
+ {
+ return e.dll.get () == f;
+ }) == r.end ())
+ {
+ // See if we can find a corresponding .pdb. First try "our"
+ // naming: foo.dll.pdb.
+ //
+ pdb = f;
+ pdb += ".pdb";
+
+ if (!exists (path (pdb)))
+ {
+ // 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));
}
}
+
+ return true;
};
+ library_cache lib_cache;
for (const prerequisite_target& pt: t.prerequisite_targets[a])
{
- if (pt.adhoc || pt == nullptr)
+ // Note: during execute so check for ad hoc first to avoid data races.
+ //
+ if (pt.adhoc () || pt == nullptr)
continue;
bool la;
@@ -215,7 +283,10 @@ namespace build2
( f = pt->is_a<libs> ()))
process_libraries (a, bs, li, sys_lib_dirs,
*f, la, pt.data,
- imp, lib, nullptr, true);
+ imp, lib, nullptr,
+ true /* self */,
+ false /* proc_opt_group */,
+ &lib_cache);
}
return r;
@@ -311,11 +382,16 @@ namespace build2
// of the same amalgamation. This way if the amalgamation is moved
// as a whole, the links will remain valid.
//
+ // Note: mkanylink() is from libbutl and thus doesn't handle the
+ // dry-run mode.
+ //
try
{
- switch (mkanylink (f, l,
- true /* copy */,
- f.sub (as.out_path ()) /* relative */))
+ switch (as.ctx.dry_run
+ ? entry_type::symlink
+ : mkanylink (f, l,
+ true /* copy */,
+ f.sub (as.out_path ()) /* relative */))
{
case entry_type::regular: print ("cp"); break;
case entry_type::symlink: print ("ln -s"); break;
@@ -343,16 +419,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 ());
}
}