cmGeneratorTarget: Factor INCLUDE_DIRECTORIES impl into own source
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 8faebab..d911484 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -285,6 +285,7 @@
   cmGeneratorExpression.h
   cmGeneratorTarget.cxx
   cmGeneratorTarget.h
+  cmGeneratorTarget_IncludeDirectories.cxx
   cmGeneratorTarget_Sources.cxx
   cmGeneratorTarget_TargetPropertyEntry.cxx
   cmLinkItemGraphVisitor.cxx
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index fb921fd..e0e118f 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -1414,110 +1414,6 @@
   return result;
 }
 
-namespace {
-
-enum class IncludeDirectoryFallBack
-{
-  BINARY,
-  OBJECT
-};
-
-std::string AddLangSpecificInterfaceIncludeDirectories(
-  const cmGeneratorTarget* root, const cmGeneratorTarget* target,
-  const std::string& lang, const std::string& config,
-  const std::string& propertyName, IncludeDirectoryFallBack mode,
-  cmGeneratorExpressionDAGChecker* context)
-{
-  cmGeneratorExpressionDAGChecker dag{
-    target->GetBacktrace(),     target, propertyName, nullptr, context,
-    target->GetLocalGenerator()
-  };
-  switch (dag.Check()) {
-    case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
-      dag.ReportError(
-        nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
-      CM_FALLTHROUGH;
-    case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
-      // No error. We just skip cyclic references.
-    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
-      // No error. We have already seen this transitive property.
-      return "";
-    case cmGeneratorExpressionDAGChecker::DAG:
-      break;
-  }
-
-  std::string directories;
-  if (const auto* link_interface =
-        target->GetLinkInterfaceLibraries(config, root, UseTo::Compile)) {
-    for (const cmLinkItem& library : link_interface->Libraries) {
-      if (const cmGeneratorTarget* dependency = library.Target) {
-        if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
-          auto* lg = dependency->GetLocalGenerator();
-          std::string value = dependency->GetSafeProperty(propertyName);
-          if (value.empty()) {
-            if (mode == IncludeDirectoryFallBack::BINARY) {
-              value = lg->GetCurrentBinaryDirectory();
-            } else if (mode == IncludeDirectoryFallBack::OBJECT) {
-              value = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
-                               lg->GetTargetDirectory(dependency));
-            }
-          }
-
-          if (!directories.empty()) {
-            directories += ";";
-          }
-          directories += value;
-        }
-      }
-    }
-  }
-  return directories;
-}
-
-void AddLangSpecificImplicitIncludeDirectories(
-  const cmGeneratorTarget* target, const std::string& lang,
-  const std::string& config, const std::string& propertyName,
-  IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries)
-{
-  if (const auto* libraries =
-        target->GetLinkImplementationLibraries(config, UseTo::Compile)) {
-    cmGeneratorExpressionDAGChecker dag{
-      target->GetBacktrace(),     target, propertyName, nullptr, nullptr,
-      target->GetLocalGenerator()
-    };
-
-    for (const cmLinkImplItem& library : libraries->Libraries) {
-      if (const cmGeneratorTarget* dependency = library.Target) {
-        if (!dependency->IsInBuildSystem()) {
-          continue;
-        }
-        if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
-          auto* lg = dependency->GetLocalGenerator();
-          EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
-
-          if (cmValue val = dependency->GetProperty(propertyName)) {
-            entry.Values.emplace_back(*val);
-          } else {
-            if (mode == IncludeDirectoryFallBack::BINARY) {
-              entry.Values.emplace_back(lg->GetCurrentBinaryDirectory());
-            } else if (mode == IncludeDirectoryFallBack::OBJECT) {
-              entry.Values.emplace_back(
-                dependency->GetObjectDirectory(config));
-            }
-          }
-
-          cmExpandList(
-            AddLangSpecificInterfaceIncludeDirectories(
-              target, dependency, lang, config, propertyName, mode, &dag),
-            entry.Values);
-          entries.Entries.emplace_back(std::move(entry));
-        }
-      }
-    }
-  }
-}
-
-}
 std::string cmGeneratorTarget::GetCompilePDBName(
   const std::string& config) const
 {
@@ -2874,204 +2770,6 @@
   return cmSystemTools::CollapseFullPath(path);
 }
 
-namespace {
-void processIncludeDirectories(cmGeneratorTarget const* tgt,
-                               EvaluatedTargetPropertyEntries& entries,
-                               std::vector<BT<std::string>>& includes,
-                               std::unordered_set<std::string>& uniqueIncludes,
-                               bool debugIncludes)
-{
-  for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
-    cmLinkImplItem const& item = entry.LinkImplItem;
-    std::string const& targetName = item.AsStr();
-    bool const fromImported = item.Target && item.Target->IsImported();
-    bool const checkCMP0027 = item.CheckCMP0027;
-
-    std::string usedIncludes;
-    for (std::string& entryInclude : entry.Values) {
-      if (fromImported && !cmSystemTools::FileExists(entryInclude)) {
-        std::ostringstream e;
-        MessageType messageType = MessageType::FATAL_ERROR;
-        if (checkCMP0027) {
-          switch (tgt->GetPolicyStatusCMP0027()) {
-            case cmPolicies::WARN:
-              e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n";
-              CM_FALLTHROUGH;
-            case cmPolicies::OLD:
-              messageType = MessageType::AUTHOR_WARNING;
-              break;
-            case cmPolicies::REQUIRED_ALWAYS:
-            case cmPolicies::REQUIRED_IF_USED:
-            case cmPolicies::NEW:
-              break;
-          }
-        }
-        /* clang-format off */
-        e << "Imported target \"" << targetName << "\" includes "
-             "non-existent path\n  \"" << entryInclude << "\"\nin its "
-             "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
-             "* The path was deleted, renamed, or moved to another "
-             "location.\n"
-             "* An install or uninstall procedure did not complete "
-             "successfully.\n"
-             "* The installation package was faulty and references files it "
-             "does not provide.\n";
-        /* clang-format on */
-        tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
-        return;
-      }
-
-      if (!cmSystemTools::FileIsFullPath(entryInclude)) {
-        std::ostringstream e;
-        bool noMessage = false;
-        MessageType messageType = MessageType::FATAL_ERROR;
-        if (!targetName.empty()) {
-          /* clang-format off */
-          e << "Target \"" << targetName << "\" contains relative "
-            "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
-            "  \"" << entryInclude << "\"";
-          /* clang-format on */
-        } else {
-          switch (tgt->GetPolicyStatusCMP0021()) {
-            case cmPolicies::WARN: {
-              e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n";
-              messageType = MessageType::AUTHOR_WARNING;
-            } break;
-            case cmPolicies::OLD:
-              noMessage = true;
-              break;
-            case cmPolicies::REQUIRED_IF_USED:
-            case cmPolicies::REQUIRED_ALWAYS:
-            case cmPolicies::NEW:
-              // Issue the fatal message.
-              break;
-          }
-          e << "Found relative path while evaluating include directories of "
-               "\""
-            << tgt->GetName() << "\":\n  \"" << entryInclude << "\"\n";
-        }
-        if (!noMessage) {
-          tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
-          if (messageType == MessageType::FATAL_ERROR) {
-            return;
-          }
-        }
-      }
-
-      if (!cmIsOff(entryInclude)) {
-        cmSystemTools::ConvertToUnixSlashes(entryInclude);
-      }
-
-      if (uniqueIncludes.insert(entryInclude).second) {
-        includes.emplace_back(entryInclude, entry.Backtrace);
-        if (debugIncludes) {
-          usedIncludes += " * " + entryInclude + "\n";
-        }
-      }
-    }
-    if (!usedIncludes.empty()) {
-      tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
-        MessageType::LOG,
-        std::string("Used includes for target ") + tgt->GetName() + ":\n" +
-          usedIncludes,
-        entry.Backtrace);
-    }
-  }
-}
-}
-
-std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
-  const std::string& config, const std::string& lang) const
-{
-  ConfigAndLanguage cacheKey(config, lang);
-  {
-    auto it = this->IncludeDirectoriesCache.find(cacheKey);
-    if (it != this->IncludeDirectoriesCache.end()) {
-      return it->second;
-    }
-  }
-  std::vector<BT<std::string>> includes;
-  std::unordered_set<std::string> uniqueIncludes;
-
-  cmGeneratorExpressionDAGChecker dagChecker(
-    this, "INCLUDE_DIRECTORIES", nullptr, nullptr, this->LocalGenerator);
-
-  cmList debugProperties{ this->Makefile->GetDefinition(
-    "CMAKE_DEBUG_TARGET_PROPERTIES") };
-  bool debugIncludes = !this->DebugIncludesDone &&
-    cm::contains(debugProperties, "INCLUDE_DIRECTORIES");
-
-  if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
-    this->DebugIncludesDone = true;
-  }
-
-  EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
-    this, config, lang, &dagChecker, this->IncludeDirectoriesEntries);
-
-  if (lang == "Swift") {
-    AddLangSpecificImplicitIncludeDirectories(
-      this, lang, config, "Swift_MODULE_DIRECTORY",
-      IncludeDirectoryFallBack::BINARY, entries);
-  }
-
-  if (this->CanCompileSources() && (lang != "Swift" && lang != "Fortran")) {
-
-    const std::string propertyName = "ISPC_HEADER_DIRECTORY";
-
-    // If this target has ISPC sources make sure to add the header
-    // directory to other compilation units
-    if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
-      if (cmValue val = this->GetProperty(propertyName)) {
-        includes.emplace_back(*val);
-      } else {
-        includes.emplace_back(this->GetObjectDirectory(config));
-      }
-    }
-
-    AddLangSpecificImplicitIncludeDirectories(
-      this, "ISPC", config, propertyName, IncludeDirectoryFallBack::OBJECT,
-      entries);
-  }
-
-  AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
-                      &dagChecker, entries, IncludeRuntimeInterface::Yes);
-
-  processIncludeDirectories(this, entries, includes, uniqueIncludes,
-                            debugIncludes);
-
-  if (this->IsApple()) {
-    if (cmLinkImplementationLibraries const* impl =
-          this->GetLinkImplementationLibraries(config, UseTo::Compile)) {
-      for (cmLinkImplItem const& lib : impl->Libraries) {
-        std::string libDir;
-        if (lib.Target == nullptr) {
-          libDir = cmSystemTools::CollapseFullPath(
-            lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
-        } else if (lib.Target->Target->IsFrameworkOnApple() ||
-                   this->IsImportedFrameworkFolderOnApple(config)) {
-          libDir = lib.Target->GetLocation(config);
-        } else {
-          continue;
-        }
-
-        auto fwDescriptor =
-          this->GetGlobalGenerator()->SplitFrameworkPath(libDir);
-        if (!fwDescriptor) {
-          continue;
-        }
-
-        auto fwInclude = fwDescriptor->GetFrameworkPath();
-        if (uniqueIncludes.insert(fwInclude).second) {
-          includes.emplace_back(fwInclude, cmListFileBacktrace());
-        }
-      }
-    }
-  }
-
-  this->IncludeDirectoriesCache.emplace(cacheKey, includes);
-  return includes;
-}
-
 enum class OptionsParse
 {
   None,
diff --git a/Source/cmGeneratorTarget_IncludeDirectories.cxx b/Source/cmGeneratorTarget_IncludeDirectories.cxx
new file mode 100644
index 0000000..eaa3959
--- /dev/null
+++ b/Source/cmGeneratorTarget_IncludeDirectories.cxx
@@ -0,0 +1,334 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+/* clang-format off */
+#include "cmGeneratorTarget.h"
+/* clang-format on */
+
+#include "cmConfigure.h"
+
+#include <set>
+#include <sstream>
+#include <string>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/algorithm>
+
+#include "cmEvaluatedTargetProperty.h"
+#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
+#include "cmList.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmValue.h"
+#include "cmake.h"
+
+namespace {
+using UseTo = cmGeneratorTarget::UseTo;
+
+enum class IncludeDirectoryFallBack
+{
+  BINARY,
+  OBJECT
+};
+
+std::string AddLangSpecificInterfaceIncludeDirectories(
+  const cmGeneratorTarget* root, const cmGeneratorTarget* target,
+  const std::string& lang, const std::string& config,
+  const std::string& propertyName, IncludeDirectoryFallBack mode,
+  cmGeneratorExpressionDAGChecker* context)
+{
+  cmGeneratorExpressionDAGChecker dag{
+    target->GetBacktrace(),     target, propertyName, nullptr, context,
+    target->GetLocalGenerator()
+  };
+  switch (dag.Check()) {
+    case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+      dag.ReportError(
+        nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
+      CM_FALLTHROUGH;
+    case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+      // No error. We just skip cyclic references.
+    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+      // No error. We have already seen this transitive property.
+      return "";
+    case cmGeneratorExpressionDAGChecker::DAG:
+      break;
+  }
+
+  std::string directories;
+  if (const auto* link_interface =
+        target->GetLinkInterfaceLibraries(config, root, UseTo::Compile)) {
+    for (const cmLinkItem& library : link_interface->Libraries) {
+      if (const cmGeneratorTarget* dependency = library.Target) {
+        if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
+          auto* lg = dependency->GetLocalGenerator();
+          std::string value = dependency->GetSafeProperty(propertyName);
+          if (value.empty()) {
+            if (mode == IncludeDirectoryFallBack::BINARY) {
+              value = lg->GetCurrentBinaryDirectory();
+            } else if (mode == IncludeDirectoryFallBack::OBJECT) {
+              value = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
+                               lg->GetTargetDirectory(dependency));
+            }
+          }
+
+          if (!directories.empty()) {
+            directories += ";";
+          }
+          directories += value;
+        }
+      }
+    }
+  }
+  return directories;
+}
+
+void AddLangSpecificImplicitIncludeDirectories(
+  const cmGeneratorTarget* target, const std::string& lang,
+  const std::string& config, const std::string& propertyName,
+  IncludeDirectoryFallBack mode, EvaluatedTargetPropertyEntries& entries)
+{
+  if (const auto* libraries =
+        target->GetLinkImplementationLibraries(config, UseTo::Compile)) {
+    cmGeneratorExpressionDAGChecker dag{
+      target->GetBacktrace(),     target, propertyName, nullptr, nullptr,
+      target->GetLocalGenerator()
+    };
+
+    for (const cmLinkImplItem& library : libraries->Libraries) {
+      if (const cmGeneratorTarget* dependency = library.Target) {
+        if (!dependency->IsInBuildSystem()) {
+          continue;
+        }
+        if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
+          auto* lg = dependency->GetLocalGenerator();
+          EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
+
+          if (cmValue val = dependency->GetProperty(propertyName)) {
+            entry.Values.emplace_back(*val);
+          } else {
+            if (mode == IncludeDirectoryFallBack::BINARY) {
+              entry.Values.emplace_back(lg->GetCurrentBinaryDirectory());
+            } else if (mode == IncludeDirectoryFallBack::OBJECT) {
+              entry.Values.emplace_back(
+                dependency->GetObjectDirectory(config));
+            }
+          }
+
+          cmExpandList(
+            AddLangSpecificInterfaceIncludeDirectories(
+              target, dependency, lang, config, propertyName, mode, &dag),
+            entry.Values);
+          entries.Entries.emplace_back(std::move(entry));
+        }
+      }
+    }
+  }
+}
+
+void processIncludeDirectories(cmGeneratorTarget const* tgt,
+                               EvaluatedTargetPropertyEntries& entries,
+                               std::vector<BT<std::string>>& includes,
+                               std::unordered_set<std::string>& uniqueIncludes,
+                               bool debugIncludes)
+{
+  for (EvaluatedTargetPropertyEntry& entry : entries.Entries) {
+    cmLinkImplItem const& item = entry.LinkImplItem;
+    std::string const& targetName = item.AsStr();
+    bool const fromImported = item.Target && item.Target->IsImported();
+    bool const checkCMP0027 = item.CheckCMP0027;
+
+    std::string usedIncludes;
+    for (std::string& entryInclude : entry.Values) {
+      if (fromImported && !cmSystemTools::FileExists(entryInclude)) {
+        std::ostringstream e;
+        MessageType messageType = MessageType::FATAL_ERROR;
+        if (checkCMP0027) {
+          switch (tgt->GetPolicyStatusCMP0027()) {
+            case cmPolicies::WARN:
+              e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0027) << "\n";
+              CM_FALLTHROUGH;
+            case cmPolicies::OLD:
+              messageType = MessageType::AUTHOR_WARNING;
+              break;
+            case cmPolicies::REQUIRED_ALWAYS:
+            case cmPolicies::REQUIRED_IF_USED:
+            case cmPolicies::NEW:
+              break;
+          }
+        }
+        /* clang-format off */
+        e << "Imported target \"" << targetName << "\" includes "
+             "non-existent path\n  \"" << entryInclude << "\"\nin its "
+             "INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:\n"
+             "* The path was deleted, renamed, or moved to another "
+             "location.\n"
+             "* An install or uninstall procedure did not complete "
+             "successfully.\n"
+             "* The installation package was faulty and references files it "
+             "does not provide.\n";
+        /* clang-format on */
+        tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+        return;
+      }
+
+      if (!cmSystemTools::FileIsFullPath(entryInclude)) {
+        std::ostringstream e;
+        bool noMessage = false;
+        MessageType messageType = MessageType::FATAL_ERROR;
+        if (!targetName.empty()) {
+          /* clang-format off */
+          e << "Target \"" << targetName << "\" contains relative "
+            "path in its INTERFACE_INCLUDE_DIRECTORIES:\n"
+            "  \"" << entryInclude << "\"";
+          /* clang-format on */
+        } else {
+          switch (tgt->GetPolicyStatusCMP0021()) {
+            case cmPolicies::WARN: {
+              e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0021) << "\n";
+              messageType = MessageType::AUTHOR_WARNING;
+            } break;
+            case cmPolicies::OLD:
+              noMessage = true;
+              break;
+            case cmPolicies::REQUIRED_IF_USED:
+            case cmPolicies::REQUIRED_ALWAYS:
+            case cmPolicies::NEW:
+              // Issue the fatal message.
+              break;
+          }
+          e << "Found relative path while evaluating include directories of "
+               "\""
+            << tgt->GetName() << "\":\n  \"" << entryInclude << "\"\n";
+        }
+        if (!noMessage) {
+          tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+          if (messageType == MessageType::FATAL_ERROR) {
+            return;
+          }
+        }
+      }
+
+      if (!cmIsOff(entryInclude)) {
+        cmSystemTools::ConvertToUnixSlashes(entryInclude);
+      }
+
+      if (uniqueIncludes.insert(entryInclude).second) {
+        includes.emplace_back(entryInclude, entry.Backtrace);
+        if (debugIncludes) {
+          usedIncludes += " * " + entryInclude + "\n";
+        }
+      }
+    }
+    if (!usedIncludes.empty()) {
+      tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+        MessageType::LOG,
+        std::string("Used includes for target ") + tgt->GetName() + ":\n" +
+          usedIncludes,
+        entry.Backtrace);
+    }
+  }
+}
+}
+
+std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories(
+  const std::string& config, const std::string& lang) const
+{
+  ConfigAndLanguage cacheKey(config, lang);
+  {
+    auto it = this->IncludeDirectoriesCache.find(cacheKey);
+    if (it != this->IncludeDirectoriesCache.end()) {
+      return it->second;
+    }
+  }
+  std::vector<BT<std::string>> includes;
+  std::unordered_set<std::string> uniqueIncludes;
+
+  cmGeneratorExpressionDAGChecker dagChecker(
+    this, "INCLUDE_DIRECTORIES", nullptr, nullptr, this->LocalGenerator);
+
+  cmList debugProperties{ this->Makefile->GetDefinition(
+    "CMAKE_DEBUG_TARGET_PROPERTIES") };
+  bool debugIncludes = !this->DebugIncludesDone &&
+    cm::contains(debugProperties, "INCLUDE_DIRECTORIES");
+
+  if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+    this->DebugIncludesDone = true;
+  }
+
+  EvaluatedTargetPropertyEntries entries = EvaluateTargetPropertyEntries(
+    this, config, lang, &dagChecker, this->IncludeDirectoriesEntries);
+
+  if (lang == "Swift") {
+    AddLangSpecificImplicitIncludeDirectories(
+      this, lang, config, "Swift_MODULE_DIRECTORY",
+      IncludeDirectoryFallBack::BINARY, entries);
+  }
+
+  if (this->CanCompileSources() && (lang != "Swift" && lang != "Fortran")) {
+
+    const std::string propertyName = "ISPC_HEADER_DIRECTORY";
+
+    // If this target has ISPC sources make sure to add the header
+    // directory to other compilation units
+    if (cm::contains(this->GetAllConfigCompileLanguages(), "ISPC")) {
+      if (cmValue val = this->GetProperty(propertyName)) {
+        includes.emplace_back(*val);
+      } else {
+        includes.emplace_back(this->GetObjectDirectory(config));
+      }
+    }
+
+    AddLangSpecificImplicitIncludeDirectories(
+      this, "ISPC", config, propertyName, IncludeDirectoryFallBack::OBJECT,
+      entries);
+  }
+
+  AddInterfaceEntries(this, config, "INTERFACE_INCLUDE_DIRECTORIES", lang,
+                      &dagChecker, entries, IncludeRuntimeInterface::Yes);
+
+  processIncludeDirectories(this, entries, includes, uniqueIncludes,
+                            debugIncludes);
+
+  if (this->IsApple()) {
+    if (cmLinkImplementationLibraries const* impl =
+          this->GetLinkImplementationLibraries(config, UseTo::Compile)) {
+      for (cmLinkImplItem const& lib : impl->Libraries) {
+        std::string libDir;
+        if (lib.Target == nullptr) {
+          libDir = cmSystemTools::CollapseFullPath(
+            lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
+        } else if (lib.Target->Target->IsFrameworkOnApple() ||
+                   this->IsImportedFrameworkFolderOnApple(config)) {
+          libDir = lib.Target->GetLocation(config);
+        } else {
+          continue;
+        }
+
+        auto fwDescriptor =
+          this->GetGlobalGenerator()->SplitFrameworkPath(libDir);
+        if (!fwDescriptor) {
+          continue;
+        }
+
+        auto fwInclude = fwDescriptor->GetFrameworkPath();
+        if (uniqueIncludes.insert(fwInclude).second) {
+          includes.emplace_back(fwInclude, cmListFileBacktrace());
+        }
+      }
+    }
+  }
+
+  this->IncludeDirectoriesCache.emplace(cacheKey, includes);
+  return includes;
+}
diff --git a/bootstrap b/bootstrap
index fc77bcc..c029bc7 100755
--- a/bootstrap
+++ b/bootstrap
@@ -381,6 +381,7 @@
   cmGeneratorExpressionNode \
   cmGeneratorExpressionParser \
   cmGeneratorTarget \
+  cmGeneratorTarget_IncludeDirectories \
   cmGeneratorTarget_Sources \
   cmGeneratorTarget_TargetPropertyEntry \
   cmGetCMakePropertyCommand \