From a9f355062690eba4942f789ca3420c9c319ce901 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 6 May 2021 14:19:45 +0200 Subject: See through utility libraries when looking for module interfaces --- libbuild2/cc/compile-rule.cxx | 109 +++++++++++++++++++++++------------------- libbuild2/cc/pkgconfig.cxx | 100 +++++++++++++++++++++----------------- 2 files changed, 117 insertions(+), 92 deletions(-) diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index 40fb5bb..f8529fb 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -5651,6 +5651,66 @@ namespace build2 return r; }; + // Find the module in prerequisite targets of a library (recursively) + // seeing through libu*{}. Note: sets the `done` flag. See similar + // logic in pkgconfig_save(). + // + auto find = [a, &bs, this, + &check_exact, &done] (const file& l, + const auto& find) -> void + { + for (const target* pt: l.prerequisite_targets[a]) + { + if (pt == nullptr) + continue; + + // Note that here we (try) to use whatever flavor of bmi*{} is + // available. + // + // @@ MOD: BMI compatibility check. + // + if (pt->is_a ()) + { + const string& n (cast (pt->state[a].vars[c_module_name])); + + if (const target** p = check_exact (n)) + *p = pt; + } + else if (pt->is_a (*x_mod)) + { + // This is an installed library with a list of module sources (the + // source are specified as prerequisites but the fallback file + // rule puts them into prerequisite_targets for us). + // + // The module names should be specified but if not assume + // something else is going on and ignore. + // + // Note also that besides modules, prerequisite_targets may + // contain libraries which are interface dependencies of this + // library and which may be called to resolve its module + // dependencies. + // + const string* n (cast_null (pt->vars[c_module_name])); + + if (n == nullptr) + continue; + + if (const target** p = check_exact (*n)) + *p = &this->make_module_sidebuild (a, bs, l, *pt, *n); // GCC 4.9 + } + // Note that in prerequisite targets we will have the libux{} + // members, not the group. + // + else if (const libux* pl = pt->is_a ()) + find (*pl, find); + else + continue; + + if (done) + break; + } + }; + for (prerequisite_member p: group_prerequisite_members (a, t)) { if (include (a, t, p) != include_type::normal) // Excluded/ad hoc. @@ -5671,54 +5731,7 @@ namespace build2 // if (lt != nullptr) { - for (const target* bt: lt->prerequisite_targets[a]) - { - if (bt == nullptr) - continue; - - // Note that here we (try) to use whatever flavor of bmi*{} is - // available. - // - // @@ MOD: BMI compatibility check. - // @@ UTL: we need to (recursively) see through libu*{} (and - // also in pkgconfig_save()). - // - if (bt->is_a ()) - { - const string& n ( - cast (bt->state[a].vars[c_module_name])); - - if (const target** p = check_exact (n)) - *p = bt; - } - else if (bt->is_a (*x_mod)) - { - // This is an installed library with a list of module sources - // (the source are specified as prerequisites but the fallback - // file rule puts them into prerequisite_targets for us). - // - // The module names should be specified but if not assume - // something else is going on and ignore. - // - // Note also that besides modules, prerequisite_targets may - // contain libraries which are interface dependencies of this - // library and which may be called to resolve its module - // dependencies. - // - const string* n (cast_null (bt->vars[c_module_name])); - - if (n == nullptr) - continue; - - if (const target** p = check_exact (*n)) - *p = &make_module_sidebuild (a, bs, *lt, *bt, *n); - } - else - continue; - - if (done) - break; - } + find (*lt, find); if (done) break; diff --git a/libbuild2/cc/pkgconfig.cxx b/libbuild2/cc/pkgconfig.cxx index a70e9a2..fd88b59 100644 --- a/libbuild2/cc/pkgconfig.cxx +++ b/libbuild2/cc/pkgconfig.cxx @@ -1715,66 +1715,78 @@ namespace build2 vector x_hdrs; vector c_hdrs; + // We need to (recursively) see through libu*{}. See similar logic + // in search_modules(). + // // Note that the prerequisite targets are in the member, not the // group (for now we don't support different sets of modules/headers // for static/shared library; see load above for details). // - for (const target* pt: l.prerequisite_targets[a]) + auto collect = [a, this, + &mods, + &x_hdrs, &c_hdrs] (const target& l, + const auto& collect) -> void { - if (pt == nullptr) - continue; - - // @@ UTL: we need to (recursively) see through libu*{} (and - // also in search_modules()). - // - if (modules && pt->is_a ()) + for (const target* pt: l.prerequisite_targets[a]) { - // What we have is a binary module interface. What we need is - // a module interface source it was built from. We assume it's - // the first mxx{} target that we see. - // - const target* mt (nullptr); - for (const target* t: pt->prerequisite_targets[a]) + if (pt == nullptr) + continue; + + if (modules && pt->is_a ()) { - if ((mt = t->is_a (*x_mod))) - break; - } + // What we have is a binary module interface. What we need is + // a module interface source it was built from. We assume it's + // the first mxx{} target that we see. + // + const target* mt (nullptr); + for (const target* t: pt->prerequisite_targets[a]) + { + if ((mt = t->is_a (*x_mod))) + break; + } - // Can/should there be a bmi{} without mxx{}? Can't think of a - // reason. - // - assert (mt != nullptr); + // Can/should there be a bmi{} without mxx{}? Can't think of a + // reason. + // + assert (mt != nullptr); - path p (install::resolve_file (mt->as ())); + path p (install::resolve_file (mt->as ())); - if (p.empty ()) // Not installed. - continue; + if (p.empty ()) // Not installed. + continue; - string pp; - if (const string* v = cast_null ((*mt)[x_preprocessed])) - pp = *v; - - mods.push_back ( - module { - cast (pt->state[a].vars[c_module_name]), - move (p), - move (pp), - symexport - }); - } - else if (pt->is_a (**x_hdr) || pt->is_a ()) - { - if (cast_false ((*pt)[c_importable])) + string pp; + if (const string* v = cast_null ((*mt)[x_preprocessed])) + pp = *v; + + mods.push_back ( + module { + cast (pt->state[a].vars[c_module_name]), + move (p), + move (pp), + symexport}); + } + else if (pt->is_a (**x_hdr) || pt->is_a ()) { - path p (install::resolve_file (pt->as ())); + if (cast_false ((*pt)[c_importable])) + { + path p (install::resolve_file (pt->as ())); - if (p.empty ()) // Not installed. - continue; + if (p.empty ()) // Not installed. + continue; - (pt->is_a () ? c_hdrs : x_hdrs).push_back (move (p)); + (pt->is_a () ? c_hdrs : x_hdrs).push_back (move (p)); + } } + // Note that in prerequisite targets we will have the libux{} + // members, not the group. + // + else if (pt->is_a ()) + collect (*pt, collect); } - } + }; + + collect (l, collect); if (size_t n = mods.size ()) { -- cgit v1.1