aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-05-06 09:57:03 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-05-06 09:57:03 +0200
commit17305d124705d9ab8cd89d1355f4ec6aacbf540a (patch)
tree23a8a96ed3a735f107038e4b85de977ec1e79b18
parent272dbd99d21591b694ba608f8daea75806d5fcbc (diff)
Propagate complete match rules from utility libraries in link rule
This makes sure mixed-language (e.g., C and C++) utility libraries behave as expected.
-rw-r--r--libbuild2/cc/link-rule.cxx152
-rw-r--r--libbuild2/cc/link-rule.hxx10
2 files changed, 82 insertions, 80 deletions
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index b4175d6..96e243d 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -73,17 +73,17 @@ namespace build2
// Header-only X library (or library with C source and X header).
(library && x_header (p, false /* c_hdr */)))
{
- r.seen_x = r.seen_x || true;
+ r.seen_x = true;
}
else if (p.is_a<c> () ||
// Header-only C library.
(library && p.is_a<h> ()))
{
- r.seen_c = r.seen_c || true;
+ r.seen_c = true;
}
else if (p.is_a<obj> () || p.is_a<bmi> ())
{
- r.seen_obj = r.seen_obj || true;
+ r.seen_obj = true;
}
else if (p.is_a<obje> () || p.is_a<bmie> ())
{
@@ -92,116 +92,108 @@ namespace build2
if (ot != otype::e)
fail << p.type ().name << "{} as prerequisite of " << t;
- r.seen_obj = r.seen_obj || true;
+ r.seen_obj = true;
}
else if (p.is_a<obja> () || p.is_a<bmia> ())
{
if (ot != otype::a)
fail << p.type ().name << "{} as prerequisite of " << t;
- r.seen_obj = r.seen_obj || true;
+ r.seen_obj = true;
}
else if (p.is_a<objs> () || p.is_a<bmis> ())
{
if (ot != otype::s)
fail << p.type ().name << "{} as prerequisite of " << t;
- r.seen_obj = r.seen_obj || true;
+ r.seen_obj = true;
}
else if (p.is_a<libul> () || p.is_a<libux> ())
{
// For a unility library we look at its prerequisites, recursively.
- // Since these checks are not exactly light-weight, only do them if
- // we haven't already seen any X prerequisites.
- //
- if (!r.seen_x)
- {
- // This is a bit iffy: in our model a rule can only search a
- // target's prerequisites if it matches. But we don't yet know
- // whether we match. However, it seems correct to assume that any
- // rule-specific search will always resolve to an existing target
- // if there is one. So perhaps it's time to relax this restriction
- // a little? Note that this fits particularly well with what we
- // doing here since if there is no existing target, then there can
- // be no prerequisites.
- //
- // Note, however, that we cannot link-up a prerequisite target
- // member to its group since we are not matching this target. As
- // result we have to do all the steps except for setting t.group
- // and pass both member and group (we also cannot query t.group
- // since it's racy).
- //
- const target* pg (nullptr);
- const target* pt (p.search_existing ());
+ //
+ // This is a bit iffy: in our model a rule can only search a
+ // target's prerequisites if it matches. But we don't yet know
+ // whether we match. However, it seems correct to assume that any
+ // rule-specific search will always resolve to an existing target if
+ // there is one. So perhaps it's time to relax this restriction a
+ // little? Note that this fits particularly well with what we are
+ // doing here since if there is no existing target, then there can
+ // be no prerequisites.
+ //
+ // Note, however, that we cannot link-up a prerequisite target
+ // member to its group since we are not matching this target. As
+ // result we have to do all the steps except for setting t.group and
+ // pass both member and group (we also cannot query t.group since
+ // it's racy).
+ //
+ const target* pg (nullptr);
+ const target* pt (p.search_existing ());
- if (p.is_a<libul> ())
+ if (p.is_a<libul> ())
+ {
+ if (pt != nullptr)
{
- if (pt != nullptr)
- {
- // If this is a group then try to pick (again, if exists) a
- // suitable member. If it doesn't exist, then we will only be
- // considering the group's prerequisites.
- //
- if (const target* pm =
- link_member (pt->as<libul> (),
- a,
- linfo {ot, lorder::a /* unused */},
- true /* existing */))
- {
- pg = pt;
- pt = pm;
- }
- }
- else
+ // If this is a group then try to pick (again, if exists) a
+ // suitable member. If it doesn't exist, then we will only be
+ // considering the group's prerequisites.
+ //
+ if (const target* pm =
+ link_member (pt->as<libul> (),
+ a,
+ linfo {ot, lorder::a /* unused */},
+ true /* existing */))
{
- // It's possible we have no group but have a member so try
- // that.
- //
- const target_type& tt (ot == otype::a ? libua::static_type :
- ot == otype::s ? libus::static_type :
- libue::static_type);
-
- // We know this prerequisite member is a prerequisite since
- // otherwise the above search would have returned the member
- // target.
- //
- pt = search_existing (t.ctx, p.prerequisite.key (tt));
+ pg = pt;
+ pt = pm;
}
}
- else if (!p.is_a<libue> ())
+ else
{
- // See if we also/instead have a group.
+ // It's possible we have no group but have a member so try that.
//
- pg = search_existing (t.ctx,
- p.prerequisite.key (libul::static_type));
+ const target_type& tt (ot == otype::a ? libua::static_type :
+ ot == otype::s ? libus::static_type :
+ libue::static_type);
- if (pt == nullptr)
- swap (pt, pg);
+ // We know this prerequisite member is a prerequisite since
+ // otherwise the above search would have returned the member
+ // target.
+ //
+ pt = search_existing (t.ctx, p.prerequisite.key (tt));
}
+ }
+ else if (!p.is_a<libue> ())
+ {
+ // See if we also/instead have a group.
+ //
+ pg = search_existing (t.ctx,
+ p.prerequisite.key (libul::static_type));
- if (pt != nullptr)
- {
- // If we are matching a target, use the original output type
- // since that would be the member that we pick.
- //
- otype pot (pt->is_a<libul> () ? ot : link_type (*pt).type);
- match_result pr (match (a, *pt, pg, pot, true /* lib */));
+ if (pt == nullptr)
+ swap (pt, pg);
+ }
- // Do we need to propagate any other seen_* values? Hm, that
- // would in fact match with the "see-through" semantics of
- // utility libraries we have in other places.
- //
- r.seen_x = pr.seen_x;
- }
- else
- r.seen_lib = r.seen_lib || true; // Consider as just a library.
+ if (pt != nullptr)
+ {
+ // If we are matching a target, use the original output type since
+ // that would be the member that we pick.
+ //
+ otype pot (pt->is_a<libul> () ? ot : link_type (*pt).type);
+
+ // Propagate values according to the "see-through" semantics of
+ // utility libraries.
+ //
+ r |= match (a, *pt, pg, pot, true /* lib */);
}
+ else
+ r.seen_lib = true; // Consider as just a library.
}
else if (p.is_a<lib> () ||
p.is_a<liba> () ||
p.is_a<libs> ())
{
- r.seen_lib = r.seen_lib || true;
+ r.seen_lib = true;
}
// Some other c-common header/source (say C++ in a C rule) other than
// a C header (we assume everyone can hanle that).
diff --git a/libbuild2/cc/link-rule.hxx b/libbuild2/cc/link-rule.hxx
index 33a4f1c..c49d20f 100644
--- a/libbuild2/cc/link-rule.hxx
+++ b/libbuild2/cc/link-rule.hxx
@@ -32,6 +32,16 @@ namespace build2
bool seen_cc = false;
bool seen_obj = false;
bool seen_lib = false;
+
+ match_result& operator|= (match_result y)
+ {
+ seen_x = seen_x || y.seen_x;
+ seen_c = seen_c || y.seen_c;
+ seen_cc = seen_cc || y.seen_cc;
+ seen_obj = seen_obj || y.seen_obj;
+ seen_lib = seen_lib || y.seen_lib;
+ return *this;
+ }
};
match_result