From 0353b231d51ab7ea5ead98ac838e7c2ba1b0df89 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 20 Apr 2021 11:19:28 +0200 Subject: Track changes to environment in cc rules --- libbuild2/c/init.cxx | 1 + libbuild2/cc/common.hxx | 4 +++ libbuild2/cc/compile-rule.cxx | 7 ++++- libbuild2/cc/link-rule.cxx | 11 ++++--- libbuild2/cc/module.cxx | 14 +++++++++ libbuild2/cc/module.hxx | 2 ++ libbuild2/config/utility.hxx | 4 ++- libbuild2/cxx/init.cxx | 1 + libbuild2/utility.hxx | 29 +++++++++++++++++++ libbuild2/utility.ixx | 67 +++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 134 insertions(+), 6 deletions(-) (limited to 'libbuild2') diff --git a/libbuild2/c/init.cxx b/libbuild2/c/init.cxx index afd8f88..1636816 100644 --- a/libbuild2/c/init.cxx +++ b/libbuild2/c/init.cxx @@ -343,6 +343,7 @@ namespace build2 cast (rs[cm.x_path]), cast (rs[cm.x_mode]), cast (rs[cm.x_target]), + cm.env_checksum, false, // No C modules yet. false, // No __symexport support since no modules. diff --git a/libbuild2/cc/common.hxx b/libbuild2/cc/common.hxx index 612d081..758c675 100644 --- a/libbuild2/cc/common.hxx +++ b/libbuild2/cc/common.hxx @@ -170,6 +170,8 @@ namespace build2 const string& tsys; // x.target.system const string& tclass; // x.target.class + const string& env_checksum; // config_module::env_checksum + bool modules; // x.features.modules bool symexport; // x.features.symexport @@ -230,6 +232,7 @@ namespace build2 const process_path& path, const strings& mode, const target_triplet& tgt, + const string& env_cs, bool fm, bool fs, const dir_paths& sld, @@ -250,6 +253,7 @@ namespace build2 cmaj (mj), cmin (mi), cpath (path), cmode (mode), ctgt (tgt), tsys (ctgt.system), tclass (ctgt.class_), + env_checksum (env_cs), modules (fm), symexport (fs), importable_headers (nullptr), diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index b5016bc..ce586bb 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -197,7 +197,7 @@ namespace build2 compile_rule:: compile_rule (data&& d) : common (move (d)), - rule_id (string (x) += ".compile 4") + rule_id (string (x) += ".compile 5") { static_assert (sizeof (match_data) <= target::data_size, "insufficient space"); @@ -929,6 +929,11 @@ namespace build2 if (dd.expect (cast (rs[x_checksum])) != nullptr) l4 ([&]{trace << "compiler mismatch forcing update of " << t;}); + // Then the compiler environment checksum. + // + if (dd.expect (env_checksum) != nullptr) + l4 ([&]{trace << "environment mismatch forcing update of " << t;}); + // Then the options checksum. // // The idea is to keep them exactly as they are passed to the compiler diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index 9c72969..0ab61b1 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -37,7 +37,7 @@ namespace build2 link_rule:: link_rule (data&& d) : common (move (d)), - rule_id (string (x) += ".link 2") + rule_id (string (x) += ".link 3") { static_assert (sizeof (match_data) <= target::data_size, "insufficient space"); @@ -2427,10 +2427,13 @@ namespace build2 l4 ([&]{trace << "linker mismatch forcing update of " << t;}); } - // Hash and compare any changes to the environment. + // Then the linker environment checksum (original and our modifications). // - if (dd.expect (env_cs.string ()) != nullptr) - l4 ([&]{trace << "environment mismatch forcing update of " << t;}); + { + bool e (dd.expect (env_checksum) != nullptr); + if (dd.expect (env_cs.string ()) != nullptr || e) + l4 ([&]{trace << "environment mismatch forcing update of " << t;}); + } // Next check the target. While it might be incorporated into the linker // checksum, it also might not (e.g., VC link.exe). diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx index 5bb3f60..7ef8cd5 100644 --- a/libbuild2/cc/module.cxx +++ b/libbuild2/cc/module.cxx @@ -202,8 +202,22 @@ namespace build2 } } + // Hash the environment (used for change detection). + // + // Note that for simplicity we use the combined checksum for both + // compilation and linking (which may compile, think LTO). + // + { + sha256 cs; + hash_environment (cs, xi.compiler_environment); + hash_environment (cs, xi.platform_environment); + env_checksum = cs.string (); + } + // Assign values to variables that describe the compiler. // + // @@ TODO: env_checksum. + // rs.assign (x_path) = process_path_ex (xi.path, x_name, xi.checksum); const strings& xm (cast (rs.assign (x_mode) = move (mode))); diff --git a/libbuild2/cc/module.hxx b/libbuild2/cc/module.hxx index f9d435d..ed6ec41 100644 --- a/libbuild2/cc/module.hxx +++ b/libbuild2/cc/module.hxx @@ -59,6 +59,8 @@ namespace build2 const compiler_info* x_info; + string env_checksum; // Environment checksum (also in x.path). + // Temporary storage for data::sys_*_dirs_*. // size_t sys_lib_dirs_mode; diff --git a/libbuild2/config/utility.hxx b/libbuild2/config/utility.hxx index 382c22f..8dc0650 100644 --- a/libbuild2/config/utility.hxx +++ b/libbuild2/config/utility.hxx @@ -112,6 +112,8 @@ namespace build2 // directly). The module's load() function is a natural place to do // that. // + // See also build2::hash_environment(). + // inline void save_environment (scope& rs, const string& var) { @@ -146,7 +148,7 @@ namespace build2 } } - // A NULL-terminated list of variables. + // A NULL-terminated list of variables (may itself be NULL). // inline void save_environment (scope& rs, const char* const* vars) diff --git a/libbuild2/cxx/init.cxx b/libbuild2/cxx/init.cxx index 0bbab52..74dc3ed 100644 --- a/libbuild2/cxx/init.cxx +++ b/libbuild2/cxx/init.cxx @@ -720,6 +720,7 @@ namespace build2 cast (rs[cm.x_path]), cast (rs[cm.x_mode]), cast (rs[cm.x_target]), + cm.env_checksum, modules, symexport, diff --git a/libbuild2/utility.hxx b/libbuild2/utility.hxx index 6616f78..b4a8ce4 100644 --- a/libbuild2/utility.hxx +++ b/libbuild2/utility.hxx @@ -802,6 +802,35 @@ namespace build2 const cstrings&, bool = false); + // Hash environment variable (its name and value) normally to be used as a + // checksum. See also config::save_environment(). + // + void + hash_environment (sha256&, const char* name); + + void + hash_environment (sha256&, const string& name); + + void + hash_environment (sha256&, initializer_list names); + + string + hash_environment (initializer_list names); + + void + hash_environment (sha256&, const strings& names); + + string + hash_environment (const strings& names); + + // A NULL-terminated list of variables (may itself be NULL). + // + void + hash_environment (sha256&, const char* const* names); + + string + hash_environment (const char* const* names); + // Find in the string the stem separated from other characters with the // specified separators or begin/end of the string. Return the stem's // position or npos if not found. diff --git a/libbuild2/utility.ixx b/libbuild2/utility.ixx index 9a77fae..3f9d34b 100644 --- a/libbuild2/utility.ixx +++ b/libbuild2/utility.ixx @@ -241,6 +241,73 @@ namespace build2 return find_option_prefixes (ps, s[var], ic); } + // hash_environment() + // + inline void + hash_environment (sha256& cs, const char* n) + { + cs.append (n); + + if (optional v = getenv (n)) + cs.append (*v); + } + + inline void + hash_environment (sha256& cs, const string& n) + { + hash_environment (cs, n.c_str ()); + } + + inline void + hash_environment (sha256& cs, initializer_list ns) + { + for (const char* n: ns) + hash_environment (cs, n); + } + + inline string + hash_environment (initializer_list ns) + { + sha256 cs; + hash_environment (cs, ns); + return cs.string (); + } + + inline void + hash_environment (sha256& cs, const strings& ns) + { + for (const string& n: ns) + hash_environment (cs, n); + } + + inline string + hash_environment (const strings& ns) + { + sha256 cs; + hash_environment (cs, ns); + return cs.string (); + } + + inline void + hash_environment (sha256& cs, const char* const* ns) + { + if (ns != nullptr) + { + for (; *ns != nullptr; ++ns) + hash_environment (cs, *ns); + } + } + + inline string + hash_environment (const char* const* ns) + { + sha256 cs; + hash_environment (cs, ns); + return cs.string (); + } + + // find_stem() + // inline size_t find_stem (const string& s, size_t s_p, size_t s_n, const char* stem, const char* seps) -- cgit v1.1