aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/config/init.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-03-26 16:03:29 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-04-02 12:07:38 +0200
commitb3bc26dc284cf73e97b88c9979d49368d07e686c (patch)
tree59ab65ede17e84b2fa463a4d27eaaa92fd0f8b85 /libbuild2/config/init.cxx
parent5f768f4f3e6e9e1b7310a0e8b09a97bf6d0115ea (diff)
Add support for propagating project environment
Diffstat (limited to 'libbuild2/config/init.cxx')
-rw-r--r--libbuild2/config/init.cxx86
1 files changed, 84 insertions, 2 deletions
diff --git a/libbuild2/config/init.cxx b/libbuild2/config/init.cxx
index 9911670..1e6b36b 100644
--- a/libbuild2/config/init.cxx
+++ b/libbuild2/config/init.cxx
@@ -4,6 +4,8 @@
#include <libbuild2/config/init.hxx>
#include <sstream>
+#include <cstdlib> // getenv()
+#include <cstring> // strncmp()
#include <libbuild2/file.hxx>
#include <libbuild2/rule.hxx>
@@ -28,6 +30,24 @@ namespace build2
void
functions (function_map&); // functions.cxx
+ // Compare environment variable names. Note that on Windows they are
+ // case-insensitive.
+ //
+ static inline bool
+ compare_env (const string& x, size_t xn, const string& y, size_t yn)
+ {
+ if (xn == string::npos) xn = x.size ();
+ if (yn == string::npos) yn = y.size ();
+
+ return xn == yn &&
+#ifdef _WIN32
+ icasecmp (x.c_str (), y.c_str (), xn) == 0
+#else
+ strncmp (x.c_str (), y.c_str (), xn) == 0
+#endif
+ ;
+ }
+
// Custom save function for config.config.environment.
//
// It tries to optimize the storage in subprojects by appending the
@@ -62,7 +82,7 @@ namespace build2
if (find_if (ds.rbegin (), i,
[&v, p] (const string& v1)
{
- return v.compare (0, p, v1, 0, v1.find ('=')) == 0;
+ return compare_env (v, p, v1, v1.find ('='));
}) != i)
continue;
@@ -71,7 +91,7 @@ namespace build2
auto j (find_if (bs.rbegin (), bs.rend (),
[&v, p] (const string& v1)
{
- return v.compare (0, p, v1, 0, v1.find ('=')) == 0;
+ return compare_env (v, p, v1, v1.find ('='));
}));
if (j == bs.rend () || *j != v)
@@ -375,6 +395,68 @@ namespace build2
rs["config.config.persist"]);
}
+ // Copy config.config.environment to scope::root_extra::environment.
+ //
+ // Note that we store shallow copies that point to the c.c.environment
+ // value which means it shall not change.
+ //
+ if (const strings* src = cast_null<strings> (
+ rs["config.config.environment"]))
+ {
+ vector<const char*>& dst (rs.root_extra->environment);
+
+ // The idea is to only copy entries that are effective, that is those
+ // that actually override something in the environment. This should be
+ // both more efficient and less noisy (e.g., if we decide to print
+ // this in diagnostics).
+ //
+ // Note that config.config.environment may contain duplicates and the
+ // last entry should have effect.
+ //
+ // Note also that we use std::getenv() instead of butl::getenv() to
+ // disregard any thread environment overrides.
+ //
+ for (auto i (src->rbegin ()), e (src->rend ()); i != e; ++i)
+ {
+ // Note that we must only consider variable names (up to first '='
+ // if any).
+ //
+ const string& v (*i);
+ size_t p (v.find ('='));
+
+ // Check if we have already seen this variable.
+ //
+ if (find_if (src->rbegin (), i,
+ [&v, p] (const string& v1)
+ {
+ return compare_env (v, p, v1, v1.find ('='));
+ }) != i)
+ continue;
+
+ // If it's an unset, see if it actually unsets anything.
+ //
+ if (p == string::npos)
+ {
+ if (std::getenv (v.c_str ()) == nullptr)
+ continue;
+ }
+ //
+ // And if it's a set, see if it sets a different value.
+ //
+ else
+ {
+ const char* v1 (std::getenv (string (v, 0, p).c_str ()));
+ if (v1 != nullptr && v.compare (p + 1, string::npos, v1) == 0)
+ continue;
+ }
+
+ dst.push_back (v.c_str ());
+ }
+
+ if (!dst.empty ())
+ dst.push_back (nullptr);
+ }
+
// Register alias and fallback rule for the configure meta-operation.
//
// We need this rule for out-of-any-project dependencies (e.g.,