From 44d3acdb065205f5fd69834a75b472721bea5443 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 13 May 2020 08:24:25 +0200 Subject: Support for cleaning up recipe builds --- libbuild2/cc/init.cxx | 6 +++--- libbuild2/parser.cxx | 43 ++++++++++++++++++++++++++++++++++++++++++- libbuild2/rule.cxx | 33 +++++++++++++++++++++++++++++++-- libbuild2/rule.hxx | 7 +++++++ 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/libbuild2/cc/init.cxx b/libbuild2/cc/init.cxx index 2a0dbd2..07051c5 100644 --- a/libbuild2/cc/init.cxx +++ b/libbuild2/cc/init.cxx @@ -142,9 +142,9 @@ namespace build2 // Register scope operation callback. // - // It feels natural to do clean up sidebuilds as a post operation but - // that prevents the (otherwise-empty) out root directory to be cleaned - // up (via the standard fsdir{} chain). + // It feels natural to clean up sidebuilds as a post operation but that + // prevents the (otherwise-empty) out root directory to be cleaned up + // (via the standard fsdir{} chain). // rs.operation_callbacks.emplace ( perform_clean_id, diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index db95297..8d6beea 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -1021,9 +1021,12 @@ namespace build2 // ... // }} // - // enter: percent or openining multi-curly-brace + // enter: start is percent or openining multi-curly-brace // leave: token past newline after last closing multi-curly-brace + if (stage_ == stage::boot) + fail (t) << "ad hoc recipe specified during bootstrap"; + // If we have a recipe, the target is not implied. // if (target_->implied) @@ -1035,6 +1038,10 @@ namespace build2 default_target_ = target_; } + // True if seen a recipe that requires cleanup. + // + bool clean (false); + for (token st (start);; st = t) { optional diag; @@ -1113,12 +1120,17 @@ namespace build2 location loc (get_location (st)); if (!lang) + { ar.reset (new adhoc_script_rule (move (t.value), move (diag), loc, st.value.size ())); + } else if (*lang == "c++") + { ar.reset (new adhoc_cxx_rule (move (t.value), loc, st.value.size ())); + clean = true; + } else fail (lloc) << "unknown recipe language '" << *lang << "'"; @@ -1134,6 +1146,35 @@ namespace build2 if (tt != type::percent && tt != type::multi_lcbrace) break; } + + // If we have a recipe that needs cleanup, register an operation callback + // for this project unless it has already been done. + // + if (clean) + { + action a (perform_id, clean_id); + auto f (&adhoc_rule::clean_recipes_build); + + // First check if we have already done this. + // + auto p (root_->operation_callbacks.equal_range (a)); + for (; p.first != p.second; ++p.first) + { + auto t ( + p.first->second.pre.target ()); + + if (t != nullptr && *t == f) + break; + } + + // It feels natural to clean up recipe builds as a post operation but + // that prevents the (otherwise-empty) out root directory to be cleaned + // up (via the standard fsdir{} chain). + // + if (p.first == p.second) + root_->operation_callbacks.emplace ( + a, scope::operation_callback {f, nullptr /*post*/}); + } } void parser:: diff --git a/libbuild2/rule.cxx b/libbuild2/rule.cxx index 98b4458..7286c63 100644 --- a/libbuild2/rule.cxx +++ b/libbuild2/rule.cxx @@ -305,6 +305,8 @@ namespace build2 // adhoc_rule // + const dir_path adhoc_rule::recipes_build_dir ("recipes.out"); + bool adhoc_rule:: match (action a, target& t, const string& h, optional fallback) const { @@ -317,6 +319,35 @@ namespace build2 return true; } + // Scope operation callback that cleans up recipe builds. + // + target_state adhoc_rule:: + clean_recipes_build (action, const scope& rs, const dir&) + { + context& ctx (rs.ctx); + + const dir_path& out_root (rs.out_path ()); + + dir_path d (out_root / rs.root_extra->build_dir / recipes_build_dir); + + if (exists (d)) + { + if (rmdir_r (ctx, d)) + { + // Clean up build/ if it also became empty (e.g., in case of a build + // with a transient configuration). + // + d = out_root / rs.root_extra->build_dir; + if (empty (d)) + rmdir (ctx, d); + + return target_state::changed; + } + } + + return target_state::unchanged; + } + // adhoc_script_rule // void adhoc_script_rule:: @@ -572,8 +603,6 @@ namespace build2 << ind << string (braces, '}'); } - static const dir_path recipes_build_dir ("recipes.out"); - // From module.cxx. // void diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx index 69be2cc..ca17f2e 100644 --- a/libbuild2/rule.hxx +++ b/libbuild2/rule.hxx @@ -144,6 +144,13 @@ namespace build2 // public: build2::rule_match rule_match; + + static const dir_path recipes_build_dir; + + // Scope operation callback that cleans up ad hoc recipe builds. + // + static target_state + clean_recipes_build (action, const scope&, const dir&); }; // Ad hoc script rule. -- cgit v1.1