Преглед изворни кода

Merge topic 'custom-transitive-properties'

77c7397ab4 Merge branch 'backport-3.31-custom-transitive-properties'
478d6cfd9a Merge branch 'backport-3.30-custom-transitive-properties'
8b5af40b34 GenEx: Fix evaluation of LINK_LIBRARIES as custom transitive property
161f703e76 GenEx: Restore evaluation context for conditional transitive properties
419c19d531 Tests: Extend CustomTransitiveProperties with custom transitive LINK_LIBRARIES
ff2004d430 Tests: Extend CustomTransitiveProperties with non-transitive LINK_LIBRARIES
d7f1a100d9 Tests: Split CustomTransitiveProperties argument checks into helper
5ac3cca63d Merge branch 'backport-3.31-custom-transitive-properties' (early part)
...

Acked-by: Kitware Robot <[email protected]>
Acked-by: buildbot <[email protected]>
Merge-request: !10384
Brad King пре 7 месеци
родитељ
комит
f48beab388

+ 4 - 3
Source/cmCommonTargetGenerator.cxx

@@ -500,9 +500,10 @@ std::string cmCommonTargetGenerator::GetLinkerLauncher(
   std::string propName = lang + "_LINKER_LAUNCHER";
   cmValue launcherProp = this->GeneratorTarget->GetProperty(propName);
   if (cmNonempty(launcherProp)) {
-    cmGeneratorExpressionDAGChecker dagChecker(
-      this->GeneratorTarget, propName, nullptr, nullptr,
-      this->LocalCommonGenerator, config);
+    cmGeneratorExpressionDAGChecker dagChecker{
+      this->GeneratorTarget,      propName, nullptr, nullptr,
+      this->LocalCommonGenerator, config,
+    };
     std::string evaluatedLinklauncher = cmGeneratorExpression::Evaluate(
       *launcherProp, this->LocalCommonGenerator, config, this->GeneratorTarget,
       &dagChecker, this->GeneratorTarget, lang);

+ 15 - 13
Source/cmComputeLinkDepends.cxx

@@ -626,18 +626,18 @@ cmComputeLinkDepends::cmComputeLinkDepends(cmGeneratorTarget const* target,
         if (cmValue feature = this->Target->GetProperty(key)) {
           if (!feature->empty() && key.length() > lloPrefix.length()) {
             auto item = key.substr(lloPrefix.length());
-            cmGeneratorExpressionDAGChecker dag{
-              this->Target->GetBacktrace(),
+            cmGeneratorExpressionDAGChecker dagChecker{
               this->Target,
               "LINK_LIBRARY_OVERRIDE",
               nullptr,
               nullptr,
               this->Target->GetLocalGenerator(),
-              config
+              config,
+              this->Target->GetBacktrace(),
             };
             auto overrideFeature = cmGeneratorExpression::Evaluate(
               *feature, this->Target->GetLocalGenerator(), config,
-              this->Target, &dag, this->Target, linkLanguage);
+              this->Target, &dagChecker, this->Target, linkLanguage);
             this->LinkLibraryOverride.emplace(item, overrideFeature);
           }
         }
@@ -646,16 +646,18 @@ cmComputeLinkDepends::cmComputeLinkDepends(cmGeneratorTarget const* target,
   // global override property
   if (cmValue linkLibraryOverride =
         this->Target->GetProperty("LINK_LIBRARY_OVERRIDE")) {
-    cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(),
-                                         target,
-                                         "LINK_LIBRARY_OVERRIDE",
-                                         nullptr,
-                                         nullptr,
-                                         target->GetLocalGenerator(),
-                                         config };
+    cmGeneratorExpressionDAGChecker dagChecker{
+      target,
+      "LINK_LIBRARY_OVERRIDE",
+      nullptr,
+      nullptr,
+      target->GetLocalGenerator(),
+      config,
+      target->GetBacktrace(),
+    };
     auto overrideValue = cmGeneratorExpression::Evaluate(
-      *linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag,
-      target, linkLanguage);
+      *linkLibraryOverride, target->GetLocalGenerator(), config, target,
+      &dagChecker, target, linkLanguage);
 
     std::vector<std::string> overrideList =
       cmTokenize(overrideValue, ',', cmTokenizerMode::New);

+ 8 - 3
Source/cmExportTryCompileFileGenerator.cxx

@@ -86,9 +86,14 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
       tgt, "LINK_OPTIONS", nullptr, nullptr, tgt->GetLocalGenerator(),
       this->Config);
   }
-  cmGeneratorExpressionDAGChecker dagChecker(
-    tgt, propName, nullptr, parentDagChecker.get(), tgt->GetLocalGenerator(),
-    this->Config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    tgt,
+    propName,
+    nullptr,
+    parentDagChecker.get(),
+    tgt->GetLocalGenerator(),
+    this->Config,
+  };
 
   std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*prop);
 

+ 7 - 3
Source/cmGeneratorExpression.cxx

@@ -425,10 +425,14 @@ std::string const& cmGeneratorExpressionInterpreter::Evaluate(
     this->GeneratorExpression.Parse(std::move(expression));
 
   // Specify COMPILE_OPTIONS to DAGchecker, same semantic as COMPILE_FLAGS
-  cmGeneratorExpressionDAGChecker dagChecker(
+  cmGeneratorExpressionDAGChecker dagChecker{
     this->HeadTarget,
-    property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, nullptr,
-    nullptr, this->LocalGenerator, this->Config);
+    property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property,
+    nullptr,
+    nullptr,
+    this->LocalGenerator,
+    this->Config,
+  };
 
   return this->CompiledGeneratorExpression->Evaluate(
     this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr,

+ 9 - 14
Source/cmGeneratorExpressionDAGChecker.cxx

@@ -21,32 +21,22 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   cmGeneratorTarget const* target, std::string property,
   GeneratorExpressionContent const* content,
   cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG,
-  std::string const& contextConfig)
-  : cmGeneratorExpressionDAGChecker(cmListFileBacktrace(), target,
-                                    std::move(property), content, parent,
-                                    contextLG, contextConfig)
-{
-}
-
-cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
-  cmListFileBacktrace backtrace, cmGeneratorTarget const* target,
-  std::string property, GeneratorExpressionContent const* content,
-  cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG,
-  std::string const& contextConfig)
+  std::string const& contextConfig, cmListFileBacktrace backtrace,
+  ComputingLinkLibraries computingLinkLibraries)
   : Parent(parent)
   , Top(parent ? parent->Top : this)
   , Target(target)
   , Property(std::move(property))
   , Content(content)
   , Backtrace(std::move(backtrace))
+  , ComputingLinkLibraries_(computingLinkLibraries)
 {
   if (parent) {
     this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty;
   } else {
     this->TopIsTransitiveProperty =
       this->Target
-        ->IsTransitiveProperty(this->Property, contextLG, contextConfig,
-                               this->EvaluatingLinkLibraries())
+        ->IsTransitiveProperty(this->Property, contextLG, contextConfig, this)
         .has_value();
   }
 
@@ -204,6 +194,11 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const
     "_LINKER_LAUNCHER"_s;
 }
 
+bool cmGeneratorExpressionDAGChecker::IsComputingLinkLibraries() const
+{
+  return this->Top->ComputingLinkLibraries_ == ComputingLinkLibraries::Yes;
+}
+
 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
   cmGeneratorTarget const* tgt, ForGenex genex) const
 {

+ 20 - 13
Source/cmGeneratorExpressionDAGChecker.h

@@ -17,19 +17,19 @@ class cmLocalGenerator;
 
 struct cmGeneratorExpressionDAGChecker
 {
-  cmGeneratorExpressionDAGChecker(cmListFileBacktrace backtrace,
-                                  cmGeneratorTarget const* target,
-                                  std::string property,
-                                  GeneratorExpressionContent const* content,
-                                  cmGeneratorExpressionDAGChecker* parent,
-                                  cmLocalGenerator const* contextLG,
-                                  std::string const& contextConfig);
-  cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target,
-                                  std::string property,
-                                  GeneratorExpressionContent const* content,
-                                  cmGeneratorExpressionDAGChecker* parent,
-                                  cmLocalGenerator const* contextLG,
-                                  std::string const& contextConfig);
+  enum class ComputingLinkLibraries
+  {
+    No,
+    Yes,
+  };
+  cmGeneratorExpressionDAGChecker(
+    cmGeneratorTarget const* target, std::string property,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG,
+    std::string const& contextConfig,
+    cmListFileBacktrace backtrace = cmListFileBacktrace(),
+    ComputingLinkLibraries computingLinkLibraries =
+      ComputingLinkLibraries::No);
 
   enum Result
   {
@@ -52,6 +52,11 @@ struct cmGeneratorExpressionDAGChecker
   bool EvaluatingLinkOptionsExpression() const;
   bool EvaluatingLinkerLauncher() const;
 
+  /** Returns true only when computing the actual link dependency
+      graph for cmGeneratorTarget::GetLinkImplementationLibraries
+      or cmGeneratorTarget::GetLinkInterfaceLibraries.  */
+  bool IsComputingLinkLibraries() const;
+
   enum class ForGenex
   {
     ANY,
@@ -85,4 +90,6 @@ private:
   bool TransitivePropertiesOnly = false;
   bool CMP0131 = false;
   bool TopIsTransitiveProperty = false;
+  ComputingLinkLibraries const ComputingLinkLibraries_ =
+    ComputingLinkLibraries::No;
 };

+ 19 - 9
Source/cmGeneratorExpressionNode.cxx

@@ -483,10 +483,15 @@ protected:
     cmGeneratorExpressionDAGChecker* dagCheckerParent) const
   {
     if (context->HeadTarget) {
-      cmGeneratorExpressionDAGChecker dagChecker(
-        context->Backtrace, context->HeadTarget,
-        genexOperator + ":" + expression, content, dagCheckerParent,
-        context->LG, context->Config);
+      cmGeneratorExpressionDAGChecker dagChecker{
+        context->HeadTarget,
+        genexOperator + ":" + expression,
+        content,
+        dagCheckerParent,
+        context->LG,
+        context->Config,
+        context->Backtrace,
+      };
       switch (dagChecker.Check()) {
         case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
         case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
@@ -2957,8 +2962,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
 
     if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
           target->IsTransitiveProperty(propertyName, context->LG,
-                                       context->Config,
-                                       evaluatingLinkLibraries)) {
+                                       context->Config, dagCheckerParent)) {
       interfacePropertyName = std::string(transitiveProp->InterfaceName);
       isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
       usage = transitiveProp->Usage;
@@ -2992,9 +2996,15 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
                                           dagCheckerParent, usage));
     }
 
-    cmGeneratorExpressionDAGChecker dagChecker(
-      context->Backtrace, target, propertyName, content, dagCheckerParent,
-      context->LG, context->Config);
+    cmGeneratorExpressionDAGChecker dagChecker{
+      target,
+      propertyName,
+      content,
+      dagCheckerParent,
+      context->LG,
+      context->Config,
+      context->Backtrace,
+    };
 
     switch (dagChecker.Check()) {
       case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:

+ 10 - 7
Source/cmGeneratorTarget.cxx

@@ -737,8 +737,9 @@ std::string cmGeneratorTarget::GetLinkerTypeProperty(
   std::string propName{ "LINKER_TYPE" };
   auto linkerType = this->GetProperty(propName);
   if (!linkerType.IsEmpty()) {
-    cmGeneratorExpressionDAGChecker dagChecker(
-      this, propName, nullptr, nullptr, this->LocalGenerator, config);
+    cmGeneratorExpressionDAGChecker dagChecker{
+      this, propName, nullptr, nullptr, this->LocalGenerator, config,
+    };
     auto ltype =
       cmGeneratorExpression::Evaluate(*linkerType, this->GetLocalGenerator(),
                                       config, this, &dagChecker, this, lang);
@@ -1198,9 +1199,10 @@ void cmGeneratorTarget::AddSystemIncludeCacheKey(
   std::string const& key, std::string const& config,
   std::string const& language) const
 {
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr, this->LocalGenerator,
-    config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this,    "SYSTEM_INCLUDE_DIRECTORIES", nullptr,
+    nullptr, this->LocalGenerator,         config,
+  };
 
   bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
 
@@ -1969,8 +1971,9 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
     return;
   }
 
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "AUTOUIC_OPTIONS", nullptr, nullptr, this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "AUTOUIC_OPTIONS", nullptr, nullptr, this->LocalGenerator, config,
+  };
   cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator,
                                                config, this, &dagChecker),
                result);

+ 2 - 1
Source/cmGeneratorTarget.h

@@ -1006,7 +1006,8 @@ public:
 
   cm::optional<TransitiveProperty> IsTransitiveProperty(
     cm::string_view prop, cmLocalGenerator const* lg,
-    std::string const& config, bool evaluatingLinkLibraries) const;
+    std::string const& config,
+    cmGeneratorExpressionDAGChecker const* dagChecker) const;
 
   bool HaveInstallTreeRPATH(std::string const& config) const;
 

+ 26 - 15
Source/cmGeneratorTarget_IncludeDirectories.cxx

@@ -46,13 +46,18 @@ std::string AddLangSpecificInterfaceIncludeDirectories(
   std::string const& propertyName, IncludeDirectoryFallBack mode,
   cmGeneratorExpressionDAGChecker* context)
 {
-  cmGeneratorExpressionDAGChecker dag{
-    target->GetBacktrace(),      target, propertyName, nullptr, context,
-    target->GetLocalGenerator(), config
+  cmGeneratorExpressionDAGChecker dagChecker{
+    target,
+    propertyName,
+    nullptr,
+    context,
+    target->GetLocalGenerator(),
+    config,
+    target->GetBacktrace(),
   };
-  switch (dag.Check()) {
+  switch (dagChecker.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
-      dag.ReportError(
+      dagChecker.ReportError(
         nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
       CM_FALLTHROUGH;
     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
@@ -99,9 +104,14 @@ void AddLangSpecificImplicitIncludeDirectories(
 {
   if (auto const* libraries =
         target->GetLinkImplementationLibraries(config, UseTo::Compile)) {
-    cmGeneratorExpressionDAGChecker dag{
-      target->GetBacktrace(),      target, propertyName, nullptr, nullptr,
-      target->GetLocalGenerator(), config
+    cmGeneratorExpressionDAGChecker dagChecker{
+      target,
+      propertyName,
+      nullptr,
+      nullptr,
+      target->GetLocalGenerator(),
+      config,
+      target->GetBacktrace(),
     };
 
     for (cmLinkImplItem const& library : libraries->Libraries) {
@@ -127,10 +137,10 @@ void AddLangSpecificImplicitIncludeDirectories(
             }
           }
 
-          cmExpandList(
-            AddLangSpecificInterfaceIncludeDirectories(
-              target, dependency, lang, config, propertyName, mode, &dag),
-            entry.Values);
+          cmExpandList(AddLangSpecificInterfaceIncludeDirectories(
+                         target, dependency, lang, config, propertyName, mode,
+                         &dagChecker),
+                       entry.Values);
           entries.Entries.emplace_back(std::move(entry));
         }
       }
@@ -222,9 +232,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
   std::vector<BT<std::string>> includes;
   std::unordered_set<std::string> uniqueIncludes;
 
-  cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES",
-                                             nullptr, nullptr,
-                                             this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this,    "INCLUDE_DIRECTORIES", nullptr,
+    nullptr, this->LocalGenerator,  config,
+  };
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };

+ 20 - 4
Source/cmGeneratorTarget_Link.cxx

@@ -542,8 +542,16 @@ void cmGeneratorTarget::ExpandLinkItems(std::string const& prop,
     return;
   }
   // Keep this logic in sync with ComputeLinkImplementationLibraries.
-  cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr,
-                                             this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this,
+    prop,
+    nullptr,
+    nullptr,
+    this->LocalGenerator,
+    config,
+    cmListFileBacktrace(),
+    cmGeneratorExpressionDAGChecker::ComputingLinkLibraries::Yes,
+  };
   // The $<LINK_ONLY> expression may be in a link interface to specify
   // private link dependencies that are otherwise excluded from usage
   // requirements.
@@ -1133,8 +1141,16 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
   // Collect libraries directly linked in this configuration.
   for (auto const& entry : entryRange) {
     // Keep this logic in sync with ExpandLinkItems.
-    cmGeneratorExpressionDAGChecker dagChecker(
-      this, "LINK_LIBRARIES", nullptr, nullptr, this->LocalGenerator, config);
+    cmGeneratorExpressionDAGChecker dagChecker{
+      this,
+      "LINK_LIBRARIES",
+      nullptr,
+      nullptr,
+      this->LocalGenerator,
+      config,
+      cmListFileBacktrace(),
+      cmGeneratorExpressionDAGChecker::ComputingLinkLibraries::Yes,
+    };
     // The $<LINK_ONLY> expression may be used to specify link dependencies
     // that are otherwise excluded from usage requirements.
     if (usage == UseTo::Compile) {

+ 3 - 2
Source/cmGeneratorTarget_LinkDirectories.cxx

@@ -122,8 +122,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
   std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueDirectories;
 
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "LINK_DIRECTORIES", nullptr, nullptr, this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "LINK_DIRECTORIES", nullptr, nullptr, this->LocalGenerator, config,
+  };
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };

+ 23 - 17
Source/cmGeneratorTarget_Options.cxx

@@ -230,8 +230,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
   std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueOptions;
 
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "COMPILE_OPTIONS", nullptr, nullptr, this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "COMPILE_OPTIONS", nullptr, nullptr, this->LocalGenerator, config,
+  };
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -269,8 +270,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
   std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueFeatures;
 
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "COMPILE_FEATURES", nullptr, nullptr, this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "COMPILE_FEATURES", nullptr, nullptr, this->LocalGenerator, config,
+  };
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -317,9 +319,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions(
   std::vector<BT<std::string>> list;
   std::unordered_set<std::string> uniqueOptions;
 
-  cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS",
-                                             nullptr, nullptr,
-                                             this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this,    "COMPILE_DEFINITIONS", nullptr,
+    nullptr, this->LocalGenerator,  config,
+  };
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -353,9 +356,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
   }
   std::unordered_set<std::string> uniqueOptions;
 
-  cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
-                                             nullptr, nullptr,
-                                             this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "PRECOMPILE_HEADERS", nullptr, nullptr, this->LocalGenerator, config,
+  };
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -410,8 +413,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
   std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueOptions;
 
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "LINK_OPTIONS", nullptr, nullptr, this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "LINK_OPTIONS", nullptr, nullptr, this->LocalGenerator, config,
+  };
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -591,9 +595,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions(
   std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueOptions;
 
-  cmGeneratorExpressionDAGChecker dagChecker(this, "STATIC_LIBRARY_OPTIONS",
-                                             nullptr, nullptr,
-                                             this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this,    "STATIC_LIBRARY_OPTIONS", nullptr,
+    nullptr, this->LocalGenerator,     config,
+  };
 
   EvaluatedTargetPropertyEntries entries;
   if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
@@ -635,8 +640,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends(
 {
   std::vector<BT<std::string>> result;
   std::unordered_set<std::string> uniqueOptions;
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "LINK_DEPENDS", nullptr, nullptr, this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "LINK_DEPENDS", nullptr, nullptr, this->LocalGenerator, config,
+  };
 
   EvaluatedTargetPropertyEntries entries;
   if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {

+ 3 - 2
Source/cmGeneratorTarget_Sources.cxx

@@ -240,8 +240,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
 
   this->DebugSourcesDone = true;
 
-  cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr,
-                                             this->LocalGenerator, config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this, "SOURCES", nullptr, nullptr, this->LocalGenerator, config,
+  };
 
   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
     this, config, std::string(), &dagChecker, this->SourceEntries);

+ 13 - 8
Source/cmGeneratorTarget_TransitiveProperty.cxx

@@ -109,9 +109,15 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
   // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled.  This is
   // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
   // but sufficient for transitive interface properties.
-  cmGeneratorExpressionDAGChecker dagChecker(
-    context->Backtrace, this, prop, nullptr, dagCheckerParent,
-    this->LocalGenerator, context->Config);
+  cmGeneratorExpressionDAGChecker dagChecker{
+    this,
+    prop,
+    nullptr,
+    dagCheckerParent,
+    context->LG,
+    context->Config,
+    context->Backtrace,
+  };
   switch (dagChecker.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
       dagChecker.ReportError(
@@ -177,10 +183,9 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
 }
 
 cm::optional<cmGeneratorTarget::TransitiveProperty>
-cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
-                                        cmLocalGenerator const* lg,
-                                        std::string const& config,
-                                        bool evaluatingLinkLibraries) const
+cmGeneratorTarget::IsTransitiveProperty(
+  cm::string_view prop, cmLocalGenerator const* lg, std::string const& config,
+  cmGeneratorExpressionDAGChecker const* dagChecker) const
 {
   cm::optional<TransitiveProperty> result;
   static cm::string_view const kINTERFACE_ = "INTERFACE_"_s;
@@ -202,7 +207,7 @@ cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
         result->Usage = cmGeneratorTarget::UseTo::Compile;
       }
     }
-  } else if (!evaluatingLinkLibraries) {
+  } else if (!dagChecker || !dagChecker->IsComputingLinkLibraries()) {
     // Honor TRANSITIVE_COMPILE_PROPERTIES and TRANSITIVE_LINK_PROPERTIES
     // from the link closure when we are not evaluating the closure itself.
     CustomTransitiveProperties const& ctp =

+ 8 - 6
Source/cmQtAutoGenInitializer.cxx

@@ -1920,9 +1920,10 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
     if (this->MultiConfig) {
       for (auto const& cfg : this->ConfigsList) {
         if (!cfg.empty()) {
-          cmGeneratorExpressionDAGChecker dagChecker(
-            this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr,
-            this->LocalGen, cfg);
+          cmGeneratorExpressionDAGChecker dagChecker{
+            this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr,
+            nullptr,         this->LocalGen,        cfg,
+          };
           AddInterfaceEntries(this->GenTarget, cfg,
                               "INTERFACE_AUTOMOC_MACRO_NAMES", "CXX",
                               &dagChecker, InterfaceAutoMocMacroNamesEntries,
@@ -1930,9 +1931,10 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
         }
       }
     } else {
-      cmGeneratorExpressionDAGChecker dagChecker(
-        this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr,
-        this->LocalGen, this->ConfigDefault);
+      cmGeneratorExpressionDAGChecker dagChecker{
+        this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr,
+        nullptr,         this->LocalGen,        this->ConfigDefault,
+      };
       AddInterfaceEntries(this->GenTarget, this->ConfigDefault,
                           "INTERFACE_AUTOMOC_MACRO_NAMES", "CXX", &dagChecker,
                           InterfaceAutoMocMacroNamesEntries,

+ 68 - 1
Tests/CustomTransitiveProperties/CMakeLists.txt

@@ -90,9 +90,22 @@ target_compile_definitions(CustomTransitiveProperties PRIVATE
   $<TARGET_PROPERTY:CUSTOM_W>
   )
 
+# Test TRANSITIVE_LINK_PROPERTIES containing LINK_LIBRARIES itself.
+add_library(iface10 INTERFACE)
+set_property(TARGET iface10 PROPERTY TRANSITIVE_LINK_PROPERTIES "LINK_LIBRARIES")
+add_library(iface11 INTERFACE)
+target_link_libraries(iface11 INTERFACE iface10)
+add_library(static10 STATIC static10.c)
+target_link_libraries(static10 PRIVATE iface11)
+add_library(static11 STATIC static11.c)
+target_link_libraries(static11 PRIVATE static10 iface11)
+add_executable(main10 main10.c)
+target_link_libraries(main10 PRIVATE static11 static10)
+
 # Test TRANSITIVE_*_PROPERTY evaluation outside of usage requirements.
+add_executable(check-args check-args.c)
 set(out "${CMAKE_CURRENT_BINARY_DIR}/out-$<CONFIG>.txt")
-file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced:
+set(in_CUSTOM [====[
 iface1 CUSTOM_A: '$<TARGET_PROPERTY:iface1,CUSTOM_A>'
 iface1 INTERFACE_CUSTOM_A: '$<TARGET_PROPERTY:iface1,INTERFACE_CUSTOM_A>'
 iface2 CUSTOM_A: '$<TARGET_PROPERTY:iface2,CUSTOM_A>'
@@ -125,10 +138,35 @@ main CUSTOM_V: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_V>'
 main INTERFACE_CUSTOM_V: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_V>'
 main CUSTOM_W: '$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_W>'
 main INTERFACE_CUSTOM_W: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_CUSTOM_W>'
+]====])
+set(in_LINK_LIBRARIES [====[
+iface1 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface1,LINK_LIBRARIES>'
+iface1 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface1,INTERFACE_LINK_LIBRARIES>'
+iface2 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface2,LINK_LIBRARIES>'
+iface2 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface2,INTERFACE_LINK_LIBRARIES>'
+static1 LINK_LIBRARIES: '$<TARGET_PROPERTY:static1,LINK_LIBRARIES>'
+static1 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:static1,INTERFACE_LINK_LIBRARIES>'
+main LINK_LIBRARIES: '$<TARGET_PROPERTY:CustomTransitiveProperties,LINK_LIBRARIES>'
+main INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_LINK_LIBRARIES>'
+iface10 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface10,LINK_LIBRARIES>'
+iface10 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface10,INTERFACE_LINK_LIBRARIES>'
+iface11 LINK_LIBRARIES: '$<TARGET_PROPERTY:iface11,LINK_LIBRARIES>'
+iface11 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:iface11,INTERFACE_LINK_LIBRARIES>'
+static10 LINK_LIBRARIES: '$<TARGET_PROPERTY:static10,LINK_LIBRARIES>'
+static10 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:static10,INTERFACE_LINK_LIBRARIES>'
+static11 LINK_LIBRARIES: '$<TARGET_PROPERTY:static11,LINK_LIBRARIES>'
+static11 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:static11,INTERFACE_LINK_LIBRARIES>'
+main10 LINK_LIBRARIES: '$<TARGET_PROPERTY:main10,LINK_LIBRARIES>'
+main10 INTERFACE_LINK_LIBRARIES: '$<TARGET_PROPERTY:main10,INTERFACE_LINK_LIBRARIES>'
+]====])
+file(GENERATE OUTPUT "${out}" CONTENT "# file(GENERATE) produced:
+${in_CUSTOM}
+${in_LINK_LIBRARIES}
 ")
 add_custom_target(check ALL VERBATIM
   COMMAND ${CMAKE_COMMAND} -Dconfig=$<CONFIG> -Dout=${out} -P${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
   COMMAND CustomTransitiveProperties
+  COMMAND check-args
   "$<TARGET_PROPERTY:static1,CUSTOM_A>" "CUSTOM_A_STATIC1;CUSTOM_A_IFACE2;CUSTOM_A_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_A_IFACE1;CUSTOM_A_TARGET_NAME_STATIC1"
   "$<TARGET_PROPERTY:static1,CUSTOM_B>" "CUSTOM_B_STATIC1;CUSTOM_B_IFACE1"
   "$<TARGET_PROPERTY:static1,CUSTOM_U>" "CUSTOM_U_STATIC1;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_STATIC_LIBRARY;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_STATIC1"
@@ -143,4 +181,33 @@ add_custom_target(check ALL VERBATIM
   "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_U>" "CUSTOM_U_MAIN;CUSTOM_U_STATIC1_IFACE;CUSTOM_U_IFACE2;CUSTOM_U_TARGET_TYPE_EXECUTABLE;CUSTOM_U_IFACE1;CUSTOM_U_TARGET_NAME_CUSTOMTRANSITIVEPROPERTIES;CUSTOM_U_OBJECT1_IFACE"
   "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_V>" "CUSTOM_V_MAIN;CUSTOM_V_STATIC1_IFACE;CUSTOM_V_IFACE1"
   "$<TARGET_PROPERTY:CustomTransitiveProperties,CUSTOM_W>" "CUSTOM_W_MAIN;CUSTOM_W_IFACE1;CUSTOM_W_OBJECT1_IFACE"
+  COMMAND check-args
+  "$<TARGET_PROPERTY:iface1,LINK_LIBRARIES>" ""
+  "$<TARGET_PROPERTY:iface1,INTERFACE_LINK_LIBRARIES>" ""
+  "$<TARGET_PROPERTY:iface2,LINK_LIBRARIES>" ""
+  "$<TARGET_PROPERTY:iface2,INTERFACE_LINK_LIBRARIES>" "iface1"
+  "$<TARGET_PROPERTY:static1,LINK_LIBRARIES>" "iface2"
+  "$<TARGET_PROPERTY:static1,INTERFACE_LINK_LIBRARIES>" "$<LINK_ONLY:iface2$<ANGLE-R>"
+  "$<TARGET_PROPERTY:CustomTransitiveProperties,LINK_LIBRARIES>" "static1;object1"
+  "$<TARGET_PROPERTY:CustomTransitiveProperties,INTERFACE_LINK_LIBRARIES>" ""
+  COMMAND check-args
+  "$<TARGET_PROPERTY:iface10,LINK_LIBRARIES>" ""
+  "$<TARGET_PROPERTY:iface10,INTERFACE_LINK_LIBRARIES>" ""
+  "$<TARGET_PROPERTY:iface11,LINK_LIBRARIES>" ""
+  "$<TARGET_PROPERTY:iface11,INTERFACE_LINK_LIBRARIES>" "iface10"
+  "$<TARGET_PROPERTY:static10,LINK_LIBRARIES>" "iface11;iface10"
+  #                                              _/         \__
+  #                                             /              \
+  #                               "static10[iface11];iface11[iface10]"
+  "$<TARGET_PROPERTY:static10,INTERFACE_LINK_LIBRARIES>" "iface11;iface10"
+  "$<TARGET_PROPERTY:static11,LINK_LIBRARIES>" "static10;iface11;iface11;iface10"
+  #                                             __/      __/         \__     \__________
+  #                                            /        /               \               \
+  #                              "static11[static10;iface11];static10[iface11;iface11[iface10]]"
+  "$<TARGET_PROPERTY:static11,INTERFACE_LINK_LIBRARIES>" "static10;iface11;iface11;iface10"
+  "$<TARGET_PROPERTY:main10,LINK_LIBRARIES>" "static11;static10;static10;iface11;iface11;iface10"
+  #                                      _______/ _______/         |        |        \______ \______________
+  #                                     /        /                 |        |               \               \
+  #                         "main10[static11;static10];static11[static10;iface11;static10[iface11;iface11[iface10]]]"
+  "$<TARGET_PROPERTY:main10,INTERFACE_LINK_LIBRARIES>" ""
   )

+ 16 - 0
Tests/CustomTransitiveProperties/check-args.c

@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char** argv)
+{
+  int result = 0;
+  int i;
+  for (i = 2; i < argc; i += 2) {
+    if (strcmp(argv[i - 1], argv[i]) != 0) {
+      fprintf(stderr, "Argument %d expected '%s' but got '%s'.\n", i, argv[i],
+              argv[i - 1]);
+      result = 1;
+    }
+  }
+  return result;
+}

+ 19 - 0
Tests/CustomTransitiveProperties/check.cmake

@@ -32,6 +32,25 @@ main CUSTOM_V: 'CUSTOM_V_MAIN;CUSTOM_V_STATIC1_IFACE;CUSTOM_V_IFACE1'
 main INTERFACE_CUSTOM_V: ''
 main CUSTOM_W: 'CUSTOM_W_MAIN;CUSTOM_W_IFACE1;CUSTOM_W_OBJECT1_IFACE'
 main INTERFACE_CUSTOM_W: ''
+
+iface1 LINK_LIBRARIES: ''
+iface1 INTERFACE_LINK_LIBRARIES: ''
+iface2 LINK_LIBRARIES: ''
+iface2 INTERFACE_LINK_LIBRARIES: 'iface1'
+static1 LINK_LIBRARIES: 'iface2'
+static1 INTERFACE_LINK_LIBRARIES: '\$<LINK_ONLY:iface2>'
+main LINK_LIBRARIES: 'static1;object1'
+main INTERFACE_LINK_LIBRARIES: ''
+iface10 LINK_LIBRARIES: ''
+iface10 INTERFACE_LINK_LIBRARIES: ''
+iface11 LINK_LIBRARIES: ''
+iface11 INTERFACE_LINK_LIBRARIES: 'iface10'
+static10 LINK_LIBRARIES: 'iface11;iface10'
+static10 INTERFACE_LINK_LIBRARIES: 'iface11;iface10'
+static11 LINK_LIBRARIES: 'static10;iface11;iface11;iface10'
+static11 INTERFACE_LINK_LIBRARIES: 'static10;iface11;iface11;iface10'
+main10 LINK_LIBRARIES: 'static11;static10;static10;iface11;iface11;iface10'
+main10 INTERFACE_LINK_LIBRARIES: ''
 ]])
 string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
 string(REGEX REPLACE "\n+$" "" expect "${expect}")

+ 2 - 19
Tests/CustomTransitiveProperties/main.c

@@ -1,6 +1,3 @@
-#include <stdio.h>
-#include <string.h>
-
 #ifdef CUSTOM_A_IFACE1
 #  error "CUSTOM_A_IFACE1 incorrectly defined"
 #endif
@@ -117,21 +114,7 @@
 extern int static1(void);
 extern int object1(void);
 
-int check_args(int argc, char** argv)
-{
-  int result = 0;
-  int i;
-  for (i = 2; i < argc; i += 2) {
-    if (strcmp(argv[i - 1], argv[i]) != 0) {
-      fprintf(stderr, "Argument %d expected '%s' but got '%s'.\n", i, argv[i],
-              argv[i - 1]);
-      result = 1;
-    }
-  }
-  return result;
-}
-
-int main(int argc, char** argv)
+int main(void)
 {
-  return static1() + object1() + check_args(argc, argv);
+  return static1() + object1();
 }

+ 7 - 0
Tests/CustomTransitiveProperties/main10.c

@@ -0,0 +1,7 @@
+extern int static10(void);
+extern int static11(void);
+
+int main(void)
+{
+  return static10() + static11();
+}

+ 4 - 0
Tests/CustomTransitiveProperties/static10.c

@@ -0,0 +1,4 @@
+int static10(void)
+{
+  return 0;
+}

+ 4 - 0
Tests/CustomTransitiveProperties/static11.c

@@ -0,0 +1,4 @@
+int static11(void)
+{
+  return 0;
+}