aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-07-27 14:45:05 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-07-27 14:45:05 +0200
commitbf959a7fc119f9156c4b84c9d0a10900d9153f8d (patch)
treed19b96238f58e305d936d186901edd1cf98e0c93
parent24f74ea70a19ccd7bcb489853fc73a972ab8638f (diff)
Initial infrastructure for utility libraries
-rw-r--r--build2/bin/init.cxx27
-rw-r--r--build2/bin/rule.cxx27
-rw-r--r--build2/bin/rule.hxx18
-rw-r--r--build2/bin/target.cxx78
-rw-r--r--build2/bin/target.hxx71
-rw-r--r--build2/cc/common.cxx42
-rw-r--r--build2/cc/common.hxx4
-rw-r--r--build2/cc/compile.cxx122
-rw-r--r--build2/cc/compile.hxx16
-rw-r--r--build2/cc/install.cxx2
-rw-r--r--build2/cc/link.cxx405
-rw-r--r--build2/cc/link.hxx12
-rw-r--r--build2/cc/module.cxx14
-rw-r--r--build2/cc/types.hxx19
-rw-r--r--build2/cc/utility.cxx58
-rw-r--r--build2/cc/utility.hxx13
-rw-r--r--build2/cc/utility.ixx14
-rw-r--r--build2/cc/windows-rpath.cxx12
-rw-r--r--tests/cc/libu/buildfile8
-rw-r--r--tests/cc/libu/testscript54
20 files changed, 675 insertions, 341 deletions
diff --git a/build2/bin/init.cxx b/build2/bin/init.cxx
index 71c580b..fb9dd71 100644
--- a/build2/bin/init.cxx
+++ b/build2/bin/init.cxx
@@ -24,8 +24,7 @@ namespace build2
{
namespace bin
{
- static const obj_rule obj_;
- static const bmi_rule bmi_;
+ static const fail_rule fail_;
static const lib_rule lib_;
// Default config.bin.*.lib values.
@@ -368,10 +367,17 @@ namespace build2
t.insert<bmia> ();
t.insert<bmis> ();
+ t.insert<libu> ();
+ t.insert<libue> ();
+ t.insert<libua> ();
+ t.insert<libus> ();
+
t.insert<lib> ();
t.insert<liba> ();
t.insert<libs> ();
+ // Note: libu*{} are not installable.
+ //
if (install_loaded)
{
install_path<liba> (bs, dir_path ("lib")); // Install in install.lib.
@@ -422,22 +428,25 @@ namespace build2
{
auto& r (bs.rules);
- r.insert<obj> (perform_update_id, "bin.obj", obj_);
- r.insert<obj> (perform_clean_id, "bin.obj", obj_);
+ r.insert<obj> (perform_update_id, "bin.obj", fail_);
+ r.insert<obj> (perform_clean_id, "bin.obj", fail_);
+
+ r.insert<bmi> (perform_update_id, "bin.bmi", fail_);
+ r.insert<bmi> (perform_clean_id, "bin.bmi", fail_);
- r.insert<bmi> (perform_update_id, "bin.bmi", bmi_);
- r.insert<bmi> (perform_clean_id, "bin.bmi", bmi_);
+ r.insert<libu> (perform_update_id, "bin.libu", fail_);
+ r.insert<libu> (perform_clean_id, "bin.libu", fail_);
r.insert<lib> (perform_update_id, "bin.lib", lib_);
- r.insert<lib> (perform_clean_id, "bin.lib", lib_);
+ r.insert<lib> (perform_clean_id, "bin.lib", lib_);
- // Configure member.
+ // Configure members.
//
r.insert<lib> (configure_update_id, "bin.lib", lib_);
if (install_loaded)
{
- r.insert<lib> (perform_install_id, "bin.lib", lib_);
+ r.insert<lib> (perform_install_id, "bin.lib", lib_);
r.insert<lib> (perform_uninstall_id, "bin.lib", lib_);
}
}
diff --git a/build2/bin/rule.cxx b/build2/bin/rule.cxx
index b6e5a53..bb9036b 100644
--- a/build2/bin/rule.cxx
+++ b/build2/bin/rule.cxx
@@ -17,35 +17,22 @@ namespace build2
{
namespace bin
{
- // obj
+ // fail_rule
//
- match_result obj_rule::
+ match_result fail_rule::
match (action a, target& t, const string&) const
{
- fail << diag_doing (a, t) << " target group" <<
- info << "explicitly select obje{}, obja{}, or objs{} member";
-
- return false;
- }
-
- recipe obj_rule::
- apply (action, target&) const {return empty_recipe;}
+ const char* n (t.dynamic_type ().name); // Ignore derived type.
- // bmi
- //
- match_result bmi_rule::
- match (action a, target& t, const string&) const
- {
fail << diag_doing (a, t) << " target group" <<
- info << "explicitly select bmie{}, bmia{}, or bmis{} member";
-
- return false;
+ info << "explicitly select " << n << "e{}, " << n << "a{}, or "
+ << n << "s{} member" << endf;
}
- recipe bmi_rule::
+ recipe fail_rule::
apply (action, target&) const {return empty_recipe;}
- // lib
+ // lib_rule
//
// The whole logic is pretty much as if we had our two group members as
// our prerequisites.
diff --git a/build2/bin/rule.hxx b/build2/bin/rule.hxx
index 4637479..b4835dc 100644
--- a/build2/bin/rule.hxx
+++ b/build2/bin/rule.hxx
@@ -14,22 +14,12 @@ namespace build2
{
namespace bin
{
- class obj_rule: public rule
+ // Fail rule for obj{}, bmi{}, and libu{}.
+ //
+ class fail_rule: public rule
{
public:
- obj_rule () {}
-
- virtual match_result
- match (action, target&, const string&) const override;
-
- virtual recipe
- apply (action, target&) const override;
- };
-
- class bmi_rule: public rule
- {
- public:
- bmi_rule () {}
+ fail_rule () {}
virtual match_result
match (action, target&, const string&) const override;
diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx
index f0e0152..aa37202 100644
--- a/build2/bin/target.cxx
+++ b/build2/bin/target.cxx
@@ -10,6 +10,30 @@ namespace build2
{
namespace bin
{
+ const target_type libx::static_type
+ {
+ "libx",
+ &target::static_type,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &target_search,
+ false
+ };
+
+ const target_type libux::static_type
+ {
+ "libux",
+ &file::static_type,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &target_search,
+ false
+ };
+
// Note that we link groups during the load phase since this is often
// relied upon when setting target-specific variables (e.g., we may set a
// common value for lib{} and then append liba/libs-specific values to
@@ -19,7 +43,7 @@ namespace build2
extern const char ext_var[] = "extension"; // VC14 rejects constexpr.
- // obj*{} and bmi*{} member factory.
+ // obj*{}, bmi*{}, libu*{} member factory.
//
template <typename M, typename G>
static pair<target*, optional<string>>
@@ -61,6 +85,18 @@ namespace build2
false
};
+ const target_type libue::static_type
+ {
+ "libue",
+ &libux::static_type,
+ &m_factory<libue, libu>,
+ &target_extension_var<ext_var, nullptr>,
+ &target_pattern_var<ext_var, nullptr>,
+ nullptr,
+ &target_search, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
const target_type obja::static_type
{
"obja",
@@ -85,6 +121,18 @@ namespace build2
false
};
+ const target_type libua::static_type
+ {
+ "libua",
+ &libux::static_type,
+ &m_factory<libua, libu>,
+ &target_extension_var<ext_var, nullptr>,
+ &target_pattern_var<ext_var, nullptr>,
+ nullptr,
+ &target_search, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
const target_type objs::static_type
{
"objs",
@@ -109,7 +157,19 @@ namespace build2
false
};
- // obj{} and bmi{} group factory.
+ const target_type libus::static_type
+ {
+ "libus",
+ &libux::static_type,
+ &m_factory<libus, libu>,
+ &target_extension_var<ext_var, nullptr>,
+ &target_pattern_var<ext_var, nullptr>,
+ nullptr,
+ &target_search, // Note: not _file(); don't look for an existing file.
+ false
+ };
+
+ // obj{}, bmi{}, and libu{} group factory.
//
template <typename G, typename E, typename A, typename S>
static pair<target*, optional<string>>
@@ -164,6 +224,18 @@ namespace build2
false
};
+ const target_type libu::static_type
+ {
+ "libu",
+ &libx::static_type,
+ &g_factory<libu, libue, libua, libus>,
+ nullptr,
+ nullptr,
+ nullptr,
+ &target_search,
+ false
+ };
+
// What extensions should we use? At the outset, this is platform-
// dependent. And if we consider cross-compilation, is it build or
// host-dependent? Feels like it should be host-dependent so that
@@ -238,7 +310,7 @@ namespace build2
const target_type lib::static_type
{
"lib",
- &target::static_type,
+ &libx::static_type,
&lib_factory,
nullptr,
nullptr,
diff --git a/build2/bin/target.hxx b/build2/bin/target.hxx
index 13d7596..e0c0358 100644
--- a/build2/bin/target.hxx
+++ b/build2/bin/target.hxx
@@ -117,6 +117,73 @@ namespace build2
virtual const target_type& dynamic_type () const {return static_type;}
};
+ // Common base for lib{} and libu{} groups.
+ //
+ class libx: public target
+ {
+ public:
+ using target::target;
+
+ public:
+ static const target_type static_type;
+ };
+
+ // The libu{} target group (utility library).
+ //
+ // All the members are static libraries that differ base on the kind of
+ // object files they contains. Note that the group is more like obj{}
+ // rather than lib{} in that one does not build the group directly rather
+ // picking a suitable member.
+ //
+ class libux: public file // Common base of all libuX{} static libraries.
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ };
+
+ class libue: public libux
+ {
+ public:
+ using libux::libux;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class libua: public libux
+ {
+ public:
+ using libux::libux;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class libus: public libux
+ {
+ public:
+ using libux::libux;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
+ class libu: public libx
+ {
+ public:
+ using libx::libx;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
+
// The lib{} target group.
//
class liba: public file
@@ -149,10 +216,10 @@ namespace build2
const libs* s = nullptr;
};
- class lib: public target, public lib_members
+ class lib: public libx, public lib_members
{
public:
- using target::target;
+ using libx::libx;
virtual group_view
group_members (action_type) const override;
diff --git a/build2/cc/common.cxx b/build2/cc/common.cxx
index ec89e98..8dabb07 100644
--- a/build2/cc/common.cxx
+++ b/build2/cc/common.cxx
@@ -48,7 +48,7 @@ namespace build2
process_libraries (
action act,
const scope& top_bs,
- lorder top_lo,
+ linfo top_li,
const dir_paths& top_sysd,
const file& l,
bool la,
@@ -189,7 +189,7 @@ namespace build2
}
const scope& bs (t == nullptr || cc ? top_bs : l.base_scope ());
- optional<lorder> lo; // Calculate lazily.
+ optional<linfo> li; // Calculate lazily.
const dir_paths* sysd (nullptr); // Resolve lazily.
// Find system search directories corresponding to this library, i.e.,
@@ -207,9 +207,11 @@ namespace build2
: var_pool[*t + ".sys_lib_dirs"]]);
};
- auto find_lo = [top_lo, t, cc, &bs, &l, &lo] ()
+ auto find_linfo = [top_li, t, cc, &bs, &l, &li] ()
{
- lo = (t == nullptr || cc) ? top_lo : link_order (bs, link_type (l));
+ li = (t == nullptr || cc)
+ ? top_li
+ : link_info (bs, link_type (l).type);
};
// Only go into prerequisites (implementation) if instructed and we are
@@ -223,13 +225,14 @@ namespace build2
bool a;
const file* f;
- if ((a = (f = p->is_a<liba> ()) != nullptr)
- || (f = p->is_a<libs> ()) != nullptr)
+ if ((a = (f = p->is_a<liba> ())) ||
+ (a = (f = p->is_a<libux> ())) ||
+ ( f = p->is_a<libs> ()))
{
if (sysd == nullptr) find_sysd ();
- if (!lo) find_lo ();
+ if (!li) find_linfo ();
- process_libraries (act, bs, *lo, *sysd,
+ process_libraries (act, bs, *li, *sysd,
*f, a,
proc_impl, proc_lib, proc_opt, true);
}
@@ -266,8 +269,8 @@ namespace build2
auto proc_int = [&l,
&proc_impl, &proc_lib, &proc_opt,
&sysd, &usrd,
- &find_sysd, &find_lo, &sys_simple,
- &bs, act, &lo, this] (const lookup& lu)
+ &find_sysd, &find_linfo, &sys_simple,
+ &bs, act, &li, this] (const lookup& lu)
{
const vector<name>* ns (cast_null<vector<name>> (lu));
if (ns == nullptr || ns->empty ())
@@ -290,9 +293,9 @@ namespace build2
// This is a potentially project-qualified target.
//
if (sysd == nullptr) find_sysd ();
- if (!lo) find_lo ();
+ if (!li) find_linfo ();
- const file& t (resolve_library (act, bs, n, *lo, *sysd, usrd));
+ const file& t (resolve_library (act, bs, n, *li, *sysd, usrd));
if (proc_lib)
{
@@ -313,8 +316,8 @@ namespace build2
// Process it recursively.
//
- process_libraries (act, bs, *lo, *sysd,
- t, t.is_a<liba> (),
+ process_libraries (act, bs, *li, *sysd,
+ t, t.is_a<liba> () || t.is_a<libux> (),
proc_impl, proc_lib, proc_opt, true);
}
}
@@ -394,7 +397,7 @@ namespace build2
resolve_library (action act,
const scope& s,
name n,
- lorder lo,
+ linfo li,
const dir_paths& sysd,
optional<dir_paths>& usrd) const
{
@@ -440,10 +443,10 @@ namespace build2
fail << "unable to find library " << pk;
}
- // If this is lib{}, pick appropriate member.
+ // If this is lib{}/libu{}, pick appropriate member.
//
- if (const lib* l = xt->is_a<lib> ())
- xt = &link_member (*l, act, lo); // Pick liba{} or libs{}.
+ if (const libx* l = xt->is_a<libx> ())
+ xt = &link_member (*l, act, li); // Pick lib*{e,a,s}{}.
return xt->as<file> ();
}
@@ -488,6 +491,9 @@ namespace build2
// @@ This is hairy enough to warrant a separate implementation for
// Windows.
+
+ // Note: since we are searching for a (presumably) installed library,
+ // utility libraries do not apply.
//
bool l (p.is_a<lib> ());
const optional<string>& ext (l ? nullopt : p.tk.ext); // Only liba/libs.
diff --git a/build2/cc/common.hxx b/build2/cc/common.hxx
index abeadfc..6e1d8b9 100644
--- a/build2/cc/common.hxx
+++ b/build2/cc/common.hxx
@@ -194,7 +194,7 @@ namespace build2
process_libraries (
action,
const scope&,
- lorder,
+ linfo,
const dir_paths&,
const file&,
bool,
@@ -232,7 +232,7 @@ namespace build2
resolve_library (action,
const scope&,
name,
- lorder,
+ linfo,
const dir_paths&,
optional<dir_paths>&) const;
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx
index 805ad82..8fa3296 100644
--- a/build2/cc/compile.cxx
+++ b/build2/cc/compile.cxx
@@ -256,7 +256,7 @@ namespace build2
cstrings& args,
const target& t,
action act,
- lorder lo) const
+ linfo li) const
{
auto opt = [&args, this] (
const file& l, const string& t, bool com, bool exp)
@@ -284,14 +284,16 @@ namespace build2
//
if (const target* pt = p.load ())
{
- bool a;
+ if (const libx* l = pt->is_a<libx> ())
+ pt = &link_member (*l, act, li);
- if (const lib* l = pt->is_a<lib> ())
- a = (pt = &link_member (*l, act, lo))->is_a<liba> ();
- else if (!(a = pt->is_a<liba> ()) && !pt->is_a<libs> ())
+ bool a;
+ if (!((a = pt->is_a<liba> ()) ||
+ (a = pt->is_a<libux> ()) ||
+ pt->is_a<libs> ()))
continue;
- process_libraries (act, bs, lo, sys_lib_dirs,
+ process_libraries (act, bs, li, sys_lib_dirs,
pt->as<file> (), a,
nullptr, nullptr, optf);
}
@@ -303,7 +305,7 @@ namespace build2
sha256& cs,
const target& t,
action act,
- lorder lo) const
+ linfo li) const
{
auto opt = [&cs, this] (
const file& l, const string& t, bool com, bool exp)
@@ -326,14 +328,16 @@ namespace build2
{
if (const target* pt = p.load ())
{
- bool a;
+ if (const libx* l = pt->is_a<libx> ())
+ pt = &link_member (*l, act, li);
- if (const lib* l = pt->is_a<lib> ())
- a = (pt = &link_member (*l, act, lo))->is_a<liba> ();
- else if (!(a = pt->is_a<liba> ()) && !pt->is_a<libs> ())
+ bool a;
+ if (!((a = pt->is_a<liba> ()) ||
+ (a = pt->is_a<libux> ()) ||
+ pt->is_a<libs> ()))
continue;
- process_libraries (act, bs, lo, sys_lib_dirs,
+ process_libraries (act, bs, li, sys_lib_dirs,
pt->as<file> (), a,
nullptr, nullptr, optf);
}
@@ -348,7 +352,7 @@ namespace build2
prefix_map& m,
target& t,
action act,
- lorder lo) const
+ linfo li) const
{
auto opt = [&m, this] (
const file& l, const string& t, bool com, bool exp)
@@ -371,14 +375,16 @@ namespace build2
{
if (const target* pt = p.load ())
{
- bool a;
+ if (const libx* l = pt->is_a<libx> ())
+ pt = &link_member (*l, act, li);
- if (const lib* l = pt->is_a<lib> ())
- a = (pt = &link_member (*l, act, lo))->is_a<liba> ();
- else if (!(a = pt->is_a<liba> ()) && !pt->is_a<libs> ())
+ bool a;
+ if (!((a = pt->is_a<liba> ()) ||
+ (a = pt->is_a<libux> ()) ||
+ pt->is_a<libs> ()))
continue;
- process_libraries (act, bs, lo, sys_lib_dirs,
+ process_libraries (act, bs, li, sys_lib_dirs,
pt->as<file> (), a,
nullptr, nullptr, optf);
}
@@ -461,9 +467,9 @@ namespace build2
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
- otype ct (compile_type (t, mod));
- lorder lo (link_order (bs, ct));
- compile_target_types tt (compile_types (ct));
+ otype ot (compile_type (t, mod));
+ linfo li (link_info (bs, ot)); // Link info for selecting libraries.
+ compile_target_types tt (compile_types (ot));
// Derive file name from target name.
//
@@ -473,7 +479,7 @@ namespace build2
if (tsys == "win32-msvc")
{
- switch (ct)
+ switch (ot)
{
case otype::e: e = "exe."; break;
case otype::a: e = "lib."; break;
@@ -483,7 +489,7 @@ namespace build2
}
else if (tsys == "mingw32")
{
- switch (ct)
+ switch (ot)
{
case otype::e: e = "exe."; break;
case otype::a: e = "a."; break;
@@ -492,7 +498,7 @@ namespace build2
}
else if (tsys == "darwin")
{
- switch (ct)
+ switch (ot)
{
case otype::e: e = ""; break;
case otype::a: e = "a."; break;
@@ -501,7 +507,7 @@ namespace build2
}
else
{
- switch (ct)
+ switch (ot)
{
case otype::e: e = ""; break;
case otype::a: e = "a."; break;
@@ -573,7 +579,10 @@ namespace build2
// *.export.poptions, modules, etc. This is the "library
// meta-information protocol". See also append_lib_options().
//
- if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ())
+ if (p.is_a<libx> () ||
+ p.is_a<liba> () ||
+ p.is_a<libs> () ||
+ p.is_a<libux> ())
{
if (act.operation () == update_id)
{
@@ -592,8 +601,8 @@ namespace build2
pt = &p.search (t);
- if (const lib* l = pt->is_a<lib> ())
- pt = &link_member (*l, act, lo);
+ if (const libx* l = pt->is_a<libx> ())
+ pt = &link_member (*l, act, li);
}
else
continue;
@@ -633,11 +642,12 @@ namespace build2
// match in link::apply() it will be safe unless someone is building
// an obj?{} target directory.
//
- if (build2::match (act,
- *pt,
- pt->is_a<liba> () || pt->is_a<libs> ()
- ? unmatch::safe
- : unmatch::none))
+ if (build2::match (
+ act,
+ *pt,
+ pt->is_a<liba> () || pt->is_a<libs> () || pt->is_a<libux> ()
+ ? unmatch::safe
+ : unmatch::none))
pt = nullptr; // Ignore in execute.
}
@@ -718,7 +728,7 @@ namespace build2
// Hash *.export.poptions from prerequisite libraries.
//
- hash_lib_options (bs, cs, t, act, lo);
+ hash_lib_options (bs, cs, t, act, li);
// Extra system header dirs (last).
//
@@ -730,7 +740,7 @@ namespace build2
hash_options (cs, t, x_coptions);
hash_options (cs, tstd);
- if (ct == otype::s)
+ if (ot == otype::s)
{
// On Darwin, Win32 -fPIC is the default.
//
@@ -795,7 +805,7 @@ namespace build2
//
pair<auto_rmfile, bool> psrc (auto_rmfile (), false);
if (md.pp < preprocessed::includes)
- psrc = extract_headers (act, t, lo, src, md, dd, u, mt);
+ psrc = extract_headers (act, t, li, src, md, dd, u, mt);
// Next we "obtain" the translation unit information. What exactly
// "obtain" entails is tricky: If things changed, then we re-parse the
@@ -818,7 +828,7 @@ namespace build2
{
if (u)
{
- auto p (parse_unit (act, t, lo, src, psrc.first, md));
+ auto p (parse_unit (act, t, li, src, psrc.first, md));
if (cs != p.second)
{
@@ -875,7 +885,7 @@ namespace build2
// NOTE: assumes that no further targets will be added into
// t.prerequisite_targets!
//
- extract_modules (act, t, lo, tt, src, md, move (tu.mod), dd, u);
+ extract_modules (act, t, li, tt, src, md, move (tu.mod), dd, u);
}
// If anything got updated, then we didn't rely on the cache. However,
@@ -1073,7 +1083,7 @@ namespace build2
auto compile::
build_prefix_map (const scope& bs,
target& t,
- action act, lorder lo) const -> prefix_map
+ action act, linfo li) const -> prefix_map
{
prefix_map m;
@@ -1084,7 +1094,7 @@ namespace build2
// Then process the include directories from prerequisite libraries.
//
- append_lib_prefixes (bs, m, t, act, lo);
+ append_lib_prefixes (bs, m, t, act, li);
return m;
}
@@ -1273,7 +1283,7 @@ namespace build2
pair<auto_rmfile, bool> compile::
extract_headers (action act,
file& t,
- lorder lo,
+ linfo li,
const file& src,
const match_data& md,
depdb& dd,
@@ -1429,7 +1439,7 @@ namespace build2
// Return NULL if the dependency information goes to stdout and a
// pointer to the temporary file path otherwise.
//
- auto init_args = [&t, act, lo,
+ auto init_args = [&t, act, li,
&src, &md, &psrc, &sense_diag,
&rs, &bs,
pp, &env, &args, &args_gen, &args_i, &out, &drm, this]
@@ -1477,7 +1487,7 @@ namespace build2
// Add *.export.poptions from prerequisite libraries.
//
- append_lib_options (bs, args, t, act, lo);
+ append_lib_options (bs, args, t, act, li);
append_options (args, t, c_poptions);
append_options (args, t, x_poptions);
@@ -1715,7 +1725,7 @@ namespace build2
// extraction process should be restarted.
//
auto add = [&trace, &pm,
- act, &t, lo,
+ act, &t, li,
&dd, &updating, mt,
&bs, this] (path f, bool cache) -> bool
{
@@ -1845,7 +1855,7 @@ namespace build2
// then we would have failed below.
//
if (pm.empty ())
- pm = build_prefix_map (bs, t, act, lo);
+ pm = build_prefix_map (bs, t, act, li);
// First try the whole file. Then just the directory.
//
@@ -2340,7 +2350,7 @@ namespace build2
pair<translation_unit, string> compile::
parse_unit (action act,
file& t,
- lorder lo,
+ linfo lo,
const file& src,
auto_rmfile& psrc,
const match_data& md) const
@@ -2592,7 +2602,7 @@ namespace build2
void compile::
extract_modules (action act,
file& t,
- lorder lo,
+ linfo li,
const compile_target_types& tt,
const file& src,
match_data& md,
@@ -2648,7 +2658,7 @@ namespace build2
sha256 cs;
if (!mi.imports.empty ())
- md.mods = search_modules (act, t, lo, tt.bmi, src, mi.imports, cs);
+ md.mods = search_modules (act, t, li, tt.bmi, src, mi.imports, cs);
if (dd.expect (cs.string ()) != nullptr)
updating = true;
@@ -2708,7 +2718,7 @@ namespace build2
module_positions compile::
search_modules (action act,
file& t,
- lorder lo,
+ linfo li,
const target_type& mtt,
const file& src,
module_imports& imports,
@@ -2959,9 +2969,9 @@ namespace build2
{
const target* lt (nullptr);
- if (const lib* l = pt->is_a<lib> ())
- lt = &link_member (*l, act, lo);
- else if (pt->is_a<liba> () || pt->is_a<libs> ())
+ if (const libx* l = pt->is_a<libx> ())
+ lt = &link_member (*l, act, li);
+ else if (pt->is_a<liba> () || pt->is_a<libs> () || pt->is_a<libux> ())
lt = pt;
// If this is a library, check its bmi{}s.
@@ -3371,8 +3381,8 @@ namespace build2
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
- otype ct (compile_type (t, mod));
- lorder lo (link_order (bs, ct));
+ otype ot (compile_type (t, mod));
+ linfo li (link_info (bs, ot));
environment env;
cstrings args {cpath.recall_string ()};
@@ -3398,7 +3408,7 @@ namespace build2
// Add *.export.poptions from prerequisite libraries.
//
- append_lib_options (bs, args, t, act, lo);
+ append_lib_options (bs, args, t, act, li);
// Extra system header dirs (last).
//
@@ -3521,7 +3531,7 @@ namespace build2
}
else
{
- if (ct == otype::s)
+ if (ot == otype::s)
{
// On Darwin, Win32 -fPIC is the default.
//
diff --git a/build2/cc/compile.hxx b/build2/cc/compile.hxx
index afd0cfc..ffe9fd7 100644
--- a/build2/cc/compile.hxx
+++ b/build2/cc/compile.hxx
@@ -62,13 +62,13 @@ namespace build2
append_lib_options (const scope&,
cstrings&,
const target&,
- action, lorder) const;
+ action, linfo) const;
void
hash_lib_options (const scope&,
sha256&,
const target&,
- action, lorder) const;
+ action, linfo) const;
// Mapping of include prefixes (e.g., foo in <foo/bar>) for auto-
// generated headers to directories where they will be generated.
@@ -89,10 +89,10 @@ namespace build2
append_lib_prefixes (const scope&,
prefix_map&,
target&,
- action, lorder) const;
+ action, linfo) const;
prefix_map
- build_prefix_map (const scope&, target&, action, lorder) const;
+ build_prefix_map (const scope&, target&, action, linfo) const;
// Reverse-lookup target type from extension.
//
@@ -100,21 +100,21 @@ namespace build2
map_extension (const scope&, const string&, const string&) const;
pair<auto_rmfile, bool>
- extract_headers (action, file&, lorder,
+ extract_headers (action, file&, linfo,
const file&, const match_data&,
depdb&, bool&, timestamp) const;
pair<translation_unit, string>
- parse_unit (action, file&, lorder,
+ parse_unit (action, file&, linfo,
const file&, auto_rmfile&, const match_data&) const;
void
- extract_modules (action, file&, lorder, const compile_target_types&,
+ extract_modules (action, file&, linfo, const compile_target_types&,
const file&, match_data&,
module_info&&, depdb&, bool&) const;
module_positions
- search_modules (action, file&, lorder, const target_type&,
+ search_modules (action, file&, linfo, const target_type&,
const file&, module_imports&, sha256&) const;
void
diff --git a/build2/cc/install.cxx b/build2/cc/install.cxx
index 529a758..c35e931 100644
--- a/build2/cc/install.cxx
+++ b/build2/cc/install.cxx
@@ -48,7 +48,7 @@ namespace build2
//
if (const lib* l = pt->is_a<lib> ())
pt = &link_member (
- *l, a, link_order (t.base_scope (), link_type (t)));
+ *l, a, link_info (t.base_scope (), link_type (t).type));
if (pt->is_a<libs> ()) // Can be liba{}.
return pt->in (t.weak_scope ()) ? pt : nullptr;
diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx
index b113adb..7b14621 100644
--- a/build2/cc/link.cxx
+++ b/build2/cc/link.cxx
@@ -56,15 +56,18 @@ namespace build2
// (i.e., a utility library).
//
- otype lt (link_type (t));
+ ltype lt (link_type (t));
+ otype ot (lt.type);
- // If this is a library, link-up to our group (this is the lib{} target
- // group protocol which means this can be done whether we match or not).
+ // If this is a library, link-up to our group (this is the target group
+ // protocol which means this can be done whether we match or not).
//
- if (lt == otype::a || lt == otype::s)
+ if (lt.library ())
{
if (t.group == nullptr)
- t.group = targets.find<lib> (t.dir, t.out, t.name);
+ t.group = targets.find (
+ lt.utility ? libu::static_type : lib::static_type,
+ t.dir, t.out, t.name);
}
// Scan prerequisites and see if we can work with what we've got. Note
@@ -90,28 +93,29 @@ namespace build2
}
else if (p.is_a<obje> () || p.is_a<bmie> ())
{
- if (lt != otype::e)
+ if (ot != otype::e)
fail << p.type ().name << "{} as prerequisite of " << t;
seen_obj = seen_obj || true;
}
else if (p.is_a<obja> () || p.is_a<bmia> ())
{
- if (lt != otype::a)
+ if (ot != otype::a)
fail << p.type ().name << "{} as prerequisite of " << t;
seen_obj = seen_obj || true;
}
else if (p.is_a<objs> () || p.is_a<bmis> ())
{
- if (lt != otype::s)
+ if (ot != otype::s)
fail << p.type ().name << "{} as prerequisite of " << t;
seen_obj = seen_obj || true;
}
- else if (p.is_a<lib> () ||
- p.is_a<liba> () ||
- p.is_a<libs> ())
+ else if (p.is_a<libx> () ||
+ p.is_a<liba> () ||
+ p.is_a<libs> () ||
+ p.is_a<libux> ())
{
seen_lib = seen_lib || true;
}
@@ -300,12 +304,13 @@ namespace build2
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
- otype lt (link_type (t));
- lorder lo (link_order (bs, lt));
+ ltype lt (link_type (t));
+ otype ot (lt.type);
+ linfo li (link_info (bs, ot));
// Set the library type (C, C++, etc).
//
- if (lt != otype::e)
+ if (lt.library ())
t.vars.assign (c_type) = string (x);
// Derive file name(s) and add ad hoc group members.
@@ -325,57 +330,119 @@ namespace build2
const char* p (nullptr); // Prefix.
const char* s (nullptr); // Suffix.
- switch (lt)
+ if (lt.utility)
{
- case otype::e:
+ // These are all static libraries with names indicating the kind of
+ // object files they contain (similar to how we name object files
+ // themselves). We add the 'u' extension to avoid clashes with
+ // real libraries/import stubs.
+ //
+ // libue libhello.u.a hello.exe.u.lib
+ // libua libhello.a.u.a hello.lib.u.lib
+ // libus libhello.so.u.a hello.dll.u.lib hello.dylib.u.lib
+ //
+ // Note that we currently don't add bin.lib.{prefix,suffix} since
+ // these are not installed.
+ //
+ if (tsys == "win32-msvc")
{
- if (tclass == "windows")
- e = "exe";
- else
- e = "";
+ switch (ot)
+ {
+ case otype::e: e = "exe.u.lib"; break;
+ case otype::a: e = "lib.u.lib"; break;
+ case otype::s: e = "dll.u.lib"; break;
+ }
+ }
+ else
+ {
+ p = "lib";
- if (auto l = t["bin.exe.prefix"]) p = cast<string> (l).c_str ();
- if (auto l = t["bin.exe.suffix"]) s = cast<string> (l).c_str ();
+ if (tsys == "mingw32")
+ {
+ switch (ot)
+ {
+ case otype::e: e = "exe.u.a"; break;
+ case otype::a: e = "a.u.a"; break;
+ case otype::s: e = "dll.u.a"; break;
+ }
- t.derive_path (e, p, s);
- break;
+ }
+ else if (tsys == "darwin")
+ {
+ switch (ot)
+ {
+ case otype::e: e = "u.a"; break;
+ case otype::a: e = "a.u.a"; break;
+ case otype::s: e = "dylib.u.a"; break;
+ }
+ }
+ else
+ {
+ switch (ot)
+ {
+ case otype::e: e = "u.a"; break;
+ case otype::a: e = "a.u.a"; break;
+ case otype::s: e = "so.u.a"; break;
+ }
+ }
}
- case otype::a:
+
+ t.derive_path (e, p, s);
+ }
+ else
+ {
+ switch (ot)
{
- if (cid == compiler_id::msvc)
- e = "lib";
- else
+ case otype::e:
{
- p = "lib";
- e = "a";
+ if (tclass == "windows")
+ e = "exe";
+ else
+ e = "";
+
+ if (auto l = t["bin.exe.prefix"]) p = cast<string> (l).c_str ();
+ if (auto l = t["bin.exe.suffix"]) s = cast<string> (l).c_str ();
+
+ t.derive_path (e, p, s);
+ break;
}
+ case otype::a:
+ {
+ if (cid == compiler_id::msvc)
+ e = "lib";
+ else
+ {
+ p = "lib";
+ e = "a";
+ }
- if (auto l = t["bin.lib.prefix"]) p = cast<string> (l).c_str ();
- if (auto l = t["bin.lib.suffix"]) s = cast<string> (l).c_str ();
+ if (auto l = t["bin.lib.prefix"]) p = cast<string> (l).c_str ();
+ if (auto l = t["bin.lib.suffix"]) s = cast<string> (l).c_str ();
- t.derive_path (e, p, s);
- break;
- }
- case otype::s:
- {
- // On Windows libs{} is an ad hoc group. The libs{} itself is the
- // DLL and we add libi{} import library as its member.
- //
- if (tclass == "windows")
- libi = add_adhoc (t, "libi");
+ t.derive_path (e, p, s);
+ break;
+ }
+ case otype::s:
+ {
+ // On Windows libs{} is an ad hoc group. The libs{} itself is
+ // the DLL and we add libi{} import library as its member.
+ //
+ if (tclass == "windows")
+ libi = add_adhoc (t, "libi");
- t.data (derive_libs_paths (t)); // Cache in target.
+ t.data (derive_libs_paths (t)); // Cache in target.
- if (libi)
- match_recipe (libi, group_recipe); // Set recipe and unlock.
+ if (libi)
+ match_recipe (libi, group_recipe); // Set recipe and unlock.
- break;
+ break;
+ }
}
}
// PDB
//
- if (lt != otype::a &&
+ if (!lt.static_library () &&
cid == compiler_id::msvc &&
(find_option ("/DEBUG", t, c_loptions, true) ||
find_option ("/DEBUG", t, x_loptions, true)))
@@ -419,7 +486,7 @@ namespace build2
// or a subdirectory of our project root.
//
optional<dir_paths> usr_lib_dirs; // Extract lazily.
- compile_target_types tt (compile_types (lt));
+ compile_target_types tt (compile_types (ot));
auto skip = [&act, &rs] (const target*& pt)
{
@@ -505,7 +572,10 @@ namespace build2
m = mod ? 2 : 1;
}
- else if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> ())
+ else if (p.is_a<libx> () ||
+ p.is_a<liba> () ||
+ p.is_a<libs> () ||
+ p.is_a<libux> ())
{
// Handle imported libraries.
//
@@ -524,11 +594,11 @@ namespace build2
if (skip (pt))
continue;
- // If this is the lib{} target group, then pick the appropriate
+ // If this is the lib{}/libu{} group, then pick the appropriate
// member.
//
- if (const lib* l = pt->is_a<lib> ())
- pt = &link_member (*l, act, lo);
+ if (const libx* l = pt->is_a<libx> ())
+ pt = &link_member (*l, act, li);
}
else
{
@@ -622,8 +692,9 @@ namespace build2
{
const target* pt (t.prerequisite_targets[j++]);
- if (p.is_a<lib> () || p.is_a<liba> () || p.is_a<libs> () ||
- p.is_a<bmi> () || p.is_a (tt.bmi))
+ if (p.is_a<libx> () ||
+ p.is_a<liba> () || p.is_a<libs> () || p.is_a<libux> () ||
+ p.is_a<bmi> () || p.is_a (tt.bmi))
{
ps.emplace_back (p.as_prerequisite ());
}
@@ -681,12 +752,12 @@ namespace build2
// Ignore some known target types (fsdir, headers, libraries,
// modules).
//
- if (p1.is_a<fsdir> () ||
- p1.is_a<lib> () ||
- p1.is_a<liba> () || p1.is_a<libs> () ||
- p1.is_a<bmi> () ||
- p1.is_a<bmie> () || p1.is_a<bmia> () || p1.is_a<bmis> () ||
- (p.is_a (mod ? *x_mod : x_src) && x_header (p1)) ||
+ if (p1.is_a<fsdir> () ||
+ p1.is_a<libx> () ||
+ p1.is_a<liba> () || p1.is_a<libs> () || p1.is_a<libux> () ||
+ p1.is_a<bmi> () ||
+ p1.is_a<bmie> () || p1.is_a<bmia> () || p1.is_a<bmis> () ||
+ (p.is_a (mod ? *x_mod : x_src) && x_header (p1)) ||
(p.is_a<c> () && p1.is_a<h> ()))
continue;
@@ -805,7 +876,7 @@ namespace build2
void link::
append_libraries (strings& args,
const file& l, bool la,
- const scope& bs, action act, lorder lo) const
+ 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.
@@ -850,13 +921,13 @@ namespace build2
};
process_libraries (
- act, bs, lo, sys_lib_dirs, l, la, imp, lib, opt, true);
+ act, bs, li, sys_lib_dirs, l, la, imp, lib, opt, true);
}
void link::
hash_libraries (sha256& cs,
const file& l, bool la,
- const scope& bs, action act, lorder lo) const
+ const scope& bs, action act, linfo li) const
{
bool win (tclass == "windows");
@@ -896,7 +967,7 @@ namespace build2
};
process_libraries (
- act, bs, lo, sys_lib_dirs, l, la, imp, lib, opt, true);
+ act, bs, li, sys_lib_dirs, l, la, imp, lib, opt, true);
}
void link::
@@ -904,7 +975,7 @@ namespace build2
const target& t,
const scope& bs,
action act,
- lorder lo,
+ linfo li,
bool for_install) const
{
// Use -rpath-link on targets that support it (Linux, *BSD). Note
@@ -945,7 +1016,7 @@ namespace build2
auto lib = [&d, this] (const file* l, const string& f, bool sys)
{
// We don't rpath system libraries. Why, you may ask? There are many
- // good reasons and I have them written on an napkin somewhere...
+ // good reasons and I have them written on a napkin somewhere...
//
if (sys)
return;
@@ -1001,13 +1072,14 @@ namespace build2
for (const target* pt: t.prerequisite_targets)
{
+ bool a;
const file* f;
- const liba* a;
- if ((f = a = pt->is_a<liba> ()) ||
- (f = pt->is_a<libs> ()))
+ if ((a = (f = pt->is_a<liba> ())) ||
+ (a = (f = pt->is_a<libux> ())) ||
+ ( f = pt->is_a<libs> ()))
{
- if (!for_install && a == nullptr)
+ if (!for_install && !a)
{
// Top-level sharen library dependency. It is either matched or
// imported so should be a cc library.
@@ -1017,8 +1089,8 @@ namespace build2
"-Wl,-rpath," + f->path ().directory ().string ());
}
- process_libraries (act, bs, lo, sys_lib_dirs,
- *f, a != nullptr,
+ process_libraries (act, bs, li, sys_lib_dirs,
+ *f, a,
impf, libf, nullptr);
}
}
@@ -1048,8 +1120,9 @@ namespace build2
const scope& bs (t.base_scope ());
const scope& rs (*bs.root_scope ());
- otype lt (link_type (t));
- lorder lo (link_order (bs, lt));
+ ltype lt (link_type (t));
+ otype ot (lt.type);
+ linfo li (link_info (bs, ot));
// Update prerequisites. We determine if any relevant ones render us
// out-of-date manually below.
@@ -1063,14 +1136,14 @@ namespace build2
path manifest; // Manifest itself (msvc) or compiled object file.
timestamp rpath_timestamp (timestamp_nonexistent); // DLLs timestamp.
- if (lt == otype::e && tclass == "windows")
+ if (lt.executable () && tclass == "windows")
{
// First determine if we need to add our rpath emulating assembly. The
// assembly itself is generated later, after updating the target. Omit
// it if we are updating for install.
//
if (!for_install)
- rpath_timestamp = windows_rpath_timestamp (t, bs, act, lo);
+ rpath_timestamp = windows_rpath_timestamp (t, bs, act, li);
pair<path, bool> p (
windows_manifest (t,
@@ -1182,7 +1255,7 @@ namespace build2
// Then the linker checksum (ar/ranlib or the compiler).
//
- if (lt == otype::a)
+ if (lt.static_library ())
{
ranlib = rs["bin.ranlib.path"];
@@ -1232,7 +1305,7 @@ namespace build2
string soname1, soname2;
strings sargs;
- if (lt == otype::a)
+ if (lt.static_library ())
{
if (cid == compiler_id::msvc) ;
else
@@ -1277,7 +1350,7 @@ namespace build2
{
// Set soname.
//
- if (lt == otype::s)
+ if (lt.shared_library ())
{
const libs_paths& paths (t.data<libs_paths> ());
const string& leaf (paths.effect_soname ().leaf ().string ());
@@ -1315,7 +1388,7 @@ namespace build2
// rpath of the imported libraries (i.e., we assume they are also
// installed). But we add -rpath-link for some platforms.
//
- rpath_libraries (sargs, t, bs, act, lo, for_install);
+ rpath_libraries (sargs, t, bs, act, li, for_install);
if (auto l = t["bin.rpath"])
for (const dir_path& p: cast<dir_paths> (l))
@@ -1350,10 +1423,6 @@ namespace build2
for (const target* pt: t.prerequisite_targets)
{
- const file* f;
- const liba* a (nullptr);
- const libs* s (nullptr);
-
// If this is bmi*{}, then obj*{} is its ad hoc member.
//
if (modules)
@@ -1362,18 +1431,22 @@ namespace build2
pt = pt->member;
}
+ const file* f;
+ bool a (false), s (false);
+
if ((f = pt->is_a<obje> ()) ||
(f = pt->is_a<obja> ()) ||
(f = pt->is_a<objs> ()) ||
- (lt != otype::a &&
- ((f = a = pt->is_a<liba> ()) ||
- (f = s = pt->is_a<libs> ()))))
+ (!lt.static_library () && // @@ UTL: TODO libua to liba link.
+ ((a = (f = pt->is_a<liba> ())) ||
+ (a = (f = pt->is_a<libux> ())) ||
+ (s = (f = pt->is_a<libs> ())))))
{
// Link all the dependent interface libraries (shared) or interface
// and implementation (static), recursively.
//
- if (a != nullptr || s != nullptr)
- hash_libraries (cs, *f, a != nullptr, bs, act, lo);
+ if (a || s)
+ hash_libraries (cs, *f, a, bs, act, li);
else
cs.append (f->path ().string ());
}
@@ -1393,7 +1466,7 @@ namespace build2
// Treat them as inputs, not options.
//
- if (lt != otype::a)
+ if (!lt.static_library ())
{
hash_options (cs, t, c_libs);
hash_options (cs, t, x_libs);
@@ -1429,13 +1502,13 @@ namespace build2
path relt (relative (tp));
const process_path* ld (nullptr);
- switch (lt)
+ if (lt.static_library ())
{
- case otype::a:
- {
- ld = &cast<process_path> (rs["bin.ar.path"]);
+ ld = &cast<process_path> (rs["bin.ar.path"]);
- if (cid == compiler_id::msvc)
+ switch (cid)
+ {
+ case compiler_id::msvc:
{
// lib.exe has /LIBPATH but it's not clear/documented what it's
// used for. Perhaps for link-time code generation (/LTCG)? If
@@ -1449,25 +1522,30 @@ namespace build2
out = "/OUT:" + relt.string ();
args.push_back (out.c_str ());
+ break;
}
- else
+ default:
+ {
args.push_back (relt.string ().c_str ());
-
- break;
+ break;
+ }
}
- // The options are usually similar enough to handle them together.
+ }
+ else
+ {
+ // The options are usually similar enough to handle executables
+ // and shared libraries together.
//
- case otype::e:
- case otype::s:
+ switch (cid)
{
- if (cid == compiler_id::msvc)
+ case compiler_id::msvc:
{
// Using link.exe directly.
//
ld = &cast<process_path> (rs["bin.ld.path"]);
args.push_back ("/NOLOGO");
- if (lt == otype::s)
+ if (ot == otype::s)
args.push_back ("/DLL");
// Add /MACHINE.
@@ -1519,7 +1597,7 @@ namespace build2
args.push_back (out3.c_str ());
}
- if (lt == otype::s)
+ if (ot == otype::s)
{
// On Windows libs{} is the DLL and its first ad hoc group
// member is the import library.
@@ -1539,7 +1617,7 @@ namespace build2
if (find_option ("/DEBUG", args, true))
{
auto& pdb (
- (lt == otype::e ? t.member : t.member->member)->as<file> ());
+ (ot == otype::e ? t.member : t.member->member)->as<file> ());
out1 = "/PDB:" + relative (pdb.path ()).string ();
args.push_back (out1.c_str ());
}
@@ -1553,15 +1631,16 @@ namespace build2
//
out = "/OUT:" + relt.string ();
args.push_back (out.c_str ());
+ break;
}
- else
+ default:
{
ld = &cpath;
// Add the option that triggers building a shared library and take
// care of any extras (e.g., import library).
//
- if (lt == otype::s)
+ if (ot == otype::s)
{
if (tclass == "macos")
args.push_back ("-dynamiclib");
@@ -1581,9 +1660,8 @@ namespace build2
args.push_back ("-o");
args.push_back (relt.string ().c_str ());
+ break;
}
-
- break;
}
}
@@ -1593,28 +1671,28 @@ namespace build2
//
for (const target* pt: t.prerequisite_targets)
{
- const file* f;
- const liba* a (nullptr);
- const libs* s (nullptr);
-
if (modules)
{
if (pt->is_a<bmie> () || pt->is_a<bmia> () || pt->is_a<bmis> ())
pt = pt->member;
}
+ const file* f;
+ bool a (false), s (false);
+
if ((f = pt->is_a<obje> ()) ||
(f = pt->is_a<obja> ()) ||
(f = pt->is_a<objs> ()) ||
- (lt != otype::a &&
- ((f = a = pt->is_a<liba> ()) ||
- (f = s = pt->is_a<libs> ()))))
+ (!lt.static_library () && // @@ UTL: TODO libua to liba link.
+ ((a = (f = pt->is_a<liba> ())) ||
+ (a = (f = pt->is_a<libux> ())) ||
+ (s = (f = pt->is_a<libs> ())))))
{
// Link all the dependent interface libraries (shared) or interface
// and implementation (static), recursively.
//
- if (a != nullptr || s != nullptr)
- append_libraries (sargs, *f, a != nullptr, bs, act, lo);
+ if (a || s)
+ append_libraries (sargs, *f, a, bs, act, li);
else
sargs.push_back (relative (f->path ()).string ()); // string()&&
}
@@ -1631,7 +1709,7 @@ namespace build2
for (const string& a: sargs)
args.push_back (a.c_str ());
- if (lt != otype::a)
+ if (!lt.static_library ())
{
append_options (args, t, c_libs);
append_options (args, t, x_libs);
@@ -1641,7 +1719,7 @@ namespace build2
// Cleanup old (versioned) libraries.
//
- if (lt == otype::s)
+ if (lt.shared_library ())
{
const libs_paths& paths (t.data<libs_paths> ());
const path& p (paths.clean);
@@ -1697,7 +1775,7 @@ namespace build2
// something like this) we are going to redirect stdout to stderr. For
// sane compilers this should be harmless.
//
- bool filter (cid == compiler_id::msvc && lt != otype::a);
+ bool filter (cid == compiler_id::msvc && !lt.static_library ());
process pr (*ld, args.data (), 0, (filter ? -1 : 2));
@@ -1708,7 +1786,7 @@ namespace build2
ifdstream is (
move (pr.in_ofd), fdstream_mode::text, ifdstream::badbit);
- msvc_filter_link (is, t, lt);
+ msvc_filter_link (is, t, ot);
// If anything remains in the stream, send it all to stderr. Note
// that the eof check is important: if the stream is at eof, this
@@ -1780,13 +1858,13 @@ namespace build2
// For Windows generate rpath-emulating assembly (unless updaing for
// install).
//
- if (lt == otype::e && !for_install)
- windows_rpath_assembly (t, bs, act, lo,
+ if (lt.executable () && !for_install)
+ windows_rpath_assembly (t, bs, act, li,
cast<string> (rs[x_target_cpu]),
rpath_timestamp,
scratch);
}
- else if (lt == otype::s)
+ else if (lt.shared_library ())
{
// For shared libraries we may need to create a bunch of symlinks.
//
@@ -1835,56 +1913,49 @@ namespace build2
perform_clean (action act, const target& xt) const
{
const file& t (xt.as<file> ());
+ ltype lt (link_type (t));
- switch (link_type (t))
+ if (lt.executable ())
{
- case otype::a:
- break; // Default.
- case otype::e:
- {
- if (tclass == "windows")
- {
- if (tsys == "mingw32")
- return clean_extra (
- act, t, {".d", ".dlls/", ".manifest.o", ".manifest"});
- else
- // Assuming it's VC or alike. Clean up .ilk in case the user
- // enabled incremental linking (note that .ilk replaces .exe).
- //
- return clean_extra (
- act, t, {".d", ".dlls/", ".manifest", "-.ilk"});
- }
-
- break;
- }
- case otype::s:
+ if (tclass == "windows")
{
- if (tclass == "windows")
- {
- // Assuming it's VC or alike. Clean up .exp and .ilk.
- //
- // Note that .exp is based on the .lib, not .dll name. And with
- // versioning their bases may not be the same.
- //
- if (tsys != "mingw32")
- return clean_extra (act, t, {{".d", "-.ilk"}, {"-.exp"}});
- }
+ if (tsys == "mingw32")
+ return clean_extra (
+ act, t, {".d", ".dlls/", ".manifest.o", ".manifest"});
else
- {
- // Here we can have a bunch of symlinks that we need to remove. If
- // the paths are empty, then they will be ignored.
+ // Assuming it's VC or alike. Clean up .ilk in case the user
+ // enabled incremental linking (note that .ilk replaces .exe).
//
- const libs_paths& paths (t.data<libs_paths> ());
-
- return clean_extra (act, t, {".d",
- paths.link.string ().c_str (),
- paths.soname.string ().c_str (),
- paths.interm.string ().c_str ()});
- }
+ return clean_extra (
+ act, t, {".d", ".dlls/", ".manifest", "-.ilk"});
+ }
+ }
+ else if (lt.shared_library ())
+ {
+ if (tclass == "windows")
+ {
+ // Assuming it's VC or alike. Clean up .exp and .ilk.
+ //
+ // Note that .exp is based on the .lib, not .dll name. And with
+ // versioning their bases may not be the same.
+ //
+ if (tsys != "mingw32")
+ return clean_extra (act, t, {{".d", "-.ilk"}, {"-.exp"}});
+ }
+ else
+ {
+ // Here we can have a bunch of symlinks that we need to remove. If
+ // the paths are empty, then they will be ignored.
+ //
+ const libs_paths& paths (t.data<libs_paths> ());
- break;
+ return clean_extra (act, t, {".d",
+ paths.link.string ().c_str (),
+ paths.soname.string ().c_str (),
+ paths.interm.string ().c_str ()});
}
}
+ // For static library it's just the defaults.
return clean_extra (act, t, {".d"});
}
diff --git a/build2/cc/link.hxx b/build2/cc/link.hxx
index 4dc722a..0256774 100644
--- a/build2/cc/link.hxx
+++ b/build2/cc/link.hxx
@@ -76,17 +76,17 @@ namespace build2
void
append_libraries (strings&,
const file&, bool,
- const scope&, action, lorder) const;
+ const scope&, action, linfo) const;
void
hash_libraries (sha256&,
const file&, bool,
- const scope&, action, lorder) const;
+ const scope&, action, linfo) const;
void
rpath_libraries (strings&,
const target&,
- const scope&, action, lorder,
+ const scope&, action, linfo,
bool) const;
// Windows rpath emulation (windows-rpath.cxx).
@@ -105,13 +105,13 @@ namespace build2
timestamp
windows_rpath_timestamp (const file&,
const scope&,
- action, lorder) const;
+ action, linfo) const;
windows_dlls
- windows_rpath_dlls (const file&, const scope&, action, lorder) const;
+ windows_rpath_dlls (const file&, const scope&, action, linfo) const;
void
- windows_rpath_assembly (const file&, const scope&, action, lorder,
+ windows_rpath_assembly (const file&, const scope&, action, linfo,
const string&,
timestamp,
bool) const;
diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx
index 3755817..2b19e70 100644
--- a/build2/cc/module.cxx
+++ b/build2/cc/module.cxx
@@ -401,6 +401,18 @@ namespace build2
r.insert<bmis> (configure_update_id, x_compile, cr);
}
+ r.insert<libue> (perform_update_id, x_link, lr);
+ r.insert<libue> (perform_clean_id, x_link, lr);
+ r.insert<libue> (configure_update_id, x_link, lr);
+
+ r.insert<libua> (perform_update_id, x_link, lr);
+ r.insert<libua> (perform_clean_id, x_link, lr);
+ r.insert<libua> (configure_update_id, x_link, lr);
+
+ r.insert<libus> (perform_update_id, x_link, lr);
+ r.insert<libus> (perform_clean_id, x_link, lr);
+ r.insert<libus> (configure_update_id, x_link, lr);
+
r.insert<exe> (perform_update_id, x_link, lr);
r.insert<exe> (perform_clean_id, x_link, lr);
r.insert<exe> (configure_update_id, x_link, lr);
@@ -413,6 +425,8 @@ namespace build2
r.insert<libs> (perform_clean_id, x_link, lr);
r.insert<libs> (configure_update_id, x_link, lr);
+ // Note that libu*{} are not installable.
+ //
if (install_loaded)
{
const install& ir (*this);
diff --git a/build2/cc/types.hxx b/build2/cc/types.hxx
index 3170942..417370f 100644
--- a/build2/cc/types.hxx
+++ b/build2/cc/types.hxx
@@ -61,6 +61,17 @@ namespace build2
//
enum class otype {e, a, s};
+ struct ltype
+ {
+ otype type;
+ bool utility; // True for utility libraries.
+
+ bool executable () const {return type == otype::e || !utility;}
+ bool library () const {return type != otype::e || utility;}
+ bool static_library () const {return type == otype::a || utility;}
+ bool shared_library () const {return type == otype::s && !utility;}
+ };
+
// Compile target types.
//
struct compile_target_types
@@ -72,6 +83,14 @@ namespace build2
// Library link order.
//
enum class lorder {a, s, a_s, s_a};
+
+ // Link information: output type and link order.
+ //
+ struct linfo
+ {
+ otype type;
+ lorder order;
+ };
}
}
diff --git a/build2/cc/utility.cxx b/build2/cc/utility.cxx
index 7a03b54..fa5061e 100644
--- a/build2/cc/utility.cxx
+++ b/build2/cc/utility.cxx
@@ -39,34 +39,50 @@ namespace build2
}
const target&
- link_member (const bin::lib& l, action a, lorder lo)
+ link_member (const bin::libx& x, action a, linfo li)
{
- // Make sure group members are resolved.
- //
- group_view gv (resolve_group_members (a, l));
- assert (gv.members != nullptr);
-
- bool ls (true);
- switch (lo)
+ if (const libu* u = x.is_a<libu> ())
{
- case lorder::a:
- case lorder::a_s:
- ls = false; // Fall through.
- case lorder::s:
- case lorder::s_a:
+ 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);
+ }
+ else
+ {
+ const lib& l (x.as<lib> ());
+
+ // Make sure group members are resolved.
+ //
+ group_view gv (resolve_group_members (a, l));
+ assert (gv.members != nullptr);
+
+ lorder lo (li.order);
+
+ bool ls (true);
+ switch (lo)
{
- if (ls ? l.s == nullptr : l.a == nullptr)
+ case lorder::a:
+ case lorder::a_s:
+ ls = false; // Fall through.
+ case lorder::s:
+ case lorder::s_a:
{
- if (lo == lorder::a_s || lo == lorder::s_a)
- ls = !ls;
- else
- fail << (ls ? "shared" : "static") << " variant of " << l
- << " is not available";
+ if (ls ? l.s == nullptr : l.a == nullptr)
+ {
+ if (lo == lorder::a_s || lo == lorder::s_a)
+ ls = !ls;
+ else
+ fail << (ls ? "shared" : "static") << " variant of " << l
+ << " is not available";
+ }
}
}
- }
- return *(ls ? static_cast<const target*> (l.s) : l.a);
+ return *(ls ? static_cast<const target*> (l.s) : l.a);
+ }
}
}
}
diff --git a/build2/cc/utility.hxx b/build2/cc/utility.hxx
index 895d9c5..2f6834f 100644
--- a/build2/cc/utility.hxx
+++ b/build2/cc/utility.hxx
@@ -29,7 +29,7 @@ namespace build2
// Link output type.
//
- otype
+ ltype
link_type (const target&);
// Library link order.
@@ -44,10 +44,17 @@ namespace build2
lorder
link_order (const scope& base, otype);
- // Given the link order return the library member (liba or libs) to link.
+ inline linfo
+ link_info (const scope& base, otype ot)
+ {
+ return linfo {ot, link_order (base, ot)};
+ }
+
+ // Given the link order return the library member to link. That is, liba{}
+ // or libs{} for lib{} and libue{}, libua{} or libus{} for libu{}.
//
const target&
- link_member (const bin::lib&, action, lorder);
+ link_member (const bin::libx&, action, linfo);
}
}
diff --git a/build2/cc/utility.ixx b/build2/cc/utility.ixx
index d372dac..d13a0ff 100644
--- a/build2/cc/utility.ixx
+++ b/build2/cc/utility.ixx
@@ -17,15 +17,19 @@ namespace build2
otype::s;
}
- inline otype
+ inline ltype
link_type (const target& t)
{
using namespace bin;
- return
- t.is_a<exe> () ? otype::e :
- t.is_a<liba> () ? otype::a :
- otype::s;
+ bool u (false);
+ otype o (
+ t.is_a<exe> () || (u = t.is_a<libue> ()) ? otype::e :
+ t.is_a<liba> () || (u = t.is_a<libua> ()) ? otype::a :
+ t.is_a<libs> () || (u = t.is_a<libus> ()) ? otype::s :
+ static_cast<otype> (0xFF));
+
+ return ltype {o, u};
}
inline compile_target_types
diff --git a/build2/cc/windows-rpath.cxx b/build2/cc/windows-rpath.cxx
index 450a0f5..1fc195a 100644
--- a/build2/cc/windows-rpath.cxx
+++ b/build2/cc/windows-rpath.cxx
@@ -49,7 +49,7 @@ namespace build2
windows_rpath_timestamp (const file& t,
const scope& bs,
action act,
- lorder lo) const
+ linfo li) const
{
timestamp r (timestamp_nonexistent);
@@ -109,7 +109,7 @@ namespace build2
if ((f = a = pt->is_a<liba> ()) ||
(f = pt->is_a<libs> ()))
- process_libraries (act, bs, lo, sys_lib_dirs,
+ process_libraries (act, bs, li, sys_lib_dirs,
*f, a != nullptr,
imp, lib, nullptr, true);
}
@@ -124,7 +124,7 @@ namespace build2
windows_rpath_dlls (const file& t,
const scope& bs,
action act,
- lorder lo) const -> windows_dlls
+ linfo li) const -> windows_dlls
{
windows_dlls r;
@@ -191,7 +191,7 @@ namespace build2
if ((f = a = pt->is_a<liba> ()) ||
(f = pt->is_a<libs> ()))
- process_libraries (act, bs, lo, sys_lib_dirs,
+ process_libraries (act, bs, li, sys_lib_dirs,
*f, a != nullptr,
imp, lib, nullptr, true);
}
@@ -214,7 +214,7 @@ namespace build2
windows_rpath_assembly (const file& t,
const scope& bs,
action act,
- lorder lo,
+ linfo li,
const string& tcpu,
timestamp ts,
bool scratch) const
@@ -251,7 +251,7 @@ namespace build2
windows_dlls dlls;
if (!empty)
- dlls = windows_rpath_dlls (t, bs, act, lo);
+ dlls = windows_rpath_dlls (t, bs, act, li);
// Clean the assembly directory and make sure it exists. Maybe it would
// have been faster to overwrite the existing manifest rather than
diff --git a/tests/cc/libu/buildfile b/tests/cc/libu/buildfile
new file mode 100644
index 0000000..104a645
--- /dev/null
+++ b/tests/cc/libu/buildfile
@@ -0,0 +1,8 @@
+# file : tests/cc/libu/buildfile
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+# Test utility library support.
+#
+
+./: test{testscript} $b
diff --git a/tests/cc/libu/testscript b/tests/cc/libu/testscript
new file mode 100644
index 0000000..454a443
--- /dev/null
+++ b/tests/cc/libu/testscript
@@ -0,0 +1,54 @@
+# file : tests/cc/libu/testscript
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+crosstest = false
+test.arguments = config.cxx="$recall($cxx.path)"
+
+.include ../../common.test
+
++cat <<EOI >=build/root.build
+cxx.std = latest
+
+using cxx
+
+hxx{*}: extension = hxx
+cxx{*}: extension = cxx
+EOI
+
+# Common source files that are symlinked in the test directories if used.
+#
++cat <<EOI >=foo.hxx
+ #ifndef LIBFOO_EXPORT
+ # define LIBFOO_EXPORT
+ #endif
+
+ LIBFOO_EXPORT void f ();
+ EOI
+
++cat <<EOI >=foo.cxx
+ void f () {}
+ EOI
+
++cat <<EOI >=driver.cxx
+ #include <foo.hxx>
+ int main () {f ();}
+ EOI
+
+: members
+:
+: Test building individual libuX{} members.
+:
+ln -s ../foo.hxx ../foo.cxx ../driver.cxx ./;
+$* update clean <<EOI
+ cc.poptions += "-I$src_base"
+
+ # {exe liba libs}{foo}
+ ./: {exe}{foo}
+
+ exe{foo}: cxx{driver} libue{foo}
+ liba{foo}: libua{foo}
+ libs{foo}: libus{foo}
+
+ libu{foo}: cxx{foo}
+ EOI