From b6dfd0e94aad546069eee7749a0b78eda45f6a78 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 7 Sep 2022 10:56:46 +0200 Subject: Fix fsdir{} handling corner cases in ad hoc buildscript recipes/rules --- libbuild2/adhoc-rule-buildscript.cxx | 34 +++++++++++++++++++++++++++++++--- libbuild2/algorithm.cxx | 4 ++-- libbuild2/algorithm.hxx | 10 +++++----- libbuild2/rule.cxx | 2 +- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx index 9a38a31..c5eaa60 100644 --- a/libbuild2/adhoc-rule-buildscript.cxx +++ b/libbuild2/adhoc-rule-buildscript.cxx @@ -325,7 +325,11 @@ namespace build2 // We do it always instead of only if one of the targets is path-based in // case the recipe creates temporary files or some such. // - const fsdir* dir (inject_fsdir (a, xt)); + // Note that we disable the prerequisite search for fsdir{} because of the + // prerequisites injected by the pattern. So we have to handle this ad hoc + // below. + // + const fsdir* dir (inject_fsdir (a, xt, false /* prereq */)); // Match prerequisites. // @@ -382,6 +386,9 @@ namespace build2 const target& pt (p.search (xt)); + if (&pt == dir) // Don't add injected fsdir{} twice. + continue; + if (clean && !pt.in (*bs.root_scope ())) continue; @@ -405,7 +412,7 @@ namespace build2 for (const prerequisite_target& pt: pts) { - if (pt.target == dir) + if (pt.target == dir) // Don't match injected fsdir{} twice. continue; match_async (a, *pt.target, ctx.count_busy (), xt[a].task_count); @@ -417,7 +424,7 @@ namespace build2 // for (prerequisite_target& pt: pts) { - if (pt.target == dir) + if (pt.target == dir) // See above. continue; // Handle update=unmatch. @@ -525,6 +532,27 @@ namespace build2 file& t (xt.as ()); const path& tp (t.path ()); + // Re-acquire fsdir{} specified by the user, similar to inject_fsdir() + // (which we have disabled; see above). + // + if (dir == nullptr) + { + for (const target* pt: pts) + { + if (pt != nullptr) + { + if (const fsdir* dt = pt->is_a ()) + { + if (dt->dir == t.dir) + { + dir = dt; + break; + } + } + } + } + } + if (dir != nullptr) fsdir_rule::perform_update_direct (a, t); diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index e2873fb..fcff50e 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -1291,7 +1291,7 @@ namespace build2 } const fsdir* - inject_fsdir (action a, target& t, bool parent) + inject_fsdir (action a, target& t, bool prereq, bool parent) { tracer trace ("inject_fsdir"); @@ -1320,7 +1320,7 @@ namespace build2 // r = &search (t, d, dir_path (), string (), nullptr, nullptr); } - else + else if (prereq) { // See if one was mentioned explicitly. // diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx index 0f981a9..b7f6809 100644 --- a/libbuild2/algorithm.hxx +++ b/libbuild2/algorithm.hxx @@ -546,13 +546,13 @@ namespace build2 // the injected target or NULL. Normally this function is called from the // rule's apply() function. // - // As an extension, this function will also search for an existing fsdir{} - // prerequisite for the directory and if one exists, return that (even if - // the target is in src tree). This can be used, for example, to place - // output into an otherwise non-existent directory. + // As an extension, unless prereq is false, this function will also search + // for an existing fsdir{} prerequisite for the directory and if one exists, + // return that (even if the target is in src tree). This can be used, for + // example, to place output into an otherwise non-existent directory. // LIBBUILD2_SYMEXPORT const fsdir* - inject_fsdir (action, target&, bool parent = true); + inject_fsdir (action, target&, bool prereq = true, bool parent = true); // Execute the action on target, assuming a rule has been matched and the // recipe for this action has been set. This is the synchrounous executor diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index 6ede2dd..210f1ef 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -195,7 +195,7 @@ namespace build2 // Inject dependency on our directory (note: not parent) so that it is // automatically created on update and removed on clean. // - inject_fsdir (a, t, false); + inject_fsdir (a, t, true, false); match_prerequisites (a, t); return default_recipe; -- cgit v1.1