Răsfoiți Sursa

cmTarget: Add cmFileSet and associated properties

Kyle Edwards 4 ani în urmă
părinte
comite
f2a44a8afa
6 a modificat fișierele cu 553 adăugiri și 1 ștergeri
  1. 2 0
      Source/CMakeLists.txt
  2. 151 0
      Source/cmFileSet.cxx
  3. 64 0
      Source/cmFileSet.h
  4. 320 1
      Source/cmTarget.cxx
  5. 15 0
      Source/cmTarget.h
  6. 1 0
      bootstrap

+ 2 - 0
Source/CMakeLists.txt

@@ -261,6 +261,8 @@ set(SRCS
   cmFileLockResult.h
   cmFilePathChecksum.cxx
   cmFilePathChecksum.h
+  cmFileSet.cxx
+  cmFileSet.h
   cmFileTime.cxx
   cmFileTime.h
   cmFileTimeCache.cxx

+ 151 - 0
Source/cmFileSet.cxx

@@ -0,0 +1,151 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmFileSet.h"
+
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMessageType.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+cmFileSet::cmFileSet(std::string name, std::string type)
+  : Name(std::move(name))
+  , Type(std::move(type))
+{
+}
+
+void cmFileSet::ClearDirectoryEntries()
+{
+  this->DirectoryEntries.clear();
+}
+
+void cmFileSet::AddDirectoryEntry(BT<std::string> directories)
+{
+  this->DirectoryEntries.push_back(std::move(directories));
+}
+
+void cmFileSet::ClearFileEntries()
+{
+  this->FileEntries.clear();
+}
+
+void cmFileSet::AddFileEntry(BT<std::string> files)
+{
+  this->FileEntries.push_back(std::move(files));
+}
+
+std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
+cmFileSet::CompileFileEntries() const
+{
+  std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
+
+  for (auto const& entry : this->FileEntries) {
+    for (auto const& ex : cmExpandedList(entry.Value)) {
+      cmGeneratorExpression ge(entry.Backtrace);
+      auto cge = ge.Parse(ex);
+      result.push_back(std::move(cge));
+    }
+  }
+
+  return result;
+}
+
+std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
+cmFileSet::CompileDirectoryEntries() const
+{
+  std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result;
+
+  for (auto const& entry : this->DirectoryEntries) {
+    for (auto const& ex : cmExpandedList(entry.Value)) {
+      cmGeneratorExpression ge(entry.Backtrace);
+      auto cge = ge.Parse(ex);
+      result.push_back(std::move(cge));
+    }
+  }
+
+  return result;
+}
+
+std::vector<std::string> cmFileSet::EvaluateDirectoryEntries(
+  const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>& cges,
+  cmLocalGenerator* lg, const std::string& config,
+  const cmGeneratorTarget* target,
+  cmGeneratorExpressionDAGChecker* dagChecker) const
+{
+  std::vector<std::string> result;
+  for (auto const& cge : cges) {
+    auto entry = cge->Evaluate(lg, config, target, dagChecker);
+    auto dirs = cmExpandedList(entry);
+    for (std::string dir : dirs) {
+      if (!cmSystemTools::FileIsFullPath(dir)) {
+        dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir);
+      }
+      auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
+      for (auto const& priorDir : result) {
+        auto collapsedPriorDir = cmSystemTools::CollapseFullPath(priorDir);
+        if (!cmSystemTools::SameFile(collapsedDir, collapsedPriorDir) &&
+            (cmSystemTools::IsSubDirectory(collapsedDir, collapsedPriorDir) ||
+             cmSystemTools::IsSubDirectory(collapsedPriorDir, collapsedDir))) {
+          lg->GetCMakeInstance()->IssueMessage(
+            MessageType::FATAL_ERROR,
+            cmStrCat(
+              "Base directories in file set cannot be subdirectories of each "
+              "other:\n  ",
+              priorDir, "\n  ", dir),
+            cge->GetBacktrace());
+          return {};
+        }
+      }
+      result.push_back(dir);
+    }
+  }
+  return result;
+}
+
+void cmFileSet::EvaluateFileEntry(
+  const std::vector<std::string>& dirs,
+  std::map<std::string, std::vector<std::string>>& filesPerDir,
+  const std::unique_ptr<cmCompiledGeneratorExpression>& cge,
+  cmLocalGenerator* lg, const std::string& config,
+  const cmGeneratorTarget* target,
+  cmGeneratorExpressionDAGChecker* dagChecker) const
+{
+  auto files = cge->Evaluate(lg, config, target, dagChecker);
+  for (std::string file : cmExpandedList(files)) {
+    if (!cmSystemTools::FileIsFullPath(file)) {
+      file = cmStrCat(lg->GetCurrentSourceDirectory(), '/', file);
+    }
+    auto collapsedFile = cmSystemTools::CollapseFullPath(file);
+    bool found = false;
+    std::string relDir;
+    for (auto const& dir : dirs) {
+      auto collapsedDir = cmSystemTools::CollapseFullPath(dir);
+      if (cmSystemTools::IsSubDirectory(collapsedFile, collapsedDir)) {
+        found = true;
+        relDir = cmSystemTools::GetParentDirectory(
+          cmSystemTools::RelativePath(collapsedDir, collapsedFile));
+        break;
+      }
+    }
+    if (!found) {
+      std::ostringstream e;
+      e << "File:\n  " << file
+        << "\nmust be in one of the file set's base directories:";
+      for (auto const& dir : dirs) {
+        e << "\n  " << dir;
+      }
+      lg->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+                                           cge->GetBacktrace());
+      return;
+    }
+
+    filesPerDir[relDir].push_back(file);
+  }
+}

+ 64 - 0
Source/cmFileSet.h

@@ -0,0 +1,64 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "cmListFileCache.h"
+
+class cmCompiledGeneratorExpression;
+struct cmGeneratorExpressionDAGChecker;
+class cmGeneratorTarget;
+class cmLocalGenerator;
+
+class cmFileSet
+{
+public:
+  cmFileSet(std::string name, std::string type);
+
+  const std::string& GetName() const { return this->Name; }
+  const std::string& GetType() const { return this->Type; }
+
+  void ClearDirectoryEntries();
+  void AddDirectoryEntry(BT<std::string> directories);
+  const std::vector<BT<std::string>>& GetDirectoryEntries() const
+  {
+    return this->DirectoryEntries;
+  }
+
+  void ClearFileEntries();
+  void AddFileEntry(BT<std::string> files);
+  const std::vector<BT<std::string>>& GetFileEntries() const
+  {
+    return this->FileEntries;
+  }
+
+  std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
+  CompileFileEntries() const;
+
+  std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>
+  CompileDirectoryEntries() const;
+
+  std::vector<std::string> EvaluateDirectoryEntries(
+    const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>& cges,
+    cmLocalGenerator* lg, const std::string& config,
+    const cmGeneratorTarget* target,
+    cmGeneratorExpressionDAGChecker* dagChecker = nullptr) const;
+
+  void EvaluateFileEntry(
+    const std::vector<std::string>& dirs,
+    std::map<std::string, std::vector<std::string>>& filesPerDir,
+    const std::unique_ptr<cmCompiledGeneratorExpression>& cge,
+    cmLocalGenerator* lg, const std::string& config,
+    const cmGeneratorTarget* target,
+    cmGeneratorExpressionDAGChecker* dagChecker = nullptr) const;
+
+private:
+  std::string Name;
+  std::string Type;
+  std::vector<BT<std::string>> DirectoryEntries;
+  std::vector<BT<std::string>> FileEntries;
+};

+ 320 - 1
Source/cmTarget.cxx

@@ -14,11 +14,13 @@
 
 #include <cm/memory>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
+#include "cmFileSet.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -200,8 +202,11 @@ public:
   std::vector<BT<std::string>> LinkOptionsEntries;
   std::vector<BT<std::string>> LinkDirectoriesEntries;
   std::vector<BT<std::string>> LinkImplementationPropertyEntries;
+  std::vector<BT<std::string>> HeaderSetsEntries;
+  std::vector<BT<std::string>> InterfaceHeaderSetsEntries;
   std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>>
     TLLCommands;
+  std::map<std::string, cmFileSet> FileSets;
   cmListFileBacktrace Backtrace;
 
   bool CheckImportedLibName(std::string const& prop,
@@ -1110,6 +1115,16 @@ cmBTStringRange cmTarget::GetLinkImplementationEntries() const
   return cmMakeRange(this->impl->LinkImplementationPropertyEntries);
 }
 
+cmBTStringRange cmTarget::GetHeaderSetsEntries() const
+{
+  return cmMakeRange(this->impl->HeaderSetsEntries);
+}
+
+cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const
+{
+  return cmMakeRange(this->impl->InterfaceHeaderSetsEntries);
+}
+
 namespace {
 #define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
 MAKE_PROP(C_STANDARD);
@@ -1139,6 +1154,10 @@ MAKE_PROP(BINARY_DIR);
 MAKE_PROP(SOURCE_DIR);
 MAKE_PROP(FALSE);
 MAKE_PROP(TRUE);
+MAKE_PROP(HEADER_DIRS);
+MAKE_PROP(HEADER_SET);
+MAKE_PROP(HEADER_SETS);
+MAKE_PROP(INTERFACE_HEADER_SETS);
 #undef MAKE_PROP
 }
 
@@ -1158,6 +1177,21 @@ std::string ConvertToString<cmValue>(cmValue value)
 {
   return std::string(*value);
 }
+
+template <typename ValueType>
+bool StringIsEmpty(ValueType value);
+
+template <>
+bool StringIsEmpty<const char*>(const char* value)
+{
+  return cmValue::IsEmpty(value);
+}
+
+template <>
+bool StringIsEmpty<cmValue>(cmValue value)
+{
+  return value.IsEmpty();
+}
 }
 
 template <typename ValueType>
@@ -1321,6 +1355,104 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
     } else {
       this->impl->LanguageStandardProperties.erase(prop);
     }
+  } else if (prop == propHEADER_DIRS) {
+    auto* fileSet = this->GetFileSet("HEADERS");
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        "The default header set has not yet been created.");
+      return;
+    }
+    fileSet->ClearDirectoryEntries();
+    if (!StringIsEmpty(value)) {
+      fileSet->AddDirectoryEntry(
+        BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+    }
+  } else if (prop == propHEADER_SET) {
+    auto* fileSet = this->GetFileSet("HEADERS");
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        "The default header set has not yet been created.");
+      return;
+    }
+    fileSet->ClearFileEntries();
+    if (!StringIsEmpty(value)) {
+      fileSet->AddFileEntry(
+        BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+    }
+  } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) {
+    auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_"));
+    if (fileSetName.empty()) {
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                         "Header set name cannot be empty.");
+      return;
+    }
+    auto* fileSet = this->GetFileSet(fileSetName);
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Header set \"", fileSetName,
+                 "\" has not yet been created."));
+      return;
+    }
+    fileSet->ClearDirectoryEntries();
+    if (!StringIsEmpty(value)) {
+      fileSet->AddDirectoryEntry(
+        BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+    }
+  } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) {
+    auto fileSetName = prop.substr(cmStrLen("HEADER_SET_"));
+    if (fileSetName.empty()) {
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                         "Header set name cannot be empty.");
+      return;
+    }
+    auto* fileSet = this->GetFileSet(fileSetName);
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Header set \"", fileSetName,
+                 "\" has not yet been created."));
+      return;
+    }
+    fileSet->ClearFileEntries();
+    if (!StringIsEmpty(value)) {
+      fileSet->AddFileEntry(
+        BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+    }
+  } else if (prop == propHEADER_SETS) {
+    if (value) {
+      for (auto const& name : cmExpandedList(value)) {
+        if (!this->GetFileSet(name)) {
+          this->impl->Makefile->IssueMessage(
+            MessageType::FATAL_ERROR,
+            cmStrCat("Header set \"", name, "\" has not yet been created."));
+          return;
+        }
+      }
+    }
+    this->impl->HeaderSetsEntries.clear();
+    if (!StringIsEmpty(value)) {
+      this->impl->HeaderSetsEntries.emplace_back(
+        value, this->impl->Makefile->GetBacktrace());
+    }
+  } else if (prop == propINTERFACE_HEADER_SETS) {
+    if (value) {
+      for (auto const& name : cmExpandedList(value)) {
+        if (!this->GetFileSet(name)) {
+          this->impl->Makefile->IssueMessage(
+            MessageType::FATAL_ERROR,
+            cmStrCat("Header set \"", name, "\" has not yet been created."));
+          return;
+        }
+      }
+    }
+    this->impl->InterfaceHeaderSetsEntries.clear();
+    if (!StringIsEmpty(value)) {
+      this->impl->InterfaceHeaderSetsEntries.emplace_back(
+        value, this->impl->Makefile->GetBacktrace());
+    }
   } else {
     this->impl->Properties.SetProperty(prop, value);
   }
@@ -1415,6 +1547,82 @@ void cmTarget::AppendProperty(const std::string& prop,
              prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") {
     this->impl->Makefile->IssueMessage(
       MessageType::FATAL_ERROR, prop + " property may not be appended.");
+  } else if (prop == "HEADER_DIRS") {
+    auto* fileSet = this->GetFileSet("HEADERS");
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        "The default header set has not yet been created.");
+      return;
+    }
+    fileSet->AddDirectoryEntry(
+      BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+  } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) {
+    auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_"));
+    if (fileSetName.empty()) {
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                         "Header set name cannot be empty.");
+      return;
+    }
+    auto* fileSet = this->GetFileSet(fileSetName);
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Header set \"", fileSetName,
+                 "\" has not yet been created."));
+      return;
+    }
+    fileSet->AddDirectoryEntry(
+      BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+  } else if (prop == "HEADER_SET") {
+    auto* fileSet = this->GetFileSet("HEADERS");
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        "The default header set has not yet been created.");
+      return;
+    }
+    fileSet->AddFileEntry(
+      BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+  } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) {
+    auto fileSetName = prop.substr(cmStrLen("HEADER_SET_"));
+    if (fileSetName.empty()) {
+      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+                                         "Header set name cannot be empty.");
+      return;
+    }
+    auto* fileSet = this->GetFileSet(fileSetName);
+    if (!fileSet) {
+      this->impl->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Header set \"", fileSetName,
+                 "\" has not yet been created."));
+      return;
+    }
+    fileSet->AddFileEntry(
+      BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
+  } else if (prop == "HEADER_SETS") {
+    for (auto const& name : cmExpandedList(value)) {
+      if (!this->GetFileSet(name)) {
+        this->impl->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("Header set \"", name, "\" has not yet been created."));
+        return;
+      }
+    }
+    this->impl->HeaderSetsEntries.emplace_back(
+      value, this->impl->Makefile->GetBacktrace());
+  } else if (prop == "INTERFACE_HEADER_SETS") {
+    for (auto const& name : cmExpandedList(value)) {
+      if (!this->GetFileSet(name)) {
+        this->impl->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("Header set \"", name, "\" has not yet been created."));
+        return;
+      }
+    }
+    this->impl->InterfaceHeaderSetsEntries.emplace_back(
+      value, this->impl->Makefile->GetBacktrace());
   } else {
     this->impl->Properties.AppendProperty(prop, value, asString);
   }
@@ -1633,7 +1841,11 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
     propNAME,
     propBINARY_DIR,
     propSOURCE_DIR,
-    propSOURCES
+    propSOURCES,
+    propHEADER_DIRS,
+    propHEADER_SET,
+    propHEADER_SETS,
+    propINTERFACE_HEADER_SETS,
   };
   if (specialProps.count(prop)) {
     if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
@@ -1759,6 +1971,60 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
                        .GetDirectory()
                        .GetCurrentSource());
     }
+    if (prop == propHEADER_DIRS) {
+      auto const* fileSet = this->GetFileSet("HEADERS");
+      if (!fileSet) {
+        return nullptr;
+      }
+      static std::string output;
+      output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s);
+      return cmValue(output);
+    }
+    if (prop == propHEADER_SET) {
+      auto const* fileSet = this->GetFileSet("HEADERS");
+      if (!fileSet) {
+        return nullptr;
+      }
+      static std::string output;
+      output = cmJoin(fileSet->GetFileEntries(), ";"_s);
+      return cmValue(output);
+    }
+    if (prop == propHEADER_SETS) {
+      static std::string output;
+      output = cmJoin(this->impl->HeaderSetsEntries, ";"_s);
+      return cmValue(output);
+    }
+    if (prop == propINTERFACE_HEADER_SETS) {
+      static std::string output;
+      output = cmJoin(this->impl->InterfaceHeaderSetsEntries, ";"_s);
+      return cmValue(output);
+    }
+  }
+  if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) {
+    std::string fileSetName = prop.substr(cmStrLen("HEADER_DIRS_"));
+    if (fileSetName.empty()) {
+      return nullptr;
+    }
+    auto const* fileSet = this->GetFileSet(fileSetName);
+    if (!fileSet) {
+      return nullptr;
+    }
+    static std::string output;
+    output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s);
+    return cmValue(output);
+  }
+  if (cmHasLiteralPrefix(prop, "HEADER_SET_")) {
+    std::string fileSetName = prop.substr(cmStrLen("HEADER_SET_"));
+    if (fileSetName.empty()) {
+      return nullptr;
+    }
+    auto const* fileSet = this->GetFileSet(fileSetName);
+    if (!fileSet) {
+      return nullptr;
+    }
+    static std::string output;
+    output = cmJoin(fileSet->GetFileEntries(), ";"_s);
+    return cmValue(output);
   }
 
   cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
@@ -2015,6 +2281,59 @@ std::string cmTarget::ImportedGetFullPath(
   return result;
 }
 
+const cmFileSet* cmTarget::GetFileSet(const std::string& name) const
+{
+  auto it = this->impl->FileSets.find(name);
+  return it == this->impl->FileSets.end() ? nullptr : &it->second;
+}
+
+cmFileSet* cmTarget::GetFileSet(const std::string& name)
+{
+  auto it = this->impl->FileSets.find(name);
+  return it == this->impl->FileSets.end() ? nullptr : &it->second;
+}
+
+std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
+  const std::string& name, const std::string& type)
+{
+  auto result =
+    this->impl->FileSets.emplace(std::make_pair(name, cmFileSet(name, type)));
+  return std::make_pair(&result.first->second, result.second);
+}
+
+std::string cmTarget::GetFileSetsPropertyName(const std::string& type)
+{
+  if (type == "HEADERS") {
+    return "HEADER_SETS";
+  }
+  return "";
+}
+
+std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& type)
+{
+  if (type == "HEADERS") {
+    return "INTERFACE_HEADER_SETS";
+  }
+  return "";
+}
+
+std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const
+{
+  std::vector<std::string> result;
+  auto inserter = std::back_inserter(result);
+
+  auto appendEntries = [=](const std::vector<BT<std::string>>& entries) {
+    for (auto const& entry : entries) {
+      auto expanded = cmExpandedList(entry.Value);
+      std::copy(expanded.begin(), expanded.end(), inserter);
+    }
+  };
+
+  appendEntries(this->impl->InterfaceHeaderSetsEntries);
+
+  return result;
+}
+
 bool cmTargetInternals::CheckImportedLibName(std::string const& prop,
                                              std::string const& value) const
 {

+ 15 - 0
Source/cmTarget.h

@@ -20,6 +20,7 @@
 #include "cmValue.h"
 
 class cmCustomCommand;
+class cmFileSet;
 class cmGlobalGenerator;
 class cmInstallTargetGenerator;
 class cmMakefile;
@@ -260,6 +261,10 @@ public:
 
   cmBTStringRange GetLinkImplementationEntries() const;
 
+  cmBTStringRange GetHeaderSetsEntries() const;
+
+  cmBTStringRange GetInterfaceHeaderSetsEntries() const;
+
   std::string ImportedGetFullPath(const std::string& config,
                                   cmStateEnums::ArtifactType artifact) const;
 
@@ -268,6 +273,16 @@ public:
     bool operator()(cmTarget const* t1, cmTarget const* t2) const;
   };
 
+  const cmFileSet* GetFileSet(const std::string& name) const;
+  cmFileSet* GetFileSet(const std::string& name);
+  std::pair<cmFileSet*, bool> GetOrCreateFileSet(const std::string& name,
+                                                 const std::string& type);
+
+  std::vector<std::string> GetAllInterfaceFileSets() const;
+
+  static std::string GetFileSetsPropertyName(const std::string& type);
+  static std::string GetInterfaceFileSetsPropertyName(const std::string& type);
+
 private:
   template <typename ValueType>
   void StoreProperty(const std::string& prop, ValueType value);

+ 1 - 0
bootstrap

@@ -341,6 +341,7 @@ CMAKE_CXX_SOURCES="\
   cmFileCommand \
   cmFileCopier \
   cmFileInstaller \
+  cmFileSet \
   cmFileTime \
   cmFileTimeCache \
   cmFileTimes \