aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-06-24 05:44:37 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-06-24 05:44:37 +0200
commit7c57f2a85aa520db784a36ced65ec5c832dbfbc8 (patch)
treedd99be01f18303868d9c5158feb2230fdc7c12bb
parent52128dcc2d88a262238c07fe8acdbcfad684035c (diff)
Add ability to get common interface options via $x.lib_poptions()
Specifically, the output target type may now be omitted for utility libraries (libul{} and libu[eas]{}). In this case, only "common interface" options will be returned for lib{} dependencies. This is primarily useful for obtaining poptions to be passed to tools other than C/C++ compilers (for example, Qt moc).
-rw-r--r--libbuild2/cc/common.cxx80
-rw-r--r--libbuild2/cc/common.hxx6
-rw-r--r--libbuild2/cc/compile-rule.cxx35
-rw-r--r--libbuild2/cc/compile-rule.hxx4
-rw-r--r--libbuild2/cc/functions.cxx77
-rw-r--r--libbuild2/cc/link-rule.cxx15
-rw-r--r--libbuild2/cc/pkgconfig.cxx10
-rw-r--r--libbuild2/cc/windows-rpath.cxx8
8 files changed, 169 insertions, 66 deletions
diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx
index cd89c79..976127f 100644
--- a/libbuild2/cc/common.cxx
+++ b/libbuild2/cc/common.cxx
@@ -39,6 +39,11 @@ namespace build2
// 3. dependency libs (prerequisite_targets, left to right, depth-first)
// 4. dependency libs (*.libs variables).
//
+ // If proc_opt_group is true, then pass to proc_opt the group rather than
+ // the member if a member was picked (according to linfo) form a group.
+ // This is useful when we only want to see the common options set on the
+ // group.
+ //
// If either proc_opt or proc_lib return false, then any further
// processing of this library or its dependencies is skipped. This can be
// used to "prune" the graph traversal in case of duplicates. Note that
@@ -72,10 +77,14 @@ namespace build2
// not to pick the liba/libs{} member for installed libraries instead
// passing the lib{} group itself. This can be used to match the semantics
// of file_rule which, when matching prerequisites, does not pick the
- // liba/libs{} member (naturally) but just matches the lib{} group.
+ // liba/libs{} member (naturally) but just matches the lib{} group. Note
+ // that currently this truly only works for installed lib{} since non-
+ // installed ones don't have cc.type set. See proc_opt_group for an
+ // alternative way to (potentially) achieve the desired semantics.
//
// Note that if top_li is present, then the target passed to proc_impl,
- // proc_lib, and proc_opt is always a file.
+ // proc_lib, and proc_opt (unless proc_opt_group is true) is always a
+ // file.
//
// The dedup argument is part of the interface dependency deduplication
// functionality, similar to $x.deduplicate_export_libs(). Note, however,
@@ -87,7 +96,7 @@ namespace build2
const scope& top_bs,
optional<linfo> top_li,
const dir_paths& top_sysd,
- const mtime_target& l, // liba/libs{} or lib{}
+ const mtime_target& l, // liba/libs{}, libux{}, or lib{}
bool la,
lflags lf,
const function<bool (const target&,
@@ -102,7 +111,8 @@ namespace build2
const string& lang, // lang from cc.type
bool com, // cc. or x.
bool exp)>& proc_opt, // *.export.
- bool self /*= false*/, // Call proc_lib on l?
+ bool self, // Call proc_lib on l?
+ bool proc_opt_group, // Call proc_opt on group instead of member?
library_cache* cache) const
{
library_cache cache_storage;
@@ -115,8 +125,9 @@ namespace build2
chain.push_back (nullptr);
process_libraries_impl (a, top_bs, top_li, top_sysd,
- l, la, lf,
- proc_impl, proc_lib, proc_opt, self,
+ nullptr, l, la, lf,
+ proc_impl, proc_lib, proc_opt,
+ self, proc_opt_group,
cache, &chain, nullptr);
}
@@ -126,6 +137,7 @@ namespace build2
const scope& top_bs,
optional<linfo> top_li,
const dir_paths& top_sysd,
+ const target* lg,
const mtime_target& l,
bool la,
lflags lf,
@@ -142,6 +154,7 @@ namespace build2
bool com,
bool exp)>& proc_opt,
bool self,
+ bool proc_opt_group,
library_cache* cache,
small_vector<const target*, 32>* chain,
small_vector<const target*, 32>* dedup) const
@@ -237,12 +250,14 @@ namespace build2
//
if (proc_opt)
{
+ const target& ol (proc_opt_group && lg != nullptr ? *lg : l);
+
// If all we know is it's a C-common library, then in both cases
// we only look for cc.export.*.
//
if (cc)
{
- if (!proc_opt (l, t, true, true)) break;
+ if (!proc_opt (ol, t, true, true)) break;
}
else
{
@@ -259,24 +274,24 @@ namespace build2
//
// Note: options come from *.export.* variables.
//
- if (!proc_opt (l, t, false, true) ||
- !proc_opt (l, t, true, true)) break;
+ if (!proc_opt (ol, t, false, true) ||
+ !proc_opt (ol, t, true, true)) break;
}
else
{
// For default export we use the same options as were used
// to build the library.
//
- if (!proc_opt (l, t, false, false) ||
- !proc_opt (l, t, true, false)) break;
+ if (!proc_opt (ol, t, false, false) ||
+ !proc_opt (ol, t, true, false)) break;
}
}
else
{
// Interface: only add *.export.* (interface dependencies).
//
- if (!proc_opt (l, t, false, true) ||
- !proc_opt (l, t, true, true)) break;
+ if (!proc_opt (ol, t, false, true) ||
+ !proc_opt (ol, t, true, true)) break;
}
}
}
@@ -380,12 +395,17 @@ namespace build2
(la = (f = pt->is_a<libux> ())) ||
( f = pt->is_a<libs> ()))
{
+ // See link_rule for details.
+ //
+ const target* g ((pt.include & 4) != 0 ? f->group : nullptr);
+
if (sysd == nullptr) find_sysd ();
if (!li) find_linfo ();
process_libraries_impl (a, bs, *li, *sysd,
- *f, la, pt.data,
- proc_impl, proc_lib, proc_opt, true,
+ g, *f, la, pt.data,
+ proc_impl, proc_lib, proc_opt,
+ true /* self */, proc_opt_group,
cache, chain, nullptr);
}
}
@@ -480,7 +500,7 @@ namespace build2
return make_pair (n, s);
};
- auto proc_intf = [&l, cache, chain,
+ auto proc_intf = [&l, proc_opt_group, cache, chain,
&proc_impl, &proc_lib, &proc_lib_name, &proc_opt,
&sysd, &usrd,
&find_sysd, &find_linfo, &sense_fragment,
@@ -530,7 +550,7 @@ namespace build2
if (sysd == nullptr) find_sysd ();
if (!li) find_linfo ();
- const mtime_target& t (
+ pair<const mtime_target&, const target*> p (
resolve_library (a,
bs,
n,
@@ -539,6 +559,9 @@ namespace build2
*sysd, usrd,
cache));
+ const mtime_target& t (p.first);
+ const target* g (p.second);
+
// Deduplicate.
//
// Note that dedup_start makes sure we only consider our
@@ -599,8 +622,9 @@ namespace build2
//
process_libraries_impl (
a, bs, *li, *sysd,
- t, t.is_a<liba> () || t.is_a<libux> (), 0,
- proc_impl, proc_lib, proc_opt, true,
+ g, t, t.is_a<liba> () || t.is_a<libux> (), 0,
+ proc_impl, proc_lib, proc_opt,
+ true /* self */, proc_opt_group,
cache, chain, dedup);
}
@@ -746,9 +770,10 @@ namespace build2
//
// If li is absent, then don't pick the liba/libs{} member, returning the
// lib{} target itself. If li is present, then the returned target is
- // always a file.
+ // always a file. The second half of the returned pair is the group, if
+ // the member was picked.
//
- const mtime_target& common::
+ pair<const mtime_target&, const target*> common::
resolve_library (action a,
const scope& s,
const name& cn,
@@ -769,7 +794,8 @@ namespace build2
// large number of times (see Boost for an extreme example of this).
//
// Note also that for non-utility libraries we know that only the link
- // order from linfo is used.
+ // order from linfo is used. While not caching it and always picking an
+ // alternative could also work, we cache it to avoid the lookup.
//
if (cache != nullptr)
{
@@ -789,7 +815,7 @@ namespace build2
}));
if (i != cache->end ())
- return i->lib;
+ return pair<const mtime_target&, const target*> {i->lib, i->group};
}
else
cache = nullptr; // Do not cache.
@@ -831,18 +857,22 @@ namespace build2
// If this is lib{}/libul{}, pick appropriate member unless we were
// instructed not to.
//
+ const target* g (nullptr);
if (li)
{
if (const libx* l = xt->is_a<libx> ())
+ {
+ g = xt;
xt = link_member (*l, a, *li); // Pick lib*{e,a,s}{}.
+ }
}
auto& t (xt->as<mtime_target> ());
if (cache != nullptr)
- cache->push_back (library_cache_entry {lo, cn.type, cn.value, t});
+ cache->push_back (library_cache_entry {lo, cn.type, cn.value, t, g});
- return t;
+ return pair<const mtime_target&, const target*> {t, g};
}
// Note that pk's scope should not be NULL (even if dir is absolute).
diff --git a/libbuild2/cc/common.hxx b/libbuild2/cc/common.hxx
index 1e74b22..a5a4859 100644
--- a/libbuild2/cc/common.hxx
+++ b/libbuild2/cc/common.hxx
@@ -300,6 +300,7 @@ namespace build2
string type; // name::type
string value; // name::value
reference_wrapper<const mtime_target> lib;
+ const target* group;
};
using library_cache = small_vector<library_cache_entry, 32>;
@@ -319,6 +320,7 @@ namespace build2
lflags, const string*, bool)>&,
const function<bool (const target&, const string&, bool, bool)>&,
bool = false,
+ bool = false,
library_cache* = nullptr) const;
void
@@ -327,6 +329,7 @@ namespace build2
const scope&,
optional<linfo>,
const dir_paths&,
+ const target*,
const mtime_target&,
bool,
lflags,
@@ -336,6 +339,7 @@ namespace build2
lflags, const string*, bool)>&,
const function<bool (const target&, const string&, bool, bool)>&,
bool,
+ bool,
library_cache*,
small_vector<const target*, 32>*,
small_vector<const target*, 32>*) const;
@@ -365,7 +369,7 @@ namespace build2
}
public:
- const mtime_target&
+ pair<const mtime_target&, const target*>
resolve_library (action,
const scope&,
const name&,
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index f5d50ec..7059f15 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -489,13 +489,16 @@ namespace build2
// Append or hash library options from a pair of *.export.* variables
// (first is x.* then cc.*) recursively, prerequisite libraries first.
+ // If common is true, then only append common options from the lib{}
+ // groups.
//
template <typename T>
void compile_rule::
append_library_options (appended_libraries& ls, T& args,
const scope& bs,
const scope* is, // Internal scope.
- action a, const file& l, bool la, linfo li,
+ action a, const file& l, bool la,
+ linfo li, bool common,
library_cache* lib_cache) const
{
struct data
@@ -509,7 +512,7 @@ namespace build2
//
auto imp = [] (const target& l, bool la) {return la && l.is_a<libux> ();};
- auto opt = [&d, this] (const target& lt,
+ auto opt = [&d, this] (const target& l, // Note: could be lib{}
const string& t, bool com, bool exp)
{
// Note that in our model *.export.poptions are always "interface",
@@ -518,8 +521,6 @@ namespace build2
if (!exp) // Ignore libux.
return true;
- const file& l (lt.as<file> ());
-
// Suppress duplicates.
//
// Compilation is the simple case: we can add the options on the first
@@ -678,16 +679,24 @@ namespace build2
process_libraries (a, bs, li, sys_lib_dirs,
l, la, 0, // lflags unused.
- imp, nullptr, opt, false /* self */, lib_cache);
+ imp, nullptr, opt,
+ false /* self */,
+ common /* proc_opt_group */,
+ lib_cache);
}
void compile_rule::
append_library_options (appended_libraries& ls, strings& args,
const scope& bs,
- action a, const file& l, bool la, linfo li) const
+ action a, const file& l, bool la,
+ linfo li,
+ bool common) const
{
+ // @@ Is this a good idea? We don't know which tool will be using
+ // these...
+ //
const scope* is (isystem (*this) ? effective_iscope (bs) : nullptr);
- append_library_options (ls, args, bs, is, a, l, la, li, nullptr);
+ append_library_options (ls, args, bs, is, a, l, la, li, common, nullptr);
}
template <typename T>
@@ -728,7 +737,9 @@ namespace build2
append_library_options (ls,
args,
bs, iscope (),
- a, *f, la, li,
+ a, *f, la,
+ li,
+ false /* common */,
&lc);
}
}
@@ -810,7 +821,9 @@ namespace build2
process_libraries (a, bs, li, sys_lib_dirs,
pt->as<file> (), la, 0, // lflags unused.
- impf, nullptr, optf, false /* self */,
+ impf, nullptr, optf,
+ false /* self */,
+ false /* proc_opt_group */,
&lib_cache);
}
}
@@ -6222,7 +6235,9 @@ namespace build2
//
process_libraries (a, bs, nullopt, sys_lib_dirs,
*f, la, 0, // lflags unused.
- imp, lib, nullptr, true /* self */,
+ imp, lib, nullptr,
+ true /* self */,
+ false /* proc_opt_group */,
&lib_cache);
if (lt != nullptr)
diff --git a/libbuild2/cc/compile-rule.hxx b/libbuild2/cc/compile-rule.hxx
index 49d33eb..f3e4a9b 100644
--- a/libbuild2/cc/compile-rule.hxx
+++ b/libbuild2/cc/compile-rule.hxx
@@ -66,7 +66,7 @@ namespace build2
void
append_library_options (appended_libraries&, strings&,
const scope&,
- action, const file&, bool, linfo) const;
+ action, const file&, bool, linfo, bool) const;
optional<path>
find_system_header (const path&) const;
@@ -87,7 +87,7 @@ namespace build2
append_library_options (appended_libraries&, T&,
const scope&,
const scope*,
- action, const file&, bool, linfo,
+ action, const file&, bool, linfo, bool,
library_cache*) const;
template <typename T>
diff --git a/libbuild2/cc/functions.cxx b/libbuild2/cc/functions.cxx
index 9b7a3d9..a0a0b4f 100644
--- a/libbuild2/cc/functions.cxx
+++ b/libbuild2/cc/functions.cxx
@@ -85,14 +85,26 @@ namespace build2
return value (move (r));
}
- // Common thunk for $x.lib_*(<targets>, <otype> [, ...]) functions.
+ // Common thunk for $x.lib_*(...) functions.
+ //
+ // The two supported function signatures are:
+ //
+ // $x.lib_*(<targets>, <otype> [, ...]])
+ //
+ // $x.lib_*(<targets>)
+ //
+ // For the first signature, the passed targets cannot be library groups
+ // (so they are always file-based) and linfo is always present.
+ //
+ // For the second signature, targets can only be utility libraries
+ // (including the libul{} group).
//
struct lib_thunk_data
{
const char* x;
void (*f) (void*, strings&,
const vector_view<value>&, const module&, const scope&,
- action, const file&, bool, linfo);
+ action, const target&, bool, optional<linfo>);
};
static value
@@ -120,13 +132,15 @@ namespace build2
if (m == nullptr)
fail << f.name << " called without " << d.x << " module loaded";
- // We can assume these are present due to function's types signature.
+ // We can assume this is present due to function's types signature.
//
names& ts_ns (vs[0].as<names> ()); // <targets>
- names& ot_ns (vs[1].as<names> ()); // <otype>
- linfo li;
+ optional<linfo> li;
+ if (vs.size () > 1)
{
+ names& ot_ns (vs[1].as<names> ()); // <otype>
+
string t (convert<string> (move (ot_ns)));
const target_type* tt (bs->find_target_type (t));
@@ -172,21 +186,22 @@ namespace build2
name& n (*i), o;
const target& t (to_target (*bs, move (n), move (n.pair ? *++i : o)));
- const file* f;
bool la (false);
-
- if ((la = (f = t.is_a<libux> ())) ||
- (la = (f = t.is_a<liba> ())) ||
- ( (f = t.is_a<libs> ())))
+ if (li
+ ? ((la = t.is_a<libux> ()) ||
+ (la = t.is_a<liba> ()) ||
+ ( t.is_a<libs> ()))
+ : ((la = t.is_a<libux> ()) ||
+ ( t.is_a<libul> ())))
{
if (!t.matched (a))
fail << t << " is not matched" <<
info << "make sure this target is listed as prerequisite";
- d.f (ls, r, vs, *m, *bs, a, *f, la, li);
+ d.f (ls, r, vs, *m, *bs, a, t, la, li);
}
else
- fail << t << " is not a library target";
+ fail << t << " is not a library of expected type";
}
return value (move (r));
@@ -213,12 +228,18 @@ namespace build2
void compile_rule::
functions (function_family& f, const char* x)
{
- // $<module>.lib_poptions(<lib-targets>, <otype>)
+ // $<module>.lib_poptions(<lib-targets>[, <otype>])
//
// Return the preprocessor options that should be passed when compiling
// sources that depend on the specified libraries. The second argument
// is the output target type (obje, objs, etc).
//
+ // The output target type may be omitted for utility libraries (libul{}
+ // or libu[eas]{}). In this case, only "common interface" options will
+ // be returned for lib{} dependencies. This is primarily useful for
+ // obtaining poptions to be passed to tools other than C/C++ compilers
+ // (for example, Qt moc).
+ //
// Note that passing multiple targets at once is not a mere convenience:
// this also allows for more effective duplicate suppression.
//
@@ -230,17 +251,31 @@ namespace build2
// Note that this function is not pure.
//
f.insert (".lib_poptions", false).
- insert<lib_thunk_data, names, names> (
+ insert<lib_thunk_data, names, optional<names>> (
&lib_thunk<appended_libraries>,
lib_thunk_data {
x,
[] (void* ls, strings& r,
const vector_view<value>&, const module& m, const scope& bs,
- action a, const file& l, bool la, linfo li)
+ action a, const target& l, bool la, optional<linfo> li)
{
+ // If this is libul{}, get the matched member (see bin::libul_rule
+ // for details).
+ //
+ const file& f (
+ la || li
+ ? l.as<file> ()
+ : (la = true,
+ l.prerequisite_targets[a].back ().target->as<file> ()));
+
+ bool common (!li);
+
+ if (!li)
+ li = link_info (bs, link_type (f).type);
+
m.append_library_options (
*static_cast<appended_libraries*> (ls), r,
- bs, a, l, la, li);
+ bs, a, f, la, *li, common);
}});
// $<module>.find_system_header(<name>)
@@ -318,7 +353,7 @@ namespace build2
x,
[] (void* ls, strings& r,
const vector_view<value>& vs, const module& m, const scope& bs,
- action a, const file& l, bool la, linfo li)
+ action a, const target& l, bool la, optional<linfo> li)
{
lflags lf (0);
bool rel (true);
@@ -342,7 +377,8 @@ namespace build2
m.append_libraries (
*static_cast<appended_libraries*> (ls), r,
nullptr /* sha256 */, nullptr /* update */, timestamp_unknown,
- bs, a, l, la, lf, li, nullopt /* for_install */, self, rel);
+ bs, a, l.as<file> (), la, lf, *li,
+ nullopt /* for_install */, self, rel);
}});
// $<module>.lib_rpaths(<lib-targets>, <otype> [, <link> [, <self>]])
@@ -374,13 +410,12 @@ namespace build2
x,
[] (void* ls, strings& r,
const vector_view<value>& vs, const module& m, const scope& bs,
- action a, const file& l, bool la, linfo li)
+ action a, const target& l, bool la, optional<linfo> li)
{
bool link (vs.size () > 2 ? convert<bool> (vs[2]) : false);
bool self (vs.size () > 3 ? convert<bool> (vs[3]) : true);
m.rpath_libraries (*static_cast<rpathed_libraries*> (ls), r,
- bs,
- a, l, la, li, link, self);
+ bs, a, l.as<file> (), la, *li, link, self);
}});
// $cxx.obj_modules(<obj-targets>)
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index fff8716..0081fe2 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -1138,10 +1138,14 @@ namespace build2
m = 3; // Mark so it is not matched.
// If this is the lib{}/libul{} group, then pick the appropriate
- // member.
+ // member. Also note this in prerequisite_target::include (used
+ // by process_libraries()).
//
if (const libx* l = pt->is_a<libx> ())
+ {
pt = link_member (*l, a, li);
+ pto.include |= 4;
+ }
}
else
{
@@ -2360,7 +2364,9 @@ namespace build2
process_libraries (a, bs, li, sys_lib_dirs,
l, la,
- lf, imp, lib, opt, self,
+ lf, imp, lib, opt,
+ self,
+ false /* proc_opt_group */,
lib_cache);
}
@@ -2574,7 +2580,10 @@ namespace build2
process_libraries (a, bs, li, sys_lib_dirs,
l, la, 0 /* lflags */,
- imp, lib, nullptr, false /* self */, lib_cache);
+ imp, lib, nullptr,
+ false /* self */,
+ false /* proc_opt_group */,
+ lib_cache);
}
void link_rule::
diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx
index a48d99c..1fd96da 100644
--- a/libbuild2/cc/pkgconfig.cxx
+++ b/libbuild2/cc/pkgconfig.cxx
@@ -1967,7 +1967,10 @@ namespace build2
library_cache lib_cache;
process_libraries (a, bs, li, sys_lib_dirs,
l, la, 0, // Link flags.
- imp, lib, opt, !binless /* self */, &lib_cache);
+ imp, lib, opt,
+ !binless /* self */,
+ false /* proc_opt_group */, // @@ !priv?
+ &lib_cache);
for (const string& a: args)
os << ' ' << a;
@@ -1989,7 +1992,10 @@ namespace build2
process_libraries (a, bs, li, sys_lib_dirs,
l, la, 0, // Link flags.
- imp, lib, opt, false /* self */, &lib_cache);
+ imp, lib, opt,
+ false /* self */,
+ false /* proc_opt_group */, // @@ !priv?
+ &lib_cache);
for (const string& a: args)
os << ' ' << a;
diff --git a/libbuild2/cc/windows-rpath.cxx b/libbuild2/cc/windows-rpath.cxx
index a8bf104..9387078 100644
--- a/libbuild2/cc/windows-rpath.cxx
+++ b/libbuild2/cc/windows-rpath.cxx
@@ -139,7 +139,9 @@ namespace build2
( f = pt->is_a<libs> ()))
process_libraries (a, bs, li, sys_lib_dirs,
*f, la, pt.data,
- imp, lib, nullptr, true /* self */,
+ imp, lib, nullptr,
+ true /* self */,
+ false /* proc_opt_group */,
&lib_cache);
}
@@ -264,7 +266,9 @@ namespace build2
( f = pt->is_a<libs> ()))
process_libraries (a, bs, li, sys_lib_dirs,
*f, la, pt.data,
- imp, lib, nullptr, true /* self */,
+ imp, lib, nullptr,
+ true /* self */,
+ false /* proc_opt_group */,
&lib_cache);
}