diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2018-06-29 10:39:26 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2018-06-29 10:39:26 +0200 |
commit | 50e1ffc8f9c48e3e81bd5fa38381193942182df3 (patch) | |
tree | befd6198abbbfbee98c2d87f48bb06b667941415 | |
parent | 67b17701d5b1753dc6aaf5a63a4dc2ef2642ba83 (diff) |
Use depdb to track changes to cli compiler, options, etc
-rw-r--r-- | build2/algorithm.cxx | 29 | ||||
-rw-r--r-- | build2/algorithm.hxx | 6 | ||||
-rw-r--r-- | build2/cli/init.cxx | 33 | ||||
-rw-r--r-- | build2/cli/rule.cxx | 77 |
4 files changed, 123 insertions, 22 deletions
diff --git a/build2/algorithm.cxx b/build2/algorithm.cxx index 5dc3637..c46e878 100644 --- a/build2/algorithm.cxx +++ b/build2/algorithm.cxx @@ -2056,4 +2056,33 @@ namespace build2 r |= reverse_execute_prerequisites (a, g); return r; } + + target_state + perform_clean_group_depdb (action a, const target& g) + { + // The same twisted target state merging logic as in clean_extra(). + // + target_state er (target_state::unchanged); + path ep; + + group_view gv (g.group_members (a)); + if (gv.count != 0) + { + ep = gv.members[0]->as<file> ().path () + ".d"; + + if (rmfile (ep, 3)) + er = target_state::changed; + } + + target_state tr (perform_clean_group (a, g)); + + if (tr != target_state::changed && er == target_state::changed) + { + if (verb > (current_diag_noise ? 0 : 1) && verb < 3) + text << "rm " << ep; + } + + tr |= er; + return tr; + } } diff --git a/build2/algorithm.hxx b/build2/algorithm.hxx index 48f48c8..93fe131 100644 --- a/build2/algorithm.hxx +++ b/build2/algorithm.hxx @@ -616,6 +616,12 @@ namespace build2 target_state perform_clean_group (action, const target&); + // As above but clean both the target group and depdb. The depdb file path + // is derived from the first member file path. + // + target_state + perform_clean_group_depdb (action, const target&); + // Helper for custom perform(clean) implementations that cleans extra files // and directories (recursively) specified as a list of either absolute // paths or "path derivation directives". The directive string can be NULL, diff --git a/build2/cli/init.cxx b/build2/cli/init.cxx index 88a8d69..8e0abdb 100644 --- a/build2/cli/init.cxx +++ b/build2/cli/init.cxx @@ -53,7 +53,11 @@ namespace build2 v.insert<path> ("config.cli", true); v.insert<strings> ("config.cli.options", true); + //@@ TODO: split version into componets (it is stdver). + // v.insert<process_path> ("cli.path"); + v.insert<string> ("cli.version"); + v.insert<string> ("cli.checksum"); v.insert<strings> ("cli.options"); } @@ -214,11 +218,23 @@ namespace build2 nv = p.second; } - // Note that we are unconfigured so that we don't keep re-testing this - // on each run. - // - if (!conf) + string checksum; + if (conf) + { + // Hash the compiler path and version. + // + sha256 cs; + cs.append (pp.effect_string ()); + cs.append (ver); + checksum = cs.string (); + } + else + { + // Note that we are unconfigured so that we don't keep re-testing + // this on each run. + // nv = config::unconfigured (rs, "cli", true) || nv; + } // If this is a new value (e.g., we are configuring), then print the // report at verbosity level 2 and up (-v). @@ -230,13 +246,18 @@ namespace build2 if (conf) dr << " cli " << pp << '\n' - << " version " << ver; + << " version " << ver << '\n' + << " checksum " << checksum; else dr << " cli " << "not found, leaving unconfigured"; } if (conf) - rs.assign<process_path> ("cli.path") = move (pp); + { + rs.assign ("cli.path") = move (pp); + rs.assign ("cli.version") = move (ver); + rs.assign ("cli.checksum") = move (checksum); + } } if (conf) diff --git a/build2/cli/rule.cxx b/build2/cli/rule.cxx index 45b8185..27668c1 100644 --- a/build2/cli/rule.cxx +++ b/build2/cli/rule.cxx @@ -4,6 +4,7 @@ #include <build2/cli/rule.hxx> +#include <build2/depdb.hxx> #include <build2/scope.hxx> #include <build2/target.hxx> #include <build2/context.hxx> @@ -166,10 +167,12 @@ namespace build2 // match_prerequisite_members (a, t); + //@@ TODO: inject dependency on exe{cli}. + switch (a) { case perform_update_id: return &perform_update; - case perform_clean_id: return &perform_clean_group; // Standard impl. + case perform_clean_id: return &perform_clean_group_depdb; default: return noop_recipe; // Configure/dist update. } } @@ -206,34 +209,76 @@ namespace build2 target_state compile_rule:: perform_update (action a, const target& xt) { + tracer trace ("cli::compile_rule::perform_update"); + + // The rule has been matched which means the members should be resolved + // and paths assigned. We use the header file as our "target path" for + // timestamp, depdb, etc. + // const cli_cxx& t (xt.as<cli_cxx> ()); + const scope& rs (t.root_scope ()); + const path& tp (t.h->path ()); // Update prerequisites and determine if any relevant ones render us - // out-of-date. Note that currently we treat all the prerequisites - // as potentially affecting the result (think prologues/epilogues, - // etc). + // out-of-date. Note that currently we treat all the prerequisites as + // potentially affecting the result (think prologues/epilogues, etc). // + timestamp mt (t.load_mtime (tp)); + auto pr (execute_prerequisites<cli> (a, t, mt)); - // The rule has been matched which means the members should be resolved - // and paths assigned. + bool update (!pr.first); + target_state ts (update ? target_state::changed : *pr.first); + + const cli& s (pr.second); + + // We use depdb to track changes to the .cli file name, options, + // compiler, etc. // - auto pr ( - execute_prerequisites<cli> ( - a, t, t.load_mtime (t.h->path ()))); + { + depdb dd (tp + ".d"); - if (pr.first) - return *pr.first; + // First should come the rule name/version. + // + if (dd.expect ("cli.compile 1") != nullptr) + l4 ([&]{trace << "rule mismatch forcing update of " << t;}); - const cli& s (pr.second); + // Then the compiler checksum. + // + if (dd.expect (cast<string> (rs["cli.checksum"])) != nullptr) + l4 ([&]{trace << "compiler mismatch forcing update of " << t;}); - // Translate paths to relative (to working directory). This - // results in easier to read diagnostics. + // Then the options checksum. + // + sha256 cs; + hash_options (cs, t, "cli.options"); + + if (dd.expect (cs.string ()) != nullptr) + l4 ([&]{trace << "options mismatch forcing update of " << t;}); + + // Finally the .cli input file. + // + if (dd.expect (s.path ()) != nullptr) + l4 ([&]{trace << "input file mismatch forcing update of " << t;}); + + // Update if depdb mismatch. + // + if (dd.writing () || dd.mtime () > mt) + update = true; + + dd.close (); + } + + // If nothing changed, then we are done. + // + if (!update) + return ts; + + // Translate paths to relative (to working directory). This results in + // easier to read diagnostics. // path relo (relative (t.dir)); path rels (relative (s.path ())); - const scope& rs (t.root_scope ()); - const process_path& cli (cast<process_path> (rs["cli.path"])); cstrings args {cli.recall_string ()}; |