1
0
Эх сурвалжийг харах

export: Factor out CMake-specific export generation (2/2)

In order to support generation of Common Package Specifications, the
mechanisms CMake uses to export package information need to be made more
abstract. The prior commits began this refactoring; this continues by
(actually) restructuring the classes used to generate the actual export files.
To minimize churn, this introduces virtual base classes and
diamond inheritance in order to separate logic which is format-agnostic
but depends on the export mode (build-tree versus install-tree) from
logic which is format-specific but mode-agnostic.

This could probably be refactored further to use helper classes instead,
and a future commit may do that, however an initial attempt to do that
was proving even more invasive, such that this approach was deemed more
manageable.

While we're at it, add 'const' in more places where possible.
Matthew Woehlke 1 жил өмнө
parent
commit
20fa4ce8d8
30 өөрчлөгдсөн 1050 нэмэгдсэн , 4362 устгасан
  1. 8 0
      Source/CMakeLists.txt
  2. 20 51
      Source/cmExportAndroidMKGenerator.cxx
  3. 46 35
      Source/cmExportAndroidMKGenerator.h
  4. 33 160
      Source/cmExportBuildAndroidMKGenerator.cxx
  5. 12 27
      Source/cmExportBuildAndroidMKGenerator.h
  6. 10 269
      Source/cmExportBuildCMakeConfigGenerator.cxx
  7. 9 92
      Source/cmExportBuildCMakeConfigGenerator.h
  8. 53 382
      Source/cmExportBuildFileGenerator.cxx
  9. 26 27
      Source/cmExportBuildFileGenerator.h
  10. 22 1019
      Source/cmExportCMakeConfigGenerator.cxx
  11. 21 176
      Source/cmExportCMakeConfigGenerator.h
  12. 9 5
      Source/cmExportCommand.cxx
  13. 81 864
      Source/cmExportFileGenerator.cxx
  14. 69 123
      Source/cmExportFileGenerator.h
  15. 50 64
      Source/cmExportInstallAndroidMKGenerator.cxx
  16. 29 31
      Source/cmExportInstallAndroidMKGenerator.h
  17. 21 314
      Source/cmExportInstallCMakeConfigGenerator.cxx
  18. 15 86
      Source/cmExportInstallCMakeConfigGenerator.h
  19. 371 529
      Source/cmExportInstallFileGenerator.cxx
  20. 68 43
      Source/cmExportInstallFileGenerator.h
  21. 9 2
      Source/cmExportTryCompileFileGenerator.cxx
  22. 8 4
      Source/cmExportTryCompileFileGenerator.h
  23. 1 9
      Source/cmInstallAndroidMKExportGenerator.cxx
  24. 5 9
      Source/cmInstallAndroidMKExportGenerator.h
  25. 6 3
      Source/cmInstallCMakeConfigExportGenerator.cxx
  26. 1 1
      Source/cmInstallCMakeConfigExportGenerator.h
  27. 1 1
      Source/cmInstallCommand.cxx
  28. 41 34
      Source/cmInstallExportGenerator.cxx
  29. 2 2
      Source/cmInstallExportGenerator.h
  30. 3 0
      bootstrap

+ 8 - 0
Source/CMakeLists.txt

@@ -199,14 +199,22 @@ add_library(
   cmEvaluatedTargetProperty.cxx
   cmEvaluatedTargetProperty.h
   cmExprParserHelper.cxx
+  cmExportAndroidMKGenerator.h
+  cmExportAndroidMKGenerator.cxx
   cmExportBuildAndroidMKGenerator.h
   cmExportBuildAndroidMKGenerator.cxx
+  cmExportBuildCMakeConfigGenerator.h
+  cmExportBuildCMakeConfigGenerator.cxx
   cmExportBuildFileGenerator.h
   cmExportBuildFileGenerator.cxx
+  cmExportCMakeConfigGenerator.h
+  cmExportCMakeConfigGenerator.cxx
   cmExportFileGenerator.h
   cmExportFileGenerator.cxx
   cmExportInstallAndroidMKGenerator.h
   cmExportInstallAndroidMKGenerator.cxx
+  cmExportInstallCMakeConfigGenerator.h
+  cmExportInstallCMakeConfigGenerator.cxx
   cmExportInstallFileGenerator.h
   cmExportInstallFileGenerator.cxx
   cmExportTryCompileFileGenerator.h

+ 20 - 51
Source/cmExportAndroidMKGenerator.cxx

@@ -2,12 +2,12 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExportAndroidMKGenerator.h"
 
-#include <map>
 #include <sstream>
 #include <utility>
 #include <vector>
 
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmGeneratorTarget.h"
 #include "cmLinkItem.h"
@@ -20,75 +20,44 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 
-cmExportAndroidMKGenerator::cmExportAndroidMKGenerator()
-{
-  this->LG = nullptr;
-  this->ExportSet = nullptr;
-}
+cmExportAndroidMKGenerator::cmExportAndroidMKGenerator() = default;
 
-void cmExportAndroidMKGenerator::GenerateImportHeaderCode(std::ostream& os,
-                                                          std::string const&)
+cm::string_view cmExportAndroidMKGenerator::GetImportPrefixWithSlash() const
 {
-  os << "LOCAL_PATH := $(call my-dir)\n\n";
+  return "$(_IMPORT_PREFIX)/"_s;
 }
 
-void cmExportAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
+bool cmExportAndroidMKGenerator::GenerateImportFile(std::ostream& os)
 {
-}
+  if (!this->AppendMode) {
+    // Start with the import file header.
+    this->GenerateImportHeaderCode(os);
+  }
 
-void cmExportAndroidMKGenerator::GenerateExpectedTargetsCode(
-  std::ostream&, std::string const&)
-{
-}
+  // Create all the imported targets.
+  std::stringstream mainFileBuffer;
+  bool result = this->GenerateMainFile(mainFileBuffer);
 
-void cmExportAndroidMKGenerator::GenerateImportTargetCode(
-  std::ostream& os, cmGeneratorTarget const* target,
-  cmStateEnums::TargetType /*targetType*/)
-{
-  std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
-  os << "include $(CLEAR_VARS)\n";
-  os << "LOCAL_MODULE := ";
-  os << targetName << "\n";
-  os << "LOCAL_SRC_FILES := ";
-  std::string const noConfig; // FIXME: What config to use here?
-  std::string path =
-    cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig));
-  os << path << "\n";
-}
+  // Write cached import code.
+  os << mainFileBuffer.rdbuf();
 
-void cmExportAndroidMKGenerator::GenerateImportPropertyCode(
-  std::ostream&, std::string const&, std::string const&,
-  cmGeneratorTarget const*, ImportPropertyMap const&, std::string const&)
-{
-}
-
-void cmExportAndroidMKGenerator::GenerateMissingTargetsCheckCode(std::ostream&)
-{
+  return result;
 }
 
 void cmExportAndroidMKGenerator::GenerateInterfaceProperties(
   cmGeneratorTarget const* target, std::ostream& os,
   ImportPropertyMap const& properties)
 {
-  std::string config;
-  if (!this->Configurations.empty()) {
-    config = this->Configurations[0];
-  }
-  cmExportAndroidMKGenerator::GenerateInterfaceProperties(
-    target, os, properties, cmExportAndroidMKGenerator::BUILD, config);
-}
+  std::string const config =
+    (this->Configurations.empty() ? std::string{} : this->Configurations[0]);
+  GenerateType const type = this->GetGenerateType();
 
-void cmExportAndroidMKGenerator::GenerateInterfaceProperties(
-  cmGeneratorTarget const* target, std::ostream& os,
-  ImportPropertyMap const& properties, GenerateType type,
-  std::string const& config)
-{
   bool const newCMP0022Behavior =
     target->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
     target->GetPolicyStatusCMP0022() != cmPolicies::OLD;
   if (!newCMP0022Behavior) {
     std::ostringstream w;
-    if (type == cmExportAndroidMKGenerator::BUILD) {
+    if (type == BUILD) {
       w << "export(TARGETS ... ANDROID_MK) called with policy CMP0022";
     } else {
       w << "install( EXPORT_ANDROID_MK ...) called with policy CMP0022";
@@ -123,7 +92,7 @@ void cmExportAndroidMKGenerator::GenerateInterfaceProperties(
             }
           } else {
             bool relpath = false;
-            if (type == cmExportAndroidMKGenerator::INSTALL) {
+            if (type == INSTALL) {
               relpath = cmHasLiteralPrefix(lib, "../");
             }
             // check for full path or if it already has a -l, or

+ 46 - 35
Source/cmExportAndroidMKGenerator.h

@@ -5,58 +5,69 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
+#include <map>
 #include <string>
 
-#include "cmExportBuildFileGenerator.h"
+#include <cm/string_view>
+
+#include "cmExportFileGenerator.h"
 #include "cmStateTypes.h"
 
 class cmGeneratorTarget;
 
 /** \class cmExportAndroidMKGenerator
- * \brief Generate a file exporting targets from a build tree.
- *
- * cmExportAndroidMKGenerator generates a file exporting targets from
- * a build tree.  This exports the targets to the Android ndk build tool
- * makefile format for prebuilt libraries.
+ * \brief Generate CMake configuration files exporting targets from a build or
+ * install tree.
  *
- * This is used to implement the export() command.
+ * cmExportAndroidMKGenerator is the superclass for
+ * cmExportBuildAndroidMKGenerator and cmExportInstallAndroidMKGenerator.
+ * It contains common code generation routines for the two kinds of export
+ * implementations.
  */
-class cmExportAndroidMKGenerator : public cmExportBuildFileGenerator
+class cmExportAndroidMKGenerator : virtual public cmExportFileGenerator
 {
 public:
   cmExportAndroidMKGenerator();
-  // this is so cmExportInstallAndroidMKGenerator can share this
-  // function as they are almost the same
+
+  using cmExportFileGenerator::GenerateImportFile;
+
+protected:
   enum GenerateType
   {
     BUILD,
     INSTALL
   };
-  static void GenerateInterfaceProperties(cmGeneratorTarget const* target,
-                                          std::ostream& os,
-                                          ImportPropertyMap const& properties,
-                                          GenerateType type,
-                                          std::string const& config);
+  virtual GenerateType GetGenerateType() const = 0;
 
-protected:
-  // Implement virtual methods from the superclass.
-  void GeneratePolicyHeaderCode(std::ostream&) override {}
-  void GeneratePolicyFooterCode(std::ostream&) override {}
-  void GenerateImportHeaderCode(std::ostream& os,
-                                std::string const& config = "") override;
-  void GenerateImportFooterCode(std::ostream& os) override;
-  void GenerateImportTargetCode(
+  using ImportPropertyMap = std::map<std::string, std::string>;
+
+  cm::string_view GetImportPrefixWithSlash() const override;
+
+  void GenerateInterfaceProperties(cmGeneratorTarget const* target,
+                                   std::ostream& os,
+                                   ImportPropertyMap const& properties);
+
+  // Methods to implement export file code generation.
+  bool GenerateImportFile(std::ostream& os) override;
+  virtual void GenerateImportHeaderCode(std::ostream& os,
+                                        std::string const& config = "") = 0;
+  virtual void GenerateImportTargetCode(
     std::ostream& os, cmGeneratorTarget const* target,
-    cmStateEnums::TargetType /*targetType*/) override;
-  void GenerateExpectedTargetsCode(
-    std::ostream& os, std::string const& expectedTargets) override;
-  void GenerateImportPropertyCode(
-    std::ostream& os, std::string const& config, std::string const& suffix,
-    cmGeneratorTarget const* target, ImportPropertyMap const& properties,
-    std::string const& importedXcFrameworkLocation) override;
-  void GenerateMissingTargetsCheckCode(std::ostream& os) override;
-  void GenerateFindDependencyCalls(std::ostream&) override {}
-  void GenerateInterfaceProperties(
-    cmGeneratorTarget const* target, std::ostream& os,
-    ImportPropertyMap const& properties) override;
+    cmStateEnums::TargetType targetType) = 0;
+
+  void GenerateImportTargetsConfig(std::ostream& /*os*/,
+                                   std::string const& /*config*/,
+                                   std::string const& /*suffix*/) override
+  {
+  }
+
+  std::string GetCxxModuleFile(std::string const& /*name*/) const override
+  {
+    return {};
+  }
+
+  void GenerateCxxModuleConfigInformation(std::string const& /*name*/,
+                                          std::ostream& /*os*/) const override
+  {
+  }
 };

+ 33 - 160
Source/cmExportBuildAndroidMKGenerator.cxx

@@ -2,28 +2,50 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExportBuildAndroidMKGenerator.h"
 
-#include <map>
 #include <sstream>
-#include <utility>
 #include <vector>
 
-#include <cmext/algorithm>
-
+#include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
-#include "cmLinkItem.h"
-#include "cmList.h"
-#include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 
-cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator()
+cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator() = default;
+
+bool cmExportBuildAndroidMKGenerator::GenerateMainFile(std::ostream& os)
 {
-  this->LG = nullptr;
-  this->ExportSet = nullptr;
+  if (!this->CollectExports([&](cmGeneratorTarget const*) {})) {
+    return false;
+  }
+
+  // Create all the imported targets.
+  for (auto const& exp : this->Exports) {
+    cmGeneratorTarget* gte = exp.Target;
+
+    this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte));
+
+    gte->Target->AppendBuildInterfaceIncludes();
+
+    ImportPropertyMap properties;
+    if (!this->PopulateInterfaceProperties(gte, properties)) {
+      return false;
+    }
+
+    bool const newCMP0022Behavior =
+      gte->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+      gte->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+    if (newCMP0022Behavior) {
+      this->PopulateInterfaceLinkLibrariesProperty(
+        gte, cmGeneratorExpression::BuildInterface, properties);
+    }
+
+    this->GenerateInterfaceProperties(gte, os, properties);
+  }
+
+  return true;
 }
 
 void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode(
@@ -32,15 +54,6 @@ void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode(
   os << "LOCAL_PATH := $(call my-dir)\n\n";
 }
 
-void cmExportBuildAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
-{
-}
-
-void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode(
-  std::ostream&, std::string const&)
-{
-}
-
 void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
   std::ostream& os, cmGeneratorTarget const* target,
   cmStateEnums::TargetType /*targetType*/)
@@ -55,143 +68,3 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
     cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig));
   os << path << "\n";
 }
-
-void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode(
-  std::ostream&, std::string const&, std::string const&,
-  cmGeneratorTarget const*, ImportPropertyMap const&, std::string const&)
-{
-}
-
-void cmExportBuildAndroidMKGenerator::GenerateMissingTargetsCheckCode(
-  std::ostream&)
-{
-}
-
-void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
-  cmGeneratorTarget const* target, std::ostream& os,
-  ImportPropertyMap const& properties)
-{
-  std::string config;
-  if (!this->Configurations.empty()) {
-    config = this->Configurations[0];
-  }
-  cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
-    target, os, properties, cmExportBuildAndroidMKGenerator::BUILD, config);
-}
-
-void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
-  cmGeneratorTarget const* target, std::ostream& os,
-  ImportPropertyMap const& properties, GenerateType type,
-  std::string const& config)
-{
-  bool const newCMP0022Behavior =
-    target->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
-    target->GetPolicyStatusCMP0022() != cmPolicies::OLD;
-  if (!newCMP0022Behavior) {
-    std::ostringstream w;
-    if (type == cmExportBuildAndroidMKGenerator::BUILD) {
-      w << "export(TARGETS ... ANDROID_MK) called with policy CMP0022";
-    } else {
-      w << "install( EXPORT_ANDROID_MK ...) called with policy CMP0022";
-    }
-    w << " set to OLD for target " << target->Target->GetName() << ". "
-      << "The export will only work with CMP0022 set to NEW.";
-    target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
-  }
-  if (!properties.empty()) {
-    os << "LOCAL_CPP_FEATURES := rtti exceptions\n";
-    for (auto const& property : properties) {
-      if (property.first == "INTERFACE_COMPILE_OPTIONS") {
-        os << "LOCAL_CPP_FEATURES += ";
-        os << (property.second) << "\n";
-      } else if (property.first == "INTERFACE_LINK_LIBRARIES") {
-        std::string staticLibs;
-        std::string sharedLibs;
-        std::string ldlibs;
-        cmLinkInterfaceLibraries const* linkIFace =
-          target->GetLinkInterfaceLibraries(config, target,
-                                            cmGeneratorTarget::UseTo::Link);
-        for (cmLinkItem const& item : linkIFace->Libraries) {
-          cmGeneratorTarget const* gt = item.Target;
-          std::string const& lib = item.AsStr();
-          if (gt) {
-
-            if (gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
-                gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
-              sharedLibs += " " + lib;
-            } else {
-              staticLibs += " " + lib;
-            }
-          } else {
-            bool relpath = false;
-            if (type == cmExportBuildAndroidMKGenerator::INSTALL) {
-              relpath = cmHasLiteralPrefix(lib, "../");
-            }
-            // check for full path or if it already has a -l, or
-            // in the case of an install check for relative paths
-            // if it is full or a link library then use string directly
-            if (cmSystemTools::FileIsFullPath(lib) ||
-                cmHasLiteralPrefix(lib, "-l") || relpath) {
-              ldlibs += " " + lib;
-              // if it is not a path and does not have a -l then add -l
-            } else if (!lib.empty()) {
-              ldlibs += " -l" + lib;
-            }
-          }
-        }
-        if (!sharedLibs.empty()) {
-          os << "LOCAL_SHARED_LIBRARIES :=" << sharedLibs << "\n";
-        }
-        if (!staticLibs.empty()) {
-          os << "LOCAL_STATIC_LIBRARIES :=" << staticLibs << "\n";
-        }
-        if (!ldlibs.empty()) {
-          os << "LOCAL_EXPORT_LDLIBS :=" << ldlibs << "\n";
-        }
-      } else if (property.first == "INTERFACE_INCLUDE_DIRECTORIES") {
-        std::string includes = property.second;
-        cmList includeList{ includes };
-        os << "LOCAL_EXPORT_C_INCLUDES := ";
-        std::string end;
-        for (std::string const& i : includeList) {
-          os << end << i;
-          end = "\\\n";
-        }
-        os << "\n";
-      } else if (property.first == "INTERFACE_LINK_OPTIONS") {
-        os << "LOCAL_EXPORT_LDFLAGS := ";
-        cmList linkFlagsList{ property.second };
-        os << linkFlagsList.join(" ") << "\n";
-      } else {
-        os << "# " << property.first << " " << (property.second) << "\n";
-      }
-    }
-  }
-
-  // Tell the NDK build system if prebuilt static libraries use C++.
-  if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
-    cmLinkImplementation const* li =
-      target->GetLinkImplementation(config, cmGeneratorTarget::UseTo::Link);
-    if (cm::contains(li->Languages, "CXX")) {
-      os << "LOCAL_HAS_CPP := true\n";
-    }
-  }
-
-  switch (target->GetType()) {
-    case cmStateEnums::SHARED_LIBRARY:
-    case cmStateEnums::MODULE_LIBRARY:
-      os << "include $(PREBUILT_SHARED_LIBRARY)\n";
-      break;
-    case cmStateEnums::STATIC_LIBRARY:
-      os << "include $(PREBUILT_STATIC_LIBRARY)\n";
-      break;
-    case cmStateEnums::EXECUTABLE:
-    case cmStateEnums::UTILITY:
-    case cmStateEnums::OBJECT_LIBRARY:
-    case cmStateEnums::GLOBAL_TARGET:
-    case cmStateEnums::INTERFACE_LIBRARY:
-    case cmStateEnums::UNKNOWN_LIBRARY:
-      break;
-  }
-  os << "\n";
-}

+ 12 - 27
Source/cmExportBuildAndroidMKGenerator.h

@@ -7,6 +7,7 @@
 #include <iosfwd>
 #include <string>
 
+#include "cmExportAndroidMKGenerator.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmStateTypes.h"
 
@@ -21,42 +22,26 @@ class cmGeneratorTarget;
  *
  * This is used to implement the export() command.
  */
-class cmExportBuildAndroidMKGenerator : public cmExportBuildFileGenerator
+class cmExportBuildAndroidMKGenerator
+  : public cmExportBuildFileGenerator
+  , public cmExportAndroidMKGenerator
 {
 public:
   cmExportBuildAndroidMKGenerator();
-  // this is so cmExportInstallAndroidMKGenerator can share this
-  // function as they are almost the same
-  enum GenerateType
-  {
-    BUILD,
-    INSTALL
-  };
-  static void GenerateInterfaceProperties(cmGeneratorTarget const* target,
-                                          std::ostream& os,
-                                          ImportPropertyMap const& properties,
-                                          GenerateType type,
-                                          std::string const& config);
+
+  /** Set whether to append generated code to the output file.  */
+  void SetAppendMode(bool append) { this->AppendMode = append; }
 
 protected:
+  GenerateType GetGenerateType() const override { return BUILD; }
+
   // Implement virtual methods from the superclass.
-  void GeneratePolicyHeaderCode(std::ostream&) override {}
-  void GeneratePolicyFooterCode(std::ostream&) override {}
+  bool GenerateMainFile(std::ostream& os) override;
   void GenerateImportHeaderCode(std::ostream& os,
                                 std::string const& config = "") override;
-  void GenerateImportFooterCode(std::ostream& os) override;
   void GenerateImportTargetCode(
     std::ostream& os, cmGeneratorTarget const* target,
     cmStateEnums::TargetType /*targetType*/) override;
-  void GenerateExpectedTargetsCode(
-    std::ostream& os, std::string const& expectedTargets) override;
-  void GenerateImportPropertyCode(
-    std::ostream& os, std::string const& config, std::string const& suffix,
-    cmGeneratorTarget const* target, ImportPropertyMap const& properties,
-    std::string const& importedXcFrameworkLocation) override;
-  void GenerateMissingTargetsCheckCode(std::ostream& os) override;
-  void GenerateFindDependencyCalls(std::ostream&) override {}
-  void GenerateInterfaceProperties(
-    cmGeneratorTarget const* target, std::ostream& os,
-    ImportPropertyMap const& properties) override;
+
+  std::string GetCxxModulesDirectory() const override { return {}; }
 };

+ 10 - 269
Source/cmExportBuildCMakeConfigGenerator.cxx

@@ -9,6 +9,7 @@
 #include <set>
 #include <sstream>
 #include <utility>
+#include <vector>
 
 #include <cm/string_view>
 #include <cmext/string_view>
@@ -19,8 +20,6 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
-#include "cmGlobalGenerator.h"
-#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -30,11 +29,6 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
-#include "cmTargetExport.h"
-#include "cmValue.h"
-#include "cmake.h"
-
-class cmSourceFile;
 
 cmExportBuildCMakeConfigGenerator::cmExportBuildCMakeConfigGenerator()
 {
@@ -42,38 +36,22 @@ cmExportBuildCMakeConfigGenerator::cmExportBuildCMakeConfigGenerator()
   this->ExportSet = nullptr;
 }
 
-void cmExportBuildCMakeConfigGenerator::Compute(cmLocalGenerator* lg)
-{
-  this->LG = lg;
-  if (this->ExportSet) {
-    this->ExportSet->Compute(lg);
-  }
-}
-
 bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
 {
   {
     std::string expectedTargets;
     std::string sep;
-    std::vector<TargetExport> targets;
     bool generatedInterfaceRequired = false;
-    this->GetTargets(targets);
-    for (auto const& tei : targets) {
-      cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name);
+    auto visitor = [&](cmGeneratorTarget const* te) {
       expectedTargets += sep + this->Namespace + te->GetExportName();
       sep = " ";
-      if (this->ExportedTargets.insert(te).second) {
-        this->Exports.emplace_back(te, tei.XcFrameworkLocation);
-      } else {
-        std::ostringstream e;
-        e << "given target \"" << te->GetName() << "\" more than once.";
-        this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-          MessageType::FATAL_ERROR, e.str(),
-          this->LG->GetMakefile()->GetBacktrace());
-        return false;
-      }
+
       generatedInterfaceRequired |=
         this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY;
+    };
+
+    if (!this->CollectExports(visitor)) {
+      return false;
     }
 
     if (generatedInterfaceRequired) {
@@ -90,57 +68,7 @@ bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
     gte->Target->AppendBuildInterfaceIncludes();
 
     ImportPropertyMap properties;
-
-    this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
-                                    properties);
-
-    std::string errorMessage;
-    if (!this->PopulateCxxModuleExportProperties(
-          gte, properties, cmGeneratorExpression::BuildInterface, {},
-          errorMessage)) {
-      this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-        MessageType::FATAL_ERROR, errorMessage,
-        this->LG->GetMakefile()->GetBacktrace());
-      return false;
-    }
-
-    if (!this->PopulateExportProperties(gte, properties, errorMessage)) {
-      this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-        MessageType::FATAL_ERROR, errorMessage,
-        this->LG->GetMakefile()->GetBacktrace());
+    if (!this->PopulateInterfaceProperties(gte, properties)) {
       return false;
     }
 
@@ -151,9 +79,6 @@ bool cmExportBuildCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
       this->PopulateInterfaceLinkLibrariesProperty(
         gte, cmGeneratorExpression::BuildInterface, properties);
     }
-    this->PopulateCompatibleInterfaceProperties(gte, properties);
-    this->PopulateCustomTransitiveInterfaceProperties(
-      gte, cmGeneratorExpression::BuildInterface, properties);
 
     this->GenerateInterfaceProperties(gte, os, properties);
 
@@ -239,185 +164,6 @@ void cmExportBuildCMakeConfigGenerator::GenerateImportTargetsConfig(
   }
 }
 
-cmStateEnums::TargetType
-cmExportBuildCMakeConfigGenerator::GetExportTargetType(
-  cmGeneratorTarget const* target) const
-{
-  cmStateEnums::TargetType targetType = target->GetType();
-  // An object library exports as an interface library if we cannot
-  // tell clients where to find the objects.  This is sufficient
-  // to support transitive usage requirements on other targets that
-  // use the object library.
-  if (targetType == cmStateEnums::OBJECT_LIBRARY &&
-      !target->Target->HasKnownObjectFileLocation(nullptr)) {
-    targetType = cmStateEnums::INTERFACE_LIBRARY;
-  }
-  return targetType;
-}
-
-void cmExportBuildCMakeConfigGenerator::SetExportSet(cmExportSet* exportSet)
-{
-  this->ExportSet = exportSet;
-}
-
-void cmExportBuildCMakeConfigGenerator::SetImportLocationProperty(
-  std::string const& config, std::string const& suffix,
-  cmGeneratorTarget* target, ImportPropertyMap& properties)
-{
-  // Get the makefile in which to lookup target information.
-  cmMakefile* mf = target->Makefile;
-
-  if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
-    std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix);
-
-    // Compute all the object files inside this target and setup
-    // IMPORTED_OBJECTS as a list of object files
-    std::vector<cmSourceFile const*> objectSources;
-    target->GetObjectSources(objectSources, config);
-    std::string const obj_dir = target->GetObjectDirectory(config);
-    std::vector<std::string> objects;
-    for (cmSourceFile const* sf : objectSources) {
-      std::string const& obj = target->GetObjectName(sf);
-      objects.push_back(obj_dir + obj);
-    }
-
-    // Store the property.
-    properties[prop] = cmList::to_string(objects);
-  } else {
-    // Add the main target file.
-    {
-      std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);
-      std::string value;
-      if (target->IsAppBundleOnApple()) {
-        value =
-          target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
-      } else {
-        value = target->GetFullPath(config,
-                                    cmStateEnums::RuntimeBinaryArtifact, true);
-      }
-      properties[prop] = value;
-    }
-
-    // Add the import library for windows DLLs.
-    if (target->HasImportLibrary(config)) {
-      std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);
-      std::string value =
-        target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact, true);
-      if (mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
-        target->GetImplibGNUtoMS(config, value, value,
-                                 "${CMAKE_IMPORT_LIBRARY_SUFFIX}");
-      }
-      properties[prop] = value;
-    }
-  }
-}
-
-void cmExportBuildCMakeConfigGenerator::HandleMissingTarget(
-  std::string& link_libs, cmGeneratorTarget const* depender,
-  cmGeneratorTarget* dependee)
-{
-  // The target is not in the export.
-  if (!this->AppendMode) {
-    std::string const name = dependee->GetName();
-    cmGlobalGenerator* gg =
-      dependee->GetLocalGenerator()->GetGlobalGenerator();
-    auto exportInfo = this->FindBuildExportInfo(gg, name);
-    std::vector<std::string> const& exportFiles = exportInfo.first;
-
-    if (exportFiles.size() == 1) {
-      std::string missingTarget = exportInfo.second;
-
-      missingTarget += dependee->GetExportName();
-      link_libs += missingTarget;
-      this->MissingTargets.emplace_back(std::move(missingTarget));
-      return;
-    }
-    // We are not appending, so all exported targets should be
-    // known here.  This is probably user-error.
-    this->ComplainAboutMissingTarget(depender, dependee, exportFiles);
-  }
-  // Assume the target will be exported by another command.
-  // Append it with the export namespace.
-  link_libs += this->Namespace;
-  link_libs += dependee->GetExportName();
-}
-
-void cmExportBuildCMakeConfigGenerator::GetTargets(
-  std::vector<TargetExport>& targets) const
-{
-  if (this->ExportSet) {
-    for (std::unique_ptr<cmTargetExport> const& te :
-         this->ExportSet->GetTargetExports()) {
-      if (te->NamelinkOnly) {
-        continue;
-      }
-      targets.emplace_back(te->TargetName, te->XcFrameworkLocation);
-    }
-    return;
-  }
-  targets = this->Targets;
-}
-
-std::pair<std::vector<std::string>, std::string>
-cmExportBuildCMakeConfigGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
-                                                       std::string const& name)
-{
-  std::vector<std::string> exportFiles;
-  std::string ns;
-
-  auto& exportSets = gg->GetBuildExportSets();
-
-  for (auto const& exp : exportSets) {
-    auto const& exportSet = exp.second;
-    std::vector<TargetExport> targets;
-    exportSet->GetTargets(targets);
-    if (std::any_of(
-          targets.begin(), targets.end(),
-          [&name](TargetExport const& te) { return te.Name == name; })) {
-      exportFiles.push_back(exp.first);
-      ns = exportSet->GetNamespace();
-    }
-  }
-
-  return { exportFiles, ns };
-}
-
-void cmExportBuildCMakeConfigGenerator::ComplainAboutMissingTarget(
-  cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
-  std::vector<std::string> const& exportFiles)
-{
-  std::ostringstream e;
-  e << "export called with target \"" << depender->GetName()
-    << "\" which requires target \"" << dependee->GetName() << "\" ";
-  if (exportFiles.empty()) {
-    e << "that is not in any export set.";
-  } else {
-    e << "that is not in this export set, but in multiple other export sets: "
-      << cmJoin(exportFiles, ", ") << ".\n";
-    e << "An exported target cannot depend upon another target which is "
-         "exported multiple times. Consider consolidating the exports of the "
-         "\""
-      << dependee->GetName() << "\" target to a single export.";
-  }
-
-  this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-    MessageType::FATAL_ERROR, e.str(),
-    this->LG->GetMakefile()->GetBacktrace());
-}
-
-std::string cmExportBuildCMakeConfigGenerator::InstallNameDir(
-  cmGeneratorTarget const* target, std::string const& config)
-{
-  std::string install_name_dir;
-
-  cmMakefile* mf = target->Target->GetMakefile();
-  if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
-    install_name_dir = target->GetInstallNameDirForBuildTree(config);
-  }
-
-  return install_name_dir;
-}
-
 namespace {
 bool EntryIsContextSensitive(
   std::unique_ptr<cmCompiledGeneratorExpression> const& cge)
@@ -427,7 +173,7 @@ bool EntryIsContextSensitive(
 }
 
 std::string cmExportBuildCMakeConfigGenerator::GetFileSetDirectories(
-  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/)
+  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* /*te*/)
 {
   std::vector<std::string> resultVector;
 
@@ -475,7 +221,7 @@ std::string cmExportBuildCMakeConfigGenerator::GetFileSetDirectories(
 }
 
 std::string cmExportBuildCMakeConfigGenerator::GetFileSetFiles(
-  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/)
+  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* /*te*/)
 {
   std::vector<std::string> resultVector;
 
@@ -536,11 +282,6 @@ std::string cmExportBuildCMakeConfigGenerator::GetFileSetFiles(
   return cmJoin(resultVector, " ");
 }
 
-std::string cmExportBuildCMakeConfigGenerator::GetCxxModulesDirectory() const
-{
-  return this->CxxModulesDirectory;
-}
-
 void cmExportBuildCMakeConfigGenerator::GenerateCxxModuleConfigInformation(
   std::string const& name, std::ostream& os) const
 {

+ 9 - 92
Source/cmExportBuildCMakeConfigGenerator.h

@@ -6,130 +6,47 @@
 
 #include <iosfwd>
 #include <string>
-#include <utility>
-#include <vector>
 
-#include <cmext/algorithm>
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportCMakeConfigGenerator.h"
 
-#include "cmExportFileGenerator.h"
-#include "cmStateTypes.h"
-
-class cmExportSet;
 class cmFileSet;
 class cmGeneratorTarget;
-class cmGlobalGenerator;
-class cmLocalGenerator;
 class cmTargetExport;
 
 /** \class cmExportBuildCMakeConfigGenerator
  * \brief Generate a file exporting targets from a build tree.
  *
  * cmExportBuildCMakeConfigGenerator generates a file exporting targets from
- * a build tree.  A single file exports information for all
+ * a build tree.  This exports the targets to CMake's native package
+ * configuration format.  A single file exports information for all
  * configurations built.
  *
  * This is used to implement the export() command.
  */
-class cmExportBuildCMakeConfigGenerator : public cmExportFileGenerator
+class cmExportBuildCMakeConfigGenerator
+  : public cmExportCMakeConfigGenerator
+  , public cmExportBuildFileGenerator
 {
 public:
-  struct TargetExport
-  {
-    TargetExport(std::string name, std::string xcFrameworkLocation)
-      : Name(std::move(name))
-      , XcFrameworkLocation(std::move(xcFrameworkLocation))
-    {
-    }
-
-    std::string Name;
-    std::string XcFrameworkLocation;
-  };
-
   cmExportBuildCMakeConfigGenerator();
 
-  /** Set the list of targets to export.  */
-  void SetTargets(std::vector<TargetExport> const& targets)
-  {
-    this->Targets = targets;
-  }
-  void GetTargets(std::vector<TargetExport>& targets) const;
-  void AppendTargets(std::vector<TargetExport> const& targets)
-  {
-    cm::append(this->Targets, targets);
-  }
-  void SetExportSet(cmExportSet*);
-
-  /** Set the name of the C++ module directory.  */
-  void SetCxxModuleDirectory(std::string cxx_module_dir)
-  {
-    this->CxxModulesDirectory = std::move(cxx_module_dir);
-  }
-  std::string const& GetCxxModuleDirectory() const
-  {
-    return this->CxxModulesDirectory;
-  }
-
   /** Set whether to append generated code to the output file.  */
   void SetAppendMode(bool append) { this->AppendMode = append; }
 
-  void Compute(cmLocalGenerator* lg);
-
 protected:
   // Implement virtual methods from the superclass.
   bool GenerateMainFile(std::ostream& os) override;
   void GenerateImportTargetsConfig(std::ostream& os, std::string const& config,
                                    std::string const& suffix) override;
-  cmStateEnums::TargetType GetExportTargetType(
-    cmGeneratorTarget const* target) const;
-  void HandleMissingTarget(std::string& link_libs,
-                           cmGeneratorTarget const* depender,
-                           cmGeneratorTarget* dependee) override;
-
-  void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
-                                  cmGeneratorTarget const* dependee,
-                                  std::vector<std::string> const& namespaces);
-
-  /** Fill in properties indicating built file locations.  */
-  void SetImportLocationProperty(std::string const& config,
-                                 std::string const& suffix,
-                                 cmGeneratorTarget* target,
-                                 ImportPropertyMap& properties);
-
-  std::string InstallNameDir(cmGeneratorTarget const* target,
-                             std::string const& config) override;
 
   std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                                    cmTargetExport* te) override;
+                                    cmTargetExport const* te) override;
   std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                              cmTargetExport* te) override;
-  cmExportSet* GetExportSet() const override { return this->ExportSet; }
+                              cmTargetExport const* te) override;
 
-  std::string GetCxxModulesDirectory() const override;
   void GenerateCxxModuleConfigInformation(std::string const&,
                                           std::ostream&) const override;
   bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&,
                                                     std::string) const;
-
-  std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
-    cmGlobalGenerator* gg, std::string const& name);
-
-  struct TargetExportPrivate
-  {
-    TargetExportPrivate(cmGeneratorTarget* target,
-                        std::string xcFrameworkLocation)
-      : Target(target)
-      , XcFrameworkLocation(std::move(xcFrameworkLocation))
-    {
-    }
-
-    cmGeneratorTarget* Target;
-    std::string XcFrameworkLocation;
-  };
-
-  std::vector<TargetExport> Targets;
-  cmExportSet* ExportSet;
-  std::vector<TargetExportPrivate> Exports;
-  cmLocalGenerator* LG;
-  // The directory for C++ module information.
-  std::string CxxModulesDirectory;
 };

+ 53 - 382
Source/cmExportBuildFileGenerator.cxx

@@ -3,20 +3,13 @@
 #include "cmExportBuildFileGenerator.h"
 
 #include <algorithm>
-#include <cstddef>
 #include <map>
 #include <memory>
 #include <set>
 #include <sstream>
 #include <utility>
 
-#include <cm/string_view>
-#include <cmext/string_view>
-
-#include "cmCryptoHash.h"
 #include "cmExportSet.h"
-#include "cmFileSet.h"
-#include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -24,11 +17,8 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmOutputConverter.h"
-#include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
-#include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetExport.h"
 #include "cmValue.h"
@@ -50,195 +40,6 @@ void cmExportBuildFileGenerator::Compute(cmLocalGenerator* lg)
   }
 }
 
-bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
-{
-  {
-    std::string expectedTargets;
-    std::string sep;
-    std::vector<TargetExport> targets;
-    bool generatedInterfaceRequired = false;
-    this->GetTargets(targets);
-    for (auto const& tei : targets) {
-      cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name);
-      expectedTargets += sep + this->Namespace + te->GetExportName();
-      sep = " ";
-      if (this->ExportedTargets.insert(te).second) {
-        this->Exports.emplace_back(te, tei.XcFrameworkLocation);
-      } else {
-        std::ostringstream e;
-        e << "given target \"" << te->GetName() << "\" more than once.";
-        this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-          MessageType::FATAL_ERROR, e.str(),
-          this->LG->GetMakefile()->GetBacktrace());
-        return false;
-      }
-      generatedInterfaceRequired |=
-        this->GetExportTargetType(te) == cmStateEnums::INTERFACE_LIBRARY;
-    }
-
-    if (generatedInterfaceRequired) {
-      this->SetRequiredCMakeVersion(3, 0, 0);
-    }
-    this->GenerateExpectedTargetsCode(os, expectedTargets);
-  }
-
-  // Create all the imported targets.
-  for (auto const& exp : this->Exports) {
-    cmGeneratorTarget* gte = exp.Target;
-    this->GenerateImportTargetCode(os, gte, this->GetExportTargetType(gte));
-
-    gte->Target->AppendBuildInterfaceIncludes();
-
-    ImportPropertyMap properties;
-
-    this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_SOURCES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte,
-                                    cmGeneratorExpression::BuildInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gte,
-                                    properties);
-
-    std::string errorMessage;
-    if (!this->PopulateCxxModuleExportProperties(
-          gte, properties, cmGeneratorExpression::BuildInterface, {},
-          errorMessage)) {
-      this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-        MessageType::FATAL_ERROR, errorMessage,
-        this->LG->GetMakefile()->GetBacktrace());
-      return false;
-    }
-
-    if (!this->PopulateExportProperties(gte, properties, errorMessage)) {
-      this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-        MessageType::FATAL_ERROR, errorMessage,
-        this->LG->GetMakefile()->GetBacktrace());
-      return false;
-    }
-
-    bool const newCMP0022Behavior =
-      gte->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
-      gte->GetPolicyStatusCMP0022() != cmPolicies::OLD;
-    if (newCMP0022Behavior) {
-      this->PopulateInterfaceLinkLibrariesProperty(
-        gte, cmGeneratorExpression::BuildInterface, properties);
-    }
-    this->PopulateCompatibleInterfaceProperties(gte, properties);
-    this->PopulateCustomTransitiveInterfaceProperties(
-      gte, cmGeneratorExpression::BuildInterface, properties);
-
-    this->GenerateInterfaceProperties(gte, os, properties);
-
-    this->GenerateTargetFileSets(gte, os);
-  }
-
-  std::string cxx_modules_name;
-  if (this->ExportSet) {
-    cxx_modules_name = this->ExportSet->GetName();
-  } else {
-    cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
-    constexpr std::size_t HASH_TRUNCATION = 12;
-    for (auto const& target : this->Targets) {
-      hasher.Append(target.Name);
-    }
-    cxx_modules_name = hasher.FinalizeHex().substr(0, HASH_TRUNCATION);
-  }
-
-  this->GenerateCxxModuleInformation(cxx_modules_name, os);
-
-  // Generate import file content for each configuration.
-  for (std::string const& c : this->Configurations) {
-    this->GenerateImportConfig(os, c);
-  }
-
-  // Generate import file content for each configuration.
-  for (std::string const& c : this->Configurations) {
-    this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, c);
-  }
-
-  this->GenerateMissingTargetsCheckCode(os);
-
-  return true;
-}
-
-void cmExportBuildFileGenerator::GenerateImportTargetsConfig(
-  std::ostream& os, std::string const& config, std::string const& suffix)
-{
-  for (auto const& exp : this->Exports) {
-    cmGeneratorTarget* target = exp.Target;
-
-    // Collect import properties for this target.
-    ImportPropertyMap properties;
-
-    if (this->GetExportTargetType(target) != cmStateEnums::INTERFACE_LIBRARY) {
-      this->SetImportLocationProperty(config, suffix, target, properties);
-    }
-    if (!properties.empty()) {
-      // Get the rest of the target details.
-      if (this->GetExportTargetType(target) !=
-          cmStateEnums::INTERFACE_LIBRARY) {
-        this->SetImportDetailProperties(config, suffix, target, properties);
-        this->SetImportLinkInterface(config, suffix,
-                                     cmGeneratorExpression::BuildInterface,
-                                     target, properties);
-      }
-
-      // TODO: PUBLIC_HEADER_LOCATION
-      // This should wait until the build feature propagation stuff
-      // is done.  Then this can be a propagated include directory.
-      // this->GenerateImportProperty(config, te->HeaderGenerator,
-      //                              properties);
-
-      // Generate code in the export file.
-      std::string importedXcFrameworkLocation = exp.XcFrameworkLocation;
-      if (!importedXcFrameworkLocation.empty()) {
-        importedXcFrameworkLocation = cmGeneratorExpression::Preprocess(
-          importedXcFrameworkLocation,
-          cmGeneratorExpression::PreprocessContext::BuildInterface);
-        importedXcFrameworkLocation = cmGeneratorExpression::Evaluate(
-          importedXcFrameworkLocation, exp.Target->GetLocalGenerator(), config,
-          exp.Target, nullptr, exp.Target);
-        if (!importedXcFrameworkLocation.empty() &&
-            !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation)) {
-          importedXcFrameworkLocation =
-            cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/',
-                     importedXcFrameworkLocation);
-        }
-      }
-      this->GenerateImportPropertyCode(os, config, suffix, target, properties,
-                                       importedXcFrameworkLocation);
-    }
-  }
-}
-
 cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType(
   cmGeneratorTarget const* target) const
 {
@@ -311,13 +112,32 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
   }
 }
 
+bool cmExportBuildFileGenerator::CollectExports(
+  std::function<void(cmGeneratorTarget const*)> visitor)
+{
+  std::vector<TargetExport> targets;
+  this->GetTargets(targets);
+  for (auto const& tei : targets) {
+    cmGeneratorTarget* te = this->LG->FindGeneratorTargetToUse(tei.Name);
+    if (this->ExportedTargets.insert(te).second) {
+      this->Exports.emplace_back(te, tei.XcFrameworkLocation);
+      visitor(te);
+    } else {
+      this->ComplainAboutDuplicateTarget(te->GetName());
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void cmExportBuildFileGenerator::HandleMissingTarget(
   std::string& link_libs, cmGeneratorTarget const* depender,
   cmGeneratorTarget* dependee)
 {
   // The target is not in the export.
   if (!this->AppendMode) {
-    std::string const name = dependee->GetName();
+    std::string const& name = dependee->GetName();
     cmGlobalGenerator* gg =
       dependee->GetLocalGenerator()->GetGlobalGenerator();
     auto exportInfo = this->FindBuildExportInfo(gg, name);
@@ -383,7 +203,7 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg,
 
 void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
   cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
-  std::vector<std::string> const& exportFiles)
+  std::vector<std::string> const& exportFiles) const
 {
   std::ostringstream e;
   e << "export called with target \"" << depender->GetName()
@@ -399,8 +219,22 @@ void cmExportBuildFileGenerator::ComplainAboutMissingTarget(
       << dependee->GetName() << "\" target to a single export.";
   }
 
+  this->ReportError(e.str());
+}
+
+void cmExportBuildFileGenerator::ComplainAboutDuplicateTarget(
+  std::string const& targetName) const
+{
+  std::ostringstream e;
+  e << "given target \"" << targetName << "\" more than once.";
+  this->ReportError(e.str());
+}
+
+void cmExportBuildFileGenerator::ReportError(
+  std::string const& errorMessage) const
+{
   this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-    MessageType::FATAL_ERROR, e.str(),
+    MessageType::FATAL_ERROR, errorMessage,
     this->LG->GetMakefile()->GetBacktrace());
 }
 
@@ -417,185 +251,22 @@ std::string cmExportBuildFileGenerator::InstallNameDir(
   return install_name_dir;
 }
 
-namespace {
-bool EntryIsContextSensitive(
-  std::unique_ptr<cmCompiledGeneratorExpression> const& cge)
-{
-  return cge->GetHadContextSensitiveCondition();
-}
-}
-
-std::string cmExportBuildFileGenerator::GetFileSetDirectories(
-  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* /*te*/)
-{
-  std::vector<std::string> resultVector;
-
-  auto configs =
-    gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
-  auto directoryEntries = fileSet->CompileDirectoryEntries();
-
-  for (auto const& config : configs) {
-    auto directories = fileSet->EvaluateDirectoryEntries(
-      directoryEntries, gte->LocalGenerator, config, gte);
-
-    bool const contextSensitive =
-      std::any_of(directoryEntries.begin(), directoryEntries.end(),
-                  EntryIsContextSensitive);
-
-    auto const& type = fileSet->GetType();
-    // C++ modules do not support interface file sets which are dependent upon
-    // the configuration.
-    if (contextSensitive && type == "CXX_MODULES"_s) {
-      auto* mf = this->LG->GetMakefile();
-      std::ostringstream e;
-      e << "The \"" << gte->GetName() << "\" target's interface file set \""
-        << fileSet->GetName() << "\" of type \"" << type
-        << "\" contains context-sensitive base directory entries which is not "
-           "supported.";
-      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      return std::string{};
-    }
-
-    for (auto const& directory : directories) {
-      auto dest = cmOutputConverter::EscapeForCMake(
-        directory, cmOutputConverter::WrapQuotes::NoWrap);
-
-      if (contextSensitive && configs.size() != 1) {
-        resultVector.push_back(
-          cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
-      } else {
-        resultVector.emplace_back(cmStrCat('"', dest, '"'));
-        break;
-      }
-    }
-  }
-
-  return cmJoin(resultVector, " ");
-}
-
-std::string cmExportBuildFileGenerator::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();
-
-  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);
-    }
-
-    bool const contextSensitive =
-      std::any_of(directoryEntries.begin(), directoryEntries.end(),
-                  EntryIsContextSensitive) ||
-      std::any_of(fileEntries.begin(), fileEntries.end(),
-                  EntryIsContextSensitive);
-
-    auto const& type = fileSet->GetType();
-    // C++ modules do not support interface file sets which are dependent upon
-    // the configuration.
-    if (contextSensitive && type == "CXX_MODULES"_s) {
-      auto* mf = this->LG->GetMakefile();
-      std::ostringstream e;
-      e << "The \"" << gte->GetName() << "\" target's interface file set \""
-        << fileSet->GetName() << "\" of type \"" << type
-        << "\" contains context-sensitive file entries which is not "
-           "supported.";
-      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      return std::string{};
-    }
-
-    for (auto const& it : files) {
-      for (auto const& filename : it.second) {
-        auto escapedFile = cmOutputConverter::EscapeForCMake(
-          filename, cmOutputConverter::WrapQuotes::NoWrap);
-        if (contextSensitive && configs.size() != 1) {
-          resultVector.push_back(
-            cmStrCat("\"$<$<CONFIG:", config, ">:", escapedFile, ">\""));
-        } else {
-          resultVector.emplace_back(cmStrCat('"', escapedFile, '"'));
-        }
-      }
-    }
-
-    if (!(contextSensitive && configs.size() != 1)) {
-      break;
-    }
-  }
-
-  return cmJoin(resultVector, " ");
-}
-
-std::string cmExportBuildFileGenerator::GetCxxModulesDirectory() const
-{
-  return this->CxxModulesDirectory;
-}
-
-void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation(
-  std::string const& name, std::ostream& os) const
+bool cmExportBuildFileGenerator::PopulateInterfaceProperties(
+  cmGeneratorTarget const* target, ImportPropertyMap& properties)
 {
-  char const* opt = "";
-  if (this->Configurations.size() > 1) {
-    // With more than one configuration, each individual file is optional.
-    opt = " OPTIONAL";
-  }
-
-  // Generate import file content for each configuration.
-  for (std::string c : this->Configurations) {
-    if (c.empty()) {
-      c = "noconfig";
-    }
-    os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << '-'
-       << c << ".cmake\"" << opt << ")\n";
-  }
-}
-
-bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion(
-  std::string const& name, std::string config) const
-{
-  auto cxx_modules_dirname = this->GetCxxModulesDirectory();
-  if (cxx_modules_dirname.empty()) {
-    return true;
-  }
-
-  if (config.empty()) {
-    config = "noconfig";
-  }
-
-  std::string fileName =
-    cmStrCat(this->FileDir, '/', cxx_modules_dirname, "/cxx-modules-", name,
-             '-', config, ".cmake");
-
-  cmGeneratedFileStream os(fileName, true);
-  if (!os) {
-    std::string se = cmSystemTools::GetLastSystemError();
-    std::ostringstream e;
-    e << "cannot write to file \"" << fileName << "\": " << se;
-    cmSystemTools::Error(e.str());
-    return false;
-  }
-  os.SetCopyIfDifferent(true);
-
-  for (auto const* tgt : this->ExportedTargets) {
-    // Only targets with C++ module sources will have a
-    // collator-generated install script.
-    if (!tgt->HaveCxx20ModuleSources()) {
-      continue;
-    }
-
-    os << "include(\"${CMAKE_CURRENT_LIST_DIR}/target-"
-       << tgt->GetFilesystemExportName() << '-' << config << ".cmake\")\n";
-  }
-
-  return true;
+  this->PopulateInterfaceProperty("INTERFACE_INCLUDE_DIRECTORIES", target,
+                                  cmGeneratorExpression::BuildInterface,
+                                  properties);
+  this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", target,
+                                  cmGeneratorExpression::BuildInterface,
+                                  properties);
+  this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", target,
+                                  cmGeneratorExpression::BuildInterface,
+                                  properties);
+  this->PopulateInterfaceProperty("INTERFACE_SOURCES", target,
+                                  cmGeneratorExpression::BuildInterface,
+                                  properties);
+
+  return this->PopulateInterfaceProperties(
+    target, {}, cmGeneratorExpression::BuildInterface, properties);
 }

+ 26 - 27
Source/cmExportBuildFileGenerator.h

@@ -4,7 +4,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include <iosfwd>
+#include <functional>
 #include <string>
 #include <utility>
 #include <vector>
@@ -15,22 +15,19 @@
 #include "cmStateTypes.h"
 
 class cmExportSet;
-class cmFileSet;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
 class cmLocalGenerator;
-class cmTargetExport;
 
-/** \class cmExportBuildFileGenerator
+/** \class cmExportBuildCMakeConfigGenerator
  * \brief Generate a file exporting targets from a build tree.
  *
- * cmExportBuildFileGenerator generates a file exporting targets from
- * a build tree.  A single file exports information for all
- * configurations built.
+ * cmExportBuildCMakeConfigGenerator is the interface class for generating a
+ * file exporting targets from a build tree.
  *
  * This is used to implement the export() command.
  */
-class cmExportBuildFileGenerator : public cmExportFileGenerator
+class cmExportBuildFileGenerator : virtual public cmExportFileGenerator
 {
 public:
   struct TargetExport
@@ -69,25 +66,28 @@ public:
     return this->CxxModulesDirectory;
   }
 
-  /** Set whether to append generated code to the output file.  */
-  void SetAppendMode(bool append) { this->AppendMode = append; }
-
   void Compute(cmLocalGenerator* lg);
 
 protected:
-  // Implement virtual methods from the superclass.
-  bool GenerateMainFile(std::ostream& os) override;
-  void GenerateImportTargetsConfig(std::ostream& os, std::string const& config,
-                                   std::string const& suffix) override;
   cmStateEnums::TargetType GetExportTargetType(
     cmGeneratorTarget const* target) const;
+
+  /** Walk the list of targets to be exported.  Returns true iff no duplicates
+      are found.  */
+  bool CollectExports(std::function<void(cmGeneratorTarget const*)> visitor);
+
   void HandleMissingTarget(std::string& link_libs,
                            cmGeneratorTarget const* depender,
                            cmGeneratorTarget* dependee) override;
 
-  void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
-                                  cmGeneratorTarget const* dependee,
-                                  std::vector<std::string> const& namespaces);
+  void ComplainAboutMissingTarget(
+    cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
+    std::vector<std::string> const& namespaces) const;
+
+  void ComplainAboutDuplicateTarget(
+    std::string const& targetName) const override;
+
+  void ReportError(std::string const& errorMessage) const override;
 
   /** Fill in properties indicating built file locations.  */
   void SetImportLocationProperty(std::string const& config,
@@ -98,21 +98,20 @@ protected:
   std::string InstallNameDir(cmGeneratorTarget const* target,
                              std::string const& config) override;
 
-  std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                                    cmTargetExport* te) override;
-  std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                              cmTargetExport* te) override;
   cmExportSet* GetExportSet() const override { return this->ExportSet; }
 
-  std::string GetCxxModulesDirectory() const override;
-  void GenerateCxxModuleConfigInformation(std::string const&,
-                                          std::ostream&) const override;
-  bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&,
-                                                    std::string) const;
+  std::string GetCxxModulesDirectory() const override
+  {
+    return this->CxxModulesDirectory;
+  }
 
   std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
     cmGlobalGenerator* gg, std::string const& name);
 
+  using cmExportFileGenerator::PopulateInterfaceProperties;
+  bool PopulateInterfaceProperties(cmGeneratorTarget const* target,
+                                   ImportPropertyMap& properties);
+
   struct TargetExportPrivate
   {
     TargetExportPrivate(cmGeneratorTarget* target,

+ 22 - 1019
Source/cmExportCMakeConfigGenerator.cxx

@@ -3,33 +3,26 @@
 #include "cmExportCMakeConfigGenerator.h"
 
 #include <algorithm>
-#include <array>
 #include <cassert>
-#include <cstring>
 #include <sstream>
 #include <utility>
+#include <vector>
 
-#include <cm/memory>
 #include <cm/optional>
 #include <cm/string_view>
 #include <cmext/string_view>
 
-#include "cmsys/FStream.hxx"
-
-#include "cmComputeLinkInformation.h"
 #include "cmExportSet.h"
 #include "cmFileSet.h"
 #include "cmFindPackageStack.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmLinkItem.h"
-#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmPropertyMap.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -37,7 +30,7 @@
 #include "cmValue.h"
 #include "cmVersion.h"
 
-static std::string cmExportCMakeConfigGeneratorEscape(std::string const& str)
+static std::string cmExportFileGeneratorEscape(std::string const& str)
 {
   // Escape a property value for writing into a .cmake file.
   std::string result = cmOutputConverter::EscapeForCMake(str);
@@ -49,56 +42,15 @@ static std::string cmExportCMakeConfigGeneratorEscape(std::string const& str)
   return result;
 }
 
-cmExportCMakeConfigGenerator::cmExportCMakeConfigGenerator()
-{
-  this->AppendMode = false;
-  this->ExportOld = false;
-}
-
-void cmExportCMakeConfigGenerator::AddConfiguration(std::string const& config)
-{
-  this->Configurations.push_back(config);
-}
+cmExportCMakeConfigGenerator::cmExportCMakeConfigGenerator() = default;
 
-void cmExportCMakeConfigGenerator::SetExportFile(char const* mainFile)
+cm::string_view cmExportCMakeConfigGenerator::GetImportPrefixWithSlash() const
 {
-  this->MainImportFile = mainFile;
-  this->FileDir = cmSystemTools::GetFilenamePath(this->MainImportFile);
-  this->FileBase =
-    cmSystemTools::GetFilenameWithoutLastExtension(this->MainImportFile);
-  this->FileExt =
-    cmSystemTools::GetFilenameLastExtension(this->MainImportFile);
+  return "${_IMPORT_PREFIX}/"_s;
 }
 
-std::string const& cmExportCMakeConfigGenerator::GetMainExportFileName() const
+bool cmExportCMakeConfigGenerator::GenerateImportFile(std::ostream& os)
 {
-  return this->MainImportFile;
-}
-
-bool cmExportCMakeConfigGenerator::GenerateImportFile()
-{
-  // Open the output file to generate it.
-  std::unique_ptr<cmsys::ofstream> foutPtr;
-  if (this->AppendMode) {
-    // Open for append.
-    auto openmodeApp = std::ios::app;
-    foutPtr = cm::make_unique<cmsys::ofstream>(this->MainImportFile.c_str(),
-                                               openmodeApp);
-  } else {
-    // Generate atomically and with copy-if-different.
-    std::unique_ptr<cmGeneratedFileStream> ap(
-      new cmGeneratedFileStream(this->MainImportFile, true));
-    ap->SetCopyIfDifferent(true);
-    foutPtr = std::move(ap);
-  }
-  if (!foutPtr || !*foutPtr) {
-    std::string se = cmSystemTools::GetLastSystemError();
-    std::ostringstream e;
-    e << "cannot write to file \"" << this->MainImportFile << "\": " << se;
-    cmSystemTools::Error(e.str());
-    return false;
-  }
-  std::ostream& os = *foutPtr;
   std::stringstream mainFileWithHeadersAndFootersBuffer;
 
   // Start with the import file header.
@@ -132,499 +84,6 @@ bool cmExportCMakeConfigGenerator::GenerateImportFile()
   return result;
 }
 
-void cmExportCMakeConfigGenerator::GenerateImportConfig(
-  std::ostream& os, std::string const& config)
-{
-  // Construct the property configuration suffix.
-  std::string suffix = "_";
-  if (!config.empty()) {
-    suffix += cmSystemTools::UpperCase(config);
-  } else {
-    suffix += "NOCONFIG";
-  }
-
-  // Generate the per-config target information.
-  this->GenerateImportTargetsConfig(os, config, suffix);
-}
-
-void cmExportCMakeConfigGenerator::PopulateInterfaceProperty(
-  std::string const& propName, cmGeneratorTarget const* target,
-  ImportPropertyMap& properties)
-{
-  cmValue input = target->GetProperty(propName);
-  if (input) {
-    properties[propName] = *input;
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateInterfaceProperty(
-  std::string const& propName, std::string const& outputName,
-  cmGeneratorTarget const* target,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties)
-{
-  cmValue input = target->GetProperty(propName);
-  if (input) {
-    if (input->empty()) {
-      // Set to empty
-      properties[outputName].clear();
-      return;
-    }
-
-    std::string prepro =
-      cmGeneratorExpression::Preprocess(*input, preprocessRule);
-    if (!prepro.empty()) {
-      this->ResolveTargetsInGeneratorExpressions(prepro, target);
-      properties[outputName] = prepro;
-    }
-  }
-}
-
-bool cmExportCMakeConfigGenerator::PopulateInterfaceLinkLibrariesProperty(
-  cmGeneratorTarget const* target,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties)
-{
-  if (!target->IsLinkable()) {
-    return false;
-  }
-  static std::array<std::string, 3> const linkIfaceProps = {
-    { "INTERFACE_LINK_LIBRARIES", "INTERFACE_LINK_LIBRARIES_DIRECT",
-      "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE" }
-  };
-  bool hadINTERFACE_LINK_LIBRARIES = false;
-  for (std::string const& linkIfaceProp : linkIfaceProps) {
-    if (cmValue input = target->GetProperty(linkIfaceProp)) {
-      std::string prepro =
-        cmGeneratorExpression::Preprocess(*input, preprocessRule);
-      if (!prepro.empty()) {
-        this->ResolveTargetsInGeneratorExpressions(prepro, target,
-                                                   ReplaceFreeTargets);
-        properties[linkIfaceProp] = prepro;
-        hadINTERFACE_LINK_LIBRARIES = true;
-      }
-    }
-  }
-  return hadINTERFACE_LINK_LIBRARIES;
-}
-
-static bool isSubDirectory(std::string const& a, std::string const& b)
-{
-  return (cmSystemTools::ComparePath(a, b) ||
-          cmSystemTools::IsSubDirectory(a, b));
-}
-
-static bool checkInterfaceDirs(std::string const& prepro,
-                               cmGeneratorTarget const* target,
-                               std::string const& prop)
-{
-  std::string const& installDir =
-    target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
-  std::string const& topSourceDir =
-    target->GetLocalGenerator()->GetSourceDirectory();
-  std::string const& topBinaryDir =
-    target->GetLocalGenerator()->GetBinaryDirectory();
-
-  std::vector<std::string> parts;
-  cmGeneratorExpression::Split(prepro, parts);
-
-  bool const inSourceBuild = topSourceDir == topBinaryDir;
-
-  bool hadFatalError = false;
-
-  for (std::string const& li : parts) {
-    size_t genexPos = cmGeneratorExpression::Find(li);
-    if (genexPos == 0) {
-      continue;
-    }
-    if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) {
-      continue;
-    }
-    MessageType messageType = MessageType::FATAL_ERROR;
-    std::ostringstream e;
-    if (genexPos != std::string::npos) {
-      if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
-        switch (target->GetPolicyStatusCMP0041()) {
-          case cmPolicies::WARN:
-            messageType = MessageType::WARNING;
-            e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0041) << "\n";
-            break;
-          case cmPolicies::OLD:
-            continue;
-          case cmPolicies::REQUIRED_IF_USED:
-          case cmPolicies::REQUIRED_ALWAYS:
-          case cmPolicies::NEW:
-            hadFatalError = true;
-            break; // Issue fatal message.
-        }
-      } else {
-        hadFatalError = true;
-      }
-    }
-    if (!cmSystemTools::FileIsFullPath(li)) {
-      /* clang-format off */
-      e << "Target \"" << target->GetName() << "\" " << prop <<
-           " property contains relative path:\n"
-           "  \"" << li << "\"";
-      /* clang-format on */
-      target->GetLocalGenerator()->IssueMessage(messageType, e.str());
-    }
-    bool inBinary = isSubDirectory(li, topBinaryDir);
-    bool inSource = isSubDirectory(li, topSourceDir);
-    if (isSubDirectory(li, installDir)) {
-      // The include directory is inside the install tree.  If the
-      // install tree is not inside the source tree or build tree then
-      // fall through to the checks below that the include directory is not
-      // also inside the source tree or build tree.
-      bool shouldContinue =
-        (!inBinary || isSubDirectory(installDir, topBinaryDir)) &&
-        (!inSource || isSubDirectory(installDir, topSourceDir));
-
-      if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
-        if (!shouldContinue) {
-          switch (target->GetPolicyStatusCMP0052()) {
-            case cmPolicies::WARN: {
-              std::ostringstream s;
-              s << cmPolicies::GetPolicyWarning(cmPolicies::CMP0052) << "\n";
-              s << "Directory:\n    \"" << li
-                << "\"\nin "
-                   "INTERFACE_INCLUDE_DIRECTORIES of target \""
-                << target->GetName()
-                << "\" is a subdirectory of the install "
-                   "directory:\n    \""
-                << installDir
-                << "\"\nhowever it is also "
-                   "a subdirectory of the "
-                << (inBinary ? "build" : "source") << " tree:\n    \""
-                << (inBinary ? topBinaryDir : topSourceDir) << "\"\n";
-              target->GetLocalGenerator()->IssueMessage(
-                MessageType::AUTHOR_WARNING, s.str());
-              CM_FALLTHROUGH;
-            }
-            case cmPolicies::OLD:
-              shouldContinue = true;
-              break;
-            case cmPolicies::REQUIRED_ALWAYS:
-            case cmPolicies::REQUIRED_IF_USED:
-            case cmPolicies::NEW:
-              break;
-          }
-        }
-      }
-      if (shouldContinue) {
-        continue;
-      }
-    }
-    if (inBinary) {
-      /* clang-format off */
-      e << "Target \"" << target->GetName() << "\" " << prop <<
-           " property contains path:\n"
-           "  \"" << li << "\"\nwhich is prefixed in the build directory.";
-      /* clang-format on */
-      target->GetLocalGenerator()->IssueMessage(messageType, e.str());
-    }
-    if (!inSourceBuild) {
-      if (inSource) {
-        e << "Target \"" << target->GetName() << "\" " << prop
-          << " property contains path:\n"
-             "  \""
-          << li << "\"\nwhich is prefixed in the source directory.";
-        target->GetLocalGenerator()->IssueMessage(messageType, e.str());
-      }
-    }
-  }
-  return !hadFatalError;
-}
-
-static void prefixItems(std::string& exportDirs)
-{
-  std::vector<std::string> entries;
-  cmGeneratorExpression::Split(exportDirs, entries);
-  exportDirs.clear();
-  char const* sep = "";
-  for (std::string const& e : entries) {
-    exportDirs += sep;
-    sep = ";";
-    if (!cmSystemTools::FileIsFullPath(e) &&
-        e.find("${_IMPORT_PREFIX}") == std::string::npos) {
-      exportDirs += "${_IMPORT_PREFIX}/";
-    }
-    exportDirs += e;
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateSourcesInterface(
-  cmGeneratorTarget const* gt,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties)
-{
-  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
-
-  char const* propName = "INTERFACE_SOURCES";
-  cmValue input = gt->GetProperty(propName);
-
-  if (!input) {
-    return;
-  }
-
-  if (input->empty()) {
-    properties[propName].clear();
-    return;
-  }
-
-  std::string prepro =
-    cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
-  if (!prepro.empty()) {
-    this->ResolveTargetsInGeneratorExpressions(prepro, gt);
-
-    if (!checkInterfaceDirs(prepro, gt, propName)) {
-      return;
-    }
-    properties[propName] = prepro;
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateIncludeDirectoriesInterface(
-  cmGeneratorTarget const* target,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties, cmTargetExport const& te,
-  std::string& includesDestinationDirs)
-{
-  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
-
-  includesDestinationDirs.clear();
-
-  char const* propName = "INTERFACE_INCLUDE_DIRECTORIES";
-  cmValue input = target->GetProperty(propName);
-
-  cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance());
-
-  std::string dirs = cmGeneratorExpression::Preprocess(
-    cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)),
-    preprocessRule, true);
-  this->ReplaceInstallPrefix(dirs);
-  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);
-  std::string exportDirs =
-    cge->Evaluate(target->GetLocalGenerator(), "", target);
-
-  if (cge->GetHadContextSensitiveCondition()) {
-    cmLocalGenerator* lg = target->GetLocalGenerator();
-    std::ostringstream e;
-    e << "Target \"" << target->GetName()
-      << "\" is installed with "
-         "INCLUDES DESTINATION set to a context sensitive path.  Paths which "
-         "depend on the configuration, policy values or the link interface "
-         "are "
-         "not supported.  Consider using target_include_directories instead.";
-    lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
-    return;
-  }
-
-  if (!input && exportDirs.empty()) {
-    return;
-  }
-  if ((input && input->empty()) && exportDirs.empty()) {
-    // Set to empty
-    properties[propName].clear();
-    return;
-  }
-
-  prefixItems(exportDirs);
-  includesDestinationDirs = exportDirs;
-
-  std::string includes = (input ? *input : "");
-  char const* sep = input ? ";" : "";
-  includes += sep + exportDirs;
-  std::string prepro =
-    cmGeneratorExpression::Preprocess(includes, preprocessRule, true);
-  if (!prepro.empty()) {
-    this->ResolveTargetsInGeneratorExpressions(prepro, target);
-
-    if (!checkInterfaceDirs(prepro, target, propName)) {
-      return;
-    }
-    properties[propName] = prepro;
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateLinkDependsInterface(
-  cmGeneratorTarget const* gt,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties)
-{
-  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
-
-  char const* propName = "INTERFACE_LINK_DEPENDS";
-  cmValue input = gt->GetProperty(propName);
-
-  if (!input) {
-    return;
-  }
-
-  if (input->empty()) {
-    properties[propName].clear();
-    return;
-  }
-
-  std::string prepro =
-    cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
-  if (!prepro.empty()) {
-    this->ResolveTargetsInGeneratorExpressions(prepro, gt);
-
-    if (!checkInterfaceDirs(prepro, gt, propName)) {
-      return;
-    }
-    properties[propName] = prepro;
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateLinkDirectoriesInterface(
-  cmGeneratorTarget const* gt,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties)
-{
-  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
-
-  char const* propName = "INTERFACE_LINK_DIRECTORIES";
-  cmValue input = gt->GetProperty(propName);
-
-  if (!input) {
-    return;
-  }
-
-  if (input->empty()) {
-    properties[propName].clear();
-    return;
-  }
-
-  std::string prepro =
-    cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
-  if (!prepro.empty()) {
-    this->ResolveTargetsInGeneratorExpressions(prepro, gt);
-
-    if (!checkInterfaceDirs(prepro, gt, propName)) {
-      return;
-    }
-    properties[propName] = prepro;
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateInterfaceProperty(
-  std::string const& propName, cmGeneratorTarget const* target,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties)
-{
-  this->PopulateInterfaceProperty(propName, propName, target, preprocessRule,
-                                  properties);
-}
-
-static void getPropertyContents(cmGeneratorTarget const* tgt,
-                                std::string const& prop,
-                                std::set<std::string>& ifaceProperties)
-{
-  cmValue p = tgt->GetProperty(prop);
-  if (!p) {
-    return;
-  }
-  cmList content{ *p };
-  ifaceProperties.insert(content.begin(), content.end());
-}
-
-static void getCompatibleInterfaceProperties(
-  cmGeneratorTarget const* target, std::set<std::string>& ifaceProperties,
-  std::string const& config)
-{
-  if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
-    // object libraries have no link information, so nothing to compute
-    return;
-  }
-
-  cmComputeLinkInformation* info = target->GetLinkInformation(config);
-
-  if (!info) {
-    cmLocalGenerator* lg = target->GetLocalGenerator();
-    std::ostringstream e;
-    e << "Exporting the target \"" << target->GetName()
-      << "\" is not "
-         "allowed since its linker language cannot be determined";
-    lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
-    return;
-  }
-
-  cmComputeLinkInformation::ItemVector const& deps = info->GetItems();
-
-  for (auto const& dep : deps) {
-    if (!dep.Target || dep.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
-      continue;
-    }
-    getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_BOOL",
-                        ifaceProperties);
-    getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_STRING",
-                        ifaceProperties);
-    getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_NUMBER_MIN",
-                        ifaceProperties);
-    getPropertyContents(dep.Target, "COMPATIBLE_INTERFACE_NUMBER_MAX",
-                        ifaceProperties);
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateCompatibleInterfaceProperties(
-  cmGeneratorTarget const* gtarget, ImportPropertyMap& properties)
-{
-  this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", gtarget,
-                                  properties);
-  this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_STRING", gtarget,
-                                  properties);
-  this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MIN", gtarget,
-                                  properties);
-  this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_NUMBER_MAX", gtarget,
-                                  properties);
-
-  std::set<std::string> ifaceProperties;
-
-  getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_BOOL", ifaceProperties);
-  getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_STRING", ifaceProperties);
-  getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MIN",
-                      ifaceProperties);
-  getPropertyContents(gtarget, "COMPATIBLE_INTERFACE_NUMBER_MAX",
-                      ifaceProperties);
-
-  if (gtarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
-    std::vector<std::string> configNames =
-      gtarget->Target->GetMakefile()->GetGeneratorConfigs(
-        cmMakefile::IncludeEmptyConfig);
-
-    for (std::string const& cn : configNames) {
-      getCompatibleInterfaceProperties(gtarget, ifaceProperties, cn);
-    }
-  }
-
-  for (std::string const& ip : ifaceProperties) {
-    this->PopulateInterfaceProperty("INTERFACE_" + ip, gtarget, properties);
-  }
-}
-
-void cmExportCMakeConfigGenerator::PopulateCustomTransitiveInterfaceProperties(
-  cmGeneratorTarget const* target,
-  cmGeneratorExpression::PreprocessContext preprocessRule,
-  ImportPropertyMap& properties)
-{
-  this->PopulateInterfaceProperty("TRANSITIVE_COMPILE_PROPERTIES", target,
-                                  properties);
-  this->PopulateInterfaceProperty("TRANSITIVE_LINK_PROPERTIES", target,
-                                  properties);
-  std::set<std::string> ifaceProperties;
-  for (std::string const& config : this->Configurations) {
-    for (auto const& i : target->GetCustomTransitiveProperties(
-           config, cmGeneratorTarget::PropertyFor::Interface)) {
-      ifaceProperties.emplace(i.second.InterfaceName);
-    }
-  }
-  for (std::string const& ip : ifaceProperties) {
-    this->PopulateInterfaceProperty(ip, target, preprocessRule, properties);
-  }
-}
-
 void cmExportCMakeConfigGenerator::GenerateInterfaceProperties(
   cmGeneratorTarget const* target, std::ostream& os,
   ImportPropertyMap const& properties)
@@ -635,181 +94,12 @@ void cmExportCMakeConfigGenerator::GenerateInterfaceProperties(
     os << "set_target_properties(" << targetName << " PROPERTIES\n";
     for (auto const& property : properties) {
       os << "  " << property.first << " "
-         << cmExportCMakeConfigGeneratorEscape(property.second) << "\n";
+         << cmExportFileGeneratorEscape(property.second) << "\n";
     }
     os << ")\n\n";
   }
 }
 
-bool cmExportCMakeConfigGenerator::AddTargetNamespace(
-  std::string& input, cmGeneratorTarget const* target,
-  cmLocalGenerator const* lg)
-{
-  cmGeneratorTarget::TargetOrString resolved =
-    target->ResolveTargetReference(input, lg);
-
-  cmGeneratorTarget* tgt = resolved.Target;
-  if (!tgt) {
-    input = resolved.String;
-    return false;
-  }
-
-  cmFindPackageStack const& pkgStack = tgt->Target->GetFindPackageStack();
-  if (!pkgStack.Empty() ||
-      tgt->Target->GetProperty("EXPORT_FIND_PACKAGE_NAME")) {
-    this->ExternalTargets.emplace(tgt);
-  }
-
-  if (tgt->IsImported()) {
-    input = tgt->GetName();
-    return true;
-  }
-  if (this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) {
-    input = this->Namespace + tgt->GetExportName();
-  } else {
-    std::string namespacedTarget;
-    this->HandleMissingTarget(namespacedTarget, target, tgt);
-    if (!namespacedTarget.empty()) {
-      input = namespacedTarget;
-    } else {
-      input = tgt->GetName();
-    }
-  }
-  return true;
-}
-
-void cmExportCMakeConfigGenerator::ResolveTargetsInGeneratorExpressions(
-  std::string& input, cmGeneratorTarget const* target,
-  FreeTargetsReplace replace)
-{
-  cmLocalGenerator const* lg = target->GetLocalGenerator();
-  if (replace == NoReplaceFreeTargets) {
-    this->ResolveTargetsInGeneratorExpression(input, target, lg);
-    return;
-  }
-  std::vector<std::string> parts;
-  cmGeneratorExpression::Split(input, parts);
-
-  std::string sep;
-  input.clear();
-  for (std::string& li : parts) {
-    if (target->IsLinkLookupScope(li, lg)) {
-      continue;
-    }
-    if (cmGeneratorExpression::Find(li) == std::string::npos) {
-      this->AddTargetNamespace(li, target, lg);
-    } else {
-      this->ResolveTargetsInGeneratorExpression(li, target, lg);
-    }
-    input += sep + li;
-    sep = ";";
-  }
-}
-
-void cmExportCMakeConfigGenerator::ResolveTargetsInGeneratorExpression(
-  std::string& input, cmGeneratorTarget const* target,
-  cmLocalGenerator const* lg)
-{
-  std::string::size_type pos = 0;
-  std::string::size_type lastPos = pos;
-
-  while ((pos = input.find("$<TARGET_PROPERTY:", lastPos)) !=
-         std::string::npos) {
-    std::string::size_type nameStartPos = pos + cmStrLen("$<TARGET_PROPERTY:");
-    std::string::size_type closePos = input.find('>', nameStartPos);
-    std::string::size_type commaPos = input.find(',', nameStartPos);
-    std::string::size_type nextOpenPos = input.find("$<", nameStartPos);
-    if (commaPos == std::string::npos    // Implied 'this' target
-        || closePos == std::string::npos // Incomplete expression.
-        || closePos < commaPos           // Implied 'this' target
-        || nextOpenPos < commaPos)       // Non-literal
-    {
-      lastPos = nameStartPos;
-      continue;
-    }
-
-    std::string targetName =
-      input.substr(nameStartPos, commaPos - nameStartPos);
-
-    if (this->AddTargetNamespace(targetName, target, lg)) {
-      input.replace(nameStartPos, commaPos - nameStartPos, targetName);
-    }
-    lastPos = nameStartPos + targetName.size() + 1;
-  }
-
-  std::string errorString;
-  pos = 0;
-  lastPos = pos;
-  while ((pos = input.find("$<TARGET_NAME:", lastPos)) != std::string::npos) {
-    std::string::size_type nameStartPos = pos + cmStrLen("$<TARGET_NAME:");
-    std::string::size_type endPos = input.find('>', nameStartPos);
-    if (endPos == std::string::npos) {
-      errorString = "$<TARGET_NAME:...> expression incomplete";
-      break;
-    }
-    std::string targetName = input.substr(nameStartPos, endPos - nameStartPos);
-    if (targetName.find("$<") != std::string::npos) {
-      errorString = "$<TARGET_NAME:...> requires its parameter to be a "
-                    "literal.";
-      break;
-    }
-    if (!this->AddTargetNamespace(targetName, target, lg)) {
-      errorString = "$<TARGET_NAME:...> requires its parameter to be a "
-                    "reachable target.";
-      break;
-    }
-    input.replace(pos, endPos - pos + 1, targetName);
-    lastPos = pos + targetName.size();
-  }
-
-  pos = 0;
-  lastPos = pos;
-  while (errorString.empty() &&
-         (pos = input.find("$<LINK_ONLY:", lastPos)) != std::string::npos) {
-    std::string::size_type nameStartPos = pos + cmStrLen("$<LINK_ONLY:");
-    std::string::size_type endPos = input.find('>', nameStartPos);
-    if (endPos == std::string::npos) {
-      errorString = "$<LINK_ONLY:...> expression incomplete";
-      break;
-    }
-    std::string libName = input.substr(nameStartPos, endPos - nameStartPos);
-    if (cmGeneratorExpression::IsValidTargetName(libName) &&
-        this->AddTargetNamespace(libName, target, lg)) {
-      input.replace(nameStartPos, endPos - nameStartPos, libName);
-    }
-    lastPos = nameStartPos + libName.size() + 1;
-  }
-
-  while (errorString.empty() &&
-         (pos = input.find("$<COMPILE_ONLY:", lastPos)) != std::string::npos) {
-    std::string::size_type nameStartPos = pos + cmStrLen("$<COMPILE_ONLY:");
-    std::string::size_type endPos = input.find('>', nameStartPos);
-    if (endPos == std::string::npos) {
-      errorString = "$<COMPILE_ONLY:...> expression incomplete";
-      break;
-    }
-    std::string libName = input.substr(nameStartPos, endPos - nameStartPos);
-    if (cmGeneratorExpression::IsValidTargetName(libName) &&
-        this->AddTargetNamespace(libName, target, lg)) {
-      input.replace(nameStartPos, endPos - nameStartPos, libName);
-    }
-    lastPos = nameStartPos + libName.size() + 1;
-  }
-
-  this->ReplaceInstallPrefix(input);
-
-  if (!errorString.empty()) {
-    target->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
-                                              errorString);
-  }
-}
-
-void cmExportCMakeConfigGenerator::ReplaceInstallPrefix(
-  std::string& /*unused*/)
-{
-  // Do nothing
-}
-
 void cmExportCMakeConfigGenerator::SetImportLinkInterface(
   std::string const& config, std::string const& suffix,
   cmGeneratorExpression::PreprocessContext preprocessRule,
@@ -870,131 +160,16 @@ void cmExportCMakeConfigGenerator::SetImportLinkInterface(
   }
 }
 
-void cmExportCMakeConfigGenerator::SetImportDetailProperties(
-  std::string const& config, std::string const& suffix,
-  cmGeneratorTarget* target, ImportPropertyMap& properties)
-{
-  // Get the makefile in which to lookup target information.
-  cmMakefile* mf = target->Makefile;
-
-  // Add the soname for unix shared libraries.
-  if (target->GetType() == cmStateEnums::SHARED_LIBRARY ||
-      target->GetType() == cmStateEnums::MODULE_LIBRARY) {
-    if (!target->IsDLLPlatform()) {
-      std::string prop;
-      std::string value;
-      if (target->HasSOName(config)) {
-        if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
-          value = this->InstallNameDir(target, config);
-        }
-        prop = "IMPORTED_SONAME";
-        value += target->GetSOName(config);
-      } else {
-        prop = "IMPORTED_NO_SONAME";
-        value = "TRUE";
-      }
-      prop += suffix;
-      properties[prop] = value;
-    }
-  }
-
-  // Add the transitive link dependencies for this configuration.
-  if (cmLinkInterface const* iface =
-        target->GetLinkInterface(config, target)) {
-    this->SetImportLinkProperty(
-      suffix, target, "IMPORTED_LINK_INTERFACE_LANGUAGES", iface->Languages,
-      properties, ImportLinkPropertyTargetNames::No);
-
-    // Export IMPORTED_LINK_DEPENDENT_LIBRARIES to help consuming linkers
-    // find private dependencies of shared libraries.
-    std::size_t oldMissingTargetsSize = this->MissingTargets.size();
-    auto oldExternalTargets = this->ExternalTargets;
-    this->SetImportLinkProperty(
-      suffix, target, "IMPORTED_LINK_DEPENDENT_LIBRARIES", iface->SharedDeps,
-      properties, ImportLinkPropertyTargetNames::Yes);
-    // Avoid enforcing shared library private dependencies as public package
-    // dependencies by ignoring missing targets added for them.
-    this->MissingTargets.resize(oldMissingTargetsSize);
-    this->ExternalTargets = std::move(oldExternalTargets);
-
-    if (iface->Multiplicity > 0) {
-      std::string prop =
-        cmStrCat("IMPORTED_LINK_INTERFACE_MULTIPLICITY", suffix);
-      properties[prop] = std::to_string(iface->Multiplicity);
-    }
-  }
-
-  // Add information if this target is a managed target
-  if (target->GetManagedType(config) !=
-      cmGeneratorTarget::ManagedType::Native) {
-    std::string prop = cmStrCat("IMPORTED_COMMON_LANGUAGE_RUNTIME", suffix);
-    std::string propval;
-    if (cmValue p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
-      propval = *p;
-    } else if (target->IsCSharpOnly()) {
-      // C# projects do not have the /clr flag, so we set the property
-      // here to mark the target as (only) managed (i.e. no .lib file
-      // to link to). Otherwise the  COMMON_LANGUAGE_RUNTIME target
-      // property would have to be set manually for C# targets to make
-      // exporting/importing work.
-      propval = "CSharp";
-    }
-    properties[prop] = propval;
-  }
-}
-
-static std::string const& asString(std::string const& l)
-{
-  return l;
-}
-
-static std::string const& asString(cmLinkItem const& l)
-{
-  return l.AsStr();
-}
-
-template <typename T>
-void cmExportCMakeConfigGenerator::SetImportLinkProperty(
-  std::string const& suffix, cmGeneratorTarget const* target,
-  std::string const& propName, std::vector<T> const& entries,
-  ImportPropertyMap& properties, ImportLinkPropertyTargetNames targetNames)
-{
-  // Skip the property if there are no entries.
-  if (entries.empty()) {
-    return;
-  }
-
-  cmLocalGenerator const* lg = target->GetLocalGenerator();
-
-  // Construct the property value.
-  std::string link_entries;
-  char const* sep = "";
-  for (T const& l : entries) {
-    // Separate this from the previous entry.
-    link_entries += sep;
-    sep = ";";
-
-    if (targetNames == ImportLinkPropertyTargetNames::Yes) {
-      std::string temp = asString(l);
-      this->AddTargetNamespace(temp, target, lg);
-      link_entries += temp;
-    } else {
-      link_entries += asString(l);
-    }
-  }
-
-  // Store the property.
-  std::string prop = cmStrCat(propName, suffix);
-  properties[prop] = link_entries;
-}
-
 void cmExportCMakeConfigGenerator::GeneratePolicyHeaderCode(std::ostream& os)
 {
   // Protect that file against use with older CMake versions.
   /* clang-format off */
   os << "# Generated by CMake\n\n";
   os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.8)\n"
-     << "   message(FATAL_ERROR \"CMake >= 2.8.0 required\")\n"
+     << "   message(FATAL_ERROR \"CMake >= "
+     << this->RequiredCMakeVersionMajor << '.'
+     << this->RequiredCMakeVersionMinor << '.'
+     << this->RequiredCMakeVersionPatch << " required\")\n"
      << "endif()\n"
      << "if(CMAKE_VERSION VERSION_LESS \""
      << this->RequiredCMakeVersionMajor << '.'
@@ -1010,7 +185,7 @@ void cmExportCMakeConfigGenerator::GeneratePolicyHeaderCode(std::ostream& os)
   // Isolate the file policy level.
   // Support CMake versions as far back as the
   // RequiredCMakeVersion{Major,Minor,Patch}, but also support using NEW
-  // policy settings for up to CMake 3.28 (this upper limit may be reviewed
+  // policy settings for up to CMake 3.29 (this upper limit may be reviewed
   // and increased from time to time). This reduces the opportunity for CMake
   // warnings when an older export file is later used with newer CMake
   // versions.
@@ -1019,7 +194,7 @@ void cmExportCMakeConfigGenerator::GeneratePolicyHeaderCode(std::ostream& os)
      << "cmake_policy(VERSION "
      << this->RequiredCMakeVersionMajor << '.'
      << this->RequiredCMakeVersionMinor << '.'
-     << this->RequiredCMakeVersionPatch << "...3.28)\n";
+     << this->RequiredCMakeVersionPatch << "...3.29)\n";
   /* clang-format on */
 }
 
@@ -1162,8 +337,7 @@ void cmExportCMakeConfigGenerator::GenerateImportTargetCode(
   // generate DEPRECATION
   if (target->IsDeprecated()) {
     os << "set_property(TARGET " << targetName << " PROPERTY DEPRECATION "
-       << cmExportCMakeConfigGeneratorEscape(target->GetDeprecation())
-       << ")\n";
+       << cmExportFileGeneratorEscape(target->GetDeprecation()) << ")\n";
   }
 
   if (target->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
@@ -1205,7 +379,7 @@ void cmExportCMakeConfigGenerator::GenerateImportPropertyCode(
     if (importedXcFrameworkLocation.empty() ||
         property.first != importedLocationProp) {
       os << "  " << property.first << " "
-         << cmExportCMakeConfigGeneratorEscape(property.second) << "\n";
+         << cmExportFileGeneratorEscape(property.second) << "\n";
     }
   }
   os << "  )\n";
@@ -1213,14 +387,14 @@ void cmExportCMakeConfigGenerator::GenerateImportPropertyCode(
     auto importedLocationIt = properties.find(importedLocationProp);
     if (importedLocationIt != properties.end()) {
       os << "if(NOT CMAKE_VERSION VERSION_LESS \"3.28\" AND IS_DIRECTORY "
-         << cmExportCMakeConfigGeneratorEscape(importedXcFrameworkLocation)
+         << cmExportFileGeneratorEscape(importedXcFrameworkLocation)
          << ")\n"
             "  set_property(TARGET "
          << targetName << " PROPERTY " << importedLocationProp << " "
-         << cmExportCMakeConfigGeneratorEscape(importedXcFrameworkLocation)
+         << cmExportFileGeneratorEscape(importedXcFrameworkLocation)
          << ")\nelse()\n  set_property(TARGET " << targetName << " PROPERTY "
          << importedLocationProp << " "
-         << cmExportCMakeConfigGeneratorEscape(importedLocationIt->second)
+         << cmExportFileGeneratorEscape(importedLocationIt->second)
          << ")\nendif()\n";
     }
   }
@@ -1389,7 +563,7 @@ void cmExportCMakeConfigGenerator::GenerateImportedFileCheckLoop(
 }
 
 void cmExportCMakeConfigGenerator::GenerateImportedFileChecksCode(
-  std::ostream& os, cmGeneratorTarget* target,
+  std::ostream& os, cmGeneratorTarget const* target,
   ImportPropertyMap const& properties,
   std::set<std::string> const& importedLocations,
   std::string const& importedXcFrameworkLocation)
@@ -1400,193 +574,22 @@ void cmExportCMakeConfigGenerator::GenerateImportedFileChecksCode(
   os << "list(APPEND _cmake_import_check_targets " << targetName << " )\n";
   if (!importedXcFrameworkLocation.empty()) {
     os << "set(_cmake_import_check_xcframework_for_" << targetName << ' '
-       << cmExportCMakeConfigGeneratorEscape(importedXcFrameworkLocation)
-       << ")\n";
+       << cmExportFileGeneratorEscape(importedXcFrameworkLocation) << ")\n";
   }
   os << "list(APPEND _cmake_import_check_files_for_" << targetName << " ";
 
   for (std::string const& li : importedLocations) {
     auto pi = properties.find(li);
     if (pi != properties.end()) {
-      os << cmExportCMakeConfigGeneratorEscape(pi->second) << " ";
+      os << cmExportFileGeneratorEscape(pi->second) << " ";
     }
   }
 
   os << ")\n\n";
 }
 
-enum class ExportWhen
-{
-  Defined,
-  Always,
-};
-
-enum class PropertyType
-{
-  Strings,
-  Paths,
-  IncludePaths,
-};
-
-namespace {
-bool PropertyTypeIsForPaths(PropertyType pt)
-{
-  switch (pt) {
-    case PropertyType::Strings:
-      return false;
-    case PropertyType::Paths:
-    case PropertyType::IncludePaths:
-      return true;
-  }
-  return false;
-}
-}
-
-struct ModuleTargetPropertyTable
-{
-  cm::static_string_view Name;
-  ExportWhen Cond;
-};
-
-struct ModulePropertyTable
-{
-  cm::static_string_view Name;
-  PropertyType Type;
-};
-
-bool cmExportCMakeConfigGenerator::PopulateCxxModuleExportProperties(
-  cmGeneratorTarget const* gte, ImportPropertyMap& properties,
-  cmGeneratorExpression::PreprocessContext ctx,
-  std::string const& includesDestinationDirs, std::string& errorMessage)
-{
-  if (!gte->HaveCxx20ModuleSources(&errorMessage)) {
-    return true;
-  }
-
-  ModuleTargetPropertyTable const exportedDirectModuleProperties[] = {
-    { "CXX_EXTENSIONS"_s, ExportWhen::Defined },
-    // Always define this property as it is an intrinsic property of the target
-    // and should not be inherited from the in-scope `CMAKE_CXX_MODULE_STD`
-    // variable.
-    //
-    // TODO(cxxmodules): A future policy may make this "ON" based on the target
-    // policies if unset. Add a new `ExportWhen` condition to handle it when
-    // this happens.
-    { "CXX_MODULE_STD"_s, ExportWhen::Always },
-  };
-  for (auto const& prop : exportedDirectModuleProperties) {
-    auto const propNameStr = std::string(prop.Name);
-    cmValue propValue = gte->Target->GetComputedProperty(
-      propNameStr, *gte->Target->GetMakefile());
-    if (!propValue) {
-      propValue = gte->Target->GetProperty(propNameStr);
-    }
-    if (propValue) {
-      properties[propNameStr] =
-        cmGeneratorExpression::Preprocess(*propValue, ctx);
-    } else if (prop.Cond == ExportWhen::Always) {
-      properties[propNameStr] = "";
-    }
-  }
-
-  ModulePropertyTable const exportedModuleProperties[] = {
-    { "INCLUDE_DIRECTORIES"_s, PropertyType::IncludePaths },
-    { "COMPILE_DEFINITIONS"_s, PropertyType::Strings },
-    { "COMPILE_OPTIONS"_s, PropertyType::Strings },
-    { "COMPILE_FEATURES"_s, PropertyType::Strings },
-  };
-  for (auto const& propEntry : exportedModuleProperties) {
-    auto const propNameStr = std::string(propEntry.Name);
-    cmValue prop = gte->Target->GetComputedProperty(
-      propNameStr, *gte->Target->GetMakefile());
-    if (!prop) {
-      prop = gte->Target->GetProperty(propNameStr);
-    }
-    if (prop) {
-      auto const exportedPropName =
-        cmStrCat("IMPORTED_CXX_MODULES_", propEntry.Name);
-      properties[exportedPropName] =
-        cmGeneratorExpression::Preprocess(*prop, ctx);
-      if (ctx == cmGeneratorExpression::InstallInterface &&
-          PropertyTypeIsForPaths(propEntry.Type)) {
-        this->ReplaceInstallPrefix(properties[exportedPropName]);
-        prefixItems(properties[exportedPropName]);
-        if (propEntry.Type == PropertyType::IncludePaths &&
-            !includesDestinationDirs.empty()) {
-          if (!properties[exportedPropName].empty()) {
-            properties[exportedPropName] += ';';
-          }
-          properties[exportedPropName] += includesDestinationDirs;
-        }
-      }
-    }
-  }
-
-  cm::static_string_view const exportedLinkModuleProperties[] = {
-    "LINK_LIBRARIES"_s,
-  };
-  for (auto const& propName : exportedLinkModuleProperties) {
-    auto const propNameStr = std::string(propName);
-    cmValue prop = gte->Target->GetComputedProperty(
-      propNameStr, *gte->Target->GetMakefile());
-    if (!prop) {
-      prop = gte->Target->GetProperty(propNameStr);
-    }
-    if (prop) {
-      auto const exportedPropName =
-        cmStrCat("IMPORTED_CXX_MODULES_", propName);
-      auto value = cmGeneratorExpression::Preprocess(*prop, ctx);
-      this->ResolveTargetsInGeneratorExpressions(
-        value, gte, cmExportCMakeConfigGenerator::ReplaceFreeTargets);
-      properties[exportedPropName] = value;
-    }
-  }
-
-  return true;
-}
-
-bool cmExportCMakeConfigGenerator::PopulateExportProperties(
-  cmGeneratorTarget const* gte, ImportPropertyMap& properties,
-  std::string& errorMessage)
-{
-  auto const& targetProperties = gte->Target->GetProperties();
-  if (cmValue exportProperties =
-        targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) {
-    for (auto& prop : cmList{ *exportProperties }) {
-      /* Black list reserved properties */
-      if (cmHasLiteralPrefix(prop, "IMPORTED_") ||
-          cmHasLiteralPrefix(prop, "INTERFACE_")) {
-        std::ostringstream e;
-        e << "Target \"" << gte->Target->GetName() << "\" contains property \""
-          << prop << "\" in EXPORT_PROPERTIES but IMPORTED_* and INTERFACE_* "
-          << "properties are reserved.";
-        errorMessage = e.str();
-        return false;
-      }
-      cmValue propertyValue = targetProperties.GetPropertyValue(prop);
-      if (!propertyValue) {
-        // Asked to export a property that isn't defined on the target. Do not
-        // consider this an error, there's just nothing to export.
-        continue;
-      }
-      std::string evaluatedValue = cmGeneratorExpression::Preprocess(
-        *propertyValue, cmGeneratorExpression::StripAllGeneratorExpressions);
-      if (evaluatedValue != *propertyValue) {
-        std::ostringstream e;
-        e << "Target \"" << gte->Target->GetName() << "\" contains property \""
-          << prop << "\" in EXPORT_PROPERTIES but this property contains a "
-          << "generator expression. This is not allowed.";
-        errorMessage = e.str();
-        return false;
-      }
-      properties[prop] = *propertyValue;
-    }
-  }
-  return true;
-}
-
 void cmExportCMakeConfigGenerator::GenerateTargetFileSets(
-  cmGeneratorTarget* gte, std::ostream& os, cmTargetExport* te)
+  cmGeneratorTarget* gte, std::ostream& os, cmTargetExport const* te)
 {
   auto interfaceFileSets = gte->Target->GetAllInterfaceFileSets();
   if (!interfaceFileSets.empty()) {

+ 21 - 176
Source/cmExportCMakeConfigGenerator.h

@@ -8,73 +8,45 @@
 #include <map>
 #include <set>
 #include <string>
-#include <vector>
 
+#include <cm/string_view>
+
+#include "cmExportFileGenerator.h"
 #include "cmGeneratorExpression.h"
 #include "cmStateTypes.h"
-#include "cmVersion.h"
-#include "cmVersionConfig.h"
 
-class cmExportSet;
 class cmFileSet;
 class cmGeneratorTarget;
-class cmLocalGenerator;
 class cmTargetExport;
 
-#define STRINGIFY_HELPER(X) #X
-#define STRINGIFY(X) STRINGIFY_HELPER(X)
-
-#define DEVEL_CMAKE_VERSION(major, minor)                                     \
-  (CMake_VERSION_ENCODE(major, minor, 0) >                                    \
-       CMake_VERSION_ENCODE(CMake_VERSION_MAJOR, CMake_VERSION_MINOR, 0)      \
-     ? STRINGIFY(CMake_VERSION_MAJOR) "." STRINGIFY(                          \
-         CMake_VERSION_MINOR) "." STRINGIFY(CMake_VERSION_PATCH)              \
-     : #major "." #minor ".0")
-
 /** \class cmExportCMakeConfigGenerator
- * \brief Generate a file exporting targets from a build or install tree.
+ * \brief Generate CMake configuration files exporting targets from a build or
+ * install tree.
  *
  * cmExportCMakeConfigGenerator is the superclass for
- * cmExportBuildFileGenerator and cmExportInstallFileGenerator.  It
- * contains common code generation routines for the two kinds of
- * export implementations.
+ * cmExportBuildCMakeConfigGenerator and cmExportInstallCMakeConfigGenerator.
+ * It contains common code generation routines for the two kinds of export
+ * implementations.
  */
-class cmExportCMakeConfigGenerator
+class cmExportCMakeConfigGenerator : virtual public cmExportFileGenerator
 {
 public:
   cmExportCMakeConfigGenerator();
-  virtual ~cmExportCMakeConfigGenerator() = default;
-
-  /** Set the full path to the export file to generate.  */
-  void SetExportFile(char const* mainFile);
-  std::string const& GetMainExportFileName() const;
-
-  /** Set the namespace in which to place exported target names.  */
-  void SetNamespace(std::string const& ns) { this->Namespace = ns; }
-  std::string GetNamespace() const { return this->Namespace; }
 
   void SetExportOld(bool exportOld) { this->ExportOld = exportOld; }
 
-  /** Add a configuration to be exported.  */
-  void AddConfiguration(std::string const& config);
-
-  /** Actually generate the export file.  Returns whether there was an
-      error.  */
-  bool GenerateImportFile();
-
   void SetExportPackageDependencies(bool exportPackageDependencies)
   {
     this->ExportPackageDependencies = exportPackageDependencies;
   }
 
+  using cmExportFileGenerator::GenerateImportFile;
+
 protected:
   using ImportPropertyMap = std::map<std::string, std::string>;
 
-  // Generate per-configuration target information to the given output
-  // stream.
-  void GenerateImportConfig(std::ostream& os, std::string const& config);
-
   // Methods to implement export file code generation.
+  bool GenerateImportFile(std::ostream& os) override;
   virtual void GeneratePolicyHeaderCode(std::ostream& os);
   virtual void GeneratePolicyFooterCode(std::ostream& os);
   virtual void GenerateImportHeaderCode(std::ostream& os,
@@ -89,7 +61,7 @@ protected:
     cmGeneratorTarget const* target, ImportPropertyMap const& properties,
     std::string const& importedXcFrameworkLocation);
   virtual void GenerateImportedFileChecksCode(
-    std::ostream& os, cmGeneratorTarget* target,
+    std::ostream& os, cmGeneratorTarget const* target,
     ImportPropertyMap const& properties,
     std::set<std::string> const& importedLocations,
     std::string const& importedXcFrameworkLocation);
@@ -100,165 +72,38 @@ protected:
   virtual void GenerateExpectedTargetsCode(std::ostream& os,
                                            std::string const& expectedTargets);
 
-  // Collect properties with detailed information about targets beyond
-  // their location on disk.
-  void SetImportDetailProperties(std::string const& config,
-                                 std::string const& suffix,
-                                 cmGeneratorTarget* target,
-                                 ImportPropertyMap& properties);
-
-  enum class ImportLinkPropertyTargetNames
-  {
-    Yes,
-    No,
-  };
-  template <typename T>
-  void SetImportLinkProperty(std::string const& suffix,
-                             cmGeneratorTarget const* target,
-                             std::string const& propName,
-                             std::vector<T> const& entries,
-                             ImportPropertyMap& properties,
-                             ImportLinkPropertyTargetNames targetNames);
-
-  /** Each subclass knows how to generate its kind of export file.  */
-  virtual bool GenerateMainFile(std::ostream& os) = 0;
-
-  /** Each subclass knows where the target files are located.  */
-  virtual void GenerateImportTargetsConfig(std::ostream& os,
-                                           std::string const& config,
-                                           std::string const& suffix) = 0;
+  cm::string_view GetImportPrefixWithSlash() const override;
 
-  /** Each subclass knows how to deal with a target that is  missing from an
-   *  export set.  */
-  virtual void HandleMissingTarget(std::string& link_libs,
-                                   cmGeneratorTarget const* depender,
-                                   cmGeneratorTarget* dependee) = 0;
-  void PopulateInterfaceProperty(std::string const&,
-                                 cmGeneratorTarget const* target,
-                                 cmGeneratorExpression::PreprocessContext,
-                                 ImportPropertyMap& properties);
-  bool PopulateInterfaceLinkLibrariesProperty(
-    cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext,
-    ImportPropertyMap& properties);
-  void PopulateInterfaceProperty(std::string const& propName,
-                                 cmGeneratorTarget const* target,
-                                 ImportPropertyMap& properties);
-  void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target,
-                                             ImportPropertyMap& properties);
-  void PopulateCustomTransitiveInterfaceProperties(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties);
   virtual void GenerateInterfaceProperties(
     cmGeneratorTarget const* target, std::ostream& os,
     ImportPropertyMap const& properties);
-  void PopulateIncludeDirectoriesInterface(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties, cmTargetExport const& te,
-    std::string& includesDestinationDirs);
-  void PopulateSourcesInterface(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties);
-  void PopulateLinkDirectoriesInterface(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties);
-  void PopulateLinkDependsInterface(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties);
 
   void SetImportLinkInterface(
     std::string const& config, std::string const& suffix,
     cmGeneratorExpression::PreprocessContext preprocessRule,
     cmGeneratorTarget const* target, ImportPropertyMap& properties);
 
-  enum FreeTargetsReplace
-  {
-    ReplaceFreeTargets,
-    NoReplaceFreeTargets
-  };
-
-  void ResolveTargetsInGeneratorExpressions(
-    std::string& input, cmGeneratorTarget const* target,
-    FreeTargetsReplace replace = NoReplaceFreeTargets);
-
-  bool PopulateCxxModuleExportProperties(
-    cmGeneratorTarget const* gte, ImportPropertyMap& properties,
-    cmGeneratorExpression::PreprocessContext ctx,
-    std::string const& includesDestinationDirs, std::string& errorMessage);
-  bool PopulateExportProperties(cmGeneratorTarget const* gte,
-                                ImportPropertyMap& properties,
-                                std::string& errorMessage);
-
   void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
-                              cmTargetExport* te = nullptr);
+                              cmTargetExport const* te = nullptr);
+
+  std::string GetCxxModuleFile(std::string const& name) const override;
 
   void GenerateCxxModuleInformation(std::string const& name, std::ostream& os);
 
   virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
                                             cmFileSet* fileSet,
-                                            cmTargetExport* te) = 0;
+                                            cmTargetExport const* te) = 0;
   virtual std::string GetFileSetFiles(cmGeneratorTarget* gte,
                                       cmFileSet* fileSet,
-                                      cmTargetExport* te) = 0;
-
-  virtual cmExportSet* GetExportSet() const { return nullptr; }
-
-  std::string GetCxxModuleFile(std::string const& name) const;
+                                      cmTargetExport const* te) = 0;
 
   void SetRequiredCMakeVersion(unsigned int major, unsigned int minor,
                                unsigned int patch);
 
-  // The namespace in which the exports are placed in the generated file.
-  std::string Namespace;
-
-  bool ExportOld;
-
-  // The set of configurations to export.
-  std::vector<std::string> Configurations;
-
-  // The file to generate.
-  std::string MainImportFile;
-  std::string FileDir;
-  std::string FileBase;
-  std::string FileExt;
-  bool AppendMode;
-
-  // The set of targets included in the export.
-  std::set<cmGeneratorTarget*> ExportedTargets;
-
-  std::vector<std::string> MissingTargets;
-
-  std::set<cmGeneratorTarget const*> ExternalTargets;
+  bool ExportOld = false;
+  bool ExportPackageDependencies = false;
 
   unsigned int RequiredCMakeVersionMajor = 2;
   unsigned int RequiredCMakeVersionMinor = 8;
   unsigned int RequiredCMakeVersionPatch = 3;
-
-  bool ExportPackageDependencies = false;
-
-private:
-  void PopulateInterfaceProperty(std::string const&, std::string const&,
-                                 cmGeneratorTarget const* target,
-                                 cmGeneratorExpression::PreprocessContext,
-                                 ImportPropertyMap& properties);
-
-  bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target,
-                          cmLocalGenerator const* lg);
-
-  void ResolveTargetsInGeneratorExpression(std::string& input,
-                                           cmGeneratorTarget const* target,
-                                           cmLocalGenerator const* lg);
-
-  virtual void ReplaceInstallPrefix(std::string& input);
-
-  virtual std::string InstallNameDir(cmGeneratorTarget const* target,
-                                     std::string const& config) = 0;
-
-  virtual std::string GetCxxModulesDirectory() const = 0;
-  virtual void GenerateCxxModuleConfigInformation(std::string const&,
-                                                  std::ostream& os) const = 0;
 };

+ 9 - 5
Source/cmExportCommand.cxx

@@ -19,6 +19,7 @@
 #include "cmExecutionStatus.h"
 #include "cmExperimental.h"
 #include "cmExportBuildAndroidMKGenerator.h"
+#include "cmExportBuildCMakeConfigGenerator.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExportSet.h"
 #include "cmGeneratedFileStream.h"
@@ -318,21 +319,24 @@ bool cmExportCommand(std::vector<std::string> const& args,
   // Setup export file generation.
   std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
   if (android) {
-    ebfg = cm::make_unique<cmExportBuildAndroidMKGenerator>();
+    auto ebag = cm::make_unique<cmExportBuildAndroidMKGenerator>();
+    ebag->SetAppendMode(arguments.Append);
+    ebfg = std::move(ebag);
   } else {
-    ebfg = cm::make_unique<cmExportBuildFileGenerator>();
+    auto ebcg = cm::make_unique<cmExportBuildCMakeConfigGenerator>();
+    ebcg->SetAppendMode(arguments.Append);
+    ebcg->SetExportOld(arguments.ExportOld);
+    ebcg->SetExportPackageDependencies(arguments.ExportPackageDependencies);
+    ebfg = std::move(ebcg);
   }
   ebfg->SetExportFile(fname.c_str());
   ebfg->SetNamespace(arguments.Namespace);
   ebfg->SetCxxModuleDirectory(arguments.CxxModulesDirectory);
-  ebfg->SetAppendMode(arguments.Append);
   if (exportSet != nullptr) {
     ebfg->SetExportSet(exportSet);
   } else {
     ebfg->SetTargets(targets);
   }
-  ebfg->SetExportOld(arguments.ExportOld);
-  ebfg->SetExportPackageDependencies(arguments.ExportPackageDependencies);
 
   // Compute the set of configurations exported.
   std::vector<std::string> configurationTypes =

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 81 - 864
Source/cmExportFileGenerator.cxx


+ 69 - 123
Source/cmExportFileGenerator.h

@@ -10,16 +10,13 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmGeneratorExpression.h"
-#include "cmStateTypes.h"
-#include "cmVersion.h"
-#include "cmVersionConfig.h"
 
 class cmExportSet;
-class cmFileSet;
 class cmGeneratorTarget;
 class cmLocalGenerator;
-class cmTargetExport;
 
 #define STRINGIFY_HELPER(X) #X
 #define STRINGIFY(X) STRINGIFY_HELPER(X)
@@ -32,12 +29,9 @@ class cmTargetExport;
      : #major "." #minor ".0")
 
 /** \class cmExportFileGenerator
- * \brief Generate a file exporting targets from a build or install tree.
+ * \brief Generate files exporting targets from a build or install tree.
  *
- * cmExportFileGenerator is the superclass for
- * cmExportBuildFileGenerator and cmExportInstallFileGenerator.  It
- * contains common code generation routines for the two kinds of
- * export implementations.
+ * cmExportFileGenerator is the interface class for generating export files.
  */
 class cmExportFileGenerator
 {
@@ -53,58 +47,21 @@ public:
   void SetNamespace(std::string const& ns) { this->Namespace = ns; }
   std::string GetNamespace() const { return this->Namespace; }
 
-  void SetExportOld(bool exportOld) { this->ExportOld = exportOld; }
-
   /** Add a configuration to be exported.  */
   void AddConfiguration(std::string const& config);
 
-  /** Actually generate the export file.  Returns whether there was an
-      error.  */
+  /** Create and actually generate the export file.  Returns whether there was
+      an error.  */
   bool GenerateImportFile();
 
-  void SetExportPackageDependencies(bool exportPackageDependencies)
-  {
-    this->ExportPackageDependencies = exportPackageDependencies;
-  }
-
 protected:
   using ImportPropertyMap = std::map<std::string, std::string>;
 
-  // Generate per-configuration target information to the given output
-  // stream.
-  void GenerateImportConfig(std::ostream& os, std::string const& config);
-
-  // Methods to implement export file code generation.
-  virtual void GeneratePolicyHeaderCode(std::ostream& os);
-  virtual void GeneratePolicyFooterCode(std::ostream& os);
-  virtual void GenerateImportHeaderCode(std::ostream& os,
-                                        std::string const& config = "");
-  virtual void GenerateImportFooterCode(std::ostream& os);
-  void GenerateImportVersionCode(std::ostream& os);
-  virtual void GenerateImportTargetCode(std::ostream& os,
-                                        cmGeneratorTarget const* target,
-                                        cmStateEnums::TargetType targetType);
-  virtual void GenerateImportPropertyCode(
-    std::ostream& os, std::string const& config, std::string const& suffix,
-    cmGeneratorTarget const* target, ImportPropertyMap const& properties,
-    std::string const& importedXcFrameworkLocation);
-  virtual void GenerateImportedFileChecksCode(
-    std::ostream& os, cmGeneratorTarget* target,
-    ImportPropertyMap const& properties,
-    std::set<std::string> const& importedLocations,
-    std::string const& importedXcFrameworkLocation);
-  virtual void GenerateImportedFileCheckLoop(std::ostream& os);
-  virtual void GenerateMissingTargetsCheckCode(std::ostream& os);
-  virtual void GenerateFindDependencyCalls(std::ostream& os);
-
-  virtual void GenerateExpectedTargetsCode(std::ostream& os,
-                                           std::string const& expectedTargets);
-
   // Collect properties with detailed information about targets beyond
   // their location on disk.
   void SetImportDetailProperties(std::string const& config,
                                  std::string const& suffix,
-                                 cmGeneratorTarget* target,
+                                 cmGeneratorTarget const* target,
                                  ImportPropertyMap& properties);
 
   enum class ImportLinkPropertyTargetNames
@@ -120,9 +77,17 @@ protected:
                              ImportPropertyMap& properties,
                              ImportLinkPropertyTargetNames targetNames);
 
+  /** Generate the export file to the given output stream.  Returns whether
+      there was an error.  */
+  virtual bool GenerateImportFile(std::ostream& os) = 0;
+
   /** Each subclass knows how to generate its kind of export file.  */
   virtual bool GenerateMainFile(std::ostream& os) = 0;
 
+  /** Generate per-configuration target information to the given output
+      stream.  */
+  void GenerateImportConfig(std::ostream& os, std::string const& config);
+
   /** Each subclass knows where the target files are located.  */
   virtual void GenerateImportTargetsConfig(std::ostream& os,
                                            std::string const& config,
@@ -133,47 +98,33 @@ protected:
   virtual void HandleMissingTarget(std::string& link_libs,
                                    cmGeneratorTarget const* depender,
                                    cmGeneratorTarget* dependee) = 0;
-  void PopulateInterfaceProperty(std::string const&,
+
+  /** Complain when a duplicate target is encountered.  */
+  virtual void ComplainAboutDuplicateTarget(
+    std::string const& targetName) const = 0;
+
+  virtual cm::string_view GetImportPrefixWithSlash() const = 0;
+
+  void AddImportPrefix(std::string& exportDirs) const;
+
+  void PopulateInterfaceProperty(std::string const& propName,
+                                 cmGeneratorTarget const* target,
+                                 ImportPropertyMap& properties) const;
+  void PopulateInterfaceProperty(std::string const& propName,
                                  cmGeneratorTarget const* target,
                                  cmGeneratorExpression::PreprocessContext,
                                  ImportPropertyMap& properties);
   bool PopulateInterfaceLinkLibrariesProperty(
     cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext,
     ImportPropertyMap& properties);
-  void PopulateInterfaceProperty(std::string const& propName,
-                                 cmGeneratorTarget const* target,
-                                 ImportPropertyMap& properties);
-  void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target,
-                                             ImportPropertyMap& properties);
-  void PopulateCustomTransitiveInterfaceProperties(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties);
-  virtual void GenerateInterfaceProperties(
-    cmGeneratorTarget const* target, std::ostream& os,
-    ImportPropertyMap const& properties);
-  void PopulateIncludeDirectoriesInterface(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties, cmTargetExport const& te,
-    std::string& includesDestinationDirs);
-  void PopulateSourcesInterface(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties);
-  void PopulateLinkDirectoriesInterface(
-    cmGeneratorTarget const* target,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    ImportPropertyMap& properties);
-  void PopulateLinkDependsInterface(
+
+  bool PopulateInterfaceProperties(
     cmGeneratorTarget const* target,
+    std::string const& includesDestinationDirs,
     cmGeneratorExpression::PreprocessContext preprocessRule,
     ImportPropertyMap& properties);
 
-  void SetImportLinkInterface(
-    std::string const& config, std::string const& suffix,
-    cmGeneratorExpression::PreprocessContext preprocessRule,
-    cmGeneratorTarget const* target, ImportPropertyMap& properties);
+  virtual void ReportError(std::string const& errorMessage) const = 0;
 
   enum FreeTargetsReplace
   {
@@ -185,38 +136,26 @@ protected:
     std::string& input, cmGeneratorTarget const* target,
     FreeTargetsReplace replace = NoReplaceFreeTargets);
 
-  bool PopulateCxxModuleExportProperties(
-    cmGeneratorTarget const* gte, ImportPropertyMap& properties,
-    cmGeneratorExpression::PreprocessContext ctx,
-    std::string const& includesDestinationDirs, std::string& errorMessage);
-  bool PopulateExportProperties(cmGeneratorTarget const* gte,
-                                ImportPropertyMap& properties,
-                                std::string& errorMessage);
-
-  void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
-                              cmTargetExport* te = nullptr);
+  virtual cmExportSet* GetExportSet() const { return nullptr; }
 
-  void GenerateCxxModuleInformation(std::string const& name, std::ostream& os);
+  virtual void ReplaceInstallPrefix(std::string& input) const;
 
-  virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
-                                            cmFileSet* fileSet,
-                                            cmTargetExport* te) = 0;
-  virtual std::string GetFileSetFiles(cmGeneratorTarget* gte,
-                                      cmFileSet* fileSet,
-                                      cmTargetExport* te) = 0;
+  virtual std::string InstallNameDir(cmGeneratorTarget const* target,
+                                     std::string const& config) = 0;
 
-  virtual cmExportSet* GetExportSet() const { return nullptr; }
+  /** Get the temporary location of the config-agnostic C++ module file.  */
+  virtual std::string GetCxxModuleFile(std::string const& name) const = 0;
 
-  std::string GetCxxModuleFile(std::string const& name) const;
+  virtual std::string GetCxxModulesDirectory() const = 0;
+  virtual void GenerateCxxModuleConfigInformation(std::string const&,
+                                                  std::ostream& os) const = 0;
 
-  void SetRequiredCMakeVersion(unsigned int major, unsigned int minor,
-                               unsigned int patch);
+  bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target,
+                          cmLocalGenerator const* lg);
 
   // The namespace in which the exports are placed in the generated file.
   std::string Namespace;
 
-  bool ExportOld;
-
   // The set of configurations to export.
   std::vector<std::string> Configurations;
 
@@ -225,40 +164,47 @@ protected:
   std::string FileDir;
   std::string FileBase;
   std::string FileExt;
-  bool AppendMode;
+  bool AppendMode = false;
 
   // The set of targets included in the export.
-  std::set<cmGeneratorTarget*> ExportedTargets;
+  std::set<cmGeneratorTarget const*> ExportedTargets;
 
   std::vector<std::string> MissingTargets;
 
   std::set<cmGeneratorTarget const*> ExternalTargets;
 
-  unsigned int RequiredCMakeVersionMajor = 2;
-  unsigned int RequiredCMakeVersionMinor = 8;
-  unsigned int RequiredCMakeVersionPatch = 3;
-
-  bool ExportPackageDependencies = false;
-
 private:
-  void PopulateInterfaceProperty(std::string const&, std::string const&,
+  void PopulateInterfaceProperty(std::string const& propName,
+                                 std::string const& outputName,
                                  cmGeneratorTarget const* target,
                                  cmGeneratorExpression::PreprocessContext,
                                  ImportPropertyMap& properties);
 
-  bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target,
-                          cmLocalGenerator const* lg);
+  void PopulateCompatibleInterfaceProperties(
+    cmGeneratorTarget const* target, ImportPropertyMap& properties) const;
+  void PopulateCustomTransitiveInterfaceProperties(
+    cmGeneratorTarget const* target,
+    cmGeneratorExpression::PreprocessContext preprocessRule,
+    ImportPropertyMap& properties);
+  bool PopulateCxxModuleExportProperties(
+    cmGeneratorTarget const* gte, ImportPropertyMap& properties,
+    cmGeneratorExpression::PreprocessContext ctx,
+    std::string const& includesDestinationDirs, std::string& errorMessage);
+  bool PopulateExportProperties(cmGeneratorTarget const* gte,
+                                ImportPropertyMap& properties,
+                                std::string& errorMessage) const;
 
   void ResolveTargetsInGeneratorExpression(std::string& input,
                                            cmGeneratorTarget const* target,
                                            cmLocalGenerator const* lg);
+};
 
-  virtual void ReplaceInstallPrefix(std::string& input);
-
-  virtual std::string InstallNameDir(cmGeneratorTarget const* target,
-                                     std::string const& config) = 0;
+extern template void cmExportFileGenerator::SetImportLinkProperty<std::string>(
+  std::string const&, cmGeneratorTarget const*, std::string const&,
+  std::vector<std::string> const&, ImportPropertyMap& properties,
+  ImportLinkPropertyTargetNames);
 
-  virtual std::string GetCxxModulesDirectory() const = 0;
-  virtual void GenerateCxxModuleConfigInformation(std::string const&,
-                                                  std::ostream& os) const = 0;
-};
+extern template void cmExportFileGenerator::SetImportLinkProperty<cmLinkItem>(
+  std::string const&, cmGeneratorTarget const*, std::string const&,
+  std::vector<cmLinkItem> const&, ImportPropertyMap& properties,
+  ImportLinkPropertyTargetNames);

+ 50 - 64
Source/cmExportInstallAndroidMKGenerator.cxx

@@ -4,14 +4,15 @@
 
 #include <cstddef>
 #include <memory>
-#include <ostream>
+#include <sstream>
 #include <vector>
 
-#include "cmExportBuildAndroidMKGenerator.h"
 #include "cmExportSet.h"
+#include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmInstallExportGenerator.h"
 #include "cmInstallTargetGenerator.h"
+#include "cmPolicies.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -24,6 +25,53 @@ cmExportInstallAndroidMKGenerator::cmExportInstallAndroidMKGenerator(
 {
 }
 
+void cmExportInstallAndroidMKGenerator::ReportDuplicateTarget(
+  std::string const& targetName) const
+{
+  std::ostringstream e;
+  e << "install(EXPORT_ANDROID_MK \"" << this->GetExportSet()->GetName()
+    << "\" ...) "
+    << "includes target \"" << targetName
+    << "\" more than once in the export set.";
+  this->ReportError(e.str());
+}
+
+bool cmExportInstallAndroidMKGenerator::GenerateMainFile(std::ostream& os)
+{
+  std::vector<cmTargetExport const*> allTargets;
+  {
+    auto visitor = [&](cmTargetExport const* te) { allTargets.push_back(te); };
+
+    if (!this->CollectExports(visitor)) {
+      return false;
+    }
+  }
+
+  // Create all the imported targets.
+  for (cmTargetExport const* te : allTargets) {
+    cmGeneratorTarget const* gt = te->Target;
+
+    this->GenerateImportTargetCode(os, gt, this->GetExportTargetType(te));
+
+    ImportPropertyMap properties;
+    if (!this->PopulateInterfaceProperties(te, properties)) {
+      return false;
+    }
+
+    bool const newCMP0022Behavior =
+      gt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
+      gt->GetPolicyStatusCMP0022() != cmPolicies::OLD;
+    if (newCMP0022Behavior) {
+      this->PopulateInterfaceLinkLibrariesProperty(
+        gt, cmGeneratorExpression::InstallInterface, properties);
+    }
+
+    this->GenerateInterfaceProperties(gt, os, properties);
+  }
+
+  return true;
+}
+
 void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode(
   std::ostream& os, std::string const&)
 {
@@ -53,10 +101,6 @@ void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode(
   }
 }
 
-void cmExportInstallAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
-{
-}
-
 void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode(
   std::ostream& os, cmGeneratorTarget const* target,
   cmStateEnums::TargetType /*targetType*/)
@@ -73,61 +117,3 @@ void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode(
   }
   os << target->GetFullName(config) << "\n";
 }
-
-void cmExportInstallAndroidMKGenerator::GenerateExpectedTargetsCode(
-  std::ostream&, std::string const&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateImportPropertyCode(
-  std::ostream&, std::string const&, std::string const&,
-  cmGeneratorTarget const*, ImportPropertyMap const&, std::string const&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateMissingTargetsCheckCode(
-  std::ostream&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateInterfaceProperties(
-  cmGeneratorTarget const* target, std::ostream& os,
-  ImportPropertyMap const& properties)
-{
-  std::string config;
-  if (!this->Configurations.empty()) {
-    config = this->Configurations[0];
-  }
-  cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
-    target, os, properties, cmExportBuildAndroidMKGenerator::INSTALL, config);
-}
-
-void cmExportInstallAndroidMKGenerator::LoadConfigFiles(std::ostream&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateImportPrefix(std::ostream&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::CleanupTemporaryVariables(
-  std::ostream&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateImportedFileCheckLoop(
-  std::ostream&)
-{
-}
-
-void cmExportInstallAndroidMKGenerator::GenerateImportedFileChecksCode(
-  std::ostream&, cmGeneratorTarget*, ImportPropertyMap const&,
-  std::set<std::string> const&, std::string const&)
-{
-}
-
-bool cmExportInstallAndroidMKGenerator::GenerateImportFileConfig(
-  std::string const&)
-{
-  return true;
-}

+ 29 - 31
Source/cmExportInstallAndroidMKGenerator.h

@@ -5,9 +5,10 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
-#include <set>
 #include <string>
+#include <vector>
 
+#include "cmExportAndroidMKGenerator.h"
 #include "cmExportInstallFileGenerator.h"
 #include "cmStateTypes.h"
 
@@ -15,52 +16,49 @@ class cmGeneratorTarget;
 class cmInstallExportGenerator;
 
 /** \class cmExportInstallAndroidMKGenerator
- * \brief Generate a file exporting targets from an install tree.
+ * \brief Generate files exporting targets from an install tree.
  *
  * cmExportInstallAndroidMKGenerator generates files exporting targets from
- * install an installation tree.  The files are placed in a temporary
- * location for installation by cmInstallExportGenerator.  The file format
- * is for the ndk build system and is a makefile fragment specifying prebuilt
- * libraries to the ndk build system.
+ * an installation tree.  The files are placed in a temporary location for
+ * installation by cmInstallExportGenerator.  The file format is for the ndk
+ * build system and is a makefile fragment specifying prebuilt libraries to the
+ * ndk build system.
  *
  * This is used to implement the INSTALL(EXPORT_ANDROID_MK) command.
  */
-class cmExportInstallAndroidMKGenerator : public cmExportInstallFileGenerator
+class cmExportInstallAndroidMKGenerator
+  : public cmExportAndroidMKGenerator
+  , public cmExportInstallFileGenerator
 {
 public:
   /** Construct with the export installer that will install the
       files.  */
   cmExportInstallAndroidMKGenerator(cmInstallExportGenerator* iegen);
 
+  std::string GetConfigImportFileGlob() const override { return {}; }
+
 protected:
+  GenerateType GetGenerateType() const override { return INSTALL; }
+
   // Implement virtual methods from the superclass.
-  void GeneratePolicyHeaderCode(std::ostream&) override {}
-  void GeneratePolicyFooterCode(std::ostream&) override {}
+  void ReportDuplicateTarget(std::string const& targetName) const;
+  bool GenerateMainFile(std::ostream& os) override;
   void GenerateImportHeaderCode(std::ostream& os,
                                 std::string const& config = "") override;
-  void GenerateImportFooterCode(std::ostream& os) override;
   void GenerateImportTargetCode(
     std::ostream& os, cmGeneratorTarget const* target,
     cmStateEnums::TargetType /*targetType*/) override;
-  void GenerateExpectedTargetsCode(
-    std::ostream& os, std::string const& expectedTargets) override;
-  void GenerateImportPropertyCode(
-    std::ostream& os, std::string const& config, std::string const& suffix,
-    cmGeneratorTarget const* target, ImportPropertyMap const& properties,
-    std::string const& importedXcFrameworkLocation) override;
-  void GenerateMissingTargetsCheckCode(std::ostream& os) override;
-  void GenerateFindDependencyCalls(std::ostream&) override {}
-  void GenerateInterfaceProperties(
-    cmGeneratorTarget const* target, std::ostream& os,
-    ImportPropertyMap const& properties) override;
-  void GenerateImportPrefix(std::ostream& os) override;
-  void LoadConfigFiles(std::ostream&) override;
-  void CleanupTemporaryVariables(std::ostream&) override;
-  void GenerateImportedFileCheckLoop(std::ostream& os) override;
-  void GenerateImportedFileChecksCode(
-    std::ostream& os, cmGeneratorTarget* target,
-    ImportPropertyMap const& properties,
-    std::set<std::string> const& importedLocations,
-    std::string const& importedXcFrameworkLocation) override;
-  bool GenerateImportFileConfig(std::string const& config) override;
+
+  void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
+                                  cmGeneratorTarget const* dependee,
+                                  std::vector<std::string> const& namespaces);
+
+  void GenerateImportTargetsConfig(std::ostream& os, std::string const& config,
+                                   std::string const& suffix) override
+  {
+    this->cmExportAndroidMKGenerator::GenerateImportTargetsConfig(os, config,
+                                                                  suffix);
+  }
+
+  std::string GetCxxModulesDirectory() const override { return {}; }
 };

+ 21 - 314
Source/cmExportInstallCMakeConfigGenerator.cxx

@@ -3,9 +3,12 @@
 #include "cmExportInstallCMakeConfigGenerator.h"
 
 #include <algorithm>
+#include <map>
 #include <memory>
+#include <set>
 #include <sstream>
 #include <utility>
+#include <vector>
 
 #include <cm/string_view>
 #include <cmext/string_view>
@@ -15,11 +18,8 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
-#include "cmGlobalGenerator.h"
 #include "cmInstallExportGenerator.h"
 #include "cmInstallFileSetGenerator.h"
-#include "cmInstallTargetGenerator.h"
-#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -28,17 +28,17 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmTarget.h"
 #include "cmTargetExport.h"
 #include "cmValue.h"
 
 cmExportInstallCMakeConfigGenerator::cmExportInstallCMakeConfigGenerator(
   cmInstallExportGenerator* iegen)
-  : IEGen(iegen)
+  : cmExportInstallFileGenerator(iegen)
 {
 }
 
 std::string cmExportInstallCMakeConfigGenerator::GetConfigImportFileGlob()
+  const
 {
   std::string glob = cmStrCat(this->FileBase, "-*", this->FileExt);
   return glob;
@@ -46,28 +46,18 @@ std::string cmExportInstallCMakeConfigGenerator::GetConfigImportFileGlob()
 
 bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
 {
-  std::vector<cmTargetExport*> allTargets;
+  std::vector<cmTargetExport const*> allTargets;
   {
     std::string expectedTargets;
     std::string sep;
-    for (std::unique_ptr<cmTargetExport> const& te :
-         this->GetExportSet()->GetTargetExports()) {
-      if (te->NamelinkOnly) {
-        continue;
-      }
+    auto visitor = [&](cmTargetExport const* te) {
+      allTargets.push_back(te);
       expectedTargets += sep + this->Namespace + te->Target->GetExportName();
       sep = " ";
-      if (this->ExportedTargets.insert(te->Target).second) {
-        allTargets.push_back(te.get());
-      } else {
-        std::ostringstream e;
-        e << "install(EXPORT \"" << this->GetExportSet()->GetName()
-          << "\" ...) "
-          << "includes target \"" << te->Target->GetName()
-          << "\" more than once in the export set.";
-        cmSystemTools::Error(e.str());
-        return false;
-      }
+    };
+
+    if (!this->CollectExports(visitor)) {
+      return false;
     }
 
     this->GenerateExpectedTargetsCode(os, expectedTargets);
@@ -78,7 +68,7 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
 
   bool requiresConfigFiles = false;
   // Create all the imported targets.
-  for (cmTargetExport* te : allTargets) {
+  for (cmTargetExport const* te : allTargets) {
     cmGeneratorTarget* gt = te->Target;
     cmStateEnums::TargetType targetType = this->GetExportTargetType(te);
 
@@ -88,52 +78,7 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
     this->GenerateImportTargetCode(os, gt, targetType);
 
     ImportPropertyMap properties;
-
-    std::string includesDestinationDirs;
-    this->PopulateIncludeDirectoriesInterface(
-      gt, cmGeneratorExpression::InstallInterface, properties, *te,
-      includesDestinationDirs);
-    this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface,
-                                   properties);
-    this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateLinkDirectoriesInterface(
-      gt, cmGeneratorExpression::InstallInterface, properties);
-    this->PopulateLinkDependsInterface(
-      gt, cmGeneratorExpression::InstallInterface, properties);
-
-    std::string errorMessage;
-    if (!this->PopulateCxxModuleExportProperties(
-          gt, properties, cmGeneratorExpression::InstallInterface,
-          includesDestinationDirs, errorMessage)) {
-      cmSystemTools::Error(errorMessage);
-      return false;
-    }
-
-    if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
-      cmSystemTools::Error(errorMessage);
+    if (!this->PopulateInterfaceProperties(te, properties)) {
       return false;
     }
 
@@ -156,13 +101,6 @@ bool cmExportInstallCMakeConfigGenerator::GenerateMainFile(std::ostream& os)
       this->SetRequiredCMakeVersion(3, 1, 0);
     }
 
-    this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt,
-                                    properties);
-
-    this->PopulateCompatibleInterfaceProperties(gt, properties);
-    this->PopulateCustomTransitiveInterfaceProperties(
-      gt, cmGeneratorExpression::InstallInterface, properties);
-
     this->GenerateInterfaceProperties(gt, os, properties);
 
     this->GenerateTargetFileSets(gt, os, te);
@@ -286,12 +224,6 @@ void cmExportInstallCMakeConfigGenerator::LoadConfigFiles(std::ostream& os)
   /* clang-format on */
 }
 
-void cmExportInstallCMakeConfigGenerator::ReplaceInstallPrefix(
-  std::string& input)
-{
-  cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}");
-}
-
 bool cmExportInstallCMakeConfigGenerator::GenerateImportFileConfig(
   std::string const& config)
 {
@@ -351,53 +283,20 @@ void cmExportInstallCMakeConfigGenerator::GenerateImportTargetsConfig(
     ImportPropertyMap properties;
     std::set<std::string> importedLocations;
 
-    this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
-                                    properties, importedLocations);
+    this->PopulateImportProperties(config, suffix, te.get(), properties,
+                                   importedLocations);
 
     // If any file location was set for the target add it to the
     // import file.
     if (!properties.empty()) {
-      // Get the rest of the target details.
-      cmGeneratorTarget* gtgt = te->Target;
-      this->SetImportDetailProperties(config, suffix, gtgt, properties);
+      cmGeneratorTarget const* const gtgt = te->Target;
+      std::string const importedXcFrameworkLocation =
+        this->GetImportXcFrameworkLocation(config, te.get());
 
       this->SetImportLinkInterface(config, suffix,
                                    cmGeneratorExpression::InstallInterface,
                                    gtgt, properties);
 
-      // TODO: PUBLIC_HEADER_LOCATION
-      // This should wait until the build feature propagation stuff
-      // is done.  Then this can be a propagated include directory.
-      // this->GenerateImportProperty(config, te->HeaderGenerator,
-      //                              properties);
-
-      // Generate code in the export file.
-      std::string importedXcFrameworkLocation = te->XcFrameworkLocation;
-      if (!importedXcFrameworkLocation.empty()) {
-        importedXcFrameworkLocation = cmGeneratorExpression::Preprocess(
-          importedXcFrameworkLocation,
-          cmGeneratorExpression::PreprocessContext::InstallInterface, true);
-        importedXcFrameworkLocation = cmGeneratorExpression::Evaluate(
-          importedXcFrameworkLocation, te->Target->GetLocalGenerator(), config,
-          te->Target, nullptr, te->Target);
-        if (!importedXcFrameworkLocation.empty() &&
-            !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation) &&
-            !cmHasLiteralPrefix(importedXcFrameworkLocation,
-                                "${_IMPORT_PREFIX}/")) {
-          importedXcFrameworkLocation =
-            cmStrCat("${_IMPORT_PREFIX}/", importedXcFrameworkLocation);
-        }
-      }
       this->GenerateImportPropertyCode(os, config, suffix, gtgt, properties,
                                        importedXcFrameworkLocation);
       this->GenerateImportedFileChecksCode(
@@ -406,193 +305,6 @@ void cmExportInstallCMakeConfigGenerator::GenerateImportTargetsConfig(
   }
 }
 
-void cmExportInstallCMakeConfigGenerator::SetImportLocationProperty(
-  std::string const& config, std::string const& suffix,
-  cmInstallTargetGenerator* itgen, ImportPropertyMap& properties,
-  std::set<std::string>& importedLocations)
-{
-  // Skip rules that do not match this configuration.
-  if (!(itgen && itgen->InstallsForConfig(config))) {
-    return;
-  }
-
-  // Get the target to be installed.
-  cmGeneratorTarget* target = itgen->GetTarget();
-
-  // Construct the installed location of the target.
-  std::string dest = itgen->GetDestination(config);
-  std::string value;
-  if (!cmSystemTools::FileIsFullPath(dest)) {
-    // The target is installed relative to the installation prefix.
-    value = "${_IMPORT_PREFIX}/";
-  }
-  value += dest;
-  value += "/";
-
-  if (itgen->IsImportLibrary()) {
-    // Construct the property name.
-    std::string prop = cmStrCat("IMPORTED_IMPLIB", suffix);
-
-    // Append the installed file name.
-    value += cmInstallTargetGenerator::GetInstallFilename(
-      target, config, cmInstallTargetGenerator::NameImplibReal);
-
-    // Store the property.
-    properties[prop] = value;
-    importedLocations.insert(prop);
-  } else if (itgen->GetTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
-    // Construct the property name.
-    std::string prop = cmStrCat("IMPORTED_OBJECTS", suffix);
-
-    // Compute all the object files inside this target and setup
-    // IMPORTED_OBJECTS as a list of object files
-    std::vector<std::string> objects;
-    itgen->GetInstallObjectNames(config, objects);
-    for (std::string& obj : objects) {
-      obj = cmStrCat(value, obj);
-    }
-
-    // Store the property.
-    properties[prop] = cmList::to_string(objects);
-    importedLocations.insert(prop);
-  } else {
-    if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) {
-      // store as well IMPLIB value
-      auto importProp = cmStrCat("IMPORTED_IMPLIB", suffix);
-      auto importValue =
-        cmStrCat(value,
-                 cmInstallTargetGenerator::GetInstallFilename(
-                   target, config, cmInstallTargetGenerator::NameImplibReal));
-
-      // Store the property.
-      properties[importProp] = importValue;
-      importedLocations.insert(importProp);
-    }
-
-    // Construct the property name.
-    std::string prop = cmStrCat("IMPORTED_LOCATION", suffix);
-
-    // Append the installed file name.
-    if (target->IsAppBundleOnApple()) {
-      value += cmInstallTargetGenerator::GetInstallFilename(target, config);
-      value += ".app/";
-      if (!target->Makefile->PlatformIsAppleEmbedded()) {
-        value += "Contents/MacOS/";
-      }
-      value += cmInstallTargetGenerator::GetInstallFilename(target, config);
-    } else {
-      value += cmInstallTargetGenerator::GetInstallFilename(
-        target, config, cmInstallTargetGenerator::NameReal);
-    }
-
-    // Store the property.
-    properties[prop] = value;
-    importedLocations.insert(prop);
-  }
-}
-
-cmStateEnums::TargetType
-cmExportInstallCMakeConfigGenerator::GetExportTargetType(
-  cmTargetExport const* targetExport) const
-{
-  cmStateEnums::TargetType targetType = targetExport->Target->GetType();
-  // An OBJECT library installed with no OBJECTS DESTINATION
-  // is transformed to an INTERFACE library.
-  if (targetType == cmStateEnums::OBJECT_LIBRARY &&
-      targetExport->ObjectsGenerator == nullptr) {
-    targetType = cmStateEnums::INTERFACE_LIBRARY;
-  }
-  return targetType;
-}
-
-void cmExportInstallCMakeConfigGenerator::HandleMissingTarget(
-  std::string& link_libs, cmGeneratorTarget const* depender,
-  cmGeneratorTarget* dependee)
-{
-  std::string const name = dependee->GetName();
-  cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator();
-  auto exportInfo = this->FindNamespaces(gg, name);
-  std::vector<std::string> const& exportFiles = exportInfo.first;
-  if (exportFiles.size() == 1) {
-    std::string missingTarget = exportInfo.second;
-
-    missingTarget += dependee->GetExportName();
-    link_libs += missingTarget;
-    this->MissingTargets.emplace_back(std::move(missingTarget));
-  } else {
-    // All exported targets should be known here and should be unique.
-    // This is probably user-error.
-    this->ComplainAboutMissingTarget(depender, dependee, exportFiles);
-  }
-}
-
-std::pair<std::vector<std::string>, std::string>
-cmExportInstallCMakeConfigGenerator::FindNamespaces(cmGlobalGenerator* gg,
-                                                    std::string const& name)
-{
-  std::vector<std::string> exportFiles;
-  std::string ns;
-  cmExportSetMap const& exportSets = gg->GetExportSets();
-
-  for (auto const& expIt : exportSets) {
-    cmExportSet const& exportSet = expIt.second;
-
-    bool containsTarget = false;
-    for (auto const& target : exportSet.GetTargetExports()) {
-      if (name == target->TargetName) {
-        containsTarget = true;
-        break;
-      }
-    }
-
-    if (containsTarget) {
-      std::vector<cmInstallExportGenerator const*> const* installs =
-        exportSet.GetInstallations();
-      for (cmInstallExportGenerator const* install : *installs) {
-        exportFiles.push_back(install->GetDestinationFile());
-        ns = install->GetNamespace();
-      }
-    }
-  }
-
-  return { exportFiles, ns };
-}
-
-void cmExportInstallCMakeConfigGenerator::ComplainAboutMissingTarget(
-  cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
-  std::vector<std::string> const& exportFiles)
-{
-  std::ostringstream e;
-  e << "install(EXPORT \"" << this->GetExportSet()->GetName() << "\" ...) "
-    << "includes target \"" << depender->GetName()
-    << "\" which requires target \"" << dependee->GetName() << "\" ";
-  if (exportFiles.empty()) {
-    e << "that is not in any export set.";
-  } else {
-    e << "that is not in this export set, but in multiple other export sets: "
-      << cmJoin(exportFiles, ", ") << ".\n";
-    e << "An exported target cannot depend upon another target which is "
-         "exported multiple times. Consider consolidating the exports of the "
-         "\""
-      << dependee->GetName() << "\" target to a single export.";
-  }
-  cmSystemTools::Error(e.str());
-}
-
-std::string cmExportInstallCMakeConfigGenerator::InstallNameDir(
-  cmGeneratorTarget const* target, std::string const& config)
-{
-  std::string install_name_dir;
-
-  cmMakefile* mf = target->Target->GetMakefile();
-  if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
-    install_name_dir =
-      target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}");
-  }
-
-  return install_name_dir;
-}
-
 namespace {
 bool EntryIsContextSensitive(
   std::unique_ptr<cmCompiledGeneratorExpression> const& cge)
@@ -602,7 +314,7 @@ bool EntryIsContextSensitive(
 }
 
 std::string cmExportInstallCMakeConfigGenerator::GetFileSetDirectories(
-  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* te)
 {
   std::vector<std::string> resultVector;
 
@@ -647,7 +359,7 @@ std::string cmExportInstallCMakeConfigGenerator::GetFileSetDirectories(
 }
 
 std::string cmExportInstallCMakeConfigGenerator::GetFileSetFiles(
-  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport const* te)
 {
   std::vector<std::string> resultVector;
 
@@ -745,11 +457,6 @@ void cmExportInstallCMakeConfigGenerator::GenerateCxxModuleConfigInformation(
   /* clang-format on */
 }
 
-std::string cmExportInstallCMakeConfigGenerator::GetCxxModuleFile() const
-{
-  return this->GetCxxModuleFile(this->GetExportSet()->GetName());
-}
-
 bool cmExportInstallCMakeConfigGenerator::
   GenerateImportCxxModuleConfigTargetInclusion(std::string const& name,
                                                std::string const& config)

+ 15 - 86
Source/cmExportInstallCMakeConfigGenerator.h

@@ -5,30 +5,25 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <iosfwd>
-#include <map>
-#include <set>
 #include <string>
-#include <utility>
-#include <vector>
 
-#include "cmExportFileGenerator.h"
-#include "cmInstallExportGenerator.h"
-#include "cmStateTypes.h"
+#include "cmExportCMakeConfigGenerator.h"
+#include "cmExportInstallFileGenerator.h"
 
-class cmExportSet;
 class cmFileSet;
 class cmGeneratorTarget;
-class cmGlobalGenerator;
-class cmInstallTargetGenerator;
+class cmInstallExportGenerator;
 class cmTargetExport;
 
 /** \class cmExportInstallCMakeConfigGenerator
- * \brief Generate a file exporting targets from an install tree.
+ * \brief Generate files exporting targets from an install tree.
  *
  * cmExportInstallCMakeConfigGenerator generates files exporting targets from
- * install an installation tree.  The files are placed in a temporary
- * location for installation by cmInstallExportGenerator.  One main
- * file is generated that creates the imported targets and loads
+ * an installation tree.  The files are placed in a temporary location for
+ * installation by cmInstallExportGenerator.  The file format is CMake's native
+ * package configuration format.
+ *
+ * One main file is generated that creates the imported targets and loads
  * per-configuration files.  Target locations and settings for each
  * configuration are written to these per-configuration files.  After
  * installation the main file loads the configurations that have been
@@ -36,64 +31,24 @@ class cmTargetExport;
  *
  * This is used to implement the INSTALL(EXPORT) command.
  */
-class cmExportInstallCMakeConfigGenerator : public cmExportFileGenerator
+class cmExportInstallCMakeConfigGenerator
+  : public cmExportCMakeConfigGenerator
+  , public cmExportInstallFileGenerator
 {
 public:
   /** Construct with the export installer that will install the
       files.  */
   cmExportInstallCMakeConfigGenerator(cmInstallExportGenerator* iegen);
 
-  /** Get the per-config file generated for each configuration.  This
-      maps from the configuration name to the file temporary location
-      for installation.  */
-  std::map<std::string, std::string> const& GetConfigImportFiles()
-  {
-    return this->ConfigImportFiles;
-  }
-
-  /** Get the temporary location of the config-agnostic C++ module file.  */
-  std::string GetCxxModuleFile() const;
-
-  /** Get the per-config C++ module file generated for each configuration.
-      This maps from the configuration name to the file temporary location
-      for installation.  */
-  std::map<std::string, std::string> const& GetConfigCxxModuleFiles()
-  {
-    return this->ConfigCxxModuleFiles;
-  }
-
-  /** Get the per-config C++ module file generated for each configuration.
-      This maps from the configuration name to the file temporary location
-      for installation for each target in the export set.  */
-  std::map<std::string, std::vector<std::string>> const&
-  GetConfigCxxModuleTargetFiles()
-  {
-    return this->ConfigCxxModuleTargetFiles;
-  }
-
   /** Compute the globbing expression used to load per-config import
       files from the main file.  */
-  std::string GetConfigImportFileGlob();
+  std::string GetConfigImportFileGlob() const override;
 
 protected:
   // Implement virtual methods from the superclass.
   bool GenerateMainFile(std::ostream& os) override;
   void GenerateImportTargetsConfig(std::ostream& os, std::string const& config,
                                    std::string const& suffix) override;
-  cmStateEnums::TargetType GetExportTargetType(
-    cmTargetExport const* targetExport) const;
-  void HandleMissingTarget(std::string& link_libs,
-                           cmGeneratorTarget const* depender,
-                           cmGeneratorTarget* dependee) override;
-
-  void ReplaceInstallPrefix(std::string& input) override;
-
-  void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
-                                  cmGeneratorTarget const* dependee,
-                                  std::vector<std::string> const& exportFiles);
-
-  std::pair<std::vector<std::string>, std::string> FindNamespaces(
-    cmGlobalGenerator* gg, std::string const& name);
 
   /** Generate the relative import prefix.  */
   virtual void GenerateImportPrefix(std::ostream&);
@@ -106,40 +61,14 @@ protected:
   /** Generate a per-configuration file for the targets.  */
   virtual bool GenerateImportFileConfig(std::string const& config);
 
-  /** Fill in properties indicating installed file locations.  */
-  void SetImportLocationProperty(std::string const& config,
-                                 std::string const& suffix,
-                                 cmInstallTargetGenerator* itgen,
-                                 ImportPropertyMap& properties,
-                                 std::set<std::string>& importedLocations);
-
-  std::string InstallNameDir(cmGeneratorTarget const* target,
-                             std::string const& config) override;
-
   std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                                    cmTargetExport* te) override;
+                                    cmTargetExport const* te) override;
   std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                              cmTargetExport* te) override;
-
-  using cmExportFileGenerator::GetCxxModuleFile;
+                              cmTargetExport const* te) override;
 
   std::string GetCxxModulesDirectory() const override;
   void GenerateCxxModuleConfigInformation(std::string const&,
                                           std::ostream&) const override;
   bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&,
                                                     std::string const&);
-
-  cmExportSet* GetExportSet() const override
-  {
-    return this->IEGen->GetExportSet();
-  }
-
-  cmInstallExportGenerator* IEGen;
-
-  // The import file generated for each configuration.
-  std::map<std::string, std::string> ConfigImportFiles;
-  // The C++ module property file generated for each configuration.
-  std::map<std::string, std::string> ConfigCxxModuleFiles;
-  // The C++ module property target files generated for each configuration.
-  std::map<std::string, std::vector<std::string>> ConfigCxxModuleTargetFiles;
 };

+ 371 - 529
Source/cmExportInstallFileGenerator.cxx

@@ -2,30 +2,21 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmExportInstallFileGenerator.h"
 
-#include <algorithm>
+#include <cassert>
+#include <cstddef>
 #include <memory>
+#include <set>
 #include <sstream>
-#include <utility>
-
-#include <cm/string_view>
-#include <cmext/string_view>
 
 #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 "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmOutputConverter.h"
 #include "cmPolicies.h"
-#include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
@@ -38,369 +29,71 @@ cmExportInstallFileGenerator::cmExportInstallFileGenerator(
 {
 }
 
-std::string cmExportInstallFileGenerator::GetConfigImportFileGlob()
+void cmExportInstallFileGenerator::ReplaceInstallPrefix(
+  std::string& input) const
 {
-  std::string glob = cmStrCat(this->FileBase, "-*", this->FileExt);
-  return glob;
+  cmGeneratorExpression::ReplaceInstallPrefix(input, this->GetInstallPrefix());
 }
 
-bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
+void cmExportInstallFileGenerator::PopulateImportProperties(
+  std::string const& config, std::string const& suffix,
+  cmTargetExport const* targetExport, ImportPropertyMap& properties,
+  std::set<std::string>& importedLocations)
 {
-  std::vector<cmTargetExport*> allTargets;
-  {
-    std::string expectedTargets;
-    std::string sep;
-    for (std::unique_ptr<cmTargetExport> const& te :
-         this->GetExportSet()->GetTargetExports()) {
-      if (te->NamelinkOnly) {
-        continue;
-      }
-      expectedTargets += sep + this->Namespace + te->Target->GetExportName();
-      sep = " ";
-      if (this->ExportedTargets.insert(te->Target).second) {
-        allTargets.push_back(te.get());
-      } else {
-        std::ostringstream e;
-        e << "install(EXPORT \"" << this->GetExportSet()->GetName()
-          << "\" ...) "
-          << "includes target \"" << te->Target->GetName()
-          << "\" more than once in the export set.";
-        cmSystemTools::Error(e.str());
-        return false;
-      }
-    }
-
-    this->GenerateExpectedTargetsCode(os, expectedTargets);
-  }
-
-  // Compute the relative import prefix for the file
-  this->GenerateImportPrefix(os);
-
-  bool requiresConfigFiles = false;
-  // Create all the imported targets.
-  for (cmTargetExport* te : allTargets) {
-    cmGeneratorTarget* gt = te->Target;
-    cmStateEnums::TargetType targetType = this->GetExportTargetType(te);
-
-    requiresConfigFiles =
-      requiresConfigFiles || targetType != cmStateEnums::INTERFACE_LIBRARY;
-
-    this->GenerateImportTargetCode(os, gt, targetType);
-
-    ImportPropertyMap properties;
-
-    std::string includesDestinationDirs;
-    this->PopulateIncludeDirectoriesInterface(
-      gt, cmGeneratorExpression::InstallInterface, properties, *te,
-      includesDestinationDirs);
-    this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface,
-                                   properties);
-    this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_DEFINITIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_AUTOMOC_MACRO_NAMES", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
-                                    cmGeneratorExpression::InstallInterface,
-                                    properties);
-    this->PopulateLinkDirectoriesInterface(
-      gt, cmGeneratorExpression::InstallInterface, properties);
-    this->PopulateLinkDependsInterface(
-      gt, cmGeneratorExpression::InstallInterface, properties);
-
-    std::string errorMessage;
-    if (!this->PopulateCxxModuleExportProperties(
-          gt, properties, cmGeneratorExpression::InstallInterface,
-          includesDestinationDirs, errorMessage)) {
-      cmSystemTools::Error(errorMessage);
-      return false;
-    }
-
-    if (!this->PopulateExportProperties(gt, properties, errorMessage)) {
-      cmSystemTools::Error(errorMessage);
-      return false;
-    }
-
-    bool const newCMP0022Behavior =
-      gt->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
-      gt->GetPolicyStatusCMP0022() != cmPolicies::OLD;
-    if (newCMP0022Behavior) {
-      if (this->PopulateInterfaceLinkLibrariesProperty(
-            gt, cmGeneratorExpression::InstallInterface, properties) &&
-          !this->ExportOld) {
-        this->SetRequiredCMakeVersion(2, 8, 12);
-      }
-    }
-    if (targetType == cmStateEnums::INTERFACE_LIBRARY) {
-      this->SetRequiredCMakeVersion(3, 0, 0);
-    }
-    if (gt->GetProperty("INTERFACE_SOURCES")) {
-      // We can only generate INTERFACE_SOURCES in CMake 3.3, but CMake 3.1
-      // can consume them.
-      this->SetRequiredCMakeVersion(3, 1, 0);
-    }
-
-    this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt,
-                                    properties);
-
-    this->PopulateCompatibleInterfaceProperties(gt, properties);
-    this->PopulateCustomTransitiveInterfaceProperties(
-      gt, cmGeneratorExpression::InstallInterface, properties);
-
-    this->GenerateInterfaceProperties(gt, os, properties);
-
-    this->GenerateTargetFileSets(gt, os, te);
-  }
-
-  this->LoadConfigFiles(os);
-
-  bool result = true;
-
-  std::string cxx_modules_name = this->GetExportSet()->GetName();
-  this->GenerateCxxModuleInformation(cxx_modules_name, os);
-  if (requiresConfigFiles) {
-    for (std::string const& c : this->Configurations) {
-      if (!this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name,
-                                                              c)) {
-        result = false;
-      }
-    }
-  }
-
-  this->CleanupTemporaryVariables(os);
-  this->GenerateImportedFileCheckLoop(os);
-
-  // Generate an import file for each configuration.
-  // Don't do this if we only export INTERFACE_LIBRARY targets.
-  if (requiresConfigFiles) {
-    for (std::string const& c : this->Configurations) {
-      if (!this->GenerateImportFileConfig(c)) {
-        result = false;
-      }
-    }
+  this->SetImportLocationProperty(config, suffix,
+                                  targetExport->ArchiveGenerator, properties,
+                                  importedLocations);
+  this->SetImportLocationProperty(config, suffix,
+                                  targetExport->LibraryGenerator, properties,
+                                  importedLocations);
+  this->SetImportLocationProperty(config, suffix,
+                                  targetExport->RuntimeGenerator, properties,
+                                  importedLocations);
+  this->SetImportLocationProperty(config, suffix,
+                                  targetExport->ObjectsGenerator, properties,
+                                  importedLocations);
+  this->SetImportLocationProperty(config, suffix,
+                                  targetExport->FrameworkGenerator, properties,
+                                  importedLocations);
+  this->SetImportLocationProperty(config, suffix,
+                                  targetExport->BundleGenerator, properties,
+                                  importedLocations);
+
+  // If any file location was set for the target add it to the
+  // import file.
+  if (!properties.empty()) {
+    // Get the rest of the target details.
+    cmGeneratorTarget const* const gtgt = targetExport->Target;
+    this->SetImportDetailProperties(config, suffix, gtgt, properties);
+
+    // TODO: PUBLIC_HEADER_LOCATION
+    // This should wait until the build feature propagation stuff is done.
+    // Then this can be a propagated include directory.
+    // this->GenerateImportProperty(config, te->HeaderGenerator, properties);
   }
-
-  this->GenerateMissingTargetsCheckCode(os);
-
-  return result;
 }
 
-void cmExportInstallFileGenerator::GenerateImportPrefix(std::ostream& os)
+std::string cmExportInstallFileGenerator::GetImportXcFrameworkLocation(
+  std::string const& config, cmTargetExport const* targetExport) const
 {
-  // Set an _IMPORT_PREFIX variable for import location properties
-  // to reference if they are relative to the install prefix.
-  std::string installPrefix =
-    this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
-      "CMAKE_INSTALL_PREFIX");
-  std::string const& expDest = this->IEGen->GetDestination();
-  if (cmSystemTools::FileIsFullPath(expDest)) {
-    // The export file is being installed to an absolute path so the
-    // package is not relocatable.  Use the configured install prefix.
-    /* clang-format off */
-    os <<
-      "# The installation prefix configured by this project.\n"
-      "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n"
-      "\n";
-    /* clang-format on */
-  } else {
-    // Add code to compute the installation prefix relative to the
-    // import file location.
-    std::string absDest = installPrefix + "/" + expDest;
-    std::string absDestS = absDest + "/";
-    os << "# Compute the installation prefix relative to this file.\n"
-       << "get_filename_component(_IMPORT_PREFIX"
-       << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
-    if (cmHasLiteralPrefix(absDestS, "/lib/") ||
-        cmHasLiteralPrefix(absDestS, "/lib64/") ||
-        cmHasLiteralPrefix(absDestS, "/libx32/") ||
-        cmHasLiteralPrefix(absDestS, "/usr/lib/") ||
-        cmHasLiteralPrefix(absDestS, "/usr/lib64/") ||
-        cmHasLiteralPrefix(absDestS, "/usr/libx32/")) {
-      // Handle "/usr move" symlinks created by some Linux distros.
-      /* clang-format off */
-      os <<
-        "# Use original install prefix when loaded through a\n"
-        "# cross-prefix symbolic link such as /lib -> /usr/lib.\n"
-        "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n"
-        "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n"
-        "if(_realCurr STREQUAL _realOrig)\n"
-        "  set(_IMPORT_PREFIX \"" << absDest << "\")\n"
-        "endif()\n"
-        "unset(_realOrig)\n"
-        "unset(_realCurr)\n";
-      /* clang-format on */
-    }
-    std::string dest = expDest;
-    while (!dest.empty()) {
-      os << "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" "
-            "PATH)\n";
-      dest = cmSystemTools::GetFilenamePath(dest);
+  std::string importedXcFrameworkLocation = targetExport->XcFrameworkLocation;
+  if (!importedXcFrameworkLocation.empty()) {
+    importedXcFrameworkLocation = cmGeneratorExpression::Preprocess(
+      importedXcFrameworkLocation,
+      cmGeneratorExpression::PreprocessContext::InstallInterface, true);
+    importedXcFrameworkLocation = cmGeneratorExpression::Evaluate(
+      importedXcFrameworkLocation, targetExport->Target->GetLocalGenerator(),
+      config, targetExport->Target, nullptr, targetExport->Target);
+    if (!importedXcFrameworkLocation.empty() &&
+        !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation) &&
+        !cmHasPrefix(importedXcFrameworkLocation,
+                     this->GetImportPrefixWithSlash())) {
+      return cmStrCat(this->GetImportPrefixWithSlash(),
+                      importedXcFrameworkLocation);
     }
-    os << "if(_IMPORT_PREFIX STREQUAL \"/\")\n"
-       << "  set(_IMPORT_PREFIX \"\")\n"
-       << "endif()\n"
-       << "\n";
   }
-}
 
-void cmExportInstallFileGenerator::CleanupTemporaryVariables(std::ostream& os)
-{
-  /* clang-format off */
-  os << "# Cleanup temporary variables.\n"
-     << "set(_IMPORT_PREFIX)\n"
-     << "\n";
-  /* clang-format on */
-}
-
-void cmExportInstallFileGenerator::LoadConfigFiles(std::ostream& os)
-{
-  // Now load per-configuration properties for them.
-  /* clang-format off */
-  os << "# Load information for each installed configuration.\n"
-     << "file(GLOB _cmake_config_files \"${CMAKE_CURRENT_LIST_DIR}/"
-     << this->GetConfigImportFileGlob() << "\")\n"
-     << "foreach(_cmake_config_file IN LISTS _cmake_config_files)\n"
-     << "  include(\"${_cmake_config_file}\")\n"
-     << "endforeach()\n"
-     << "unset(_cmake_config_file)\n"
-     << "unset(_cmake_config_files)\n"
-     << "\n";
-  /* clang-format on */
-}
-
-void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input)
-{
-  cmGeneratorExpression::ReplaceInstallPrefix(input, "${_IMPORT_PREFIX}");
-}
-
-bool cmExportInstallFileGenerator::GenerateImportFileConfig(
-  std::string const& config)
-{
-  // Skip configurations not enabled for this export.
-  if (!this->IEGen->InstallsForConfig(config)) {
-    return true;
-  }
-
-  // Construct the name of the file to generate.
-  std::string fileName = cmStrCat(this->FileDir, '/', this->FileBase, '-');
-  if (!config.empty()) {
-    fileName += cmSystemTools::LowerCase(config);
-  } else {
-    fileName += "noconfig";
-  }
-  fileName += this->FileExt;
-
-  // Open the output file to generate it.
-  cmGeneratedFileStream exportFileStream(fileName, true);
-  if (!exportFileStream) {
-    std::string se = cmSystemTools::GetLastSystemError();
-    std::ostringstream e;
-    e << "cannot write to file \"" << fileName << "\": " << se;
-    cmSystemTools::Error(e.str());
-    return false;
-  }
-  exportFileStream.SetCopyIfDifferent(true);
-  std::ostream& os = exportFileStream;
-
-  // Start with the import file header.
-  this->GenerateImportHeaderCode(os, config);
-
-  // Generate the per-config target information.
-  this->GenerateImportConfig(os, config);
-
-  // End with the import file footer.
-  this->GenerateImportFooterCode(os);
-
-  // Record this per-config import file.
-  this->ConfigImportFiles[config] = fileName;
-
-  return true;
-}
-
-void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
-  std::ostream& os, std::string const& config, std::string const& suffix)
-{
-  // Add each target in the set to the export.
-  for (std::unique_ptr<cmTargetExport> const& te :
-       this->GetExportSet()->GetTargetExports()) {
-    // Collect import properties for this target.
-    if (this->GetExportTargetType(te.get()) ==
-        cmStateEnums::INTERFACE_LIBRARY) {
-      continue;
-    }
-
-    ImportPropertyMap properties;
-    std::set<std::string> importedLocations;
-
-    this->SetImportLocationProperty(config, suffix, te->ArchiveGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->LibraryGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->RuntimeGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->ObjectsGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->FrameworkGenerator,
-                                    properties, importedLocations);
-    this->SetImportLocationProperty(config, suffix, te->BundleGenerator,
-                                    properties, importedLocations);
-
-    // If any file location was set for the target add it to the
-    // import file.
-    if (!properties.empty()) {
-      // Get the rest of the target details.
-      cmGeneratorTarget* gtgt = te->Target;
-      this->SetImportDetailProperties(config, suffix, gtgt, properties);
-
-      this->SetImportLinkInterface(config, suffix,
-                                   cmGeneratorExpression::InstallInterface,
-                                   gtgt, properties);
-
-      // TODO: PUBLIC_HEADER_LOCATION
-      // This should wait until the build feature propagation stuff
-      // is done.  Then this can be a propagated include directory.
-      // this->GenerateImportProperty(config, te->HeaderGenerator,
-      //                              properties);
-
-      // Generate code in the export file.
-      std::string importedXcFrameworkLocation = te->XcFrameworkLocation;
-      if (!importedXcFrameworkLocation.empty()) {
-        importedXcFrameworkLocation = cmGeneratorExpression::Preprocess(
-          importedXcFrameworkLocation,
-          cmGeneratorExpression::PreprocessContext::InstallInterface, true);
-        importedXcFrameworkLocation = cmGeneratorExpression::Evaluate(
-          importedXcFrameworkLocation, te->Target->GetLocalGenerator(), config,
-          te->Target, nullptr, te->Target);
-        if (!importedXcFrameworkLocation.empty() &&
-            !cmSystemTools::FileIsFullPath(importedXcFrameworkLocation) &&
-            !cmHasLiteralPrefix(importedXcFrameworkLocation,
-                                "${_IMPORT_PREFIX}/")) {
-          importedXcFrameworkLocation =
-            cmStrCat("${_IMPORT_PREFIX}/", importedXcFrameworkLocation);
-        }
-      }
-      this->GenerateImportPropertyCode(os, config, suffix, gtgt, properties,
-                                       importedXcFrameworkLocation);
-      this->GenerateImportedFileChecksCode(
-        os, gtgt, properties, importedLocations, importedXcFrameworkLocation);
-    }
-  }
+  return importedXcFrameworkLocation;
 }
 
 void cmExportInstallFileGenerator::SetImportLocationProperty(
@@ -501,11 +194,16 @@ cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType(
   return targetType;
 }
 
+std::string const& cmExportInstallFileGenerator::GetExportName() const
+{
+  return this->GetExportSet()->GetName();
+}
+
 void cmExportInstallFileGenerator::HandleMissingTarget(
   std::string& link_libs, cmGeneratorTarget const* depender,
   cmGeneratorTarget* dependee)
 {
-  std::string const name = dependee->GetName();
+  std::string const& name = dependee->GetName();
   cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator();
   auto exportInfo = this->FindNamespaces(gg, name);
   std::vector<std::string> const& exportFiles = exportInfo.first;
@@ -524,7 +222,7 @@ void cmExportInstallFileGenerator::HandleMissingTarget(
 
 std::pair<std::vector<std::string>, std::string>
 cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg,
-                                             std::string const& name)
+                                             std::string const& name) const
 {
   std::vector<std::string> exportFiles;
   std::string ns;
@@ -556,10 +254,11 @@ cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg,
 
 void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
   cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
-  std::vector<std::string> const& exportFiles)
+  std::vector<std::string> const& exportFiles) const
 {
   std::ostringstream e;
-  e << "install(EXPORT \"" << this->GetExportSet()->GetName() << "\" ...) "
+  e << "install(" << this->IEGen->InstallSubcommand() << " \""
+    << this->GetExportName() << "\" ...) "
     << "includes target \"" << depender->GetName()
     << "\" which requires target \"" << dependee->GetName() << "\" ";
   if (exportFiles.empty()) {
@@ -572,7 +271,24 @@ void cmExportInstallFileGenerator::ComplainAboutMissingTarget(
          "\""
       << dependee->GetName() << "\" target to a single export.";
   }
-  cmSystemTools::Error(e.str());
+  this->ReportError(e.str());
+}
+
+void cmExportInstallFileGenerator::ComplainAboutDuplicateTarget(
+  std::string const& targetName) const
+{
+  std::ostringstream e;
+  e << "install(" << this->IEGen->InstallSubcommand() << " \""
+    << this->GetExportName() << "\" ...) "
+    << "includes target \"" << targetName
+    << "\" more than once in the export set.";
+  this->ReportError(e.str());
+}
+
+void cmExportInstallFileGenerator::ReportError(
+  std::string const& errorMessage) const
+{
+  cmSystemTools::Error(errorMessage);
 }
 
 std::string cmExportInstallFileGenerator::InstallNameDir(
@@ -582,215 +298,341 @@ std::string cmExportInstallFileGenerator::InstallNameDir(
 
   cmMakefile* mf = target->Target->GetMakefile();
   if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
-    install_name_dir =
-      target->GetInstallNameDirForInstallTree(config, "${_IMPORT_PREFIX}");
+    auto const& prefix = this->GetInstallPrefix();
+    install_name_dir = target->GetInstallNameDirForInstallTree(config, prefix);
   }
 
   return install_name_dir;
 }
 
-namespace {
-bool EntryIsContextSensitive(
-  std::unique_ptr<cmCompiledGeneratorExpression> const& cge)
+std::string cmExportInstallFileGenerator::GetCxxModuleFile() const
 {
-  return cge->GetHadContextSensitiveCondition();
-}
+  return this->GetCxxModuleFile(this->GetExportSet()->GetName());
 }
 
-std::string cmExportInstallFileGenerator::GetFileSetDirectories(
-  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+bool cmExportInstallFileGenerator::CollectExports(
+  std::function<void(cmTargetExport const*)> const& visitor)
 {
-  std::vector<std::string> resultVector;
-
-  auto configs =
-    gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
-
-  cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
-  auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
-
-  for (auto const& config : configs) {
-    auto unescapedDest = cge->Evaluate(gte->LocalGenerator, config, gte);
-    auto dest = cmOutputConverter::EscapeForCMake(
-      unescapedDest, cmOutputConverter::WrapQuotes::NoWrap);
-    if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
-      dest = cmStrCat("${_IMPORT_PREFIX}/", dest);
-    }
-
-    auto const& type = fileSet->GetType();
-    // C++ modules do not support interface file sets which are dependent upon
-    // the configuration.
-    if (cge->GetHadContextSensitiveCondition() && type == "CXX_MODULES"_s) {
-      auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile();
-      std::ostringstream e;
-      e << "The \"" << gte->GetName() << "\" target's interface file set \""
-        << fileSet->GetName() << "\" of type \"" << type
-        << "\" contains context-sensitive base file entries which is not "
-           "supported.";
-      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      return std::string{};
+  for (auto const& te : this->GetExportSet()->GetTargetExports()) {
+    if (te->NamelinkOnly) {
+      continue;
     }
-
-    if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) {
-      resultVector.push_back(
-        cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
+    if (this->ExportedTargets.insert(te->Target).second) {
+      visitor(te.get());
     } else {
-      resultVector.emplace_back(cmStrCat('"', dest, '"'));
-      break;
+      this->ComplainAboutDuplicateTarget(te->Target->GetName());
+      return false;
     }
   }
+  return true;
+}
 
-  return cmJoin(resultVector, " ");
+bool cmExportInstallFileGenerator::PopulateInterfaceProperties(
+  cmTargetExport const* targetExport, ImportPropertyMap& properties)
+{
+  cmGeneratorTarget const* const gt = targetExport->Target;
+
+  std::string includesDestinationDirs;
+  this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
+                                  cmGeneratorExpression::InstallInterface,
+                                  properties);
+  this->PopulateIncludeDirectoriesInterface(
+    gt, cmGeneratorExpression::InstallInterface, properties, *targetExport,
+    includesDestinationDirs);
+  this->PopulateLinkDirectoriesInterface(
+    gt, cmGeneratorExpression::InstallInterface, properties);
+  this->PopulateLinkDependsInterface(
+    gt, cmGeneratorExpression::InstallInterface, properties);
+  this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface,
+                                 properties);
+
+  return this->PopulateInterfaceProperties(
+    gt, includesDestinationDirs, cmGeneratorExpression::InstallInterface,
+    properties);
 }
 
-std::string cmExportInstallFileGenerator::GetFileSetFiles(
-  cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te)
+namespace {
+bool isSubDirectory(std::string const& a, std::string const& b)
 {
-  std::vector<std::string> resultVector;
+  return (cmSystemTools::ComparePath(a, b) ||
+          cmSystemTools::IsSubDirectory(a, b));
+}
 
-  auto configs =
-    gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+bool checkInterfaceDirs(std::string const& prepro,
+                        cmGeneratorTarget const* target,
+                        std::string const& prop)
+{
+  std::string const& installDir =
+    target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+  std::string const& topSourceDir =
+    target->GetLocalGenerator()->GetSourceDirectory();
+  std::string const& topBinaryDir =
+    target->GetLocalGenerator()->GetBinaryDirectory();
 
-  auto fileEntries = fileSet->CompileFileEntries();
-  auto directoryEntries = fileSet->CompileDirectoryEntries();
+  std::vector<std::string> parts;
+  cmGeneratorExpression::Split(prepro, parts);
 
-  cmGeneratorExpression destGe(*gte->Makefile->GetCMakeInstance());
-  auto destCge =
-    destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
+  bool const inSourceBuild = topSourceDir == topBinaryDir;
 
-  for (auto const& config : configs) {
-    auto directories = fileSet->EvaluateDirectoryEntries(
-      directoryEntries, gte->LocalGenerator, config, gte);
+  bool hadFatalError = false;
 
-    std::map<std::string, std::vector<std::string>> files;
-    for (auto const& entry : fileEntries) {
-      fileSet->EvaluateFileEntry(directories, files, entry,
-                                 gte->LocalGenerator, config, gte);
+  for (std::string const& li : parts) {
+    size_t genexPos = cmGeneratorExpression::Find(li);
+    if (genexPos == 0) {
+      continue;
     }
-    auto unescapedDest = destCge->Evaluate(gte->LocalGenerator, config, gte);
-    auto dest =
-      cmStrCat(cmOutputConverter::EscapeForCMake(
-                 unescapedDest, cmOutputConverter::WrapQuotes::NoWrap),
-               '/');
-    if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
-      dest = cmStrCat("${_IMPORT_PREFIX}/", dest);
+    if (cmHasLiteralPrefix(li, "${_IMPORT_PREFIX}")) {
+      continue;
     }
-
-    bool const contextSensitive = destCge->GetHadContextSensitiveCondition() ||
-      std::any_of(directoryEntries.begin(), directoryEntries.end(),
-                  EntryIsContextSensitive) ||
-      std::any_of(fileEntries.begin(), fileEntries.end(),
-                  EntryIsContextSensitive);
-
-    auto const& type = fileSet->GetType();
-    // C++ modules do not support interface file sets which are dependent upon
-    // the configuration.
-    if (contextSensitive && type == "CXX_MODULES"_s) {
-      auto* mf = this->IEGen->GetLocalGenerator()->GetMakefile();
-      std::ostringstream e;
-      e << "The \"" << gte->GetName() << "\" target's interface file set \""
-        << fileSet->GetName() << "\" of type \"" << type
-        << "\" contains context-sensitive base file entries which is not "
-           "supported.";
-      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      return std::string{};
+    MessageType messageType = MessageType::FATAL_ERROR;
+    std::ostringstream e;
+    if (genexPos != std::string::npos) {
+      if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
+        switch (target->GetPolicyStatusCMP0041()) {
+          case cmPolicies::WARN:
+            messageType = MessageType::WARNING;
+            e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0041) << "\n";
+            break;
+          case cmPolicies::OLD:
+            continue;
+          case cmPolicies::REQUIRED_IF_USED:
+          case cmPolicies::REQUIRED_ALWAYS:
+          case cmPolicies::NEW:
+            hadFatalError = true;
+            break; // Issue fatal message.
+        }
+      } else {
+        hadFatalError = true;
+      }
     }
-
-    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.emplace_back(cmStrCat('"', escapedFile, '"'));
+    if (!cmSystemTools::FileIsFullPath(li)) {
+      /* clang-format off */
+      e << "Target \"" << target->GetName() << "\" " << prop <<
+           " property contains relative path:\n"
+           "  \"" << li << "\"";
+      /* clang-format on */
+      target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+    }
+    bool inBinary = isSubDirectory(li, topBinaryDir);
+    bool inSource = isSubDirectory(li, topSourceDir);
+    if (isSubDirectory(li, installDir)) {
+      // The include directory is inside the install tree.  If the
+      // install tree is not inside the source tree or build tree then
+      // fall through to the checks below that the include directory is not
+      // also inside the source tree or build tree.
+      bool shouldContinue =
+        (!inBinary || isSubDirectory(installDir, topBinaryDir)) &&
+        (!inSource || isSubDirectory(installDir, topSourceDir));
+
+      if (prop == "INTERFACE_INCLUDE_DIRECTORIES") {
+        if (!shouldContinue) {
+          switch (target->GetPolicyStatusCMP0052()) {
+            case cmPolicies::WARN: {
+              std::ostringstream s;
+              s << cmPolicies::GetPolicyWarning(cmPolicies::CMP0052) << "\n";
+              s << "Directory:\n    \"" << li
+                << "\"\nin "
+                   "INTERFACE_INCLUDE_DIRECTORIES of target \""
+                << target->GetName()
+                << "\" is a subdirectory of the install "
+                   "directory:\n    \""
+                << installDir
+                << "\"\nhowever it is also "
+                   "a subdirectory of the "
+                << (inBinary ? "build" : "source") << " tree:\n    \""
+                << (inBinary ? topBinaryDir : topSourceDir) << "\"\n";
+              target->GetLocalGenerator()->IssueMessage(
+                MessageType::AUTHOR_WARNING, s.str());
+              CM_FALLTHROUGH;
+            }
+            case cmPolicies::OLD:
+              shouldContinue = true;
+              break;
+            case cmPolicies::REQUIRED_ALWAYS:
+            case cmPolicies::REQUIRED_IF_USED:
+            case cmPolicies::NEW:
+              break;
+          }
         }
       }
+      if (shouldContinue) {
+        continue;
+      }
     }
-
-    if (!(contextSensitive && configs.size() != 1)) {
-      break;
+    if (inBinary) {
+      /* clang-format off */
+      e << "Target \"" << target->GetName() << "\" " << prop <<
+           " property contains path:\n"
+           "  \"" << li << "\"\nwhich is prefixed in the build directory.";
+      /* clang-format on */
+      target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+    }
+    if (!inSourceBuild) {
+      if (inSource) {
+        e << "Target \"" << target->GetName() << "\" " << prop
+          << " property contains path:\n"
+             "  \""
+          << li << "\"\nwhich is prefixed in the source directory.";
+        target->GetLocalGenerator()->IssueMessage(messageType, e.str());
+      }
     }
   }
-
-  return cmJoin(resultVector, " ");
+  return !hadFatalError;
 }
-
-std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const
-{
-  return IEGen->GetCxxModuleDirectory();
 }
 
-void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation(
-  std::string const& name, std::ostream& os) const
+void cmExportInstallFileGenerator::PopulateSourcesInterface(
+  cmGeneratorTarget const* gt,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
+  ImportPropertyMap& properties)
 {
-  // Now load per-configuration properties for them.
-  /* clang-format off */
-  os << "# Load information for each installed configuration.\n"
-        "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << "-*.cmake\")\n"
-        "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n"
-        "  include(\"${_cmake_cxx_module_include}\")\n"
-        "endforeach()\n"
-        "unset(_cmake_cxx_module_include)\n"
-        "unset(_cmake_cxx_module_includes)\n";
-  /* clang-format on */
+  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+  char const* const propName = "INTERFACE_SOURCES";
+  cmValue input = gt->GetProperty(propName);
+
+  if (!input) {
+    return;
+  }
+
+  if (input->empty()) {
+    properties[propName].clear();
+    return;
+  }
+
+  std::string prepro =
+    cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
+  if (!prepro.empty()) {
+    this->ResolveTargetsInGeneratorExpressions(prepro, gt);
+
+    if (!checkInterfaceDirs(prepro, gt, propName)) {
+      return;
+    }
+    properties[propName] = prepro;
+  }
 }
 
-std::string cmExportInstallFileGenerator::GetCxxModuleFile() const
+void cmExportInstallFileGenerator::PopulateIncludeDirectoriesInterface(
+  cmGeneratorTarget const* target,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
+  ImportPropertyMap& properties, cmTargetExport const& te,
+  std::string& includesDestinationDirs)
 {
-  return this->GetCxxModuleFile(this->GetExportSet()->GetName());
+  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+  includesDestinationDirs.clear();
+
+  char const* const propName = "INTERFACE_INCLUDE_DIRECTORIES";
+  cmValue input = target->GetProperty(propName);
+
+  cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance());
+
+  std::string dirs = cmGeneratorExpression::Preprocess(
+    cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)),
+    preprocessRule, true);
+  this->ReplaceInstallPrefix(dirs);
+  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);
+  std::string exportDirs =
+    cge->Evaluate(target->GetLocalGenerator(), "", target);
+
+  if (cge->GetHadContextSensitiveCondition()) {
+    cmLocalGenerator* lg = target->GetLocalGenerator();
+    std::ostringstream e;
+    e << "Target \"" << target->GetName()
+      << "\" is installed with "
+         "INCLUDES DESTINATION set to a context sensitive path.  Paths which "
+         "depend on the configuration, policy values or the link interface "
+         "are "
+         "not supported.  Consider using target_include_directories instead.";
+    lg->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    return;
+  }
+
+  if (!input && exportDirs.empty()) {
+    return;
+  }
+  if ((input && input->empty()) && exportDirs.empty()) {
+    // Set to empty
+    properties[propName].clear();
+    return;
+  }
+
+  this->AddImportPrefix(exportDirs);
+  includesDestinationDirs = exportDirs;
+
+  std::string includes = (input ? *input : "");
+  char const* const sep = input ? ";" : "";
+  includes += sep + exportDirs;
+  std::string prepro =
+    cmGeneratorExpression::Preprocess(includes, preprocessRule, true);
+  if (!prepro.empty()) {
+    this->ResolveTargetsInGeneratorExpressions(prepro, target);
+
+    if (!checkInterfaceDirs(prepro, target, propName)) {
+      return;
+    }
+    properties[propName] = prepro;
+  }
 }
 
-bool cmExportInstallFileGenerator::
-  GenerateImportCxxModuleConfigTargetInclusion(std::string const& name,
-                                               std::string const& config)
+void cmExportInstallFileGenerator::PopulateLinkDependsInterface(
+  cmGeneratorTarget const* gt,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
+  ImportPropertyMap& properties)
 {
-  auto cxx_modules_dirname = this->GetCxxModulesDirectory();
-  if (cxx_modules_dirname.empty()) {
-    return true;
+  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+  char const* const propName = "INTERFACE_LINK_DEPENDS";
+  cmValue input = gt->GetProperty(propName);
+
+  if (!input) {
+    return;
   }
 
-  std::string filename_config = config;
-  if (filename_config.empty()) {
-    filename_config = "noconfig";
+  if (input->empty()) {
+    properties[propName].clear();
+    return;
   }
 
-  std::string const dest =
-    cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/');
-  std::string fileName =
-    cmStrCat(dest, "cxx-modules-", name, '-', filename_config, ".cmake");
+  std::string prepro =
+    cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
+  if (!prepro.empty()) {
+    this->ResolveTargetsInGeneratorExpressions(prepro, gt);
 
-  cmGeneratedFileStream os(fileName, true);
-  if (!os) {
-    std::string se = cmSystemTools::GetLastSystemError();
-    std::ostringstream e;
-    e << "cannot write to file \"" << fileName << "\": " << se;
-    cmSystemTools::Error(e.str());
-    return false;
+    if (!checkInterfaceDirs(prepro, gt, propName)) {
+      return;
+    }
+    properties[propName] = prepro;
   }
-  os.SetCopyIfDifferent(true);
+}
 
-  // Record this per-config import file.
-  this->ConfigCxxModuleFiles[config] = fileName;
+void cmExportInstallFileGenerator::PopulateLinkDirectoriesInterface(
+  cmGeneratorTarget const* gt,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
+  ImportPropertyMap& properties)
+{
+  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
 
-  auto& prop_files = this->ConfigCxxModuleTargetFiles[config];
-  for (auto const* tgt : this->ExportedTargets) {
-    // Only targets with C++ module sources will have a
-    // collator-generated install script.
-    if (!tgt->HaveCxx20ModuleSources()) {
-      continue;
-    }
+  char const* const propName = "INTERFACE_LINK_DIRECTORIES";
+  cmValue input = gt->GetProperty(propName);
 
-    auto prop_filename = cmStrCat("target-", tgt->GetFilesystemExportName(),
-                                  '-', filename_config, ".cmake");
-    prop_files.emplace_back(cmStrCat(dest, prop_filename));
-    os << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << prop_filename << "\")\n";
+  if (!input) {
+    return;
   }
 
-  return true;
+  if (input->empty()) {
+    properties[propName].clear();
+    return;
+  }
+
+  std::string prepro =
+    cmGeneratorExpression::Preprocess(*input, preprocessRule, true);
+  if (!prepro.empty()) {
+    this->ResolveTargetsInGeneratorExpressions(prepro, gt);
+
+    if (!checkInterfaceDirs(prepro, gt, propName)) {
+      return;
+    }
+    properties[propName] = prepro;
+  }
 }

+ 68 - 43
Source/cmExportInstallFileGenerator.h

@@ -4,19 +4,21 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include <iosfwd>
+#include <functional>
 #include <map>
 #include <set>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmExportFileGenerator.h"
+#include "cmGeneratorExpression.h"
 #include "cmInstallExportGenerator.h"
 #include "cmStateTypes.h"
 
 class cmExportSet;
-class cmFileSet;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
 class cmInstallTargetGenerator;
@@ -25,18 +27,10 @@ class cmTargetExport;
 /** \class cmExportInstallFileGenerator
  * \brief Generate a file exporting targets from an install tree.
  *
- * cmExportInstallFileGenerator generates files exporting targets from
- * install an installation tree.  The files are placed in a temporary
- * location for installation by cmInstallExportGenerator.  One main
- * file is generated that creates the imported targets and loads
- * per-configuration files.  Target locations and settings for each
- * configuration are written to these per-configuration files.  After
- * installation the main file loads the configurations that have been
- * installed.
- *
- * This is used to implement the INSTALL(EXPORT) command.
+ * cmExportInstallFileGenerator is the generic interface class for generating
+ * export files for an install tree.
  */
-class cmExportInstallFileGenerator : public cmExportFileGenerator
+class cmExportInstallFileGenerator : virtual public cmExportFileGenerator
 {
 public:
   /** Construct with the export installer that will install the
@@ -73,38 +67,37 @@ public:
 
   /** Compute the globbing expression used to load per-config import
       files from the main file.  */
-  std::string GetConfigImportFileGlob();
+  virtual std::string GetConfigImportFileGlob() const = 0;
 
 protected:
-  // Implement virtual methods from the superclass.
-  bool GenerateMainFile(std::ostream& os) override;
-  void GenerateImportTargetsConfig(std::ostream& os, std::string const& config,
-                                   std::string const& suffix) override;
   cmStateEnums::TargetType GetExportTargetType(
     cmTargetExport const* targetExport) const;
+
+  virtual std::string const& GetExportName() const;
+
+  std::string GetInstallPrefix() const
+  {
+    cm::string_view const& prefixWithSlash = this->GetImportPrefixWithSlash();
+    return std::string(prefixWithSlash.data(), prefixWithSlash.length() - 1);
+  }
+
   void HandleMissingTarget(std::string& link_libs,
                            cmGeneratorTarget const* depender,
                            cmGeneratorTarget* dependee) override;
 
-  void ReplaceInstallPrefix(std::string& input) override;
-
-  void ComplainAboutMissingTarget(cmGeneratorTarget const* depender,
-                                  cmGeneratorTarget const* dependee,
-                                  std::vector<std::string> const& exportFiles);
+  void ReplaceInstallPrefix(std::string& input) const override;
 
-  std::pair<std::vector<std::string>, std::string> FindNamespaces(
-    cmGlobalGenerator* gg, std::string const& name);
-
-  /** Generate the relative import prefix.  */
-  virtual void GenerateImportPrefix(std::ostream&);
+  void ComplainAboutMissingTarget(
+    cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee,
+    std::vector<std::string> const& exportFiles) const;
 
-  /** Generate the relative import prefix.  */
-  virtual void LoadConfigFiles(std::ostream&);
+  void ComplainAboutDuplicateTarget(
+    std::string const& targetName) const override;
 
-  virtual void CleanupTemporaryVariables(std::ostream&);
+  std::pair<std::vector<std::string>, std::string> FindNamespaces(
+    cmGlobalGenerator* gg, std::string const& name) const;
 
-  /** Generate a per-configuration file for the targets.  */
-  virtual bool GenerateImportFileConfig(std::string const& config);
+  void ReportError(std::string const& errorMessage) const override;
 
   /** Fill in properties indicating installed file locations.  */
   void SetImportLocationProperty(std::string const& config,
@@ -116,24 +109,31 @@ protected:
   std::string InstallNameDir(cmGeneratorTarget const* target,
                              std::string const& config) override;
 
-  std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                                    cmTargetExport* te) override;
-  std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet,
-                              cmTargetExport* te) override;
-
   using cmExportFileGenerator::GetCxxModuleFile;
 
-  std::string GetCxxModulesDirectory() const override;
-  void GenerateCxxModuleConfigInformation(std::string const&,
-                                          std::ostream&) const override;
-  bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&,
-                                                    std::string const&);
+  /** Walk the list of targets to be exported.  Returns true iff no duplicates
+      are found.  */
+  bool CollectExports(
+    std::function<void(cmTargetExport const*)> const& visitor);
 
   cmExportSet* GetExportSet() const override
   {
     return this->IEGen->GetExportSet();
   }
 
+  std::string GetImportXcFrameworkLocation(
+    std::string const& config, cmTargetExport const* targetExport) const;
+
+  using cmExportFileGenerator::PopulateInterfaceProperties;
+  bool PopulateInterfaceProperties(cmTargetExport const* targetExport,
+                                   ImportPropertyMap& properties);
+
+  void PopulateImportProperties(std::string const& config,
+                                std::string const& suffix,
+                                cmTargetExport const* targetExport,
+                                ImportPropertyMap& properties,
+                                std::set<std::string>& importedLocations);
+
   cmInstallExportGenerator* IEGen;
 
   // The import file generated for each configuration.
@@ -142,4 +142,29 @@ protected:
   std::map<std::string, std::string> ConfigCxxModuleFiles;
   // The C++ module property target files generated for each configuration.
   std::map<std::string, std::vector<std::string>> ConfigCxxModuleTargetFiles;
+
+private:
+  void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target,
+                                             ImportPropertyMap& properties);
+  void PopulateCustomTransitiveInterfaceProperties(
+    cmGeneratorTarget const* target,
+    cmGeneratorExpression::PreprocessContext preprocessRule,
+    ImportPropertyMap& properties);
+  void PopulateIncludeDirectoriesInterface(
+    cmGeneratorTarget const* target,
+    cmGeneratorExpression::PreprocessContext preprocessRule,
+    ImportPropertyMap& properties, cmTargetExport const& te,
+    std::string& includesDestinationDirs);
+  void PopulateSourcesInterface(
+    cmGeneratorTarget const* target,
+    cmGeneratorExpression::PreprocessContext preprocessRule,
+    ImportPropertyMap& properties);
+  void PopulateLinkDirectoriesInterface(
+    cmGeneratorTarget const* target,
+    cmGeneratorExpression::PreprocessContext preprocessRule,
+    ImportPropertyMap& properties);
+  void PopulateLinkDependsInterface(
+    cmGeneratorTarget const* target,
+    cmGeneratorExpression::PreprocessContext preprocessRule,
+    ImportPropertyMap& properties);
 };

+ 9 - 2
Source/cmExportTryCompileFileGenerator.cxx

@@ -19,6 +19,7 @@
 #include "cmOutputConverter.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmValue.h"
 
@@ -32,6 +33,12 @@ cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator(
   gg->CreateImportedGenerationObjects(mf, targets, this->Exports);
 }
 
+void cmExportTryCompileFileGenerator::ReportError(
+  std::string const& errorMessage) const
+{
+  cmSystemTools::Error(errorMessage);
+}
+
 bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
 {
   std::set<cmGeneratorTarget const*> emitted;
@@ -153,14 +160,14 @@ std::string cmExportTryCompileFileGenerator::InstallNameDir(
 }
 
 std::string cmExportTryCompileFileGenerator::GetFileSetDirectories(
-  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport const* /*te*/)
 {
   return cmOutputConverter::EscapeForCMake(
     cmList::to_string(fileSet->GetDirectoryEntries()));
 }
 
 std::string cmExportTryCompileFileGenerator::GetFileSetFiles(
-  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
+  cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport const* /*te*/)
 {
   return cmOutputConverter::EscapeForCMake(
     cmList::to_string(fileSet->GetFileEntries()));

+ 8 - 4
Source/cmExportTryCompileFileGenerator.h

@@ -9,7 +9,7 @@
 #include <string>
 #include <vector>
 
-#include "cmExportFileGenerator.h"
+#include "cmExportCMakeConfigGenerator.h"
 
 class cmFileSet;
 class cmGeneratorTarget;
@@ -17,7 +17,7 @@ class cmGlobalGenerator;
 class cmMakefile;
 class cmTargetExport;
 
-class cmExportTryCompileFileGenerator : public cmExportFileGenerator
+class cmExportTryCompileFileGenerator : public cmExportCMakeConfigGenerator
 {
 public:
   cmExportTryCompileFileGenerator(cmGlobalGenerator* gg,
@@ -30,6 +30,10 @@ public:
 
 protected:
   // Implement virtual methods from the superclass.
+  void ComplainAboutDuplicateTarget(
+    std::string const& /*targetName*/) const override{};
+  void ReportError(std::string const& errorMessage) const override;
+
   bool GenerateMainFile(std::ostream& os) override;
 
   void GenerateImportTargetsConfig(std::ostream&, std::string const&,
@@ -50,10 +54,10 @@ protected:
 
   std::string GetFileSetDirectories(cmGeneratorTarget* target,
                                     cmFileSet* fileSet,
-                                    cmTargetExport* te) override;
+                                    cmTargetExport const* te) override;
 
   std::string GetFileSetFiles(cmGeneratorTarget* target, cmFileSet* fileSet,
-                              cmTargetExport* te) override;
+                              cmTargetExport const* te) override;
 
   std::string GetCxxModulesDirectory() const override { return {}; }
   void GenerateCxxModuleConfigInformation(std::string const&,

+ 1 - 9
Source/cmInstallAndroidMKExportGenerator.cxx

@@ -16,23 +16,15 @@ cmInstallAndroidMKExportGenerator::cmInstallAndroidMKExportGenerator(
   cmExportSet* exportSet, std::string destination, std::string filePermissions,
   std::vector<std::string> const& configurations, std::string component,
   MessageLevel message, bool excludeFromAll, std::string filename,
-  std::string targetNamespace, bool exportOld, cmListFileBacktrace backtrace)
+  std::string targetNamespace, cmListFileBacktrace backtrace)
   : cmInstallExportGenerator(exportSet, std::move(destination),
                              std::move(filePermissions), configurations,
                              std::move(component), message, excludeFromAll,
                              std::move(filename), std::move(targetNamespace),
                              std::string{}, std::move(backtrace))
-  , ExportOld(exportOld)
 {
   this->EFGen = cm::make_unique<cmExportInstallAndroidMKGenerator>(this);
 }
 
 cmInstallAndroidMKExportGenerator::~cmInstallAndroidMKExportGenerator() =
   default;
-
-void cmInstallAndroidMKExportGenerator::GenerateScript(std::ostream& os)
-{
-  this->EFGen->SetExportOld(this->ExportOld);
-
-  this->cmInstallExportGenerator::GenerateScript(os);
-}

+ 5 - 9
Source/cmInstallAndroidMKExportGenerator.h

@@ -2,7 +2,6 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #pragma once
 
-#include <iosfwd>
 #include <string>
 #include <vector>
 
@@ -22,8 +21,7 @@ public:
     std::string filePermissions,
     std::vector<std::string> const& configurations, std::string component,
     MessageLevel message, bool excludeFromAll, std::string filename,
-    std::string targetNamespace, bool exportOld,
-    cmListFileBacktrace backtrace);
+    std::string targetNamespace, cmListFileBacktrace backtrace);
   cmInstallAndroidMKExportGenerator(cmInstallAndroidMKExportGenerator const&) =
     delete;
   ~cmInstallAndroidMKExportGenerator() override;
@@ -31,10 +29,8 @@ public:
   cmInstallAndroidMKExportGenerator& operator=(
     cmInstallAndroidMKExportGenerator const&) = delete;
 
-protected:
-  char const* InstallSubcommand() const override { return "EXPORT"; }
-
-  void GenerateScript(std::ostream& os) override;
-
-  bool const ExportOld;
+  char const* InstallSubcommand() const override
+  {
+    return "EXPORT_ANDROID_MK";
+  }
 };

+ 6 - 3
Source/cmInstallCMakeConfigExportGenerator.cxx

@@ -6,6 +6,7 @@
 
 #include <cm/memory>
 
+#include "cmExportInstallCMakeConfigGenerator.h"
 #include "cmExportInstallFileGenerator.h"
 #include "cmListFileCache.h"
 
@@ -25,7 +26,7 @@ cmInstallCMakeConfigExportGenerator::cmInstallCMakeConfigExportGenerator(
   , ExportOld(exportOld)
   , ExportPackageDependencies(exportPackageDependencies)
 {
-  this->EFGen = cm::make_unique<cmExportInstallFileGenerator>(this);
+  this->EFGen = cm::make_unique<cmExportInstallCMakeConfigGenerator>(this);
 }
 
 cmInstallCMakeConfigExportGenerator::~cmInstallCMakeConfigExportGenerator() =
@@ -33,8 +34,10 @@ cmInstallCMakeConfigExportGenerator::~cmInstallCMakeConfigExportGenerator() =
 
 void cmInstallCMakeConfigExportGenerator::GenerateScript(std::ostream& os)
 {
-  this->EFGen->SetExportOld(this->ExportOld);
-  this->EFGen->SetExportPackageDependencies(this->ExportPackageDependencies);
+  auto* const efgen =
+    static_cast<cmExportInstallCMakeConfigGenerator*>(this->EFGen.get());
+  efgen->SetExportOld(this->ExportOld);
+  efgen->SetExportPackageDependencies(this->ExportPackageDependencies);
 
   this->cmInstallExportGenerator::GenerateScript(os);
 }

+ 1 - 1
Source/cmInstallCMakeConfigExportGenerator.h

@@ -32,9 +32,9 @@ public:
   cmInstallCMakeConfigExportGenerator& operator=(
     cmInstallCMakeConfigExportGenerator const&) = delete;
 
-protected:
   char const* InstallSubcommand() const override { return "EXPORT"; }
 
+protected:
   void GenerateScript(std::ostream& os) override;
 
   bool const ExportOld;

+ 1 - 1
Source/cmInstallCommand.cxx

@@ -2033,7 +2033,7 @@ bool HandleExportAndroidMKMode(std::vector<std::string> const& args,
       &exportSet, ica.GetDestination(), ica.GetPermissions(),
       ica.GetConfigurations(), ica.GetComponent(), message,
       ica.GetExcludeFromAll(), std::move(fname), std::move(name_space),
-      exportOld, helper.Makefile->GetBacktrace()));
+      helper.Makefile->GetBacktrace()));
 
   return true;
 #else

+ 41 - 34
Source/cmInstallExportGenerator.cxx

@@ -136,7 +136,8 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
   auto const cxxModuleDestination =
     cmStrCat(this->Destination, '/', this->CxxModulesDirectory);
   auto const cxxModuleInstallFilePath = this->EFGen->GetCxxModuleFile();
-  if (!cxxModuleInstallFilePath.empty()) {
+  auto const configImportFilesGlob = this->EFGen->GetConfigImportFileGlob();
+  if (!cxxModuleInstallFilePath.empty() && !configImportFilesGlob.empty()) {
     auto const cxxModuleFilename =
       cmSystemTools::GetFilenameName(cxxModuleInstallFilePath);
 
@@ -149,17 +150,20 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
     Indent indentN = indent.Next();
     Indent indentNN = indentN.Next();
     Indent indentNNN = indentNN.Next();
-    /* clang-format off */
     os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n"
        << indentN << "     \"" << installedFile << "\"\n"
        << indentN << "     \"" << cxxModuleInstallFilePath << "\")\n";
     os << indentN << "if(_cmake_export_file_changed)\n";
     os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir
-       << this->EFGen->GetConfigImportFileGlob() << "\")\n";
+       << configImportFilesGlob << "\")\n";
     os << indentNN << "if(_cmake_old_config_files)\n";
-    os << indentNNN << "string(REPLACE \";\" \", \" _cmake_old_config_files_text \"${_cmake_old_config_files}\")\n";
-    os << indentNNN << R"(message(STATUS "Old C++ module export file \")" << installedFile
-       << "\\\" will be replaced.  Removing files [${_cmake_old_config_files_text}].\")\n";
+    os << indentNNN
+       << "string(REPLACE \";\" \", \" _cmake_old_config_files_text "
+          "\"${_cmake_old_config_files}\")\n";
+    os << indentNNN << R"(message(STATUS "Old C++ module export file \")"
+       << installedFile
+       << "\\\" will be replaced.  "
+          "Removing files [${_cmake_old_config_files_text}].\")\n";
     os << indentNNN << "unset(_cmake_old_config_files_text)\n";
     os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n";
     os << indentNN << "endif()\n";
@@ -167,7 +171,6 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
     os << indentN << "endif()\n";
     os << indentN << "unset(_cmake_export_file_changed)\n";
     os << indent << "endif()\n";
-    /* clang-format on */
 
     // All of these files are siblings; get its location to know where the
     // "anchor" file is.
@@ -201,33 +204,37 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
 void cmInstallExportGenerator::GenerateScriptActions(std::ostream& os,
                                                      Indent indent)
 {
-  // Remove old per-configuration export files if the main changes.
-  std::string installedDir = cmStrCat(
-    "$ENV{DESTDIR}", ConvertToAbsoluteDestination(this->Destination), '/');
-  std::string installedFile = cmStrCat(installedDir, this->FileName);
-  os << indent << "if(EXISTS \"" << installedFile << "\")\n";
-  Indent indentN = indent.Next();
-  Indent indentNN = indentN.Next();
-  Indent indentNNN = indentNN.Next();
-  /* clang-format off */
-  os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n"
-     << indentN << "     \"" << installedFile << "\"\n"
-     << indentN << "     \"" << this->MainImportFile << "\")\n";
-  os << indentN << "if(_cmake_export_file_changed)\n";
-  os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir
-     << this->EFGen->GetConfigImportFileGlob() << "\")\n";
-  os << indentNN << "if(_cmake_old_config_files)\n";
-  os << indentNNN << "string(REPLACE \";\" \", \" _cmake_old_config_files_text \"${_cmake_old_config_files}\")\n";
-  os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile
-     << "\\\" will be replaced.  Removing files [${_cmake_old_config_files_text}].\")\n";
-  os << indentNNN << "unset(_cmake_old_config_files_text)\n";
-  os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n";
-  os << indentNN << "endif()\n";
-  os << indentNN << "unset(_cmake_old_config_files)\n";
-  os << indentN << "endif()\n";
-  os << indentN << "unset(_cmake_export_file_changed)\n";
-  os << indent << "endif()\n";
-  /* clang-format on */
+  auto const configImportFilesGlob = this->EFGen->GetConfigImportFileGlob();
+  if (!configImportFilesGlob.empty()) {
+    // Remove old per-configuration export files if the main changes.
+    std::string installedDir = cmStrCat(
+      "$ENV{DESTDIR}", ConvertToAbsoluteDestination(this->Destination), '/');
+    std::string installedFile = cmStrCat(installedDir, this->FileName);
+    os << indent << "if(EXISTS \"" << installedFile << "\")\n";
+    Indent indentN = indent.Next();
+    Indent indentNN = indentN.Next();
+    Indent indentNNN = indentNN.Next();
+    os << indentN << "file(DIFFERENT _cmake_export_file_changed FILES\n"
+       << indentN << "     \"" << installedFile << "\"\n"
+       << indentN << "     \"" << this->MainImportFile << "\")\n";
+    os << indentN << "if(_cmake_export_file_changed)\n";
+    os << indentNN << "file(GLOB _cmake_old_config_files \"" << installedDir
+       << configImportFilesGlob << "\")\n";
+    os << indentNN << "if(_cmake_old_config_files)\n";
+    os << indentNNN
+       << "string(REPLACE \";\" \", \" _cmake_old_config_files_text "
+          "\"${_cmake_old_config_files}\")\n";
+    os << indentNNN << R"(message(STATUS "Old export file \")" << installedFile
+       << "\\\" will be replaced.  "
+          "Removing files [${_cmake_old_config_files_text}].\")\n";
+    os << indentNNN << "unset(_cmake_old_config_files_text)\n";
+    os << indentNNN << "file(REMOVE ${_cmake_old_config_files})\n";
+    os << indentNN << "endif()\n";
+    os << indentNN << "unset(_cmake_old_config_files)\n";
+    os << indentN << "endif()\n";
+    os << indentN << "unset(_cmake_export_file_changed)\n";
+    os << indent << "endif()\n";
+  }
 
   // Install the main export file.
   std::vector<std::string> files;

+ 2 - 2
Source/cmInstallExportGenerator.h

@@ -36,6 +36,8 @@ public:
   cmInstallExportGenerator& operator=(const cmInstallExportGenerator&) =
     delete;
 
+  virtual char const* InstallSubcommand() const = 0;
+
   cmExportSet* GetExportSet() { return this->ExportSet; }
 
   bool Compute(cmLocalGenerator* lg) override;
@@ -56,8 +58,6 @@ public:
   }
 
 protected:
-  virtual char const* InstallSubcommand() const = 0;
-
   void GenerateScript(std::ostream& os) override;
   void GenerateScriptConfigs(std::ostream& os, Indent indent) override;
   void GenerateScriptActions(std::ostream& os, Indent indent) override;

+ 3 - 0
bootstrap

@@ -345,8 +345,11 @@ CMAKE_CXX_SOURCES="\
   cmExecuteProcessCommand \
   cmExpandedCommandArgument \
   cmExperimental \
+  cmExportBuildCMakeConfigGenerator \
   cmExportBuildFileGenerator \
+  cmExportCMakeConfigGenerator \
   cmExportFileGenerator \
+  cmExportInstallCMakeConfigGenerator \
   cmExportInstallFileGenerator \
   cmExportSet \
   cmExportTryCompileFileGenerator \

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно