diff options
Diffstat (limited to 'libbuild2/cc/windows-rpath.cxx')
-rw-r--r-- | libbuild2/cc/windows-rpath.cxx | 222 |
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 ()); } } |