From 1c7cbb302b1c6e41eb0c5cecfc655532f1919cba Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 28 Jul 2017 13:46:26 +0200 Subject: Implement support for linking whole archive --- build2/cc/link.cxx | 109 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 27 deletions(-) (limited to 'build2/cc/link.cxx') diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx index 7b14621..babbbed 100644 --- a/build2/cc/link.cxx +++ b/build2/cc/link.cxx @@ -632,7 +632,8 @@ namespace build2 size_t i (start), n (t.prerequisite_targets.size ()); for (prerequisite_member p: group_prerequisite_members (act, t)) { - const target*& pt (t.prerequisite_targets[i++]); + const target*& pt (t.prerequisite_targets[i].target); + uintptr_t& pd (t.prerequisite_targets[i++].data); if (pt == nullptr) continue; @@ -778,6 +779,38 @@ namespace build2 m = 2; // Needs verification. } } + else // lib*{} + { + // If this is a static library, see if we need to link it whole. + // Note that we have to do it after match since we rely on the + // group link-up. + // + bool u; + if ((u = pt->is_a ()) || pt->is_a ()) + { + const variable& var (var_pool["bin.whole"]); // @@ Cache. + + // See the bin module for the lookup semantics discussion. Note + // that the variable is not overridable so we omit find_override() + // calls. + // + //@@ TODO: prerequisite-specific lookup. + // + lookup l (pt->find_original (var, true).first); + if (!l.defined ()) + { + bool g (pt->group != nullptr); + l = bs.find_original (var, + &pt->type (), + &pt->name, + (g ? &pt->group->type () : nullptr), + (g ? &pt->group->name : nullptr)).first; + } + + if (l ? cast (*l) : u) + pd |= lflag_whole; + } + } mark (pt, m); } @@ -875,28 +908,47 @@ namespace build2 void link:: append_libraries (strings& args, - const file& l, bool la, + const file& l, bool la, lflags lf, const scope& bs, action act, linfo li) const { // Note: lack of the "small function object" optimization will really // kill us here since we are called in a loop. // - bool win (tclass == "windows"); - auto imp = [] (const file&, bool la) {return la;}; - auto lib = [&args, win] (const file* f, const string& p, bool) + auto lib = [&args, this] (const file* l, const string& p, lflags f, bool) { - if (f != nullptr) + if (l != nullptr) { // On Windows a shared library is a DLL with the import library as a // first ad hoc group member. MinGW though can link directly to DLLs // (see search_library() for details). // - if (win && f->member != nullptr && f->is_a ()) - f = &f->member->as (); + if (l->member != nullptr && l->is_a () && tclass == "windows") + l = &l->member->as (); + + string p (relative (l->path ()).string ()); - args.push_back (relative (f->path ()).string ()); + if (f & lflag_whole) + { + if (tsys == "win32-msvc") + { + p.insert (0, "/WHOLEARCHIVE:"); // Only available from VC14U2. + } + else if (tsys == "darwin") + { + p.insert (0, "-Wl,-force_load,"); + } + else + { + args.push_back ("-Wl,--whole-archive"); + args.push_back (move (p)); + args.push_back ("-Wl,--no-whole-archive"); + return; + } + } + + args.push_back (move (p)); } else args.push_back (p); @@ -921,30 +973,29 @@ namespace build2 }; process_libraries ( - act, bs, li, sys_lib_dirs, l, la, imp, lib, opt, true); + act, bs, li, sys_lib_dirs, l, la, lf, imp, lib, opt, true); } void link:: hash_libraries (sha256& cs, - const file& l, bool la, + const file& l, bool la, lflags lf, const scope& bs, action act, linfo li) const { - bool win (tclass == "windows"); - auto imp = [] (const file&, bool la) {return la;}; - auto lib = [&cs, win] (const file* f, const string& p, bool) + auto lib = [&cs, this] (const file* l, const string& p, lflags f, bool) { - if (f != nullptr) + if (l != nullptr) { // On Windows a shared library is a DLL with the import library as a // first ad hoc group member. MinGW though can link directly to DLLs // (see search_library() for details). // - if (win && f->member != nullptr && f->is_a ()) - f = &f->member->as (); + if (l->member != nullptr && l->is_a () && tclass == "windows") + l = &l->member->as (); - cs.append (f->path ().string ()); + cs.append (f); + cs.append (l->path ().string ()); } else cs.append (p); @@ -967,7 +1018,7 @@ namespace build2 }; process_libraries ( - act, bs, li, sys_lib_dirs, l, la, imp, lib, opt, true); + act, bs, li, sys_lib_dirs, l, la, lf, imp, lib, opt, true); } void link:: @@ -1013,7 +1064,7 @@ namespace build2 bool for_install; } d {args, for_install}; - auto lib = [&d, this] (const file* l, const string& f, bool sys) + auto lib = [&d, this] (const file* l, const string& f, lflags, bool sys) { // We don't rpath system libraries. Why, you may ask? There are many // good reasons and I have them written on a napkin somewhere... @@ -1068,9 +1119,9 @@ namespace build2 // In case we don't have the "small function object" optimization. // const function impf (imp); - const function libf (lib); + const function libf (lib); - for (const target* pt: t.prerequisite_targets) + for (auto pt: t.prerequisite_targets) { bool a; const file* f; @@ -1090,7 +1141,7 @@ namespace build2 } process_libraries (act, bs, li, sys_lib_dirs, - *f, a, + *f, a, pt.data, impf, libf, nullptr); } } @@ -1421,8 +1472,10 @@ namespace build2 { sha256 cs; - for (const target* pt: t.prerequisite_targets) + for (auto p: t.prerequisite_targets) { + const target* pt (p.target); + // If this is bmi*{}, then obj*{} is its ad hoc member. // if (modules) @@ -1446,7 +1499,7 @@ namespace build2 // and implementation (static), recursively. // if (a || s) - hash_libraries (cs, *f, a, bs, act, li); + hash_libraries (cs, *f, a, p.data, bs, act, li); else cs.append (f->path ().string ()); } @@ -1669,8 +1722,10 @@ namespace build2 // The same logic as during hashing above. // - for (const target* pt: t.prerequisite_targets) + for (auto p: t.prerequisite_targets) { + const target* pt (p.target); + if (modules) { if (pt->is_a () || pt->is_a () || pt->is_a ()) @@ -1692,7 +1747,7 @@ namespace build2 // and implementation (static), recursively. // if (a || s) - append_libraries (sargs, *f, a, bs, act, li); + append_libraries (sargs, *f, a, p.data, bs, act, li); else sargs.push_back (relative (f->path ()).string ()); // string()&& } -- cgit v1.1