From 54512574c11b196173d432baa3fc13f04095539a Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 17 Aug 2022 10:00:55 +0200 Subject: Handle another "in *.export.libs but not in prerequisites" case Also, enable this check even if proc_lib is not specified unless in the execute phase. --- libbuild2/cc/common.cxx | 118 ++++++++++++++++++++++++++++-------------------- libbuild2/cc/common.hxx | 5 ++ libbuild2/cc/common.txx | 4 +- 3 files changed, 78 insertions(+), 49 deletions(-) diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx index 3c4e38d..ded2902 100644 --- a/libbuild2/cc/common.cxx +++ b/libbuild2/cc/common.cxx @@ -552,65 +552,85 @@ namespace build2 if (sysd == nullptr) find_sysd (); if (!li) find_linfo (); - pair p ( - resolve_library (a, + const mtime_target* t; + const target* g; + + const char* w (nullptr); + try + { + pair p ( + resolve_library (a, bs, - n, - (n.pair ? (++i)->dir : dir_path ()), - *li, - *sysd, usrd, - cache)); + n, + (n.pair ? (++i)->dir : dir_path ()), + *li, + *sysd, usrd, + cache)); - const mtime_target& t (p.first); - const target* g (p.second); + t = &p.first; + g = p.second; - // Deduplicate. - // - // Note that dedup_start makes sure we only consider our - // interface dependencies while maintaining the "through" - // list. - // - if (dedup != nullptr) - { - if (find (dedup->begin () + dedup_start, - dedup->end (), - &t) != dedup->end ()) + // Deduplicate. + // + // Note that dedup_start makes sure we only consider our + // interface dependencies while maintaining the "through" + // list. + // + if (dedup != nullptr) { - ++i; - continue; + if (find (dedup->begin () + dedup_start, + dedup->end (), + t) != dedup->end ()) + { + ++i; + continue; + } + + dedup->push_back (t); } - - dedup->push_back (&t); } - - if (proc_lib) + catch (const non_existent_library& e) { - // This can happen if the target is mentioned in - // *.export.libs (i.e., it is an interface dependency) but - // not in the library's prerequisites (i.e., it is not an - // implementation dependency). + // This is another manifestation of the "mentioned in + // *.export.libs but not in prerequisites" case (see below). // - // Note that we used to just check for path being assigned - // but on Windows import-installed DLLs may legally have - // empty paths. + t = &e.target; + w = "unknown"; + } + + // This can happen if the target is mentioned in *.export.libs + // (i.e., it is an interface dependency) but not in the + // library's prerequisites (i.e., it is not an implementation + // dependency). + // + // Note that we used to just check for path being assigned but + // on Windows import-installed DLLs may legally have empty + // paths. + // + if (w != nullptr) + ; // See above. + else if (l.ctx.phase == run_phase::match) + { + if (!t->matched (a)) + w = "not matched"; + } + else if (proc_lib) + { + // Note that this check we only do if there is proc_lib + // (since it's valid to process library's options before + // updating it). // - const char* w (nullptr); - if (t.ctx.phase == run_phase::match) - { - if (!t.matched (a)) - w = "not matched"; - } - else if (t.mtime () == timestamp_unknown) + if (t->mtime () == timestamp_unknown) w = "out of date"; - - if (w != nullptr) - fail << (impl ? "implementation" : "interface") - << " dependency " << t << " is " << w << - info << "mentioned in *.export." << (impl ? "impl_" : "") - << "libs of target " << l << - info << "is it a prerequisite of " << l << "?"; } + if (w != nullptr) + fail << (impl ? "implementation" : "interface") + << " dependency " << *t << " is " << w << + info << "mentioned in *.export." << (impl ? "impl_" : "") + << "libs of target " << l << + info << "is it a prerequisite of " << l << "?"; + // Process it recursively. // // @@ Where can we get the link flags? Should we try to find @@ -619,7 +639,7 @@ namespace build2 // process_libraries_impl ( a, bs, *li, *sysd, - g, t, t.is_a () || t.is_a (), 0, + g, *t, t->is_a () || t->is_a (), 0, proc_impl, proc_lib, proc_opt, true /* self */, proc_opt_group, cache, chain, dedup); @@ -770,6 +790,8 @@ namespace build2 // always a file. The second half of the returned pair is the group, if // the member was picked. // + // Note: may throw non_existent_library. + // pair common:: resolve_library (action a, const scope& s, diff --git a/libbuild2/cc/common.hxx b/libbuild2/cc/common.hxx index 9c276f7..c11fa7a 100644 --- a/libbuild2/cc/common.hxx +++ b/libbuild2/cc/common.hxx @@ -384,6 +384,11 @@ namespace build2 optional&, library_cache* = nullptr) const; + struct non_existent_library + { + const mtime_target& target; + }; + template static ulock insert_library (context&, diff --git a/libbuild2/cc/common.txx b/libbuild2/cc/common.txx index d14f966..f55072c 100644 --- a/libbuild2/cc/common.txx +++ b/libbuild2/cc/common.txx @@ -27,7 +27,9 @@ namespace build2 target_decl::implied, trace)); - assert (!exist || !p.second); + if (exist && p.second) + throw non_existent_library {p.first.template as ()}; + r = &p.first.template as (); return move (p.second); } -- cgit v1.1