From b36fb3f6f1aed3c1313ff257945632d13704e1e6 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 22 Apr 2024 13:33:13 -0400
Subject: cmGeneratorExpressionNode: Remove outdated lint suppression

Since commit 895efd4e7a (cmGeneratorExpression: Consolidate
recognition of transitive properties, 2024-04-12) a lint suppression
added by commit fb461cacba (silence selected clang-tidy violations,
2016-10-18, v3.8.0-rc1~428^2~1) is no longer needed.
---
 Source/cmGeneratorExpressionNode.cxx | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 0df086b..46a7d50 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2916,8 +2916,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
           return std::string();
         }
       } else {
-        assert(dagCheckerParent
-                 ->EvaluatingTransitiveProperty()); // NOLINT(clang-tidy)
+        assert(dagCheckerParent->EvaluatingTransitiveProperty());
       }
     }
 
-- 
cgit v0.12


From e8010b67c7050aca36f5db9a75027606af35b93a Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 25 Apr 2024 15:30:49 -0400
Subject: cmGeneratorExpressionDAGChecker: Make local generator available in
 constructor

This is the local generator in the evaluation context, not that of
the current target/property pair.
---
 Source/cmCommonTargetGenerator.cxx         |  3 +-
 Source/cmComputeLinkDepends.cxx            | 21 +++++++----
 Source/cmExportTryCompileFileGenerator.cxx |  6 ++--
 Source/cmGeneratorExpression.cxx           |  2 +-
 Source/cmGeneratorExpressionDAGChecker.cxx |  8 +++--
 Source/cmGeneratorExpressionDAGChecker.h   |  7 ++--
 Source/cmGeneratorExpressionNode.cxx       |  8 +++--
 Source/cmGeneratorTarget.cxx               | 57 +++++++++++++++++-------------
 Source/cmQtAutoGenInitializer.cxx          |  5 +--
 9 files changed, 70 insertions(+), 47 deletions(-)

diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 677bb48..fbf39e2 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -501,7 +501,8 @@ std::string cmCommonTargetGenerator::GetLinkerLauncher(
   cmValue launcherProp = this->GeneratorTarget->GetProperty(propName);
   if (cmNonempty(launcherProp)) {
     cmGeneratorExpressionDAGChecker dagChecker(this->GeneratorTarget, propName,
-                                               nullptr, nullptr);
+                                               nullptr, nullptr,
+                                               this->LocalCommonGenerator);
     std::string evaluatedLinklauncher = cmGeneratorExpression::Evaluate(
       *launcherProp, this->LocalCommonGenerator, config, this->GeneratorTarget,
       &dagChecker, this->GeneratorTarget, lang);
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index f4b26f3..f6ff71a 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -451,10 +451,14 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* 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(),
-                                                 this->Target,
-                                                 "LINK_LIBRARY_OVERRIDE",
-                                                 nullptr, nullptr };
+            cmGeneratorExpressionDAGChecker dag{
+              this->Target->GetBacktrace(),
+              this->Target,
+              "LINK_LIBRARY_OVERRIDE",
+              nullptr,
+              nullptr,
+              this->Target->GetLocalGenerator()
+            };
             auto overrideFeature = cmGeneratorExpression::Evaluate(
               *feature, this->Target->GetLocalGenerator(), config,
               this->Target, &dag, this->Target, linkLanguage);
@@ -466,9 +470,12 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target,
   // global override property
   if (cmValue linkLibraryOverride =
         this->Target->GetProperty("LINK_LIBRARY_OVERRIDE")) {
-    cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
-                                         "LINK_LIBRARY_OVERRIDE", nullptr,
-                                         nullptr };
+    cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(),
+                                         target,
+                                         "LINK_LIBRARY_OVERRIDE",
+                                         nullptr,
+                                         nullptr,
+                                         target->GetLocalGenerator() };
     auto overrideValue = cmGeneratorExpression::Evaluate(
       *linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag,
       target, linkLanguage);
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index 00c9173..41b1049 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -76,10 +76,10 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
     // To please constraint checks of DAGChecker, this property must have
     // LINK_OPTIONS property as parent
     parentDagChecker = cm::make_unique<cmGeneratorExpressionDAGChecker>(
-      tgt, "LINK_OPTIONS", nullptr, nullptr);
+      tgt, "LINK_OPTIONS", nullptr, nullptr, tgt->GetLocalGenerator());
   }
-  cmGeneratorExpressionDAGChecker dagChecker(tgt, propName, nullptr,
-                                             parentDagChecker.get());
+  cmGeneratorExpressionDAGChecker dagChecker(
+    tgt, propName, nullptr, parentDagChecker.get(), tgt->GetLocalGenerator());
 
   std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*prop);
 
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 0b96c3f..0583fd5 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -425,7 +425,7 @@ const std::string& cmGeneratorExpressionInterpreter::Evaluate(
   cmGeneratorExpressionDAGChecker dagChecker(
     this->HeadTarget,
     property == "COMPILE_FLAGS" ? "COMPILE_OPTIONS" : property, nullptr,
-    nullptr);
+    nullptr, this->LocalGenerator);
 
   return this->CompiledGeneratorExpression->Evaluate(
     this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr,
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index fda7ec3..8bad91b 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -20,16 +20,17 @@
 cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   cmGeneratorTarget const* target, std::string property,
   const GeneratorExpressionContent* content,
-  cmGeneratorExpressionDAGChecker* parent)
+  cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG)
   : cmGeneratorExpressionDAGChecker(cmListFileBacktrace(), target,
-                                    std::move(property), content, parent)
+                                    std::move(property), content, parent,
+                                    contextLG)
 {
 }
 
 cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   cmListFileBacktrace backtrace, cmGeneratorTarget const* target,
   std::string property, const GeneratorExpressionContent* content,
-  cmGeneratorExpressionDAGChecker* parent)
+  cmGeneratorExpressionDAGChecker* parent, cmLocalGenerator const* contextLG)
   : Parent(parent)
   , Top(parent ? parent->Top : this)
   , Target(target)
@@ -37,6 +38,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   , Content(content)
   , Backtrace(std::move(backtrace))
 {
+  static_cast<void>(contextLG);
   if (parent) {
     this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty;
   } else {
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index 068ba6b..ea29b96 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -13,6 +13,7 @@
 struct GeneratorExpressionContent;
 struct cmGeneratorExpressionContext;
 class cmGeneratorTarget;
+class cmLocalGenerator;
 
 #define CM_SELECT_BOTH(F, A1, A2) F(A1, A2)
 #define CM_SELECT_FIRST(F, A1, A2) F(A1)
@@ -47,11 +48,13 @@ struct cmGeneratorExpressionDAGChecker
                                   cmGeneratorTarget const* target,
                                   std::string property,
                                   const GeneratorExpressionContent* content,
-                                  cmGeneratorExpressionDAGChecker* parent);
+                                  cmGeneratorExpressionDAGChecker* parent,
+                                  cmLocalGenerator const* contextLG);
   cmGeneratorExpressionDAGChecker(cmGeneratorTarget const* target,
                                   std::string property,
                                   const GeneratorExpressionContent* content,
-                                  cmGeneratorExpressionDAGChecker* parent);
+                                  cmGeneratorExpressionDAGChecker* parent,
+                                  cmLocalGenerator const* contextLG);
 
   enum Result
   {
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 46a7d50..34c0b7b 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -487,7 +487,8 @@ protected:
     if (context->HeadTarget) {
       cmGeneratorExpressionDAGChecker dagChecker(
         context->Backtrace, context->HeadTarget,
-        genexOperator + ":" + expression, content, dagCheckerParent);
+        genexOperator + ":" + expression, content, dagCheckerParent,
+        context->LG);
       switch (dagChecker.Check()) {
         case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
         case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE: {
@@ -2927,8 +2928,9 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
           cmGeneratorTarget::LinkInterfaceFor::Usage));
     }
 
-    cmGeneratorExpressionDAGChecker dagChecker(
-      context->Backtrace, target, propertyName, content, dagCheckerParent);
+    cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, target,
+                                               propertyName, content,
+                                               dagCheckerParent, context->LG);
 
     switch (dagChecker.Check()) {
       case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index d6560d0..13ac815 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -877,7 +877,7 @@ std::string cmGeneratorTarget::GetLinkerTypeProperty(
   auto linkerType = this->GetProperty(propName);
   if (!linkerType.IsEmpty()) {
     cmGeneratorExpressionDAGChecker dagChecker(this, propName, nullptr,
-                                               nullptr);
+                                               nullptr, this->LocalGenerator);
     auto ltype =
       cmGeneratorExpression::Evaluate(*linkerType, this->GetLocalGenerator(),
                                       config, this, &dagChecker, this, lang);
@@ -1342,7 +1342,8 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory(
 
   if (iter == this->SystemIncludesCache.end()) {
     cmGeneratorExpressionDAGChecker dagChecker(
-      this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr);
+      this, "SYSTEM_INCLUDE_DIRECTORIES", nullptr, nullptr,
+      this->LocalGenerator);
 
     bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
 
@@ -1450,7 +1451,8 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
   // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
   // but sufficient for transitive interface properties.
   cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop,
-                                             nullptr, dagCheckerParent);
+                                             nullptr, dagCheckerParent,
+                                             this->LocalGenerator);
   switch (dagChecker.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
       dagChecker.ReportError(
@@ -1529,8 +1531,10 @@ std::string AddLangSpecificInterfaceIncludeDirectories(
   const std::string& propertyName, IncludeDirectoryFallBack mode,
   cmGeneratorExpressionDAGChecker* context)
 {
-  cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
-                                       propertyName, nullptr, context };
+  cmGeneratorExpressionDAGChecker dag{
+    target->GetBacktrace(),     target, propertyName, nullptr, context,
+    target->GetLocalGenerator()
+  };
   switch (dag.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
       dag.ReportError(
@@ -1580,8 +1584,10 @@ void AddLangSpecificImplicitIncludeDirectories(
 {
   if (const auto* libraries = target->GetLinkImplementationLibraries(
         config, LinkInterfaceFor::Usage)) {
-    cmGeneratorExpressionDAGChecker dag{ target->GetBacktrace(), target,
-                                         propertyName, nullptr, nullptr };
+    cmGeneratorExpressionDAGChecker dag{
+      target->GetBacktrace(),     target, propertyName, nullptr, nullptr,
+      target->GetLocalGenerator()
+    };
 
     for (const cmLinkImplItem& library : libraries->Libraries) {
       if (const cmGeneratorTarget* dependency = library.Target) {
@@ -1833,8 +1839,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths(
     this->DebugSourcesDone = true;
   }
 
-  cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr,
-                                             nullptr);
+  cmGeneratorExpressionDAGChecker dagChecker(this, "SOURCES", nullptr, nullptr,
+                                             this->LocalGenerator);
 
   EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
     this, config, std::string(), &dagChecker, this->SourceEntries);
@@ -3048,7 +3054,7 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result,
   }
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "AUTOUIC_OPTIONS", nullptr,
-                                             nullptr);
+                                             nullptr, this->LocalGenerator);
   cmExpandList(cmGeneratorExpression::Evaluate(prop, this->LocalGenerator,
                                                config, this, &dagChecker),
                result);
@@ -3848,8 +3854,8 @@ 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);
+  cmGeneratorExpressionDAGChecker dagChecker(
+    this, "INCLUDE_DIRECTORIES", nullptr, nullptr, this->LocalGenerator);
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4113,7 +4119,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions(
   std::unordered_set<std::string> uniqueOptions;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr,
-                                             nullptr);
+                                             nullptr, this->LocalGenerator);
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4154,7 +4160,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures(
   std::unordered_set<std::string> uniqueFeatures;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr,
-                                             nullptr);
+                                             nullptr, this->LocalGenerator);
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4203,8 +4209,8 @@ 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);
+  cmGeneratorExpressionDAGChecker dagChecker(
+    this, "COMPILE_DEFINITIONS", nullptr, nullptr, this->LocalGenerator);
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4267,8 +4273,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
   }
   std::unordered_set<std::string> uniqueOptions;
 
-  cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS",
-                                             nullptr, nullptr);
+  cmGeneratorExpressionDAGChecker dagChecker(
+    this, "PRECOMPILE_HEADERS", nullptr, nullptr, this->LocalGenerator);
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4657,7 +4663,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions(
   std::unordered_set<std::string> uniqueOptions;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr,
-                                             nullptr);
+                                             nullptr, this->LocalGenerator);
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4825,8 +4831,8 @@ 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);
+  cmGeneratorExpressionDAGChecker dagChecker(
+    this, "STATIC_LIBRARY_OPTIONS", nullptr, nullptr, this->LocalGenerator);
 
   EvaluatedTargetPropertyEntries entries;
   if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) {
@@ -4939,7 +4945,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories(
   std::unordered_set<std::string> uniqueDirectories;
 
   cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
-                                             nullptr);
+                                             nullptr, this->LocalGenerator);
 
   cmList debugProperties{ this->Makefile->GetDefinition(
     "CMAKE_DEBUG_TARGET_PROPERTIES") };
@@ -4983,7 +4989,7 @@ 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);
+                                             nullptr, this->LocalGenerator);
 
   EvaluatedTargetPropertyEntries entries;
   if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) {
@@ -6969,7 +6975,8 @@ void cmGeneratorTarget::ExpandLinkItems(
     return;
   }
   // Keep this logic in sync with ComputeLinkImplementationLibraries.
-  cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
+  cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr,
+                                             this->LocalGenerator);
   // The $<LINK_ONLY> expression may be in a link interface to specify
   // private link dependencies that are otherwise excluded from usage
   // requirements.
@@ -8640,7 +8647,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
   for (auto const& entry : entryRange) {
     // Keep this logic in sync with ExpandLinkItems.
     cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
-                                               nullptr);
+                                               nullptr, this->LocalGenerator);
     // The $<LINK_ONLY> expression may be used to specify link dependencies
     // that are otherwise excluded from usage requirements.
     if (implFor == LinkInterfaceFor::Usage) {
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 0ccebfd..34a47cc 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -1918,8 +1918,9 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
     info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode);
     info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix);
 
-    cmGeneratorExpressionDAGChecker dagChecker(
-      this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr);
+    cmGeneratorExpressionDAGChecker dagChecker(this->GenTarget,
+                                               "AUTOMOC_MACRO_NAMES", nullptr,
+                                               nullptr, this->LocalGen);
     EvaluatedTargetPropertyEntries InterfaceAutoMocMacroNamesEntries;
 
     if (this->MultiConfig) {
-- 
cgit v0.12


From 79a3ae9a0d6b4cf8369b40e5c371617ad3cc9e11 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 29 Apr 2024 14:25:34 -0400
Subject: cmGeneratorExpressionDAGChecker: Simplify transitive property table

Refactor the table of builtin transitive properties to avoid
preprocessor-generated cascading-if blocks with duplicate code.
---
 Source/cmExportTryCompileFileGenerator.cxx | 12 +++----
 Source/cmGeneratorExpressionDAGChecker.cxx | 52 ++++++------------------------
 Source/cmGeneratorExpressionDAGChecker.h   | 33 +------------------
 Source/cmGeneratorExpressionNode.cxx       | 21 +++---------
 Source/cmGeneratorTarget.cxx               | 40 +++++++++++++++++++++++
 Source/cmGeneratorTarget.h                 | 12 +++++++
 6 files changed, 73 insertions(+), 97 deletions(-)

diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index 41b1049..4c41ff5 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -2,9 +2,11 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExportTryCompileFileGenerator.h"
 
+#include <map>
 #include <utility>
 
 #include <cm/memory>
+#include <cm/string_view>
 
 #include "cmFileSet.h"
 #include "cmGeneratorExpression.h"
@@ -44,12 +46,10 @@ bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
       ImportPropertyMap properties;
 
       for (std::string const& lang : this->Languages) {
-#define FIND_TARGETS(PROPERTY)                                                \
-  this->FindTargets("INTERFACE_" #PROPERTY, te, lang, emittedDeps);
-
-        CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(FIND_TARGETS)
-
-#undef FIND_TARGETS
+        for (auto i : cmGeneratorTarget::BuiltinTransitiveProperties) {
+          this->FindTargets(std::string(i.second.InterfaceName), te, lang,
+                            emittedDeps);
+        }
       }
 
       this->PopulateProperties(te, properties, emittedDeps);
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index 8bad91b..bb1f4b4 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -2,10 +2,10 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGeneratorExpressionDAGChecker.h"
 
-#include <cstring>
 #include <sstream>
 #include <utility>
 
+#include <cm/optional>
 #include <cm/string_view>
 #include <cmext/string_view>
 
@@ -38,14 +38,12 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
   , Content(content)
   , Backtrace(std::move(backtrace))
 {
-  static_cast<void>(contextLG);
   if (parent) {
     this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty;
   } else {
-#define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) this->METHOD() ||
-    this->TopIsTransitiveProperty = (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
-      TEST_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(*)
-#undef TEST_TRANSITIVE_PROPERTY_METHOD
+    this->TopIsTransitiveProperty =
+      this->Target->IsTransitiveProperty(this->Property, contextLG)
+        .has_value();
   }
 
   this->CheckResult = this->CheckGraph();
@@ -171,6 +169,12 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
     property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s;
 }
 
+bool cmGeneratorExpressionDAGChecker::EvaluatingSources() const
+{
+  return this->Property == "SOURCES"_s ||
+    this->Property == "INTERFACE_SOURCES"_s;
+}
+
 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
 {
   cm::string_view property(this->Top->Property);
@@ -224,39 +228,3 @@ cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
 {
   return this->Top->Target;
 }
-
-enum class TransitiveProperty
-{
-#define DEFINE_ENUM_ENTRY(NAME) NAME,
-  CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(DEFINE_ENUM_ENTRY)
-#undef DEFINE_ENUM_ENTRY
-    Terminal
-};
-
-template <TransitiveProperty>
-bool additionalTest(const char* const /*unused*/)
-{
-  return false;
-}
-
-template <>
-bool additionalTest<TransitiveProperty::COMPILE_DEFINITIONS>(
-  const char* const prop)
-{
-  return cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_");
-}
-
-#define DEFINE_TRANSITIVE_PROPERTY_METHOD(METHOD, PROPERTY)                   \
-  bool cmGeneratorExpressionDAGChecker::METHOD() const                        \
-  {                                                                           \
-    const char* const prop = this->Property.c_str();                          \
-    if (strcmp(prop, #PROPERTY) == 0 ||                                       \
-        strcmp(prop, "INTERFACE_" #PROPERTY) == 0) {                          \
-      return true;                                                            \
-    }                                                                         \
-    return additionalTest<TransitiveProperty::PROPERTY>(prop);                \
-  }
-
-CM_FOR_EACH_TRANSITIVE_PROPERTY(DEFINE_TRANSITIVE_PROPERTY_METHOD)
-
-#undef DEFINE_TRANSITIVE_PROPERTY_METHOD
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index ea29b96..b230188 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -15,33 +15,6 @@ struct cmGeneratorExpressionContext;
 class cmGeneratorTarget;
 class cmLocalGenerator;
 
-#define CM_SELECT_BOTH(F, A1, A2) F(A1, A2)
-#define CM_SELECT_FIRST(F, A1, A2) F(A1)
-#define CM_SELECT_SECOND(F, A1, A2) F(A2)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, SELECT)                       \
-  SELECT(F, EvaluatingIncludeDirectories, INCLUDE_DIRECTORIES)                \
-  SELECT(F, EvaluatingSystemIncludeDirectories, SYSTEM_INCLUDE_DIRECTORIES)   \
-  SELECT(F, EvaluatingCompileDefinitions, COMPILE_DEFINITIONS)                \
-  SELECT(F, EvaluatingCompileOptions, COMPILE_OPTIONS)                        \
-  SELECT(F, EvaluatingAutoMocMacroNames, AUTOMOC_MACRO_NAMES)                 \
-  SELECT(F, EvaluatingAutoUicOptions, AUTOUIC_OPTIONS)                        \
-  SELECT(F, EvaluatingSources, SOURCES)                                       \
-  SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES)                      \
-  SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS)                              \
-  SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES)                      \
-  SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS)                              \
-  SELECT(F, EvaluatingPrecompileHeaders, PRECOMPILE_HEADERS)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F)                                    \
-  CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(F)                             \
-  CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_FIRST)
-
-#define CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(F)                               \
-  CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_SECOND)
-
 struct cmGeneratorExpressionDAGChecker
 {
   cmGeneratorExpressionDAGChecker(cmListFileBacktrace backtrace,
@@ -86,11 +59,7 @@ struct cmGeneratorExpressionDAGChecker
   bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr,
                                ForGenex genex = ForGenex::ANY) const;
 
-#define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const;
-
-  CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(DECLARE_TRANSITIVE_PROPERTY_METHOD)
-
-#undef DECLARE_TRANSITIVE_PROPERTY_METHOD
+  bool EvaluatingSources() const;
 
   bool GetTransitivePropertiesOnly() const;
   void SetTransitivePropertiesOnly() { this->TransitivePropertiesOnly = true; }
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 34c0b7b..52ba8bc 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2877,24 +2877,11 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
     std::string interfacePropertyName;
     bool isInterfaceProperty = false;
 
-#define POPULATE_INTERFACE_PROPERTY_NAME(prop)                                \
-  if (propertyName == #prop) {                                                \
-    interfacePropertyName = "INTERFACE_" #prop;                               \
-  } else if (propertyName == "INTERFACE_" #prop) {                            \
-    interfacePropertyName = "INTERFACE_" #prop;                               \
-    isInterfaceProperty = true;                                               \
-  } else
-
-    CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(POPULATE_INTERFACE_PROPERTY_NAME)
-    // Note that the above macro terminates with an else
-    /* else */ if (cmHasLiteralPrefix(propertyName, "COMPILE_DEFINITIONS_")) {
-      cmPolicies::PolicyStatus polSt =
-        context->LG->GetPolicyStatus(cmPolicies::CMP0043);
-      if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
-        interfacePropertyName = "INTERFACE_COMPILE_DEFINITIONS";
-      }
+    if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
+          target->IsTransitiveProperty(propertyName, context->LG)) {
+      interfacePropertyName = std::string(transitiveProp->InterfaceName);
+      isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
     }
-#undef POPULATE_INTERFACE_PROPERTY_NAME
 
     bool evaluatingLinkLibraries = false;
 
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 13ac815..d0573da 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -65,6 +65,7 @@
 
 namespace {
 using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor;
+using TransitiveProperty = cmGeneratorTarget::TransitiveProperty;
 
 const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES";
 const std::string kINTERFACE_LINK_LIBRARIES_DIRECT =
@@ -73,6 +74,23 @@ const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE =
   "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE";
 }
 
+const std::map<cm::string_view, TransitiveProperty>
+  cmGeneratorTarget::BuiltinTransitiveProperties = {
+    { "AUTOMOC_MACRO_NAMES"_s, { "INTERFACE_AUTOMOC_MACRO_NAMES"_s } },
+    { "AUTOUIC_OPTIONS"_s, { "INTERFACE_AUTOUIC_OPTIONS"_s } },
+    { "COMPILE_DEFINITIONS"_s, { "INTERFACE_COMPILE_DEFINITIONS"_s } },
+    { "COMPILE_FEATURES"_s, { "INTERFACE_COMPILE_FEATURES"_s } },
+    { "COMPILE_OPTIONS"_s, { "INTERFACE_COMPILE_OPTIONS"_s } },
+    { "INCLUDE_DIRECTORIES"_s, { "INTERFACE_INCLUDE_DIRECTORIES"_s } },
+    { "LINK_DEPENDS"_s, { "INTERFACE_LINK_DEPENDS"_s } },
+    { "LINK_DIRECTORIES"_s, { "INTERFACE_LINK_DIRECTORIES"_s } },
+    { "LINK_OPTIONS"_s, { "INTERFACE_LINK_OPTIONS"_s } },
+    { "PRECOMPILE_HEADERS"_s, { "INTERFACE_PRECOMPILE_HEADERS"_s } },
+    { "SOURCES"_s, { "INTERFACE_SOURCES"_s } },
+    { "SYSTEM_INCLUDE_DIRECTORIES"_s,
+      { "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"_s } },
+  };
+
 template <>
 cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
   cmGeneratorTarget const* tgt, cmMakefile const& /* mf */)
@@ -1517,6 +1535,28 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty(
   return result;
 }
 
+cm::optional<cmGeneratorTarget::TransitiveProperty>
+cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
+                                        cmLocalGenerator const* lg) const
+{
+  cm::optional<TransitiveProperty> result;
+  static const cm::string_view kINTERFACE_ = "INTERFACE_"_s;
+  if (cmHasPrefix(prop, kINTERFACE_)) {
+    prop = prop.substr(kINTERFACE_.length());
+  }
+  auto i = BuiltinTransitiveProperties.find(prop);
+  if (i != BuiltinTransitiveProperties.end()) {
+    result = i->second;
+  } else if (cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_")) {
+    cmPolicies::PolicyStatus cmp0043 =
+      lg->GetPolicyStatus(cmPolicies::CMP0043);
+    if (cmp0043 == cmPolicies::WARN || cmp0043 == cmPolicies::OLD) {
+      result = TransitiveProperty{ "INTERFACE_COMPILE_DEFINITIONS"_s };
+    }
+  }
+  return result;
+}
+
 namespace {
 
 enum class IncludeDirectoryFallBack
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index fbc71e5..fc625b9 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include <cm/optional>
+#include <cm/string_view>
 
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
@@ -885,6 +886,17 @@ public:
     cmGeneratorExpressionDAGChecker* dagCheckerParent,
     LinkInterfaceFor interfaceFor) const;
 
+  struct TransitiveProperty
+  {
+    cm::string_view InterfaceName;
+  };
+
+  static const std::map<cm::string_view, TransitiveProperty>
+    BuiltinTransitiveProperties;
+
+  cm::optional<TransitiveProperty> IsTransitiveProperty(
+    cm::string_view prop, cmLocalGenerator const* lg) const;
+
   bool HaveInstallTreeRPATH(const std::string& config) const;
 
   bool GetBuildRPATH(const std::string& config, std::string& rpath) const;
-- 
cgit v0.12


From 7d3d728a72c51fd4c0bdeaac9fd14ceae6730df3 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 29 Apr 2024 16:31:38 -0400
Subject: Help: Clarify CMP0099 documentation and summary text

---
 Help/manual/cmake-policies.7.rst |  2 +-
 Help/policy/CMP0099.rst          | 13 ++++++++-----
 Source/cmPolicies.h              |  4 ++--
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index e46e88e..dd202a2 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -214,7 +214,7 @@ Policies Introduced by CMake 3.17
    CMP0102: mark_as_advanced() does nothing if a cache entry does not exist. </policy/CMP0102>
    CMP0101: target_compile_options honors BEFORE keyword in all scopes. </policy/CMP0101>
    CMP0100: Let AUTOMOC and AUTOUIC process .hh header files. </policy/CMP0100>
-   CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099>
+   CMP0099: Link properties are transitive over private dependencies of static libraries. </policy/CMP0099>
    CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098>
 
 Policies Introduced by CMake 3.16
diff --git a/Help/policy/CMP0099.rst b/Help/policy/CMP0099.rst
index c0db99d..e836cf3 100644
--- a/Help/policy/CMP0099.rst
+++ b/Help/policy/CMP0099.rst
@@ -3,13 +3,16 @@ CMP0099
 
 .. versionadded:: 3.17
 
-Target link properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
-:prop_tgt:`INTERFACE_LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DEPENDS`
-are now transitive over private dependencies of static libraries.
+Link properties are transitive over private dependencies of static libraries.
 
-In CMake 3.16 and below the interface link properties attached to libraries
-are not propagated for private dependencies of static libraries.
+In CMake 3.16 and below, evaluation of target properties
+:prop_tgt:`INTERFACE_LINK_OPTIONS`, :prop_tgt:`INTERFACE_LINK_DIRECTORIES`,
+and :prop_tgt:`INTERFACE_LINK_DEPENDS` during buildsystem generation does not
+follow private dependencies of static libraries, which appear in their
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded by :genex:`LINK_ONLY` generator
+expressions.
 Only the libraries themselves are propagated to link the dependent binary.
+
 CMake 3.17 and later prefer to propagate all interface link properties.
 This policy provides compatibility for projects that have not been updated
 to expect the new behavior.
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index ada87dd..1aa5f79 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -294,8 +294,8 @@ class cmMakefile;
          "FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing.", 3, \
          17, 0, cmPolicies::WARN)                                             \
   SELECT(POLICY, CMP0099,                                                     \
-         "Link properties are transitive over private dependency on static "  \
-         "libraries.",                                                        \
+         "Link properties are transitive over private dependencies of "       \
+         "static libraries.",                                                 \
          3, 17, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3,    \
          17, 0, cmPolicies::WARN)                                             \
-- 
cgit v0.12


From abf607c2ec8e0260ce6e453a047d75bcbecf91e7 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 22 Apr 2024 14:35:06 -0400
Subject: Tests: Cover TARGET_PROPERTY genex evaluation of transitive build
 properties

---
 .../GenEx-TARGET_PROPERTY/RunCMakeTest.cmake       |  1 +
 .../TransitiveBuild-check.cmake                    | 25 ++++++++
 .../GenEx-TARGET_PROPERTY/TransitiveBuild.cmake    | 66 ++++++++++++++++++++++
 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h       |  0
 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c      |  0
 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h      |  0
 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h      |  0
 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h      |  0
 Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c        |  4 ++
 9 files changed, 96 insertions(+)
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c

diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
index b613ad1..1e7f556 100644
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
@@ -13,6 +13,7 @@ run_cmake(LinkImplementationCycle5)
 run_cmake(LinkImplementationCycle6)
 run_cmake(LOCATION)
 run_cmake(SOURCES)
+run_cmake(TransitiveBuild)
 
 block()
   run_cmake(Scope)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake
new file mode 100644
index 0000000..65adfaf
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild-check.cmake
@@ -0,0 +1,25 @@
+set(expect [[
+# file\(GENERATE\) produced:
+main INCLUDE_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1'
+main SYSTEM_INCLUDE_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/sys1'
+main COMPILE_DEFINITIONS: 'DEFM;DEF1'
+main COMPILE_FEATURES: 'cxx_std_20;cxx_std_11'
+main COMPILE_OPTIONS: '-optM;-opt1'
+main PRECOMPILE_HEADERS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h'
+main SOURCES: 'main.c;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c'
+main AUTOMOC_MACRO_NAMES: 'MOCM;MOC1'
+main AUTOUIC_OPTIONS: '-uicM;-uic1'
+]])
+
+string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
+string(REGEX REPLACE "\n+$" "" expect "${expect}")
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" actual)
+string(REGEX REPLACE "\r\n" "\n" actual "${actual}")
+string(REGEX REPLACE "\n+$" "" actual "${actual}")
+
+if(NOT actual MATCHES "^${expect}$")
+  string(REPLACE "\n" "\n expect> " expect " expect> ${expect}")
+  string(REPLACE "\n" "\n actual> " actual " actual> ${actual}")
+  message(FATAL_ERROR "Expected file(GENERATE) output:\n${expect}\ndoes not match actual output:\n${actual}")
+endif()
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake
new file mode 100644
index 0000000..8f8eb96
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveBuild.cmake
@@ -0,0 +1,66 @@
+enable_language(C)
+set(CMAKE_PCH_EXTENSION "") # suppress cmake_pch from SOURCES
+
+add_library(foo1 STATIC empty.c)
+target_link_libraries(foo1 PRIVATE foo2 foo3)
+target_include_directories(foo1 INTERFACE dir1)
+target_compile_definitions(foo1 INTERFACE DEF1)
+target_compile_features(foo1 INTERFACE cxx_std_11)
+target_compile_options(foo1 INTERFACE -opt1)
+target_precompile_headers(foo1 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty1.h")
+target_sources(foo1 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty1.c")
+set_target_properties(foo1 PROPERTIES
+  INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys1"
+  INTERFACE_AUTOMOC_MACRO_NAMES "MOC1"
+  INTERFACE_AUTOUIC_OPTIONS "-uic1"
+  )
+
+add_library(foo2 STATIC empty.c)
+target_include_directories(foo2 INTERFACE dir2)
+target_compile_definitions(foo2 INTERFACE DEF2)
+target_compile_features(foo2 INTERFACE cxx_std_14)
+target_compile_options(foo2 INTERFACE -opt2)
+target_precompile_headers(foo2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty2.h")
+target_sources(foo2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/empty2.c")
+set_target_properties(foo2 PROPERTIES
+  INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys2"
+  INTERFACE_AUTOMOC_MACRO_NAMES "MOC2"
+  INTERFACE_AUTOUIC_OPTIONS "-uic2"
+  )
+
+add_library(foo3 STATIC empty.c)
+target_include_directories(foo3 PRIVATE dir3)
+target_compile_definitions(foo3 PRIVATE DEF3)
+target_compile_features(foo3 PRIVATE cxx_std_17)
+target_compile_options(foo3 PRIVATE -opt3)
+target_precompile_headers(foo3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty3.h")
+target_sources(foo3 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty3.c")
+set_target_properties(foo3 PROPERTIES
+  SYSTEM_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/sys3"
+  AUTOMOC_MACRO_NAMES "MOC3"
+  AUTOUIC_OPTIONS "-uic3"
+  )
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo1)
+target_include_directories(main PRIVATE dirM)
+target_compile_definitions(main PRIVATE DEFM)
+target_compile_features(main PRIVATE cxx_std_20)
+target_compile_options(main PRIVATE -optM)
+target_precompile_headers(main PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/empty.h")
+set_target_properties(main PROPERTIES
+  AUTOMOC_MACRO_NAMES "MOCM"
+  AUTOUIC_OPTIONS "-uicM"
+  )
+
+file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced:
+main INCLUDE_DIRECTORIES: '$<TARGET_PROPERTY:main,INCLUDE_DIRECTORIES>'
+main SYSTEM_INCLUDE_DIRECTORIES: '$<TARGET_PROPERTY:main,SYSTEM_INCLUDE_DIRECTORIES>'
+main COMPILE_DEFINITIONS: '$<TARGET_PROPERTY:main,COMPILE_DEFINITIONS>'
+main COMPILE_FEATURES: '$<TARGET_PROPERTY:main,COMPILE_FEATURES>'
+main COMPILE_OPTIONS: '$<TARGET_PROPERTY:main,COMPILE_OPTIONS>'
+main PRECOMPILE_HEADERS: '$<TARGET_PROPERTY:main,PRECOMPILE_HEADERS>'
+main SOURCES: '$<TARGET_PROPERTY:main,SOURCES>'
+main AUTOMOC_MACRO_NAMES: '$<TARGET_PROPERTY:main,AUTOMOC_MACRO_NAMES>'
+main AUTOUIC_OPTIONS: '$<TARGET_PROPERTY:main,AUTOUIC_OPTIONS>'
+")
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty.h
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.c
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty1.h
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty2.h
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h b/Tests/RunCMake/GenEx-TARGET_PROPERTY/empty3.h
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}
-- 
cgit v0.12


From 8d1d6a1437f8bce3c771f93cdafbffcfc7d6173a Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 22 Apr 2024 14:48:08 -0400
Subject: Tests: Cover TARGET_PROPERTY genex evaluation of transitive link
 properties

Demonstrate that TARGET_PROPERTY does not honor CMP0099 from CMake 3.17.
---
 .../RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt  |  2 +-
 .../GenEx-TARGET_PROPERTY/RunCMakeTest.cmake       |  1 +
 .../TransitiveLink-check.cmake                     | 21 +++++++++++
 .../GenEx-TARGET_PROPERTY/TransitiveLink.cmake     | 42 ++++++++++++++++++++++
 4 files changed, 65 insertions(+), 1 deletion(-)
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake

diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
index 32d92d8..b8eda77 100644
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.17)
 if(RunCMake_TEST STREQUAL "LOCATION")
   cmake_minimum_required(VERSION 2.8.12) # Leave CMP0026 unset.
 endif()
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
index 1e7f556..2ed42c9 100644
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
@@ -14,6 +14,7 @@ run_cmake(LinkImplementationCycle6)
 run_cmake(LOCATION)
 run_cmake(SOURCES)
 run_cmake(TransitiveBuild)
+run_cmake(TransitiveLink)
 
 block()
   run_cmake(Scope)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake
new file mode 100644
index 0000000..c48b722
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake
@@ -0,0 +1,21 @@
+# FIXME: TARGET_PROPERTY evaluation does not pierce LINK_ONLY
+set(expect [[
+# file\(GENERATE\) produced:
+main LINK_LIBRARIES: 'foo1' # not transitive
+main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1'
+main LINK_OPTIONS: '-optM;-opt1'
+main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-build/dep1'
+]])
+
+string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
+string(REGEX REPLACE "\n+$" "" expect "${expect}")
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" actual)
+string(REGEX REPLACE "\r\n" "\n" actual "${actual}")
+string(REGEX REPLACE "\n+$" "" actual "${actual}")
+
+if(NOT actual MATCHES "^${expect}$")
+  string(REPLACE "\n" "\n expect> " expect " expect> ${expect}")
+  string(REPLACE "\n" "\n actual> " actual " actual> ${actual}")
+  message(FATAL_ERROR "Expected file(GENERATE) output:\n${expect}\ndoes not match actual output:\n${actual}")
+endif()
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake
new file mode 100644
index 0000000..c120366
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake
@@ -0,0 +1,42 @@
+enable_language(C)
+
+add_library(foo1 STATIC empty.c)
+target_link_libraries(foo1 PRIVATE foo2 foo3)
+target_link_directories(foo1 INTERFACE dir1)
+target_link_options(foo1 INTERFACE -opt1)
+set_target_properties(foo1 PROPERTIES
+  INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep1"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep1" "")
+
+add_library(foo2 STATIC empty.c)
+target_link_directories(foo2 INTERFACE dir2)
+target_link_options(foo2 INTERFACE -opt2)
+set_target_properties(foo2 PROPERTIES
+  INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep2"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep2" "")
+
+add_library(foo3 STATIC empty.c)
+target_link_directories(foo3 PRIVATE dir3)
+target_link_options(foo3 PRIVATE -opt3)
+set_target_properties(foo3 PROPERTIES
+  LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep3"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep3" "")
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo1)
+target_link_directories(main PRIVATE dirM)
+target_link_options(main PRIVATE -optM)
+set_target_properties(main PROPERTIES
+  LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/depM"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/depM" "")
+
+file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced:
+main LINK_LIBRARIES: '$<TARGET_PROPERTY:main,LINK_LIBRARIES>' # not transitive
+main LINK_DIRECTORIES: '$<TARGET_PROPERTY:main,LINK_DIRECTORIES>'
+main LINK_OPTIONS: '$<TARGET_PROPERTY:main,LINK_OPTIONS>'
+main LINK_DEPENDS: '$<TARGET_PROPERTY:main,LINK_DEPENDS>'
+")
-- 
cgit v0.12


From 862b8e28adbbab55c666a2d6eb3eecf0bf452bab Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 29 Apr 2024 14:58:33 -0400
Subject: GenEx: Teach TARGET_PROPERTY evaluation to optionally pierce
 LINK_ONLY

---
 Source/cmGeneratorExpressionNode.cxx | 16 +++++++++-------
 Source/cmGeneratorTarget.cxx         | 37 +++++++++++++++++++++++-------------
 Source/cmGeneratorTarget.h           |  1 +
 3 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 52ba8bc..b9feb87 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2701,7 +2701,8 @@ static const struct DeviceLinkNode : public cmGeneratorExpressionNode
 static std::string getLinkedTargetsContent(
   cmGeneratorTarget const* target, std::string const& prop,
   cmGeneratorExpressionContext* context,
-  cmGeneratorExpressionDAGChecker* dagChecker)
+  cmGeneratorExpressionDAGChecker* dagChecker,
+  cmGeneratorTarget::LinkInterfaceFor interfaceFor)
 {
   std::string result;
   if (cmLinkImplementationLibraries const* impl =
@@ -2717,8 +2718,7 @@ static std::string getLinkedTargetsContent(
           target, context->EvaluateForBuildsystem, lib.Backtrace,
           context->Language);
         std::string libResult = lib.Target->EvaluateInterfaceProperty(
-          prop, &libContext, dagChecker,
-          cmGeneratorTarget::LinkInterfaceFor::Usage);
+          prop, &libContext, dagChecker, interfaceFor);
         if (!libResult.empty()) {
           if (result.empty()) {
             result = std::move(libResult);
@@ -2876,11 +2876,14 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
 
     std::string interfacePropertyName;
     bool isInterfaceProperty = false;
+    cmGeneratorTarget::LinkInterfaceFor interfaceFor =
+      cmGeneratorTarget::LinkInterfaceFor::Usage;
 
     if (cm::optional<cmGeneratorTarget::TransitiveProperty> transitiveProp =
           target->IsTransitiveProperty(propertyName, context->LG)) {
       interfacePropertyName = std::string(transitiveProp->InterfaceName);
       isInterfaceProperty = transitiveProp->InterfaceName == propertyName;
+      interfaceFor = transitiveProp->InterfaceFor;
     }
 
     bool evaluatingLinkLibraries = false;
@@ -2910,9 +2913,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
 
     if (isInterfaceProperty) {
       return cmGeneratorExpression::StripEmptyListElements(
-        target->EvaluateInterfaceProperty(
-          propertyName, context, dagCheckerParent,
-          cmGeneratorTarget::LinkInterfaceFor::Usage));
+        target->EvaluateInterfaceProperty(propertyName, context,
+                                          dagCheckerParent, interfaceFor));
     }
 
     cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, target,
@@ -2999,7 +3001,7 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
         this->EvaluateDependentExpression(result, context->LG, context, target,
                                           &dagChecker, target));
       std::string linkedTargetsContent = getLinkedTargetsContent(
-        target, interfacePropertyName, context, &dagChecker);
+        target, interfacePropertyName, context, &dagChecker, interfaceFor);
       if (!linkedTargetsContent.empty()) {
         result += (result.empty() ? "" : ";") + linkedTargetsContent;
       }
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index d0573da..6bf0095 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -76,19 +76,29 @@ const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE =
 
 const std::map<cm::string_view, TransitiveProperty>
   cmGeneratorTarget::BuiltinTransitiveProperties = {
-    { "AUTOMOC_MACRO_NAMES"_s, { "INTERFACE_AUTOMOC_MACRO_NAMES"_s } },
-    { "AUTOUIC_OPTIONS"_s, { "INTERFACE_AUTOUIC_OPTIONS"_s } },
-    { "COMPILE_DEFINITIONS"_s, { "INTERFACE_COMPILE_DEFINITIONS"_s } },
-    { "COMPILE_FEATURES"_s, { "INTERFACE_COMPILE_FEATURES"_s } },
-    { "COMPILE_OPTIONS"_s, { "INTERFACE_COMPILE_OPTIONS"_s } },
-    { "INCLUDE_DIRECTORIES"_s, { "INTERFACE_INCLUDE_DIRECTORIES"_s } },
-    { "LINK_DEPENDS"_s, { "INTERFACE_LINK_DEPENDS"_s } },
-    { "LINK_DIRECTORIES"_s, { "INTERFACE_LINK_DIRECTORIES"_s } },
-    { "LINK_OPTIONS"_s, { "INTERFACE_LINK_OPTIONS"_s } },
-    { "PRECOMPILE_HEADERS"_s, { "INTERFACE_PRECOMPILE_HEADERS"_s } },
-    { "SOURCES"_s, { "INTERFACE_SOURCES"_s } },
+    { "AUTOMOC_MACRO_NAMES"_s,
+      { "INTERFACE_AUTOMOC_MACRO_NAMES"_s, LinkInterfaceFor::Usage } },
+    { "AUTOUIC_OPTIONS"_s,
+      { "INTERFACE_AUTOUIC_OPTIONS"_s, LinkInterfaceFor::Usage } },
+    { "COMPILE_DEFINITIONS"_s,
+      { "INTERFACE_COMPILE_DEFINITIONS"_s, LinkInterfaceFor::Usage } },
+    { "COMPILE_FEATURES"_s,
+      { "INTERFACE_COMPILE_FEATURES"_s, LinkInterfaceFor::Usage } },
+    { "COMPILE_OPTIONS"_s,
+      { "INTERFACE_COMPILE_OPTIONS"_s, LinkInterfaceFor::Usage } },
+    { "INCLUDE_DIRECTORIES"_s,
+      { "INTERFACE_INCLUDE_DIRECTORIES"_s, LinkInterfaceFor::Usage } },
+    { "LINK_DEPENDS"_s,
+      { "INTERFACE_LINK_DEPENDS"_s, LinkInterfaceFor::Usage } },
+    { "LINK_DIRECTORIES"_s,
+      { "INTERFACE_LINK_DIRECTORIES"_s, LinkInterfaceFor::Usage } },
+    { "LINK_OPTIONS"_s,
+      { "INTERFACE_LINK_OPTIONS"_s, LinkInterfaceFor::Usage } },
+    { "PRECOMPILE_HEADERS"_s,
+      { "INTERFACE_PRECOMPILE_HEADERS"_s, LinkInterfaceFor::Usage } },
+    { "SOURCES"_s, { "INTERFACE_SOURCES"_s, LinkInterfaceFor::Usage } },
     { "SYSTEM_INCLUDE_DIRECTORIES"_s,
-      { "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"_s } },
+      { "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"_s, LinkInterfaceFor::Usage } },
   };
 
 template <>
@@ -1551,7 +1561,8 @@ cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
     cmPolicies::PolicyStatus cmp0043 =
       lg->GetPolicyStatus(cmPolicies::CMP0043);
     if (cmp0043 == cmPolicies::WARN || cmp0043 == cmPolicies::OLD) {
-      result = TransitiveProperty{ "INTERFACE_COMPILE_DEFINITIONS"_s };
+      result = TransitiveProperty{ "INTERFACE_COMPILE_DEFINITIONS"_s,
+                                   LinkInterfaceFor::Usage };
     }
   }
   return result;
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index fc625b9..e316eb8 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -889,6 +889,7 @@ public:
   struct TransitiveProperty
   {
     cm::string_view InterfaceName;
+    LinkInterfaceFor InterfaceFor;
   };
 
   static const std::map<cm::string_view, TransitiveProperty>
-- 
cgit v0.12


From ddb9442f487808b74ed3429832a74385a1214582 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Mon, 22 Apr 2024 15:17:20 -0400
Subject: GenEx: Fix TARGET_PROPERTY evaluation of transitive link properties

In commit bbba701899 (Link properties: must be transitive over private
dependency on static library, 2019-12-06, v3.17.0-rc1~323^2) and
commit af9d4f24ae (Link properties: must be transitive over private
dependency on static library, 2019-12-11, v3.17.0-rc1~305^2) we
neglected to implement CMP0099 NEW behavior for `TARGET_PROPERTY`
evaluation.  Add policy CMP0166 to fix this.
---
 Help/manual/cmake-generator-expressions.7.rst      | 17 ++++++---
 Help/manual/cmake-policies.7.rst                   |  1 +
 Help/policy/CMP0099.rst                            |  6 ++++
 Help/policy/CMP0166.rst                            | 40 +++++++++++++++++++++
 Help/release/dev/genex-link-properties.rst         |  8 +++++
 Source/cmGeneratorTarget.cxx                       | 15 ++++++--
 Source/cmPolicies.h                                |  6 +++-
 .../RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt  |  2 +-
 .../GenEx-TARGET_PROPERTY/RunCMakeTest.cmake       |  3 +-
 .../TransitiveLink-CMP0166-NEW-check.cmake         |  8 +++++
 .../TransitiveLink-CMP0166-NEW.cmake               |  2 ++
 .../TransitiveLink-CMP0166-OLD-check.cmake         |  8 +++++
 .../TransitiveLink-CMP0166-OLD.cmake               |  2 ++
 .../TransitiveLink-check-common.cmake              | 12 +++++++
 .../TransitiveLink-check.cmake                     | 21 -----------
 .../TransitiveLink-common.cmake                    | 42 ++++++++++++++++++++++
 .../GenEx-TARGET_PROPERTY/TransitiveLink.cmake     | 42 ----------------------
 17 files changed, 162 insertions(+), 73 deletions(-)
 create mode 100644 Help/policy/CMP0166.rst
 create mode 100644 Help/release/dev/genex-link-properties.rst
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake
 delete mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake
 create mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake
 delete mode 100644 Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake

diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 38fa6f9..31f0573 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -1282,7 +1282,7 @@ Compile Context
   .. versionadded:: 3.27
 
   Content of ``...``, when collecting
-  :ref:`usage requirements <Target Usage Requirements>`,
+  :ref:`transitive build properties <Transitive Build Properties>`,
   otherwise it is the empty string.  This is intended for use in an
   :prop_tgt:`INTERFACE_LINK_LIBRARIES` and :prop_tgt:`LINK_LIBRARIES` target
   properties, typically populated via the :command:`target_link_libraries` command.
@@ -1670,8 +1670,8 @@ Link Context
 
   .. versionadded:: 3.1
 
-  Content of ``...``, except while collecting
-  :ref:`usage requirements <Target Usage Requirements>`,
+  Content of ``...``, except while collecting usage requirements from
+  :ref:`transitive build properties <Transitive Build Properties>`,
   in which case it is the empty string.  This is intended for use in an
   :prop_tgt:`INTERFACE_LINK_LIBRARIES` target property, typically populated
   via the :command:`target_link_libraries` command, to specify private link
@@ -1788,7 +1788,16 @@ The expressions have special evaluation rules for some properties:
   of the value on the target itself with the values of the same properties on
   targets named by the target's :prop_tgt:`INTERFACE_LINK_LIBRARIES`.
   Evaluation is transitive over the closure of the target's
-  :prop_tgt:`INTERFACE_LINK_LIBRARIES`.
+  :prop_tgt:`INTERFACE_LINK_LIBRARIES`:
+
+  * For :ref:`Transitive Build Properties`, the transitive closure
+    *excludes* entries of :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded
+    by the :genex:`LINK_ONLY` generator expression.
+
+  * For :ref:`Transitive Link Properties`, the transitive closure is
+    *includes* entries of :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded
+    by the :genex:`LINK_ONLY` generator expression.
+    See policy :policy:`CMP0166`.
 
   Evaluation of :prop_tgt:`INTERFACE_LINK_LIBRARIES` itself is not transitive.
 
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index dd202a2..826790d 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.30
 .. toctree::
    :maxdepth: 1
 
+   CMP0166: TARGET_PROPERTY evaluates link properties transitively over private dependencies of static libraries. </policy/CMP0166>
    CMP0165: enable_language() must not be called before project(). </policy/CMP0165>
    CMP0164: add_library() rejects SHARED libraries when not supported by the platform. </policy/CMP0164>
    CMP0163: The GENERATED source file property is now visible in all directories. </policy/CMP0163>
diff --git a/Help/policy/CMP0099.rst b/Help/policy/CMP0099.rst
index e836cf3..0a2b786 100644
--- a/Help/policy/CMP0099.rst
+++ b/Help/policy/CMP0099.rst
@@ -21,6 +21,12 @@ The ``OLD`` behavior for this policy is to not propagate interface link
 properties. The ``NEW`` behavior of this policy is to propagate interface link
 properties.
 
+.. versionadded:: 3.30
+
+  Policy :policy:`CMP0166` makes :genex:`TARGET_PROPERTY` evaluation of
+  these three transitive link properties follow private dependencies of
+  static libraries too.
+
 .. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.17
 .. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
 .. include:: STANDARD_ADVICE.txt
diff --git a/Help/policy/CMP0166.rst b/Help/policy/CMP0166.rst
new file mode 100644
index 0000000..5c67880
--- /dev/null
+++ b/Help/policy/CMP0166.rst
@@ -0,0 +1,40 @@
+CMP0166
+-------
+
+.. versionadded:: 3.30
+
+:genex:`TARGET_PROPERTY` evaluates link properties transitively over private
+dependencies of static libraries.
+
+In CMake 3.29 and below, the :genex:`TARGET_PROPERTY` generator expression
+evaluates properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+as if they were :ref:`Transitive Build Properties` rather than
+:ref:`Transitive Link Properties`, even when policy :policy:`CMP0099` is
+set to ``NEW``.  Private dependencies of static libraries, which appear in
+their :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded by :genex:`LINK_ONLY`
+generator expressions, are not followed.  This is inconsistent with
+evaluation of the same target properties during buildsystem generation.
+
+CMake 3.30 and above prefer that :genex:`TARGET_PROPERTY` evaluates
+properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+as :ref:`Transitive Link Properties` such that private dependencies of static
+libraries, which appear in their :prop_tgt:`INTERFACE_LINK_LIBRARIES` guarded
+by :genex:`LINK_ONLY` generator expressions, are followed.
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for :genex:`TARGET_PROPERTY` to
+evaluate properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and :prop_tgt:`INTERFACE_LINK_DEPENDS`
+as if they were :ref:`Transitive Build Properties` by not following private
+dependencies of static libraries.  The ``NEW`` behavior for this policy is
+to evaluate them as :ref:`Transitive Link Properties` by following private
+dependencies of static libraries.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.30
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: STANDARD_ADVICE.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/release/dev/genex-link-properties.rst b/Help/release/dev/genex-link-properties.rst
new file mode 100644
index 0000000..e1e84e0
--- /dev/null
+++ b/Help/release/dev/genex-link-properties.rst
@@ -0,0 +1,8 @@
+genex-link-properties
+---------------------
+
+* The :genex:`TARGET_PROPERTY` generator expression now evaluates target
+  properties :prop_tgt:`INTERFACE_LINK_OPTIONS`,
+  :prop_tgt:`INTERFACE_LINK_DIRECTORIES`, and
+  :prop_tgt:`INTERFACE_LINK_DEPENDS` correctly by following private
+  dependencies of static libraries.  See policy :policy:`CMP0166`.
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 6bf0095..d7288b6 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -89,11 +89,11 @@ const std::map<cm::string_view, TransitiveProperty>
     { "INCLUDE_DIRECTORIES"_s,
       { "INTERFACE_INCLUDE_DIRECTORIES"_s, LinkInterfaceFor::Usage } },
     { "LINK_DEPENDS"_s,
-      { "INTERFACE_LINK_DEPENDS"_s, LinkInterfaceFor::Usage } },
+      { "INTERFACE_LINK_DEPENDS"_s, LinkInterfaceFor::Link } },
     { "LINK_DIRECTORIES"_s,
-      { "INTERFACE_LINK_DIRECTORIES"_s, LinkInterfaceFor::Usage } },
+      { "INTERFACE_LINK_DIRECTORIES"_s, LinkInterfaceFor::Link } },
     { "LINK_OPTIONS"_s,
-      { "INTERFACE_LINK_OPTIONS"_s, LinkInterfaceFor::Usage } },
+      { "INTERFACE_LINK_OPTIONS"_s, LinkInterfaceFor::Link } },
     { "PRECOMPILE_HEADERS"_s,
       { "INTERFACE_PRECOMPILE_HEADERS"_s, LinkInterfaceFor::Usage } },
     { "SOURCES"_s, { "INTERFACE_SOURCES"_s, LinkInterfaceFor::Usage } },
@@ -1557,6 +1557,15 @@ cmGeneratorTarget::IsTransitiveProperty(cm::string_view prop,
   auto i = BuiltinTransitiveProperties.find(prop);
   if (i != BuiltinTransitiveProperties.end()) {
     result = i->second;
+    if (result->InterfaceFor != cmGeneratorTarget::LinkInterfaceFor::Usage) {
+      cmPolicies::PolicyStatus cmp0166 =
+        lg->GetPolicyStatus(cmPolicies::CMP0166);
+      if ((cmp0166 == cmPolicies::WARN || cmp0166 == cmPolicies::OLD) &&
+          (prop == "LINK_DIRECTORIES"_s || prop == "LINK_DEPENDS"_s ||
+           prop == "LINK_OPTIONS"_s)) {
+        result->InterfaceFor = cmGeneratorTarget::LinkInterfaceFor::Usage;
+      }
+    }
   } else if (cmHasLiteralPrefix(prop, "COMPILE_DEFINITIONS_")) {
     cmPolicies::PolicyStatus cmp0043 =
       lg->GetPolicyStatus(cmPolicies::CMP0043);
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 1aa5f79..eb9f031 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -508,7 +508,11 @@ class cmMakefile;
          3, 30, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0165,                                                     \
          "enable_language() must not be called before project().", 3, 30, 0,  \
-         cmPolicies::WARN)
+         cmPolicies::WARN)                                                    \
+  SELECT(POLICY, CMP0166,                                                     \
+         "TARGET_PROPERTY evaluates link properties transitively over "       \
+         "private dependencies of static libraries.",                         \
+         3, 30, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
index b8eda77..5791993 100644
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/CMakeLists.txt
@@ -3,4 +3,4 @@ if(RunCMake_TEST STREQUAL "LOCATION")
   cmake_minimum_required(VERSION 2.8.12) # Leave CMP0026 unset.
 endif()
 project(${RunCMake_TEST} NONE)
-include(${RunCMake_TEST}.cmake)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
index 2ed42c9..07052eb 100644
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/RunCMakeTest.cmake
@@ -14,7 +14,8 @@ run_cmake(LinkImplementationCycle6)
 run_cmake(LOCATION)
 run_cmake(SOURCES)
 run_cmake(TransitiveBuild)
-run_cmake(TransitiveLink)
+run_cmake(TransitiveLink-CMP0166-OLD)
+run_cmake(TransitiveLink-CMP0166-NEW)
 
 block()
   run_cmake(Scope)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake
new file mode 100644
index 0000000..7ea95b8
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-check.cmake
@@ -0,0 +1,8 @@
+set(expect [[
+# file\(GENERATE\) produced:
+main LINK_LIBRARIES: 'foo1' # not transitive
+main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir2'
+main LINK_OPTIONS: '-optM;-opt1;-opt2'
+main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/dep1;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW-build/dep2'
+]])
+include(${CMAKE_CURRENT_LIST_DIR}/TransitiveLink-check-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake
new file mode 100644
index 0000000..658dd84
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0166 NEW)
+include(TransitiveLink-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake
new file mode 100644
index 0000000..2d430c2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-check.cmake
@@ -0,0 +1,8 @@
+set(expect [[
+# file\(GENERATE\) produced:
+main LINK_LIBRARIES: 'foo1' # not transitive
+main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1'
+main LINK_OPTIONS: '-optM;-opt1'
+main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD-build/dep1'
+]])
+include(${CMAKE_CURRENT_LIST_DIR}/TransitiveLink-check-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake
new file mode 100644
index 0000000..a4a4599
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-CMP0166-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0166 OLD)
+include(TransitiveLink-common.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake
new file mode 100644
index 0000000..42e63bc
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check-common.cmake
@@ -0,0 +1,12 @@
+string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
+string(REGEX REPLACE "\n+$" "" expect "${expect}")
+
+file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" actual)
+string(REGEX REPLACE "\r\n" "\n" actual "${actual}")
+string(REGEX REPLACE "\n+$" "" actual "${actual}")
+
+if(NOT actual MATCHES "^${expect}$")
+  string(REPLACE "\n" "\n expect> " expect " expect> ${expect}")
+  string(REPLACE "\n" "\n actual> " actual " actual> ${actual}")
+  message(FATAL_ERROR "Expected file(GENERATE) output:\n${expect}\ndoes not match actual output:\n${actual}")
+endif()
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake
deleted file mode 100644
index c48b722..0000000
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-check.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-# FIXME: TARGET_PROPERTY evaluation does not pierce LINK_ONLY
-set(expect [[
-# file\(GENERATE\) produced:
-main LINK_LIBRARIES: 'foo1' # not transitive
-main LINK_DIRECTORIES: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dirM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/dir1'
-main LINK_OPTIONS: '-optM;-opt1'
-main LINK_DEPENDS: '[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-build/depM;[^';]*/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-build/dep1'
-]])
-
-string(REGEX REPLACE "\r\n" "\n" expect "${expect}")
-string(REGEX REPLACE "\n+$" "" expect "${expect}")
-
-file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" actual)
-string(REGEX REPLACE "\r\n" "\n" actual "${actual}")
-string(REGEX REPLACE "\n+$" "" actual "${actual}")
-
-if(NOT actual MATCHES "^${expect}$")
-  string(REPLACE "\n" "\n expect> " expect " expect> ${expect}")
-  string(REPLACE "\n" "\n actual> " actual " actual> ${actual}")
-  message(FATAL_ERROR "Expected file(GENERATE) output:\n${expect}\ndoes not match actual output:\n${actual}")
-endif()
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake
new file mode 100644
index 0000000..c120366
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink-common.cmake
@@ -0,0 +1,42 @@
+enable_language(C)
+
+add_library(foo1 STATIC empty.c)
+target_link_libraries(foo1 PRIVATE foo2 foo3)
+target_link_directories(foo1 INTERFACE dir1)
+target_link_options(foo1 INTERFACE -opt1)
+set_target_properties(foo1 PROPERTIES
+  INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep1"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep1" "")
+
+add_library(foo2 STATIC empty.c)
+target_link_directories(foo2 INTERFACE dir2)
+target_link_options(foo2 INTERFACE -opt2)
+set_target_properties(foo2 PROPERTIES
+  INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep2"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep2" "")
+
+add_library(foo3 STATIC empty.c)
+target_link_directories(foo3 PRIVATE dir3)
+target_link_options(foo3 PRIVATE -opt3)
+set_target_properties(foo3 PROPERTIES
+  LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep3"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep3" "")
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE foo1)
+target_link_directories(main PRIVATE dirM)
+target_link_options(main PRIVATE -optM)
+set_target_properties(main PROPERTIES
+  LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/depM"
+  )
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/depM" "")
+
+file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced:
+main LINK_LIBRARIES: '$<TARGET_PROPERTY:main,LINK_LIBRARIES>' # not transitive
+main LINK_DIRECTORIES: '$<TARGET_PROPERTY:main,LINK_DIRECTORIES>'
+main LINK_OPTIONS: '$<TARGET_PROPERTY:main,LINK_OPTIONS>'
+main LINK_DEPENDS: '$<TARGET_PROPERTY:main,LINK_DEPENDS>'
+")
diff --git a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake b/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake
deleted file mode 100644
index c120366..0000000
--- a/Tests/RunCMake/GenEx-TARGET_PROPERTY/TransitiveLink.cmake
+++ /dev/null
@@ -1,42 +0,0 @@
-enable_language(C)
-
-add_library(foo1 STATIC empty.c)
-target_link_libraries(foo1 PRIVATE foo2 foo3)
-target_link_directories(foo1 INTERFACE dir1)
-target_link_options(foo1 INTERFACE -opt1)
-set_target_properties(foo1 PROPERTIES
-  INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep1"
-  )
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep1" "")
-
-add_library(foo2 STATIC empty.c)
-target_link_directories(foo2 INTERFACE dir2)
-target_link_options(foo2 INTERFACE -opt2)
-set_target_properties(foo2 PROPERTIES
-  INTERFACE_LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep2"
-  )
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep2" "")
-
-add_library(foo3 STATIC empty.c)
-target_link_directories(foo3 PRIVATE dir3)
-target_link_options(foo3 PRIVATE -opt3)
-set_target_properties(foo3 PROPERTIES
-  LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/dep3"
-  )
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dep3" "")
-
-add_executable(main main.c)
-target_link_libraries(main PRIVATE foo1)
-target_link_directories(main PRIVATE dirM)
-target_link_options(main PRIVATE -optM)
-set_target_properties(main PROPERTIES
-  LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/depM"
-  )
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/depM" "")
-
-file(GENERATE OUTPUT out.txt CONTENT "# file(GENERATE) produced:
-main LINK_LIBRARIES: '$<TARGET_PROPERTY:main,LINK_LIBRARIES>' # not transitive
-main LINK_DIRECTORIES: '$<TARGET_PROPERTY:main,LINK_DIRECTORIES>'
-main LINK_OPTIONS: '$<TARGET_PROPERTY:main,LINK_OPTIONS>'
-main LINK_DEPENDS: '$<TARGET_PROPERTY:main,LINK_DEPENDS>'
-")
-- 
cgit v0.12