Преглед на файлове

GenEx: Factor out a dedicated evaluation Context structure

The context's local generator, configuration name, and language are
constant throughout evaluation.
Brad King преди 4 седмици
родител
ревизия
e4708f007b

+ 2 - 0
Source/CMakeLists.txt

@@ -270,6 +270,8 @@ add_library(
   cmGccDepfileLexerHelper.h
   cmGccDepfileReader.cxx
   cmGccDepfileReader.h
+  cmGenExContext.cxx
+  cmGenExContext.h
   cmGenExEvaluation.cxx
   cmGenExEvaluation.h
   cmGeneratedFileStream.cxx

+ 4 - 3
Source/cmEvaluatedTargetProperty.cxx

@@ -5,6 +5,7 @@
 #include <unordered_map>
 #include <utility>
 
+#include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorTarget.h"
 #include "cmLinkItem.h"
@@ -64,9 +65,9 @@ void addInterfaceEntry(cmGeneratorTarget const* headTarget,
       // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
       // caller's property and hand-evaluate it as if it were compiled.
       // Create a context as cmCompiledGeneratorExpression::Evaluate does.
-      cm::GenEx::Evaluation eval(headTarget->GetLocalGenerator(), config,
-                                 false, headTarget, headTarget, true,
-                                 lib.Backtrace, lang);
+      cm::GenEx::Evaluation eval(
+        cm::GenEx::Context(headTarget->GetLocalGenerator(), config, lang),
+        false, headTarget, headTarget, true, lib.Backtrace);
       cmExpandList(
         lib.Target->EvaluateInterfaceProperty(prop, &eval, dagChecker, usage),
         ee.Values);

+ 19 - 0
Source/cmGenExContext.cxx

@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmGenExContext.h"
+
+#include <utility>
+
+namespace cm {
+namespace GenEx {
+
+Context::Context(cmLocalGenerator const* lg, std::string config,
+                 std::string language)
+  : LG(lg)
+  , Config(std::move(config))
+  , Language(std::move(language))
+{
+}
+
+}
+}

+ 23 - 0
Source/cmGenExContext.h

@@ -0,0 +1,23 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <string>
+
+class cmLocalGenerator;
+
+namespace cm {
+namespace GenEx {
+
+struct Context final
+{
+  Context(cmLocalGenerator const* lg, std::string config,
+          std::string language = std::string());
+
+  cmLocalGenerator const* LG;
+  std::string Config;
+  std::string Language;
+};
+
+}
+}

+ 7 - 7
Source/cmGenExEvaluation.cxx

@@ -4,18 +4,18 @@
 
 #include <utility>
 
+#include "cmGenExContext.h"
+
 namespace cm {
 namespace GenEx {
 
-Evaluation::Evaluation(cmLocalGenerator const* lg, std::string config,
-                       bool quiet, cmGeneratorTarget const* headTarget,
+Evaluation::Evaluation(GenEx::Context context, bool quiet,
+                       cmGeneratorTarget const* headTarget,
                        cmGeneratorTarget const* currentTarget,
                        bool evaluateForBuildsystem,
-                       cmListFileBacktrace backtrace, std::string language)
-  : Backtrace(std::move(backtrace))
-  , LG(lg)
-  , Config(std::move(config))
-  , Language(std::move(language))
+                       cmListFileBacktrace backtrace)
+  : Context(std::move(context))
+  , Backtrace(std::move(backtrace))
   , HeadTarget(headTarget)
   , CurrentTarget(currentTarget)
   , Quiet(quiet)

+ 4 - 7
Source/cmGenExEvaluation.h

@@ -6,22 +6,22 @@
 #include <set>
 #include <string>
 
+#include "cmGenExContext.h"
 #include "cmListFileCache.h"
 
 class cmGeneratorTarget;
-class cmLocalGenerator;
 
 namespace cm {
 namespace GenEx {
 
 struct Evaluation final
 {
-  Evaluation(cmLocalGenerator const* lg, std::string config, bool quiet,
+  Evaluation(GenEx::Context context, bool quiet,
              cmGeneratorTarget const* headTarget,
              cmGeneratorTarget const* currentTarget,
-             bool evaluateForBuildsystem, cmListFileBacktrace backtrace,
-             std::string language);
+             bool evaluateForBuildsystem, cmListFileBacktrace backtrace);
 
+  GenEx::Context const Context;
   cmListFileBacktrace Backtrace;
   std::set<cmGeneratorTarget*> DependTargets;
   std::set<cmGeneratorTarget const*> AllTargets;
@@ -29,9 +29,6 @@ struct Evaluation final
   std::set<cmGeneratorTarget const*> SourceSensitiveTargets;
   std::map<cmGeneratorTarget const*, std::map<std::string, std::string>>
     MaxLanguageStandard;
-  cmLocalGenerator const* LG;
-  std::string Config;
-  std::string Language;
   // The target whose property is being evaluated.
   cmGeneratorTarget const* HeadTarget;
   // The dependent of HeadTarget which appears

+ 4 - 3
Source/cmGeneratorExpression.cxx

@@ -12,6 +12,7 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorExpressionEvaluator.h"
@@ -68,10 +69,10 @@ std::string const& cmCompiledGeneratorExpression::Evaluate(
   cmGeneratorExpressionDAGChecker* dagChecker,
   cmGeneratorTarget const* currentTarget, std::string const& language) const
 {
-  cm::GenEx::Evaluation eval(lg, config, this->Quiet, headTarget,
+  cm::GenEx::Evaluation eval(cm::GenEx::Context(lg, config, language),
+                             this->Quiet, headTarget,
                              currentTarget ? currentTarget : headTarget,
-                             this->EvaluateForBuildsystem, this->Backtrace,
-                             language);
+                             this->EvaluateForBuildsystem, this->Backtrace);
 
   if (!this->NeedsEvaluation) {
     return this->Input;

+ 7 - 6
Source/cmGeneratorExpressionDAGChecker.cxx

@@ -9,6 +9,7 @@
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpressionEvaluator.h"
 #include "cmGeneratorTarget.h"
@@ -82,8 +83,8 @@ void cmGeneratorExpressionDAGChecker::ReportError(cm::GenEx::Evaluation* eval,
       << "  " << expr << "\n"
       << "Self reference on target \"" << eval->HeadTarget->GetName()
       << "\".\n";
-    eval->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
-                                               e.str(), parent->Backtrace);
+    eval->Context.LG->GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR, e.str(), parent->Backtrace);
     return;
   }
 
@@ -94,8 +95,8 @@ void cmGeneratorExpressionDAGChecker::ReportError(cm::GenEx::Evaluation* eval,
     << "  " << expr << "\n"
     << "Dependency loop found.";
     /* clang-format on */
-    eval->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
-                                               e.str(), eval->Backtrace);
+    eval->Context.LG->GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR, e.str(), eval->Backtrace);
   }
 
   int loopStep = 1;
@@ -105,8 +106,8 @@ void cmGeneratorExpressionDAGChecker::ReportError(cm::GenEx::Evaluation* eval,
       << "  "
       << (parent->Content ? parent->Content->GetOriginalExpression() : expr)
       << "\n";
-    eval->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
-                                               e.str(), parent->Backtrace);
+    eval->Context.LG->GetCMakeInstance()->IssueMessage(
+      MessageType::FATAL_ERROR, e.str(), parent->Backtrace);
     parent = parent->Parent;
     ++loopStep;
   }

+ 5 - 3
Source/cmGeneratorExpressionEvaluator.cxx

@@ -8,6 +8,7 @@
 #  include <cm3p/json/value.h>
 #endif
 
+#include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpressionNode.h"
 #include "cmLocalGenerator.h"
@@ -67,8 +68,9 @@ std::string GeneratorExpressionContent::Evaluate(
   cmGeneratorExpressionDAGChecker* dagChecker) const
 {
 #ifndef CMAKE_BOOTSTRAP
-  auto evalProfilingRAII = eval->LG->GetCMakeInstance()->CreateProfilingEntry(
-    "genex_eval", this->GetOriginalExpression());
+  auto evalProfilingRAII =
+    eval->Context.LG->GetCMakeInstance()->CreateProfilingEntry(
+      "genex_eval", this->GetOriginalExpression());
 #endif
 
   std::string identifier;
@@ -113,7 +115,7 @@ std::string GeneratorExpressionContent::Evaluate(
   {
 #ifndef CMAKE_BOOTSTRAP
     auto execProfilingRAII =
-      eval->LG->GetCMakeInstance()->CreateProfilingEntry(
+      eval->Context.LG->GetCMakeInstance()->CreateProfilingEntry(
         "genex_exec", identifier, [&parameters]() -> Json::Value {
           Json::Value args = Json::objectValue;
           if (!parameters.empty()) {

+ 170 - 148
Source/cmGeneratorExpressionNode.cxx

@@ -27,6 +27,7 @@
 
 #include "cmCMakePath.h"
 #include "cmComputeLinkInformation.h"
+#include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionDAGChecker.h"
@@ -57,13 +58,14 @@ std::string cmGeneratorExpressionNode::EvaluateDependentExpression(
   cmGeneratorExpressionDAGChecker* dagChecker,
   cmGeneratorTarget const* currentTarget)
 {
-  cmGeneratorExpression ge(*eval->LG->GetCMakeInstance(), eval->Backtrace);
+  cmGeneratorExpression ge(*eval->Context.LG->GetCMakeInstance(),
+                           eval->Backtrace);
   std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
   cge->SetEvaluateForBuildsystem(eval->EvaluateForBuildsystem);
   cge->SetQuiet(eval->Quiet);
   std::string result =
-    cge->Evaluate(eval->LG, eval->Config, headTarget, dagChecker,
-                  currentTarget, eval->Language);
+    cge->Evaluate(eval->Context.LG, eval->Context.Config, headTarget,
+                  dagChecker, currentTarget, eval->Context.Language);
   if (cge->GetHadContextSensitiveCondition()) {
     eval->HadContextSensitiveCondition = true;
   }
@@ -308,7 +310,7 @@ static const struct InListNode : public cmGeneratorExpressionNode
     cmList values;
     cmList checkValues;
     bool check = false;
-    switch (eval->LG->GetPolicyStatus(cmPolicies::CMP0085)) {
+    switch (eval->Context.LG->GetPolicyStatus(cmPolicies::CMP0085)) {
       case cmPolicies::WARN:
         if (parameters.front().empty()) {
           check = true;
@@ -322,7 +324,7 @@ static const struct InListNode : public cmGeneratorExpressionNode
           e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
             << "\nSearch Item:\n  \"" << parameters.front()
             << "\"\nList:\n  \"" << parameters[1] << "\"\n";
-          eval->LG->GetCMakeInstance()->IssueMessage(
+          eval->Context.LG->GetCMakeInstance()->IssueMessage(
             MessageType ::AUTHOR_WARNING, e.str(), eval->Backtrace);
           return "0";
         }
@@ -427,7 +429,8 @@ static const struct TargetExistsNode : public cmGeneratorExpressionNode
       return std::string();
     }
 
-    return eval->LG->GetMakefile()->FindTargetToUse(targetName) ? "1" : "0";
+    return eval->Context.LG->GetMakefile()->FindTargetToUse(targetName) ? "1"
+                                                                        : "0";
   }
 } targetExistsNode;
 
@@ -458,7 +461,7 @@ static const struct TargetNameIfExistsNode : public cmGeneratorExpressionNode
       return std::string();
     }
 
-    return eval->LG->GetMakefile()->FindTargetToUse(targetName)
+    return eval->Context.LG->GetMakefile()->FindTargetToUse(targetName)
       ? targetName
       : std::string();
   }
@@ -478,7 +481,7 @@ protected:
       cmGeneratorExpressionDAGChecker dagChecker{
         eval->HeadTarget, genexOperator + ":" + expression,
         content,          dagCheckerParent,
-        eval->LG,         eval->Config,
+        eval->Context.LG, eval->Context.Config,
         eval->Backtrace,
       };
       switch (dagChecker.Check()) {
@@ -524,7 +527,8 @@ static const struct TargetGenexEvalNode : public GenexEvaluator
       return std::string();
     }
 
-    auto const* target = eval->LG->FindGeneratorTargetToUse(targetName);
+    auto const* target =
+      eval->Context.LG->FindGeneratorTargetToUse(targetName);
     if (!target) {
       std::ostringstream e;
       e << "$<TARGET_GENEX_EVAL:tgt, ...> target \"" << targetName
@@ -539,9 +543,9 @@ static const struct TargetGenexEvalNode : public GenexEvaluator
     }
 
     // Replace the surrounding context with the named target.
-    cm::GenEx::Evaluation targetEval(
-      eval->LG, eval->Config, eval->Quiet, target, target,
-      eval->EvaluateForBuildsystem, eval->Backtrace, eval->Language);
+    cm::GenEx::Evaluation targetEval(eval->Context, eval->Quiet, target,
+                                     target, eval->EvaluateForBuildsystem,
+                                     eval->Backtrace);
 
     return this->EvaluateExpression("TARGET_GENEX_EVAL", expression,
                                     &targetEval, content, dagCheckerParent);
@@ -1653,7 +1657,7 @@ static const struct ListNode : public cmGeneratorExpressionNode
                   if (!selector) {
                     selector = cmList::TransformSelector::New();
                   }
-                  selector->Makefile = ev->LG->GetMakefile();
+                  selector->Makefile = ev->Context.LG->GetMakefile();
 
                   return list
                     .transform(descriptor->Action, arguments,
@@ -1861,8 +1865,9 @@ struct CompilerIdNode : public cmGeneratorExpressionNode
                                    cmGeneratorExpressionDAGChecker* /*unused*/,
                                    std::string const& lang) const
   {
-    std::string const& compilerId = eval->LG->GetMakefile()->GetSafeDefinition(
-      "CMAKE_" + lang + "_COMPILER_ID");
+    std::string const& compilerId =
+      eval->Context.LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
+                                                         "_COMPILER_ID");
     if (parameters.empty()) {
       return compilerId;
     }
@@ -1926,8 +1931,8 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode
                                    std::string const& lang) const
   {
     std::string const& compilerVersion =
-      eval->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
-                                                 "_COMPILER_VERSION");
+      eval->Context.LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
+                                                         "_COMPILER_VERSION");
     if (parameters.empty()) {
       return compilerVersion;
     }
@@ -1990,8 +1995,8 @@ struct CompilerFrontendVariantNode : public cmGeneratorExpressionNode
                                    std::string const& lang) const
   {
     std::string const& compilerFrontendVariant =
-      eval->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
-                                                 "_COMPILER_FRONTEND_VARIANT");
+      eval->Context.LG->GetMakefile()->GetSafeDefinition(
+        "CMAKE_" + lang + "_COMPILER_FRONTEND_VARIANT");
     if (parameters.empty()) {
       return compilerFrontendVariant;
     }
@@ -2038,7 +2043,7 @@ struct PlatformIdNode : public cmGeneratorExpressionNode
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
     std::string const& platformId =
-      eval->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
+      eval->Context.LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME");
     if (parameters.empty()) {
       return platformId;
     }
@@ -2136,7 +2141,7 @@ static const struct ConfigurationNode : public cmGeneratorExpressionNode
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
     eval->HadContextSensitiveCondition = true;
-    return eval->Config;
+    return eval->Context.Config;
   }
 } configurationNode;
 
@@ -2175,8 +2180,8 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
           << "  " << content->GetOriginalExpression() << "\n"
           << "The config name of \"" << param << "\" is invalid";
         /* clang-format on */
-        eval->LG->GetCMakeInstance()->IssueMessage(MessageType::WARNING,
-                                                   e.str(), eval->Backtrace);
+        eval->Context.LG->GetCMakeInstance()->IssueMessage(
+          MessageType::WARNING, e.str(), eval->Backtrace);
       }
       firstParam = false;
     }
@@ -2208,7 +2213,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
       }
       switch (eval->HeadTarget->GetPolicyStatusCMP0199()) {
         case cmPolicies::WARN:
-          if (eval->LG->GetMakefile()->PolicyOptionalWarningEnabled(
+          if (eval->Context.LG->GetMakefile()->PolicyOptionalWarningEnabled(
                 "CMAKE_POLICY_WARNING_CMP0199")) {
             std::string const err =
               cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0199),
@@ -2216,7 +2221,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
                        eval->CurrentTarget->GetName(), "\", used by \"",
                        eval->HeadTarget->GetName(),
                        "\", may match multiple configurations.\n");
-            eval->LG->GetCMakeInstance()->IssueMessage(
+            eval->Context.LG->GetCMakeInstance()->IssueMessage(
               MessageType ::AUTHOR_WARNING, err, eval->Backtrace);
           }
           CM_FALLTHROUGH;
@@ -2234,12 +2239,12 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
     if (!targetIsImported || oldPolicy) {
       // Does the consuming target's configuration match any of the arguments?
       for (auto const& param : parameters) {
-        if (eval->Config.empty()) {
+        if (eval->Context.Config.empty()) {
           if (param.empty()) {
             return "1";
           }
         } else if (cmsysString_strcasecmp(param.c_str(),
-                                          eval->Config.c_str()) == 0) {
+                                          eval->Context.Config.c_str()) == 0) {
           return "1";
         }
       }
@@ -2249,8 +2254,8 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
       cmValue loc = nullptr;
       cmValue imp = nullptr;
       std::string suffix;
-      if (eval->CurrentTarget->Target->GetMappedConfig(eval->Config, loc, imp,
-                                                       suffix)) {
+      if (eval->CurrentTarget->Target->GetMappedConfig(eval->Context.Config,
+                                                       loc, imp, suffix)) {
         if (oldPolicy) {
           // If the target has a MAP_IMPORTED_CONFIG_<CONFIG> property for the
           // consumer's <CONFIG>, match *any* config in that list, regardless
@@ -2259,8 +2264,9 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode
           // and is almost certainly wrong, but it's what CMake did for a very
           // long time, and... Hyrum's Law.
           cmList mappedConfigs;
-          std::string mapProp = cmStrCat(
-            "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(eval->Config));
+          std::string mapProp =
+            cmStrCat("MAP_IMPORTED_CONFIG_",
+                     cmSystemTools::UpperCase(eval->Context.Config));
           if (cmValue mapValue = eval->CurrentTarget->GetProperty(mapProp)) {
             mappedConfigs.assign(cmSystemTools::UpperCase(*mapValue));
 
@@ -2322,7 +2328,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
     GeneratorExpressionContent const* content,
     cmGeneratorExpressionDAGChecker* dagChecker) const override
   {
-    if (eval->Language.empty() &&
+    if (eval->Context.Language.empty() &&
         (!dagChecker || !dagChecker->EvaluatingCompileExpression())) {
       reportError(
         eval, content->GetOriginalExpression(),
@@ -2332,7 +2338,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
       return std::string();
     }
 
-    cmGlobalGenerator const* gg = eval->LG->GetGlobalGenerator();
+    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
     std::string genName = gg->GetName();
     if (genName.find("Makefiles") == std::string::npos &&
         genName.find("Ninja") == std::string::npos &&
@@ -2346,11 +2352,11 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode
       return std::string();
     }
     if (parameters.empty()) {
-      return eval->Language;
+      return eval->Context.Language;
     }
 
     for (auto const& param : parameters) {
-      if (eval->Language == param) {
+      if (eval->Context.Language == param) {
         return "1";
       }
     }
@@ -2370,7 +2376,7 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
     cmGeneratorExpressionDAGChecker* dagChecker) const override
   {
     if (!eval->HeadTarget ||
-        (eval->Language.empty() &&
+        (eval->Context.Language.empty() &&
          (!dagChecker || !dagChecker->EvaluatingCompileExpression()))) {
       // reportError(eval, content->GetOriginalExpression(), "");
       reportError(
@@ -2382,7 +2388,7 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
         "add_custom_target, or file(GENERATE) commands.");
       return std::string();
     }
-    cmGlobalGenerator const* gg = eval->LG->GetGlobalGenerator();
+    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
     std::string genName = gg->GetName();
     if (genName.find("Makefiles") == std::string::npos &&
         genName.find("Ninja") == std::string::npos &&
@@ -2397,7 +2403,7 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode
       return std::string();
     }
 
-    std::string const& lang = eval->Language;
+    std::string const& lang = eval->Context.Language;
     if (lang == parameters.front()) {
       std::vector<std::string> idParameter((parameters.cbegin() + 1),
                                            parameters.cend());
@@ -2436,7 +2442,7 @@ static const struct LinkLanguageNode : public cmGeneratorExpressionNode
       return std::string();
     }
 
-    cmGlobalGenerator const* gg = eval->LG->GetGlobalGenerator();
+    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
     std::string genName = gg->GetName();
     if (genName.find("Makefiles") == std::string::npos &&
         genName.find("Ninja") == std::string::npos &&
@@ -2456,11 +2462,11 @@ static const struct LinkLanguageNode : public cmGeneratorExpressionNode
     }
 
     if (parameters.empty()) {
-      return eval->Language;
+      return eval->Context.Language;
     }
 
     for (auto const& param : parameters) {
-      if (eval->Language == param) {
+      if (eval->Context.Language == param) {
         return "1";
       }
     }
@@ -2476,8 +2482,9 @@ struct LinkerId
                               GeneratorExpressionContent const* content,
                               std::string const& lang)
   {
-    std::string const& linkerId = eval->LG->GetMakefile()->GetSafeDefinition(
-      "CMAKE_" + lang + "_COMPILER_ID");
+    std::string const& linkerId =
+      eval->Context.LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang +
+                                                         "_COMPILER_ID");
     if (parameters.empty()) {
       return linkerId;
     }
@@ -2526,7 +2533,7 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
       return std::string();
     }
 
-    cmGlobalGenerator const* gg = eval->LG->GetGlobalGenerator();
+    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
     std::string genName = gg->GetName();
     if (genName.find("Makefiles") == std::string::npos &&
         genName.find("Ninja") == std::string::npos &&
@@ -2546,7 +2553,7 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode
       eval->HadLinkLanguageSensitiveCondition = true;
     }
 
-    std::string const& lang = eval->Language;
+    std::string const& lang = eval->Context.Language;
     if (lang == parameters.front()) {
       std::vector<std::string> idParameter((parameters.cbegin() + 1),
                                            parameters.cend());
@@ -2590,7 +2597,7 @@ struct CompilerLinkerIdNode : public cmGeneratorExpressionNode
                                    std::string const& lang) const
   {
     std::string const& compilerLinkerId =
-      eval->LG->GetMakefile()->GetSafeDefinition(
+      eval->Context.LG->GetMakefile()->GetSafeDefinition(
         cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_ID"));
     if (parameters.empty()) {
       return compilerLinkerId;
@@ -2658,7 +2665,7 @@ struct CompilerLinkerFrontendVariantNode : public cmGeneratorExpressionNode
                                    std::string const& lang) const
   {
     std::string const& compilerLinkerFrontendVariant =
-      eval->LG->GetMakefile()->GetSafeDefinition(
+      eval->Context.LG->GetMakefile()->GetSafeDefinition(
         cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_FRONTEND_VARIANT"));
     if (parameters.empty()) {
       return compilerLinkerFrontendVariant;
@@ -2915,15 +2922,19 @@ static std::string getLinkedTargetsContent(
   std::string result;
   if (cmLinkImplementationLibraries const* impl =
         target->GetLinkImplementationLibraries(
-          eval->Config, cmGeneratorTarget::UseTo::Compile)) {
+          eval->Context.Config, cmGeneratorTarget::UseTo::Compile)) {
     for (cmLinkImplItem const& lib : impl->Libraries) {
       if (lib.Target) {
         // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
         // caller's property and hand-evaluate it as if it were compiled.
         // Create a context as cmCompiledGeneratorExpression::Evaluate does.
+        cm::GenEx::Context libContext(eval->Context);
+        // FIXME: Why have we long used the target's local generator
+        // instead of that of the evaluation context?
+        libContext.LG = target->GetLocalGenerator();
         cm::GenEx::Evaluation libEval(
-          target->GetLocalGenerator(), eval->Config, eval->Quiet, target,
-          target, eval->EvaluateForBuildsystem, lib.Backtrace, eval->Language);
+          std::move(libContext), eval->Quiet, target, target,
+          eval->EvaluateForBuildsystem, lib.Backtrace);
         std::string libResult = lib.Target->EvaluateInterfaceProperty(
           prop, &libEval, dagChecker, usage);
         if (!libResult.empty()) {
@@ -2989,24 +3000,25 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
         return std::string();
       }
       if (propertyName == "ALIASED_TARGET"_s) {
-        if (eval->LG->GetMakefile()->IsAlias(targetName)) {
+        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
           if (cmGeneratorTarget* tgt =
-                eval->LG->FindGeneratorTargetToUse(targetName)) {
+                eval->Context.LG->FindGeneratorTargetToUse(targetName)) {
             return tgt->GetName();
           }
         }
         return std::string();
       }
       if (propertyName == "ALIAS_GLOBAL"_s) {
-        if (eval->LG->GetMakefile()->IsAlias(targetName)) {
-          return eval->LG->GetGlobalGenerator()->IsAlias(targetName) ? "TRUE"
-                                                                     : "FALSE";
+        if (eval->Context.LG->GetMakefile()->IsAlias(targetName)) {
+          return eval->Context.LG->GetGlobalGenerator()->IsAlias(targetName)
+            ? "TRUE"
+            : "FALSE";
         }
         return std::string();
       }
       cmLocalGenerator const* lg = eval->CurrentTarget
         ? eval->CurrentTarget->GetLocalGenerator()
-        : eval->LG;
+        : eval->Context.LG;
       target = lg->FindGeneratorTargetToUse(targetName);
 
       if (!target) {
@@ -3076,7 +3088,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
           "link libraries for a static library");
         return std::string();
       }
-      return target->GetLinkerLanguage(eval->Config);
+      return target->GetLinkerLanguage(eval->Context.Config);
     }
 
     bool const evaluatingLinkLibraries =
@@ -3087,7 +3099,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
     cmGeneratorTarget::UseTo usage = cmGeneratorTarget::UseTo::Compile;
 
     if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
-          target->IsTransitiveProperty(propertyName, eval->LG, eval->Config,
+          target->IsTransitiveProperty(propertyName, eval->Context.LG,
+                                       eval->Context.Config,
                                        dagCheckerParent)) {
       interfacePropertyName = std::string(transitiveProp->InterfaceName);
       isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
@@ -3123,8 +3136,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
     }
 
     cmGeneratorExpressionDAGChecker dagChecker{
-      target,   propertyName, content,         dagCheckerParent,
-      eval->LG, eval->Config, eval->Backtrace,
+      target,           propertyName,     content,
+      dagCheckerParent, eval->Context.LG, eval->Context.Config,
+      eval->Backtrace,
     };
 
     switch (dagChecker.Check()) {
@@ -3165,37 +3179,37 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
     // from this target and the transitive link closure to get the max or min.
     if (!haveProp && !target->IsImported()) {
       if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
-                                                       eval->Config)) {
+                                                       eval->Context.Config)) {
         eval->HadContextSensitiveCondition = true;
-        return target->GetLinkInterfaceDependentBoolProperty(propertyName,
-                                                             eval->Config)
+        return target->GetLinkInterfaceDependentBoolProperty(
+                 propertyName, eval->Context.Config)
           ? "1"
           : "0";
       }
-      if (target->IsLinkInterfaceDependentStringProperty(propertyName,
-                                                         eval->Config)) {
+      if (target->IsLinkInterfaceDependentStringProperty(
+            propertyName, eval->Context.Config)) {
         eval->HadContextSensitiveCondition = true;
         char const* propContent =
-          target->GetLinkInterfaceDependentStringProperty(propertyName,
-                                                          eval->Config);
+          target->GetLinkInterfaceDependentStringProperty(
+            propertyName, eval->Context.Config);
         return propContent ? propContent : "";
       }
     }
     if (!evaluatingLinkLibraries && !target->IsImported()) {
-      if (target->IsLinkInterfaceDependentNumberMinProperty(propertyName,
-                                                            eval->Config)) {
+      if (target->IsLinkInterfaceDependentNumberMinProperty(
+            propertyName, eval->Context.Config)) {
         eval->HadContextSensitiveCondition = true;
         char const* propContent =
-          target->GetLinkInterfaceDependentNumberMinProperty(propertyName,
-                                                             eval->Config);
+          target->GetLinkInterfaceDependentNumberMinProperty(
+            propertyName, eval->Context.Config);
         return propContent ? propContent : "";
       }
-      if (target->IsLinkInterfaceDependentNumberMaxProperty(propertyName,
-                                                            eval->Config)) {
+      if (target->IsLinkInterfaceDependentNumberMaxProperty(
+            propertyName, eval->Context.Config)) {
         eval->HadContextSensitiveCondition = true;
         char const* propContent =
-          target->GetLinkInterfaceDependentNumberMaxProperty(propertyName,
-                                                             eval->Config);
+          target->GetLinkInterfaceDependentNumberMaxProperty(
+            propertyName, eval->Context.Config);
         return propContent ? propContent : "";
       }
     }
@@ -3248,7 +3262,8 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
     std::string const& tgtName = parameters.front();
-    cmGeneratorTarget* gt = eval->LG->FindGeneratorTargetToUse(tgtName);
+    cmGeneratorTarget* gt =
+      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
     if (!gt) {
       std::ostringstream e;
       e << "Objects of target \"" << tgtName
@@ -3269,7 +3284,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
       reportError(eval, content->GetOriginalExpression(), e.str());
       return std::string();
     }
-    cmGlobalGenerator const* gg = eval->LG->GetGlobalGenerator();
+    cmGlobalGenerator const* gg = eval->Context.LG->GetGlobalGenerator();
     {
       std::string reason;
       if (!eval->EvaluateForBuildsystem &&
@@ -3291,12 +3306,13 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
       cmValue loc = nullptr;
       cmValue imp = nullptr;
       std::string suffix;
-      if (gt->Target->GetMappedConfig(eval->Config, loc, imp, suffix)) {
+      if (gt->Target->GetMappedConfig(eval->Context.Config, loc, imp,
+                                      suffix)) {
         objects.assign(*loc);
       }
       eval->HadContextSensitiveCondition = true;
     } else {
-      gt->GetTargetObjectNames(eval->Config, objects);
+      gt->GetTargetObjectNames(eval->Context.Config, objects);
 
       std::string obj_dir;
       if (eval->EvaluateForBuildsystem && !gg->SupportsCrossConfigs()) {
@@ -3305,7 +3321,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
         eval->HadContextSensitiveCondition = gt->HasContextDependentSources();
       } else {
         // Use object file directory with per-config location.
-        obj_dir = gt->GetObjectDirectory(eval->Config);
+        obj_dir = gt->GetObjectDirectory(eval->Context.Config);
         eval->HadContextSensitiveCondition = true;
       }
 
@@ -3315,7 +3331,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
     }
 
     // Create the cmSourceFile instances in the referencing directory.
-    cmMakefile* mf = eval->LG->GetMakefile();
+    cmMakefile* mf = eval->Context.LG->GetMakefile();
     for (std::string const& o : objects) {
       mf->AddTargetObject(tgtName, o);
     }
@@ -3331,7 +3347,8 @@ struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode
     GeneratorExpressionContent const* content) const
   {
     std::string const& tgtName = parameters.front();
-    cmGeneratorTarget* gt = eval->LG->FindGeneratorTargetToUse(tgtName);
+    cmGeneratorTarget* gt =
+      eval->Context.LG->FindGeneratorTargetToUse(tgtName);
     if (!gt) {
       std::ostringstream e;
       e << "Objects of target \"" << tgtName
@@ -3351,12 +3368,12 @@ struct TargetRuntimeDllsBaseNode : public cmGeneratorExpressionNode
       return std::vector<std::string>();
     }
 
-    if (auto* cli = gt->GetLinkInformation(eval->Config)) {
+    if (auto* cli = gt->GetLinkInformation(eval->Context.Config)) {
       std::vector<std::string> dllPaths;
       auto const& dlls = cli->GetRuntimeDLLs();
 
       for (auto const& dll : dlls) {
-        if (auto loc = dll->MaybeGetLocation(eval->Config)) {
+        if (auto loc = dll->MaybeGetLocation(eval->Context.Config)) {
           dllPaths.emplace_back(*loc);
         }
       }
@@ -3429,7 +3446,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
     static LangMap availableFeatures;
 
     LangMap testedFeatures;
-    cmStandardLevelResolver standardResolver(eval->LG->GetMakefile());
+    cmStandardLevelResolver standardResolver(eval->Context.LG->GetMakefile());
     for (std::string const& p : parameters) {
       std::string error;
       std::string lang;
@@ -3456,7 +3473,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
     for (auto const& lit : testedFeatures) {
       std::vector<std::string> const& langAvailable =
         availableFeatures[lit.first];
-      cmValue standardDefault = eval->LG->GetMakefile()->GetDefinition(
+      cmValue standardDefault = eval->Context.LG->GetMakefile()->GetDefinition(
         "CMAKE_" + lit.first + "_STANDARD_DEFAULT");
       for (std::string const& it : lit.second) {
         if (!cm::contains(langAvailable, it)) {
@@ -3467,10 +3484,11 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
           // All features known for the language are always available.
           continue;
         }
-        if (!standardResolver.HaveStandardAvailable(target, lit.first,
-                                                    eval->Config, it)) {
+        if (!standardResolver.HaveStandardAvailable(
+              target, lit.first, eval->Context.Config, it)) {
           if (evalLL) {
-            cmValue l = target->GetLanguageStandard(lit.first, eval->Config);
+            cmValue l =
+              target->GetLanguageStandard(lit.first, eval->Context.Config);
             if (!l) {
               l = standardDefault;
             }
@@ -3635,7 +3653,7 @@ struct TargetFilesystemArtifactDependencyCMP0112
                             cm::GenEx::Evaluation* eval)
   {
     eval->AllTargets.insert(target);
-    cmLocalGenerator const* lg = eval->LG;
+    cmLocalGenerator const* lg = eval->Context.LG;
     switch (target->GetPolicyStatusCMP0112()) {
       case cmPolicies::WARN:
         if (lg->GetMakefile()->PolicyOptionalWarningEnabled(
@@ -3720,8 +3738,9 @@ struct TargetFilesystemArtifactResultCreator<ArtifactSonameTag>
                     "AIX_SHARED_LIBRARY_ARCHIVE libraries.");
       return std::string();
     }
-    std::string result = cmStrCat(target->GetDirectory(eval->Config), '/',
-                                  target->GetSOName(eval->Config));
+    std::string result =
+      cmStrCat(target->GetDirectory(eval->Context.Config), '/',
+               target->GetSOName(eval->Context.Config));
     return result;
   }
 };
@@ -3753,12 +3772,13 @@ struct TargetFilesystemArtifactResultCreator<ArtifactSonameImportTag>
       return std::string();
     }
 
-    if (target->HasImportLibrary(eval->Config)) {
+    if (target->HasImportLibrary(eval->Context.Config)) {
       return cmStrCat(
-        target->GetDirectory(eval->Config,
+        target->GetDirectory(eval->Context.Config,
                              cmStateEnums::ImportLibraryArtifact),
         '/',
-        target->GetSOName(eval->Config, cmStateEnums::ImportLibraryArtifact));
+        target->GetSOName(eval->Context.Config,
+                          cmStateEnums::ImportLibraryArtifact));
     }
     return std::string{};
   }
@@ -3777,11 +3797,11 @@ struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
       return std::string();
     }
 
-    std::string language = target->GetLinkerLanguage(eval->Config);
+    std::string language = target->GetLinkerLanguage(eval->Context.Config);
 
     std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
 
-    if (!eval->LG->GetMakefile()->IsOn(pdbSupportVar)) {
+    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
       ::reportError(eval, content->GetOriginalExpression(),
                     "TARGET_PDB_FILE is not supported by the target linker.");
       return std::string();
@@ -3798,8 +3818,9 @@ struct TargetFilesystemArtifactResultCreator<ArtifactPdbTag>
       return std::string();
     }
 
-    std::string result = cmStrCat(target->GetPDBDirectory(eval->Config), '/',
-                                  target->GetPDBName(eval->Config));
+    std::string result =
+      cmStrCat(target->GetPDBDirectory(eval->Context.Config), '/',
+               target->GetPDBName(eval->Context.Config));
     return result;
   }
 };
@@ -3820,10 +3841,10 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
       return std::string();
     }
     cmStateEnums::ArtifactType artifact =
-      target->HasImportLibrary(eval->Config)
+      target->HasImportLibrary(eval->Context.Config)
       ? cmStateEnums::ImportLibraryArtifact
       : cmStateEnums::RuntimeBinaryArtifact;
-    return target->GetFullPath(eval->Config, artifact);
+    return target->GetFullPath(eval->Context.Config, artifact);
   }
 };
 
@@ -3845,7 +3866,7 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerLibraryTag>
 
     if (!target->IsDLLPlatform() ||
         target->GetType() == cmStateEnums::STATIC_LIBRARY) {
-      return target->GetFullPath(eval->Config,
+      return target->GetFullPath(eval->Context.Config,
                                  cmStateEnums::RuntimeBinaryArtifact);
     }
     return std::string{};
@@ -3868,8 +3889,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerImportTag>
       return std::string();
     }
 
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetFullPath(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetFullPath(eval->Context.Config,
                                  cmStateEnums::ImportLibraryArtifact);
     }
     return std::string{};
@@ -3894,8 +3915,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
       return std::string();
     }
 
-    std::string outpath = target->GetDirectory(eval->Config) + '/';
-    return target->BuildBundleDirectory(outpath, eval->Config,
+    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
+    return target->BuildBundleDirectory(outpath, eval->Context.Config,
                                         cmGeneratorTarget::BundleDirLevel);
   }
 };
@@ -3921,7 +3942,7 @@ struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirNameTag>
     }
 
     auto level = cmGeneratorTarget::BundleDirLevel;
-    auto config = eval->Config;
+    auto config = eval->Context.Config;
     if (target->IsAppBundleOnApple()) {
       return target->GetAppBundleDirectory(config, level);
     }
@@ -3955,8 +3976,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
       return std::string();
     }
 
-    std::string outpath = target->GetDirectory(eval->Config) + '/';
-    return target->BuildBundleDirectory(outpath, eval->Config,
+    std::string outpath = target->GetDirectory(eval->Context.Config) + '/';
+    return target->BuildBundleDirectory(outpath, eval->Context.Config,
                                         cmGeneratorTarget::ContentLevel);
   }
 };
@@ -3968,7 +3989,7 @@ struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
                             cm::GenEx::Evaluation* eval,
                             GeneratorExpressionContent const* /*unused*/)
   {
-    return target->GetFullPath(eval->Config,
+    return target->GetFullPath(eval->Context.Config,
                                cmStateEnums::RuntimeBinaryArtifact, true);
   }
 };
@@ -3980,8 +4001,8 @@ struct TargetFilesystemArtifactResultCreator<ArtifactImportTag>
                             cm::GenEx::Evaluation* eval,
                             GeneratorExpressionContent const* /*unused*/)
   {
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetFullPath(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetFullPath(eval->Context.Config,
                                  cmStateEnums::ImportLibraryArtifact, true);
     }
     return std::string{};
@@ -4036,7 +4057,8 @@ protected:
                     "Expression syntax not recognized.");
       return nullptr;
     }
-    cmGeneratorTarget* target = eval->LG->FindGeneratorTargetToUse(name);
+    cmGeneratorTarget* target =
+      eval->Context.LG->FindGeneratorTargetToUse(name);
     if (!target) {
       ::reportError(eval, content->GetOriginalExpression(),
                     "No target \"" + name + "\"");
@@ -4160,9 +4182,9 @@ struct TargetOutputNameArtifactResultGetter<ArtifactNameTag>
                          cm::GenEx::Evaluation* eval,
                          GeneratorExpressionContent const* /*unused*/)
   {
-    return target->GetOutputName(eval->Config,
+    return target->GetOutputName(eval->Context.Config,
                                  cmStateEnums::RuntimeBinaryArtifact) +
-      target->GetFilePostfix(eval->Config);
+      target->GetFilePostfix(eval->Context.Config);
   }
 };
 
@@ -4173,10 +4195,10 @@ struct TargetOutputNameArtifactResultGetter<ArtifactImportTag>
                          cm::GenEx::Evaluation* eval,
                          GeneratorExpressionContent const* /*unused*/)
   {
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetOutputName(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetOutputName(eval->Context.Config,
                                    cmStateEnums::ImportLibraryArtifact) +
-        target->GetFilePostfix(eval->Config);
+        target->GetFilePostfix(eval->Context.Config);
     }
     return std::string{};
   }
@@ -4198,11 +4220,11 @@ struct TargetOutputNameArtifactResultGetter<ArtifactLinkerTag>
       return std::string();
     }
     cmStateEnums::ArtifactType artifact =
-      target->HasImportLibrary(eval->Config)
+      target->HasImportLibrary(eval->Context.Config)
       ? cmStateEnums::ImportLibraryArtifact
       : cmStateEnums::RuntimeBinaryArtifact;
-    return target->GetOutputName(eval->Config, artifact) +
-      target->GetFilePostfix(eval->Config);
+    return target->GetOutputName(eval->Context.Config, artifact) +
+      target->GetFilePostfix(eval->Context.Config);
   }
 };
 
@@ -4224,9 +4246,9 @@ struct TargetOutputNameArtifactResultGetter<ArtifactLinkerLibraryTag>
 
     if (!target->IsDLLPlatform() ||
         target->GetType() == cmStateEnums::STATIC_LIBRARY) {
-      return target->GetOutputName(eval->Config,
+      return target->GetOutputName(eval->Context.Config,
                                    cmStateEnums::ImportLibraryArtifact) +
-        target->GetFilePostfix(eval->Config);
+        target->GetFilePostfix(eval->Context.Config);
     }
     return std::string{};
   }
@@ -4247,10 +4269,10 @@ struct TargetOutputNameArtifactResultGetter<ArtifactLinkerImportTag>
       return std::string();
     }
 
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetOutputName(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetOutputName(eval->Context.Config,
                                    cmStateEnums::ImportLibraryArtifact) +
-        target->GetFilePostfix(eval->Config);
+        target->GetFilePostfix(eval->Context.Config);
     }
     return std::string{};
   }
@@ -4270,11 +4292,11 @@ struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
       return std::string();
     }
 
-    std::string language = target->GetLinkerLanguage(eval->Config);
+    std::string language = target->GetLinkerLanguage(eval->Context.Config);
 
     std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
 
-    if (!eval->LG->GetMakefile()->IsOn(pdbSupportVar)) {
+    if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
       ::reportError(
         eval, content->GetOriginalExpression(),
         "TARGET_PDB_FILE_BASE_NAME is not supported by the target linker.");
@@ -4292,7 +4314,7 @@ struct TargetOutputNameArtifactResultGetter<ArtifactPdbTag>
       return std::string();
     }
 
-    return target->GetPDBOutputName(eval->Config);
+    return target->GetPDBOutputName(eval->Context.Config);
   }
 };
 
@@ -4362,7 +4384,7 @@ struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
                          cm::GenEx::Evaluation* eval,
                          GeneratorExpressionContent const*)
   {
-    return target->GetFilePrefix(eval->Config);
+    return target->GetFilePrefix(eval->Context.Config);
   }
 };
 template <>
@@ -4372,8 +4394,8 @@ struct TargetFileArtifactResultGetter<ArtifactImportFilePrefixTag>
                          cm::GenEx::Evaluation* eval,
                          GeneratorExpressionContent const*)
   {
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetFilePrefix(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetFilePrefix(eval->Context.Config,
                                    cmStateEnums::ImportLibraryArtifact);
     }
     return std::string{};
@@ -4395,11 +4417,11 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
     }
 
     cmStateEnums::ArtifactType artifact =
-      target->HasImportLibrary(eval->Config)
+      target->HasImportLibrary(eval->Context.Config)
       ? cmStateEnums::ImportLibraryArtifact
       : cmStateEnums::RuntimeBinaryArtifact;
 
-    return target->GetFilePrefix(eval->Config, artifact);
+    return target->GetFilePrefix(eval->Context.Config, artifact);
   }
 };
 template <>
@@ -4420,7 +4442,7 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFilePrefixTag>
 
     if (!target->IsDLLPlatform() ||
         target->GetType() == cmStateEnums::STATIC_LIBRARY) {
-      return target->GetFilePrefix(eval->Config,
+      return target->GetFilePrefix(eval->Context.Config,
                                    cmStateEnums::RuntimeBinaryArtifact);
     }
     return std::string{};
@@ -4441,8 +4463,8 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerImportFilePrefixTag>
       return std::string();
     }
 
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetFilePrefix(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetFilePrefix(eval->Context.Config,
                                    cmStateEnums::ImportLibraryArtifact);
     }
     return std::string{};
@@ -4455,7 +4477,7 @@ struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
                          cm::GenEx::Evaluation* eval,
                          GeneratorExpressionContent const*)
   {
-    return target->GetFileSuffix(eval->Config);
+    return target->GetFileSuffix(eval->Context.Config);
   }
 };
 template <>
@@ -4465,8 +4487,8 @@ struct TargetFileArtifactResultGetter<ArtifactImportFileSuffixTag>
                          cm::GenEx::Evaluation* eval,
                          GeneratorExpressionContent const*)
   {
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetFileSuffix(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetFileSuffix(eval->Context.Config,
                                    cmStateEnums::ImportLibraryArtifact);
     }
     return std::string{};
@@ -4488,11 +4510,11 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
     }
 
     cmStateEnums::ArtifactType artifact =
-      target->HasImportLibrary(eval->Config)
+      target->HasImportLibrary(eval->Context.Config)
       ? cmStateEnums::ImportLibraryArtifact
       : cmStateEnums::RuntimeBinaryArtifact;
 
-    return target->GetFileSuffix(eval->Config, artifact);
+    return target->GetFileSuffix(eval->Context.Config, artifact);
   }
 };
 template <>
@@ -4512,7 +4534,7 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerLibraryFileSuffixTag>
 
     if (!target->IsDLLPlatform() ||
         target->GetType() == cmStateEnums::STATIC_LIBRARY) {
-      return target->GetFileSuffix(eval->Config,
+      return target->GetFileSuffix(eval->Context.Config,
                                    cmStateEnums::RuntimeBinaryArtifact);
     }
     return std::string{};
@@ -4533,8 +4555,8 @@ struct TargetFileArtifactResultGetter<ArtifactLinkerImportFileSuffixTag>
       return std::string();
     }
 
-    if (target->HasImportLibrary(eval->Config)) {
-      return target->GetFileSuffix(eval->Config,
+    if (target->HasImportLibrary(eval->Context.Config)) {
+      return target->GetFileSuffix(eval->Context.Config,
                                    cmStateEnums::ImportLibraryArtifact);
     }
     return std::string{};
@@ -4602,7 +4624,7 @@ static const struct ShellPathNode : public cmGeneratorExpressionNode
                   "\"\" is not an absolute path.");
       return std::string();
     }
-    cmStateSnapshot snapshot = eval->LG->GetStateSnapshot();
+    cmStateSnapshot snapshot = eval->Context.LG->GetStateSnapshot();
     cmOutputConverter converter(snapshot);
     char const* separator = snapshot.GetState()->UseWindowsShell() ? ";" : ":";
     std::vector<std::string> list_out;
@@ -4799,6 +4821,6 @@ void reportError(cm::GenEx::Evaluation* eval, std::string const& expr,
     << "  " << expr << "\n"
     << result;
   /* clang-format on */
-  eval->LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
-                                             eval->Backtrace);
+  eval->Context.LG->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+                                                     e.str(), eval->Backtrace);
 }

+ 16 - 9
Source/cmGeneratorTarget_TransitiveProperty.cxx

@@ -15,6 +15,7 @@
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionDAGChecker.h"
@@ -58,7 +59,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty(std::string const& prop,
                                                    cm::GenEx::Evaluation* eval,
                                                    UseTo usage) const
 {
-  std::string const key = prop + '@' + eval->Config;
+  std::string const key = prop + '@' + eval->Context.Config;
   auto i = this->MaybeInterfacePropertyExists.find(key);
   if (i == this->MaybeInterfacePropertyExists.end()) {
     // Insert an entry now in case there is a cycle.
@@ -73,7 +74,8 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty(std::string const& prop,
       cmGeneratorTarget const* headTarget =
         eval->HeadTarget ? eval->HeadTarget : this;
       if (cmLinkInterfaceLibraries const* iface =
-            this->GetLinkInterfaceLibraries(eval->Config, headTarget, usage)) {
+            this->GetLinkInterfaceLibraries(eval->Context.Config, headTarget,
+                                            usage)) {
         if (iface->HadHeadSensitiveCondition) {
           // With a different head target we may get to a library with
           // this interface property.
@@ -110,8 +112,13 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
   // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
   // but sufficient for transitive interface properties.
   cmGeneratorExpressionDAGChecker dagChecker{
-    this,     prop,         nullptr,         dagCheckerParent,
-    eval->LG, eval->Config, eval->Backtrace,
+    this,
+    prop,
+    nullptr,
+    dagCheckerParent,
+    eval->Context.LG,
+    eval->Context.Config,
+    eval->Backtrace,
   };
   switch (dagChecker.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
@@ -135,8 +142,8 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
       *p, eval, headTarget, &dagChecker, this);
   }
 
-  if (cmLinkInterfaceLibraries const* iface =
-        this->GetLinkInterfaceLibraries(eval->Config, headTarget, usage)) {
+  if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(
+        eval->Context.Config, headTarget, usage)) {
     eval->HadContextSensitiveCondition = eval->HadContextSensitiveCondition ||
       iface->HadContextSensitiveCondition;
     for (cmLinkItem const& lib : iface->Libraries) {
@@ -147,9 +154,9 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
         // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the
         // above property and hand-evaluate it as if it were compiled.
         // Create a context as cmCompiledGeneratorExpression::Evaluate does.
-        cm::GenEx::Evaluation libEval(
-          eval->LG, eval->Config, eval->Quiet, headTarget, this,
-          eval->EvaluateForBuildsystem, eval->Backtrace, eval->Language);
+        cm::GenEx::Evaluation libEval(eval->Context, eval->Quiet, headTarget,
+                                      this, eval->EvaluateForBuildsystem,
+                                      eval->Backtrace);
         std::string libResult = cmGeneratorExpression::StripEmptyListElements(
           lib.Target->EvaluateInterfaceProperty(prop, &libEval, &dagChecker,
                                                 usage));

+ 1 - 0
bootstrap

@@ -375,6 +375,7 @@ CMAKE_CXX_SOURCES="\
   cmFunctionCommand \
   cmFSPermissions \
   cmGeneratedFileStream \
+  cmGenExContext \
   cmGenExEvaluation \
   cmGeneratorExpression \
   cmGeneratorExpressionDAGChecker \