aboutsummaryrefslogtreecommitdiff
path: root/build2/cc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-07-28 13:46:26 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-07-28 13:46:26 +0200
commit1c7cbb302b1c6e41eb0c5cecfc655532f1919cba (patch)
tree84375e8be2bfe00b2387f02cab8dcca396019299 /build2/cc
parent24402ed431c1780914576f72350f8796308cb59b (diff)
Implement support for linking whole archive
Diffstat (limited to 'build2/cc')
-rw-r--r--build2/cc/common.cxx23
-rw-r--r--build2/cc/common.hxx3
-rw-r--r--build2/cc/compile.cxx6
-rw-r--r--build2/cc/link.cxx109
-rw-r--r--build2/cc/link.hxx4
-rw-r--r--build2/cc/types.hxx6
-rw-r--r--build2/cc/utility.cxx15
-rw-r--r--build2/cc/windows-rpath.cxx12
8 files changed, 124 insertions, 54 deletions
diff --git a/build2/cc/common.cxx b/build2/cc/common.cxx
index 8dabb07..195c3b7 100644
--- a/build2/cc/common.cxx
+++ b/build2/cc/common.cxx
@@ -52,10 +52,12 @@ namespace build2
const dir_paths& top_sysd,
const file& l,
bool la,
+ lflags lf,
const function<bool (const file&,
bool la)>& proc_impl, // Implementation?
const function<void (const file*, // Can be NULL.
const string& path, // Library path.
+ lflags, // Link flags.
bool sys)>& proc_lib, // True if system library.
const function<void (const file&,
const string& type, // cc.type
@@ -185,7 +187,7 @@ namespace build2
? cast_false<bool> (l.vars[c_system])
: !p.empty () && sys (top_sysd, p.string ()));
- proc_lib (&l, p.string (), s);
+ proc_lib (&l, p.string (), lf, s);
}
const scope& bs (t == nullptr || cc ? top_bs : l.base_scope ());
@@ -220,20 +222,20 @@ namespace build2
//
if (impl && !c_e_libs.defined () && !x_e_libs.defined ())
{
- for (const target* p: l.prerequisite_targets)
+ for (auto pt: l.prerequisite_targets)
{
bool a;
const file* f;
- if ((a = (f = p->is_a<liba> ())) ||
- (a = (f = p->is_a<libux> ())) ||
- ( f = p->is_a<libs> ()))
+ if ((a = (f = pt->is_a<liba> ())) ||
+ (a = (f = pt->is_a<libux> ())) ||
+ ( f = pt->is_a<libs> ()))
{
if (sysd == nullptr) find_sysd ();
if (!li) find_linfo ();
process_libraries (act, bs, *li, *sysd,
- *f, a,
+ *f, a, pt.data,
proc_impl, proc_lib, proc_opt, true);
}
}
@@ -286,7 +288,7 @@ namespace build2
// .pc files.
//
if (proc_lib)
- proc_lib (nullptr, n.value, sys_simple (n.value));
+ proc_lib (nullptr, n.value, 0, sys_simple (n.value));
}
else
{
@@ -316,8 +318,11 @@ namespace build2
// Process it recursively.
//
+ // @@ Where can we get the link flags? Should we try to find them
+ // in the library's prerequisites? What about installed stuff?
+ //
process_libraries (act, bs, *li, *sysd,
- t, t.is_a<liba> () || t.is_a<libux> (),
+ t, t.is_a<liba> () || t.is_a<libux> (), 0,
proc_impl, proc_lib, proc_opt, true);
}
}
@@ -336,7 +341,7 @@ namespace build2
// This is something like -lpthread or shell32.lib so should be a
// valid path.
//
- proc_lib (nullptr, n, sys_simple (n));
+ proc_lib (nullptr, n, 0, sys_simple (n));
}
};
diff --git a/build2/cc/common.hxx b/build2/cc/common.hxx
index 6e1d8b9..951863a 100644
--- a/build2/cc/common.hxx
+++ b/build2/cc/common.hxx
@@ -198,8 +198,9 @@ namespace build2
const dir_paths&,
const file&,
bool,
+ lflags,
const function<bool (const file&, bool)>&,
- const function<void (const file*, const string&, bool)>&,
+ const function<void (const file*, const string&, lflags, bool)>&,
const function<void (const file&, const string&, bool, bool)>&,
bool = false) const;
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx
index 8fa3296..fbf6a19 100644
--- a/build2/cc/compile.cxx
+++ b/build2/cc/compile.cxx
@@ -294,7 +294,7 @@ namespace build2
continue;
process_libraries (act, bs, li, sys_lib_dirs,
- pt->as<file> (), a,
+ pt->as<file> (), a, 0, // Hack: lflags unused.
nullptr, nullptr, optf);
}
}
@@ -338,7 +338,7 @@ namespace build2
continue;
process_libraries (act, bs, li, sys_lib_dirs,
- pt->as<file> (), a,
+ pt->as<file> (), a, 0, // Hack: lflags unused.
nullptr, nullptr, optf);
}
}
@@ -385,7 +385,7 @@ namespace build2
continue;
process_libraries (act, bs, li, sys_lib_dirs,
- pt->as<file> (), a,
+ pt->as<file> (), a, 0, // Hack: lflags unused.
nullptr, nullptr, optf);
}
}
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<libux> ()) || pt->is_a<liba> ())
+ {
+ 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<bool> (*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<libs> ())
- f = &f->member->as<file> ();
+ if (l->member != nullptr && l->is_a<libs> () && tclass == "windows")
+ l = &l->member->as<file> ();
+
+ 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<libs> ())
- f = &f->member->as<file> ();
+ if (l->member != nullptr && l->is_a<libs> () && tclass == "windows")
+ l = &l->member->as<file> ();
- 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<bool (const file&, bool)> impf (imp);
- const function<void (const file*, const string&, bool)> libf (lib);
+ const function<void (const file*, const string&, lflags, bool)> 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<bmie> () || pt->is_a<bmia> () || pt->is_a<bmis> ())
@@ -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()&&
}
diff --git a/build2/cc/link.hxx b/build2/cc/link.hxx
index 0256774..ed28eca 100644
--- a/build2/cc/link.hxx
+++ b/build2/cc/link.hxx
@@ -75,12 +75,12 @@ namespace build2
//
void
append_libraries (strings&,
- const file&, bool,
+ const file&, bool, lflags,
const scope&, action, linfo) const;
void
hash_libraries (sha256&,
- const file&, bool,
+ const file&, bool, lflags,
const scope&, action, linfo) const;
void
diff --git a/build2/cc/types.hxx b/build2/cc/types.hxx
index b575dc7..48ffa05 100644
--- a/build2/cc/types.hxx
+++ b/build2/cc/types.hxx
@@ -91,6 +91,12 @@ namespace build2
otype type;
lorder order;
};
+
+ // Prerequisite link flags.
+ //
+ using lflags = uintptr_t; // To match prerequisite_target::data.
+
+ const lflags lflag_whole = 0x00000001U; // Link whole liba{}/libux{}.
}
}
diff --git a/build2/cc/utility.cxx b/build2/cc/utility.cxx
index fa5061e..7a2b7fe 100644
--- a/build2/cc/utility.cxx
+++ b/build2/cc/utility.cxx
@@ -43,12 +43,15 @@ namespace build2
{
if (const libu* u = x.is_a<libu> ())
{
- otype ot (li.type);
- return search (*u,
- ot == otype::e ? libue::static_type :
- ot == otype::a ? libua::static_type :
- libus::static_type,
- u->dir, u->out, u->name);
+ const target_type& tt (li.type == otype::e ? libue::static_type :
+ li.type == otype::a ? libua::static_type :
+ libus::static_type);
+
+ // Called by the compile rule during execute.
+ //
+ return phase == run_phase::match
+ ? search (*u, tt, u->dir, u->out, u->name)
+ : *search_existing (tt, u->dir, u->out, u->name);
}
else
{
diff --git a/build2/cc/windows-rpath.cxx b/build2/cc/windows-rpath.cxx
index 1fc195a..2f4f31f 100644
--- a/build2/cc/windows-rpath.cxx
+++ b/build2/cc/windows-rpath.cxx
@@ -58,7 +58,7 @@ namespace build2
//
auto imp = [] (const file&, bool) {return true;};
- auto lib = [&r] (const file* l, const string& f, bool sys)
+ auto lib = [&r] (const file* l, const string& f, lflags, bool sys)
{
// We don't rpath system libraries.
//
@@ -102,7 +102,7 @@ namespace build2
r = t;
};
- for (const target* pt: t.prerequisite_targets)
+ for (auto pt: t.prerequisite_targets)
{
const file* f;
const liba* a;
@@ -110,7 +110,7 @@ namespace build2
if ((f = a = pt->is_a<liba> ()) ||
(f = pt->is_a<libs> ()))
process_libraries (act, bs, li, sys_lib_dirs,
- *f, a != nullptr,
+ *f, a != nullptr, pt.data,
imp, lib, nullptr, true);
}
@@ -130,7 +130,7 @@ namespace build2
auto imp = [] (const file&, bool) {return true;};
- auto lib = [&r] (const file* l, const string& f, bool sys)
+ auto lib = [&r] (const file* l, const string& f, lflags, bool sys)
{
if (sys)
return;
@@ -184,7 +184,7 @@ namespace build2
}
};
- for (const target* pt: t.prerequisite_targets)
+ for (auto pt: t.prerequisite_targets)
{
const file* f;
const liba* a;
@@ -192,7 +192,7 @@ namespace build2
if ((f = a = pt->is_a<liba> ()) ||
(f = pt->is_a<libs> ()))
process_libraries (act, bs, li, sys_lib_dirs,
- *f, a != nullptr,
+ *f, a != nullptr, pt.data,
imp, lib, nullptr, true);
}