From cf6b3e34b59ad120111e0c1ead779bbb3a70c38d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 12 Mar 2015 15:43:17 +0200 Subject: Implement clean operation --- build/cxx/rule | 16 +++++------ build/cxx/rule.cxx | 84 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 71 insertions(+), 29 deletions(-) (limited to 'build/cxx') diff --git a/build/cxx/rule b/build/cxx/rule index 1dfb8b5..d2378d2 100644 --- a/build/cxx/rule +++ b/build/cxx/rule @@ -17,36 +17,36 @@ namespace build namespace cxx { // @@ Can't we do match(obj&) and then registration code extracts - // that. And no virtuals. + // that. And no virtuals? // class compile: public rule { public: virtual void* - match (action a, target&, const std::string& hint) const; + match (action, target&, const std::string& hint) const; virtual recipe - apply (action a, target&, void*) const; + apply (action, target&, void*) const; static target_state - update (action a, target&); + perform_update (action, target&); private: void - inject_prerequisites (action a, obj&, const cxx&, scope&) const; + inject_prerequisites (action, obj&, const cxx&, scope&) const; }; class link: public rule { public: virtual void* - match (action a, target&, const std::string& hint) const; + match (action, target&, const std::string& hint) const; virtual recipe - apply (action a, target&, void*) const; + apply (action, target&, void*) const; static target_state - update (action a, target&); + perform_update (action, target&); }; } } diff --git a/build/cxx/rule.cxx b/build/cxx/rule.cxx index 4c93a1a..649067e 100644 --- a/build/cxx/rule.cxx +++ b/build/cxx/rule.cxx @@ -69,17 +69,34 @@ namespace build // Search and match all the existing prerequisites. The injection // code (below) takes care of the ones it is adding. // - search_and_match (a, t); + // When cleaning, ignore prerequisites that are not in the same + // or a subdirectory of ours. + // + switch (a.operation ()) + { + case update_id: search_and_match (a, t); break; + case clean_id: search_and_match (a, t, t.dir); break; + default: assert (false); + } - // Inject additional prerequisites. + // Inject additional prerequisites. For now we only do it for + // update. // - auto& sp (*static_cast (v)); - auto& st (dynamic_cast (*sp.target)); + if (a.operation () == update_id) + { + auto& sp (*static_cast (v)); + auto& st (dynamic_cast (*sp.target)); - if (st.mtime () != timestamp_nonexistent) - inject_prerequisites (a, o, st, sp.scope); + if (st.mtime () != timestamp_nonexistent) + inject_prerequisites (a, o, st, sp.scope); + } - return &update; + switch (a) + { + case perform_update_id: return &perform_update; + case perform_clean_id: return &perform_clean_file; + default: return noop_recipe; + } } // Return the next make prerequisite starting from the specified @@ -215,9 +232,7 @@ namespace build // Resolve to target. // - path_target& t ( - dynamic_cast ( - p.target != nullptr ? *p.target : search (p))); + path_target& t (dynamic_cast (search (p))); // Assign path. // @@ -251,7 +266,7 @@ namespace build } target_state compile:: - update (action a, target& t) + perform_update (action a, target& t) { obj& o (dynamic_cast (t)); cxx* s (execute_prerequisites (a, o, o.mtime ())); @@ -359,7 +374,7 @@ namespace build } // We will only chain a C source if there is also a C++ source or we - // we explicitly told to. + // were explicitly told to. // if (seen_c && !seen_cxx && hint < "cxx") { @@ -397,10 +412,15 @@ namespace build if (p.type.id != typeid (c) && p.type.id != typeid (cxx)) { - if (p.target == nullptr) - search (p); + // The same logic as in search_and_match(). + // + target& pt (search (p)); + + if (a.operation () == clean_id && !pt.dir.sub (e.dir)) + p.target = nullptr; // Ignore. + else + build::match (a, pt); - build::match (a, *p.target); continue; } @@ -449,6 +469,26 @@ namespace build // target& ot (search (op)); + // If we are cleaning, check that this target is in the same or + // a subdirectory of ours. + // + // If it is not, then we are effectively leaving the prerequisites + // half-rewritten (we only rewrite those that we should clean). + // What will happen if, say, after clean we have update? Well, + // update will come and finish the rewrite process (it will even + // reuse op that we have created but then ignored). So all is good. + // + if (a.operation () == clean_id && !ot.dir.sub (e.dir)) + { + // If we shouldn't clean obj{}, then it is fair to assume + // we shouldn't clean cxx{} either (generated source will + // be in the same directory as obj{} and if not, well, go + // and find yourself another build system). + // + p.target = nullptr; // Skip. + continue; + } + // If this target already exists, then it needs to be "compatible" // with what we are doing here. // @@ -461,7 +501,6 @@ namespace build // work out, then we fail, in which case searching and matching // speculatively doesn't really hurt. // - // prerequisite* cp1 (nullptr); for (prerequisite& p: ot.prerequisites) { @@ -488,9 +527,7 @@ namespace build if (cp1 != nullptr) { build::match (a, ot); // Now cp1 should be resolved. - - if (cp.target == nullptr) - search (cp); // Our own prerequisite, so this is ok. + search (cp); // Our own prerequisite, so this is ok. if (cp.target != cp1->target) fail << "synthesized target for prerequisite " << cp @@ -510,11 +547,16 @@ namespace build pr = op; } - return &update; + switch (a) + { + case perform_update_id: return &perform_update; + case perform_clean_id: return &perform_clean_file; + default: return noop_recipe; + } } target_state link:: - update (action a, target& t) + perform_update (action a, target& t) { // @@ Q: // -- cgit v1.1