From 68a27c5bca208337f5749fe1959ac21c062b77fb Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 30 Nov 2023 12:17:31 +0200 Subject: Search in src for existing prerequisites with unspecified out --- libbuild2/algorithm.cxx | 12 ++++-------- libbuild2/cc/compile-rule.cxx | 6 +++--- libbuild2/search.cxx | 32 ++++++++++++++++++++++++++++---- libbuild2/search.hxx | 7 ++++++- libbuild2/target.cxx | 24 +++++++++++++++++------- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index 1bb46d8..71bf134 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -96,7 +96,7 @@ namespace build2 { return pk.proj ? import_existing (ctx, pk) - : search_existing_target (ctx, pk); + : search_existing_target (ctx, pk, false /*out_only*/); // @@ TODO } const target& @@ -104,7 +104,7 @@ namespace build2 { assert (ctx.phase == run_phase::load || ctx.phase == run_phase::match); - if (const target* pt = search_existing_target (ctx, pk)) + if (const target* pt = search_existing_target (ctx, pk, true /*out_only*/)) return *pt; return create_new_target (ctx, pk); @@ -115,7 +115,7 @@ namespace build2 { assert (ctx.phase == run_phase::load || ctx.phase == run_phase::match); - if (const target* pt = search_existing_target (ctx, pk)) + if (const target* pt = search_existing_target (ctx, pk, true /*out_only*/)) return {const_cast (*pt), ulock ()}; return create_new_target_locked (ctx, pk); @@ -176,16 +176,12 @@ namespace build2 } bool q (cn.qualified ()); - - // @@ OUT: for now we assume the prerequisite's out is undetermined. - // Would need to pass a pair of names. - // prerequisite_key pk { n.proj, {tt, &n.dir, q ? &empty_dir_path : &out, &n.value, ext}, &s}; return q ? import_existing (s.ctx, pk) - : search_existing_target (s.ctx, pk); + : search_existing_target (s.ctx, pk, false /*out_only*/); // @@ TODO } const target* diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index bbdc851..3b37cad 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -6262,9 +6262,9 @@ namespace build2 // target (which means the name can only be specified on the // target itself, not target type/pattern-spec). // - const target* t (p.search_existing ()); - const string* n (t != nullptr - ? cast_null (t->vars[c_module_name]) + const target* mt (p.search_existing ()); + const string* n (mt != nullptr + ? cast_null (mt->vars[c_module_name]) : nullptr); if (n != nullptr) { diff --git a/libbuild2/search.cxx b/libbuild2/search.cxx index 3bdb503..dee2ae8 100644 --- a/libbuild2/search.cxx +++ b/libbuild2/search.cxx @@ -15,7 +15,9 @@ using namespace butl; namespace build2 { const target* - search_existing_target (context& ctx, const prerequisite_key& pk) + search_existing_target (context& ctx, + const prerequisite_key& pk, + bool out_only) { tracer trace ("search_existing_target"); @@ -39,9 +41,10 @@ namespace build2 // Prerequisite's out directory can be one of the following: // - // empty This means out is undetermined and we simply search for a - // target that is in the out tree which happens to be indicated - // by an empty value, so we can just pass this as is. + // empty This means out is undetermined and we search for a target + // first in the out tree (which happens to be indicated by an + // empty value, so we can just pass this as is) and if not + // found, then in the src tree (unless suppressed). // // absolute This is the "final" value that doesn't require any processing // and we simply use it as is. @@ -74,6 +77,27 @@ namespace build2 const target* t ( ctx.targets.find (*tk.type, d, o, *tk.name, tk.ext, trace)); + // Try in the src tree. + // + if (t == nullptr && + !out_only && + tk.out->empty () && + tk.dir->relative () && + !pk.scope->out_eq_src ()) + { + o = move (d); + + d = pk.scope->src_path (); + + if (!tk.dir->empty ()) + { + d /= *tk.dir; + d.normalize (); + } + + t = ctx.targets.find (*tk.type, d, o, *tk.name, tk.ext, trace); + } + if (t != nullptr) l5 ([&]{trace << "existing target " << *t << " for prerequisite " << pk;}); diff --git a/libbuild2/search.hxx b/libbuild2/search.hxx index aa30648..e3b1442 100644 --- a/libbuild2/search.hxx +++ b/libbuild2/search.hxx @@ -15,8 +15,13 @@ namespace build2 // Search for an existing target in this prerequisite's scope. Scope can be // NULL if directories are absolute. // + // If dir is relative and out is not specified, then first search in the out + // tree and, if not found, then in the src tree, unless out_only is true. + // If dir is absolute, then out is expected to be specified as well, if + // necessary. + // LIBBUILD2_SYMEXPORT const target* - search_existing_target (context&, const prerequisite_key&); + search_existing_target (context&, const prerequisite_key&, bool out_only); // Search for an existing file. If the prerequisite directory is relative, // then look in the scope's src directory. Otherwise, if the absolute diff --git a/libbuild2/target.cxx b/libbuild2/target.cxx index bef7dce..1d21c07 100644 --- a/libbuild2/target.cxx +++ b/libbuild2/target.cxx @@ -1166,15 +1166,21 @@ namespace build2 // The default behavior is to look for an existing target in the // prerequisite's directory scope. // - return search_existing_target (t.ctx, pk); + // Note that it would be reasonable to assume that such a target can only + // be found in the out tree (targets that can be in the src tree should + // use file_search()). But omitting the src search will make it hard to + // keep search() (which calls this) and search_existing() (which does not) + // consistent. + // + return search_existing_target (t.ctx, pk, false /* out_only */); } const target* file_search (const target& t, const prerequisite_key& pk) { - // First see if there is an existing target. + // First see if there is an existing target in the out or src tree. // - if (const target* e = search_existing_target (t.ctx, pk)) + if (const target* e = search_existing_target (t.ctx, pk, false /*out_only*/)) return e; // Then look for an existing file in the src tree. @@ -1335,7 +1341,9 @@ namespace build2 // is pull its prerequisites. And they are handy to use as metadata // carriers. // - const target* e (search_existing_target (t.ctx, pk)); + // Doesn't feel like an alias in the src tree makes much sense. + // + const target* e (search_existing_target (t.ctx, pk, true /* out_only */)); if (e == nullptr || !(operator>= (e->decl, target_decl::implied))) fail << "no explicit target for " << pk; @@ -1451,7 +1459,9 @@ namespace build2 // The first step is like in alias_search(): looks for an existing target // (but unlike alias, no implied, think `test/: install=false`). // - const target* e (search_existing_target (t.ctx, pk)); + // Likewise, dir{} in the src tree doesn't make much sense. + // + const target* e (search_existing_target (t.ctx, pk, true /* out_only */)); if (e != nullptr && e->decl == target_decl::real) return e; @@ -1500,7 +1510,7 @@ namespace build2 // phase. // if (e == nullptr) - e = search_existing_target (t.ctx, pk); + e = search_existing_target (t.ctx, pk, true); if (e != nullptr && e->decl == target_decl::real) retest = true; @@ -1545,7 +1555,7 @@ namespace build2 if (retest) { if (e == nullptr) - e = search_existing_target (t.ctx, pk); + e = search_existing_target (t.ctx, pk, true); if (e != nullptr && e->decl == target_decl::real) return e; -- cgit v1.1