Browse Source

install(EXPORT): Install file sets

Kyle Edwards 4 years ago
parent
commit
2a78d47b16

+ 19 - 0
Source/cmExportBuildFileGenerator.cxx

@@ -11,12 +11,15 @@
 #include <cmext/algorithm>
 
 #include "cmExportSet.h"
+#include "cmFileSet.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -135,6 +138,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
     this->PopulateCompatibleInterfaceProperties(gte, properties);
 
     this->GenerateInterfaceProperties(gte, os, properties);
+
+    this->GenerateTargetFileSets(gte, os);
   }
 
   // Generate import file content for each configuration.
@@ -356,3 +361,17 @@ std::string cmExportBuildFileGenerator::InstallNameDir(
 
   return install_name_dir;
 }
+
+std::string cmExportBuildFileGenerator::GetFileSetDirectories(
+  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+{
+  return cmOutputConverter::EscapeForCMake(
+    cmJoin(fileSet->GetDirectoryEntries(), ";"));
+}
+
+std::string cmExportBuildFileGenerator::GetFileSetFiles(
+  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+{
+  return cmOutputConverter::EscapeForCMake(
+    cmJoin(fileSet->GetFileEntries(), ";"));
+}

+ 7 - 0
Source/cmExportBuildFileGenerator.h

@@ -15,9 +15,11 @@
 #include "cmStateTypes.h"
 
 class cmExportSet;
+class cmFileSet;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
 class cmLocalGenerator;
+class cmTargetExport;
 
 /** \class cmExportBuildFileGenerator
  * \brief Generate a file exporting targets from a build tree.
@@ -76,6 +78,11 @@ protected:
   std::string InstallNameDir(cmGeneratorTarget const* target,
                              const std::string& config) override;
 
+  std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
+                                    cmTargetExport* te) override;
+  std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
+                              cmTargetExport* te) override;
+
   std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
     cmGlobalGenerator* gg, const std::string& name);
 

+ 37 - 0
Source/cmExportFileGenerator.cxx

@@ -12,6 +12,7 @@
 #include "cmsys/FStream.hxx"
 
 #include "cmComputeLinkInformation.h"
+#include "cmFileSet.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -1256,3 +1257,39 @@ bool cmExportFileGenerator::PopulateExportProperties(
   }
   return true;
 }
+
+void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte,
+                                                   std::ostream& os,
+                                                   cmTargetExport* te)
+{
+  auto interfaceFileSets = gte->Target->GetAllInterfaceFileSets();
+  if (!interfaceFileSets.empty()) {
+    std::string targetName = cmStrCat(this->Namespace, gte->GetExportName());
+    os << "if(NOT CMAKE_VERSION VERSION_LESS \"" << DEVEL_CMAKE_VERSION(3, 23)
+       << "\")\n"
+          "  target_sources("
+       << targetName << "\n";
+
+    for (auto const& name : interfaceFileSets) {
+      auto* fileSet = gte->Target->GetFileSet(name);
+      if (!fileSet) {
+        gte->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("File set \"", name,
+                   "\" is listed in interface file sets of ", gte->GetName(),
+                   " but has not been created"));
+        return;
+      }
+
+      os << "    INTERFACE"
+         << "\n      FILE_SET " << cmOutputConverter::EscapeForCMake(name)
+         << "\n      TYPE "
+         << cmOutputConverter::EscapeForCMake(fileSet->GetType())
+         << "\n      BASE_DIRS "
+         << this->GetFileSetDirectories(gte, fileSet, te) << "\n      FILES "
+         << this->GetFileSetFiles(gte, fileSet, te) << "\n";
+    }
+
+    os << "  )\nendif()\n\n";
+  }
+}

+ 12 - 0
Source/cmExportFileGenerator.h

@@ -15,7 +15,9 @@
 #include "cmVersion.h"
 #include "cmVersionConfig.h"
 
+class cmFileSet;
 class cmGeneratorTarget;
+class cmTargetExport;
 
 #define STRINGIFY_HELPER(X) #X
 #define STRINGIFY(X) STRINGIFY_HELPER(X)
@@ -184,6 +186,16 @@ protected:
                                 ImportPropertyMap& properties,
                                 std::string& errorMessage);
 
+  void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
+                              cmTargetExport* te = nullptr);
+
+  virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
+                                            cmFileSet* fileSet,
+                                            cmTargetExport* te) = 0;
+  virtual std::string GetFileSetFiles(cmGeneratorTarget* gte,
+                                      cmFileSet* fileSet,
+                                      cmTargetExport* te) = 0;
+
   // The namespace in which the exports are placed in the generated file.
   std::string Namespace;
 

+ 105 - 0
Source/cmExportInstallFileGenerator.cxx

@@ -2,19 +2,23 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExportInstallFileGenerator.h"
 
+#include <algorithm>
 #include <memory>
 #include <sstream>
 #include <utility>
 
 #include "cmExportSet.h"
+#include "cmFileSet.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -147,6 +151,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
     this->PopulateCompatibleInterfaceProperties(gt, properties);
 
     this->GenerateInterfaceProperties(gt, os, properties);
+
+    this->GenerateTargetFileSets(gt, os, te);
   }
 
   if (require3_1_0) {
@@ -534,3 +540,102 @@ std::string cmExportInstallFileGenerator::InstallNameDir(
 
   return install_name_dir;
 }
+
+namespace {
+bool EntryIsContextSensitive(
+  const std::unique_ptr<cmCompiledGeneratorExpression>& cge)
+{
+  return cge->GetHadContextSensitiveCondition();
+}
+}
+
+std::string cmExportInstallFileGenerator::GetFileSetDirectories(
+  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+{
+  std::vector<std::string> resultVector;
+
+  auto configs =
+    gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+  cmGeneratorExpression ge;
+  auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
+
+  for (auto const& config : configs) {
+    auto dest = cmStrCat("${_IMPORT_PREFIX}/",
+                         cmOutputConverter::EscapeForCMake(
+                           cge->Evaluate(gte->LocalGenerator, config, gte),
+                           cmOutputConverter::WrapQuotes::NoWrap));
+
+    if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) {
+      resultVector.push_back(
+        cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
+    } else {
+      resultVector.push_back(cmStrCat('"', dest, '"'));
+      break;
+    }
+  }
+
+  return cmJoin(resultVector, " ");
+}
+
+std::string cmExportInstallFileGenerator::GetFileSetFiles(
+  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+{
+  std::vector<std::string> resultVector;
+
+  auto configs =
+    gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+  auto fileEntries = fileSet->CompileFileEntries();
+  auto directoryEntries = fileSet->CompileDirectoryEntries();
+
+  cmGeneratorExpression destGe;
+  auto destCge =
+    destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
+
+  for (auto const& config : configs) {
+    auto directories = fileSet->EvaluateDirectoryEntries(
+      directoryEntries, gte->LocalGenerator, config, gte);
+
+    std::map<std::string, std::vector<std::string>> files;
+    for (auto const& entry : fileEntries) {
+      fileSet->EvaluateFileEntry(directories, files, entry,
+                                 gte->LocalGenerator, config, gte);
+    }
+    auto dest = cmStrCat("${_IMPORT_PREFIX}/",
+                         cmOutputConverter::EscapeForCMake(
+                           destCge->Evaluate(gte->LocalGenerator, config, gte),
+                           cmOutputConverter::WrapQuotes::NoWrap),
+                         '/');
+
+    bool const contextSensitive = destCge->GetHadContextSensitiveCondition() ||
+      std::any_of(directoryEntries.begin(), directoryEntries.end(),
+                  EntryIsContextSensitive) ||
+      std::any_of(fileEntries.begin(), fileEntries.end(),
+                  EntryIsContextSensitive);
+
+    for (auto const& it : files) {
+      auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/');
+      for (auto const& filename : it.second) {
+        auto relFile =
+          cmStrCat(prefix, cmSystemTools::GetFilenameName(filename));
+        auto escapedFile =
+          cmStrCat(dest,
+                   cmOutputConverter::EscapeForCMake(
+                     relFile, cmOutputConverter::WrapQuotes::NoWrap));
+        if (contextSensitive && configs.size() != 1) {
+          resultVector.push_back(
+            cmStrCat("\"$<$<CONFIG:", config, ">:", escapedFile, ">\""));
+        } else {
+          resultVector.push_back(cmStrCat('"', escapedFile, '"'));
+        }
+      }
+    }
+
+    if (!(contextSensitive && configs.size() != 1)) {
+      break;
+    }
+  }
+
+  return cmJoin(resultVector, " ");
+}

+ 6 - 0
Source/cmExportInstallFileGenerator.h

@@ -14,6 +14,7 @@
 #include "cmExportFileGenerator.h"
 #include "cmStateTypes.h"
 
+class cmFileSet;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
 class cmInstallExportGenerator;
@@ -97,6 +98,11 @@ protected:
   std::string InstallNameDir(cmGeneratorTarget const* target,
                              const std::string& config) override;
 
+  std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
+                                    cmTargetExport* te) override;
+  std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
+                              cmTargetExport* te) override;
+
   cmInstallExportGenerator* IEGen;
 
   // The import file generated for each configuration.

+ 19 - 0
Source/cmExportTryCompileFileGenerator.cxx

@@ -7,17 +7,22 @@
 
 #include <cm/memory>
 
+#include "cmFileSet.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmOutputConverter.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
 #include "cmValue.h"
 
+class cmTargetExport;
+
 cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator(
   cmGlobalGenerator* gg, const std::vector<std::string>& targets,
   cmMakefile* mf, std::set<std::string> const& langs)
@@ -137,3 +142,17 @@ std::string cmExportTryCompileFileGenerator::InstallNameDir(
 
   return install_name_dir;
 }
+
+std::string cmExportTryCompileFileGenerator::GetFileSetDirectories(
+  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+{
+  return cmOutputConverter::EscapeForCMake(
+    cmJoin(fileSet->GetDirectoryEntries(), ";"));
+}
+
+std::string cmExportTryCompileFileGenerator::GetFileSetFiles(
+  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+{
+  return cmOutputConverter::EscapeForCMake(
+    cmJoin(fileSet->GetFileEntries(), ";"));
+}

+ 9 - 0
Source/cmExportTryCompileFileGenerator.h

@@ -11,9 +11,11 @@
 
 #include "cmExportFileGenerator.h"
 
+class cmFileSet;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
 class cmMakefile;
+class cmTargetExport;
 
 class cmExportTryCompileFileGenerator : public cmExportFileGenerator
 {
@@ -48,6 +50,13 @@ protected:
   std::string InstallNameDir(cmGeneratorTarget const* target,
                              const std::string& config) override;
 
+  std::string GetFileSetDirectories(cmGeneratorTarget* target,
+                                    cmFileSet* fileSet,
+                                    cmTargetExport* te) override;
+
+  std::string GetFileSetFiles(cmGeneratorTarget* target, cmFileSet* fileSet,
+                              cmTargetExport* te) override;
+
 private:
   std::string FindTargets(const std::string& prop,
                           const cmGeneratorTarget* tgt,

+ 32 - 5
Source/cmInstallCommand.cxx

@@ -729,9 +729,24 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
     // Track whether this is a namelink-only rule.
     bool namelinkOnly = false;
 
-    auto addTargetExport = [&]() {
+    auto addTargetExport = [&]() -> bool {
       // Add this install rule to an export if one was specified.
       if (!exports.empty()) {
+        auto interfaceFileSets = target.GetAllInterfaceFileSets();
+        if (std::any_of(
+              interfaceFileSets.begin(), interfaceFileSets.end(),
+              [=](const std::string& name) -> bool {
+                return !std::any_of(
+                  fileSetArgs.begin(), fileSetArgs.end(),
+                  [=](const cmInstallCommandFileSetArguments& fileSetArg)
+                    -> bool { return fileSetArg.GetFileSet() == name; });
+              })) {
+          status.SetError(cmStrCat(
+            "TARGETS target ", target.GetName(),
+            " is exported but not all of its file sets are installed"));
+          return false;
+        }
+
         auto te = cm::make_unique<cmTargetExport>();
         te->TargetName = target.GetName();
         te->ArchiveGenerator = archiveGenerator.get();
@@ -741,6 +756,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
         te->LibraryGenerator = libraryGenerator.get();
         te->RuntimeGenerator = runtimeGenerator.get();
         te->ObjectsGenerator = objectGenerator.get();
+        for (auto const& gen : fileSetGenerators) {
+          te->FileSetGenerators[gen->GetFileSet()] = gen.get();
+        }
         target.AddInstallIncludeDirectories(
           cmMakeRange(includesArgs.GetIncludeDirs()));
         te->NamelinkOnly = namelinkOnly;
@@ -748,6 +766,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
           ->GetExportSets()[exports]
           .AddTargetExport(std::move(te));
       }
+      return true;
     };
 
     switch (target.GetType()) {
@@ -759,7 +778,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
           // When in namelink only mode skip all libraries on Windows.
           if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
             namelinkOnly = true;
-            addTargetExport();
+            if (!addTargetExport()) {
+              return false;
+            }
             continue;
           }
 
@@ -795,7 +816,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
             // When in namelink only mode skip frameworks.
             if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
               namelinkOnly = true;
-              addTargetExport();
+              if (!addTargetExport()) {
+                return false;
+              }
               continue;
             }
 
@@ -844,7 +867,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
           // When in namelink only mode skip frameworks.
           if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
             namelinkOnly = true;
-            addTargetExport();
+            if (!addTargetExport()) {
+              return false;
+            }
             continue;
           }
 
@@ -1080,7 +1105,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
     }
 
     // Add this install rule to an export if one was specified.
-    addTargetExport();
+    if (!addTargetExport()) {
+      return false;
+    }
 
     // Keep track of whether we're installing anything in each category
     installsArchive = installsArchive || archiveGenerator;

+ 3 - 0
Source/cmTargetExport.h

@@ -6,7 +6,9 @@
 
 #include <string>
 
+class cmFileSet;
 class cmGeneratorTarget;
+class cmInstallFileSetGenerator;
 class cmInstallFilesGenerator;
 class cmInstallTargetGenerator;
 
@@ -29,6 +31,7 @@ public:
   cmInstallTargetGenerator* FrameworkGenerator;
   cmInstallTargetGenerator* BundleGenerator;
   cmInstallFilesGenerator* HeaderGenerator;
+  std::map<cmFileSet*, cmInstallFileSetGenerator*> FileSetGenerators;
   ///@}
 
   bool NamelinkOnly = false;