From 2837f592ab7642e6a769949b4ddc1ffb37e21b9c Mon Sep 17 00:00:00 2001
From: Kyle Edwards <kyle.edwards@kitware.com>
Date: Wed, 8 Nov 2023 10:21:11 -0500
Subject: cmExportFileGenerator: Add function to set required CMake version

---
 Source/cmExportBuildFileGenerator.cxx        |  2 +-
 Source/cmExportFileGenerator.cxx             | 56 ++++++++++++++++++----------
 Source/cmExportFileGenerator.h               | 10 +++--
 Source/cmExportInstallAndroidMKGenerator.cxx |  5 ---
 Source/cmExportInstallAndroidMKGenerator.h   |  2 -
 Source/cmExportInstallFileGenerator.cxx      | 17 ++-------
 6 files changed, 48 insertions(+), 44 deletions(-)

diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index bf3bb8b..eae3a74 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -76,7 +76,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
     }
 
     if (generatedInterfaceRequired) {
-      this->GenerateRequiredCMakeVersion(os, "3.0.0");
+      this->SetRequiredCMakeVersion(3, 0, 0);
     }
     this->GenerateExpectedTargetsCode(os, expectedTargets);
   }
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index bd87e11..7bf9e5d 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -30,6 +30,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmValue.h"
+#include "cmVersion.h"
 
 static std::string cmExportFileGeneratorEscape(std::string const& str)
 {
@@ -93,17 +94,22 @@ bool cmExportFileGenerator::GenerateImportFile()
     return false;
   }
   std::ostream& os = *foutPtr;
+  std::stringstream mainFileWithHeadersAndFootersBuffer;
 
   // Start with the import file header.
-  this->GeneratePolicyHeaderCode(os);
-  this->GenerateImportHeaderCode(os);
+  this->GenerateImportHeaderCode(mainFileWithHeadersAndFootersBuffer);
 
   // Create all the imported targets.
-  bool result = this->GenerateMainFile(os);
+  bool result = this->GenerateMainFile(mainFileWithHeadersAndFootersBuffer);
 
   // End with the import file footer.
-  this->GenerateImportFooterCode(os);
-  this->GeneratePolicyFooterCode(os);
+  this->GenerateImportFooterCode(mainFileWithHeadersAndFootersBuffer);
+  this->GeneratePolicyFooterCode(mainFileWithHeadersAndFootersBuffer);
+
+  // This has to be done last, after the minimum CMake version has been
+  // determined.
+  this->GeneratePolicyHeaderCode(os);
+  os << mainFileWithHeadersAndFootersBuffer.rdbuf();
 
   return result;
 }
@@ -156,17 +162,6 @@ void cmExportFileGenerator::PopulateInterfaceProperty(
   }
 }
 
-void cmExportFileGenerator::GenerateRequiredCMakeVersion(
-  std::ostream& os, const char* versionString)
-{
-  /* clang-format off */
-  os << "if(CMAKE_VERSION VERSION_LESS " << versionString << ")\n"
-        "  message(FATAL_ERROR \"This file relies on consumers using "
-        "CMake " << versionString << " or greater.\")\n"
-        "endif()\n\n";
-  /* clang-format on */
-}
-
 bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty(
   cmGeneratorTarget const* target,
   cmGeneratorExpression::PreprocessContext preprocessRule,
@@ -953,8 +948,14 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
   os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.8)\n"
      << "   message(FATAL_ERROR \"CMake >= 2.8.0 required\")\n"
      << "endif()\n"
-     << "if(CMAKE_VERSION VERSION_LESS \"2.8.3\")\n"
-     << "   message(FATAL_ERROR \"CMake >= 2.8.3 required\")\n"
+     << "if(CMAKE_VERSION VERSION_LESS \""
+     << this->RequiredCMakeVersionMajor << '.'
+     << this->RequiredCMakeVersionMinor << '.'
+     << this->RequiredCMakeVersionPatch << "\")\n"
+     << "   message(FATAL_ERROR \"CMake >= "
+     << this->RequiredCMakeVersionMajor << '.'
+     << this->RequiredCMakeVersionMinor << '.'
+     << this->RequiredCMakeVersionPatch << " required\")\n"
      << "endif()\n";
   /* clang-format on */
 
@@ -966,7 +967,10 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
   // versions.
   /* clang-format off */
   os << "cmake_policy(PUSH)\n"
-     << "cmake_policy(VERSION 2.8.3...3.27)\n";
+     << "cmake_policy(VERSION "
+     << this->RequiredCMakeVersionMajor << '.'
+     << this->RequiredCMakeVersionMinor << '.'
+     << this->RequiredCMakeVersionPatch << "...3.27)\n";
   /* clang-format on */
 }
 
@@ -1485,3 +1489,17 @@ void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os)
 
   this->GenerateCxxModuleConfigInformation(ap);
 }
+
+void cmExportFileGenerator::SetRequiredCMakeVersion(unsigned int major,
+                                                    unsigned int minor,
+                                                    unsigned int patch)
+{
+  if (CMake_VERSION_ENCODE(major, minor, patch) >
+      CMake_VERSION_ENCODE(this->RequiredCMakeVersionMajor,
+                           this->RequiredCMakeVersionMinor,
+                           this->RequiredCMakeVersionPatch)) {
+    this->RequiredCMakeVersionMajor = major;
+    this->RequiredCMakeVersionMinor = minor;
+    this->RequiredCMakeVersionPatch = patch;
+  }
+}
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index f396e0e..fd7ec99 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -173,9 +173,6 @@ protected:
     std::string& input, cmGeneratorTarget const* target,
     FreeTargetsReplace replace = NoReplaceFreeTargets);
 
-  virtual void GenerateRequiredCMakeVersion(std::ostream& os,
-                                            const char* versionString);
-
   bool PopulateCxxModuleExportProperties(
     cmGeneratorTarget const* gte, ImportPropertyMap& properties,
     cmGeneratorExpression::PreprocessContext ctx,
@@ -196,6 +193,9 @@ protected:
                                       cmFileSet* fileSet,
                                       cmTargetExport* 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;
 
@@ -216,6 +216,10 @@ protected:
 
   std::vector<std::string> MissingTargets;
 
+  unsigned int RequiredCMakeVersionMajor = 2;
+  unsigned int RequiredCMakeVersionMinor = 8;
+  unsigned int RequiredCMakeVersionPatch = 3;
+
 private:
   void PopulateInterfaceProperty(const std::string&, const std::string&,
                                  cmGeneratorTarget const* target,
diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx
index d53254d..7dfdc0e 100644
--- a/Source/cmExportInstallAndroidMKGenerator.cxx
+++ b/Source/cmExportInstallAndroidMKGenerator.cxx
@@ -110,11 +110,6 @@ void cmExportInstallAndroidMKGenerator::GenerateImportPrefix(std::ostream&)
 {
 }
 
-void cmExportInstallAndroidMKGenerator::GenerateRequiredCMakeVersion(
-  std::ostream&, const char*)
-{
-}
-
 void cmExportInstallAndroidMKGenerator::CleanupTemporaryVariables(
   std::ostream&)
 {
diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h
index 061358d..1922207 100644
--- a/Source/cmExportInstallAndroidMKGenerator.h
+++ b/Source/cmExportInstallAndroidMKGenerator.h
@@ -54,8 +54,6 @@ protected:
     const ImportPropertyMap& properties) override;
   void GenerateImportPrefix(std::ostream& os) override;
   void LoadConfigFiles(std::ostream&) override;
-  void GenerateRequiredCMakeVersion(std::ostream& os,
-                                    const char* versionString) override;
   void CleanupTemporaryVariables(std::ostream&) override;
   void GenerateImportedFileCheckLoop(std::ostream& os) override;
   void GenerateImportedFileChecksCode(
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index a264f5e..b829edd 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -76,9 +76,6 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
   // Compute the relative import prefix for the file
   this->GenerateImportPrefix(os);
 
-  bool require2_8_12 = false;
-  bool require3_0_0 = false;
-  bool require3_1_0 = false;
   bool requiresConfigFiles = false;
   // Create all the imported targets.
   for (cmTargetExport* te : allTargets) {
@@ -147,16 +144,16 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
       if (this->PopulateInterfaceLinkLibrariesProperty(
             gt, cmGeneratorExpression::InstallInterface, properties) &&
           !this->ExportOld) {
-        require2_8_12 = true;
+        this->SetRequiredCMakeVersion(2, 8, 12);
       }
     }
     if (targetType == cmStateEnums::INTERFACE_LIBRARY) {
-      require3_0_0 = true;
+      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.
-      require3_1_0 = true;
+      this->SetRequiredCMakeVersion(3, 1, 0);
     }
 
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE", gt,
@@ -169,14 +166,6 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
     this->GenerateTargetFileSets(gt, os, te);
   }
 
-  if (require3_1_0) {
-    this->GenerateRequiredCMakeVersion(os, "3.1.0");
-  } else if (require3_0_0) {
-    this->GenerateRequiredCMakeVersion(os, "3.0.0");
-  } else if (require2_8_12) {
-    this->GenerateRequiredCMakeVersion(os, "2.8.12");
-  }
-
   this->LoadConfigFiles(os);
 
   bool result = true;
-- 
cgit v0.12