From a5d0e0fb6988dccc59cb1c58013bd1c554f394a0 Mon Sep 17 00:00:00 2001 From: Daniel Pfeifer Date: Sun, 8 Mar 2026 21:45:14 +0100 Subject: [PATCH] cmEnvironment: Introduce class for a set of environment variables --- Source/CMakeLists.txt | 2 ++ Source/cmEnvironment.cxx | 66 ++++++++++++++++++++++++++++++++++++++++ Source/cmEnvironment.h | 55 +++++++++++++++++++++++++++++++++ bootstrap | 1 + 4 files changed, 124 insertions(+) create mode 100644 Source/cmEnvironment.cxx create mode 100644 Source/cmEnvironment.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 8d4a57aea7..f520816c9a 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -191,6 +191,8 @@ add_library( cmDyndepCollation.h cmELF.h cmELF.cxx + cmEnvironment.cxx + cmEnvironment.h cmEvaluatedTargetProperty.cxx cmEvaluatedTargetProperty.h cmExprParserHelper.cxx diff --git a/Source/cmEnvironment.cxx b/Source/cmEnvironment.cxx new file mode 100644 index 0000000000..9cc9bc7868 --- /dev/null +++ b/Source/cmEnvironment.cxx @@ -0,0 +1,66 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ +#include "cmEnvironment.h" + +#include + +#include +#include +#include + +#if defined(_WIN32) +# include "cmsys/String.h" +#endif + +bool cmEnvironment::EnvNameLess::operator()(std::string const& lhs, + std::string const& rhs) const +{ +#if defined(_WIN32) + // Environment variable names are case-insensitive on Windows + return cmsysString_strcasecmp(lhs.c_str(), rhs.c_str()) < 0; +#else + return lhs < rhs; +#endif +} + +cmEnvironment::cmEnvironment(std::vector const& env) +{ + for (std::string const& var : env) { + this->PutEnv(var); + } +} + +void cmEnvironment::PutEnv(std::string const& env) +{ + auto const pos = env.find('='); + if (pos != std::string::npos) { + this->Map[env.substr(0, pos)] = env.substr(pos + 1); + } else { + this->Map[env] = cm::nullopt; + } +} + +void cmEnvironment::UnPutEnv(std::string const& env) +{ + this->Map[env] = cm::nullopt; +} + +void cmEnvironment::Update(cmEnvironment&& other) +{ + for (auto& kv : other.Map) { + this->Map[kv.first] = std::move(kv.second); + } + other.Map.clear(); +} + +std::vector cmEnvironment::GetVariables() const +{ + auto result = std::vector{}; + result.reserve(this->Map.size()); + for (auto const& elem : this->Map) { + if (elem.second) { + result.push_back(elem.first + '=' + *elem.second); + } + } + return result; +} diff --git a/Source/cmEnvironment.h b/Source/cmEnvironment.h new file mode 100644 index 0000000000..5ceaa857eb --- /dev/null +++ b/Source/cmEnvironment.h @@ -0,0 +1,55 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include +#include +#include + +#include + +/** + * Helper class to represent an environment. + */ +class cmEnvironment +{ +public: + /** Initialize from `NAME=VALUE` strings. */ + cmEnvironment(std::vector const& env = {}); + + /** + * Add a single variable (or remove if no = sign) to the current + * environment. + */ + void PutEnv(std::string const& env); + + /** Remove a single variable from the current environment. */ + void UnPutEnv(std::string const& env); + + /** + * Move the environment entries from `other` into this one, overwriting + * existing variables when a key is already present. */ + void Update(cmEnvironment&& other); + + /** Modify the value of a variable in-place using a transform function. */ + template + void Modify(std::string const& name, F&& transform) + { + cm::optional& val = this->Map[name]; + if (!val.has_value()) { + val = std::string{}; + } + transform(*val); + } + + std::vector GetVariables() const; + +protected: + struct EnvNameLess + { + bool operator()(std::string const& lhs, std::string const& rhs) const; + }; + std::map, EnvNameLess> Map; +}; diff --git a/bootstrap b/bootstrap index 6041787a67..48c6491dbf 100755 --- a/bootstrap +++ b/bootstrap @@ -340,6 +340,7 @@ CMAKE_CXX_SOURCES="\ cmELF \ cmEnableLanguageCommand \ cmEnableTestingCommand \ + cmEnvironment \ cmEvaluatedTargetProperty \ cmExecProgramCommand \ cmExecuteProcessCommand \