Quellcode durchsuchen

install(EXPORT): Add ability to point to .xcframework file

Issue: #25262
Kyle Edwards vor 2 Jahren
Ursprung
Commit
256bb0cc40
30 geänderte Dateien mit 338 neuen und 43 gelöschten Zeilen
  1. 13 0
      Help/command/export.rst
  2. 6 0
      Help/release/dev/install-export-xcframework.rst
  3. 2 2
      Source/cmExportBuildAndroidMKGenerator.cxx
  4. 3 3
      Source/cmExportBuildAndroidMKGenerator.h
  5. 19 3
      Source/cmExportBuildFileGenerator.cxx
  6. 7 2
      Source/cmExportBuildFileGenerator.h
  7. 29 1
      Source/cmExportCommand.cxx
  8. 47 17
      Source/cmExportFileGenerator.cxx
  9. 6 5
      Source/cmExportFileGenerator.h
  10. 3 3
      Source/cmExportInstallAndroidMKGenerator.cxx
  11. 5 4
      Source/cmExportInstallAndroidMKGenerator.h
  12. 20 3
      Source/cmExportInstallFileGenerator.cxx
  13. 10 0
      Source/cmExportSet.cxx
  14. 3 0
      Source/cmExportSet.h
  15. 1 0
      Source/cmTargetExport.h
  16. 103 0
      Tests/RunCMake/XcFramework/RunCMakeTest.cmake
  17. 33 0
      Tests/RunCMake/XcFramework/export-macos.cmake
  18. 5 0
      Tests/RunCMake/XcFramework/import-common.cmake
  19. 5 0
      Tests/RunCMake/XcFramework/import-genex-common.cmake
  20. 2 0
      Tests/RunCMake/XcFramework/import-macos-build-specific-build-stdout.txt
  21. 2 0
      Tests/RunCMake/XcFramework/import-macos-build-specific-genex-build-stdout.txt
  22. 1 0
      Tests/RunCMake/XcFramework/import-macos-build-specific-genex.cmake
  23. 1 0
      Tests/RunCMake/XcFramework/import-macos-build-specific.cmake
  24. 2 0
      Tests/RunCMake/XcFramework/import-macos-install-specific-build-stdout.txt
  25. 2 0
      Tests/RunCMake/XcFramework/import-macos-install-specific-genex-build-stdout.txt
  26. 1 0
      Tests/RunCMake/XcFramework/import-macos-install-specific-genex.cmake
  27. 2 0
      Tests/RunCMake/XcFramework/import-macos-install-specific-no-xcframework-build-stdout.txt
  28. 1 0
      Tests/RunCMake/XcFramework/import-macos-install-specific-no-xcframework.cmake
  29. 1 0
      Tests/RunCMake/XcFramework/import-macos-install-specific.cmake
  30. 3 0
      Tests/RunCMake/XcFramework/mylib-config.cmake.in

+ 13 - 0
Help/command/export.rst

@@ -170,6 +170,9 @@ Configuring Exports
           [ENABLED (<bool-true>|<bool-false>|AUTO)]
           [EXTRA_ARGS <args>...]
          ] [...]
+         [TARGET <target>
+          [XCFRAMEWORK_LOCATION <location>]
+         ] [...]
          )
 
 .. versionadded:: 3.29
@@ -202,3 +205,13 @@ Configure the parameters of an export. The arguments are as follows:
   ``EXTRA_ARGS <args>``
     Specify additional arguments to pass to :command:`find_dependency` after
     the ``REQUIRED`` argument.
+
+``TARGET <target>``
+  Specify a target to configure in this export. This argument accepts the
+  following additional arguments:
+
+  ``XCFRAMEWORK_LOCATION``
+    Specify the location of an ``.xcframework`` which contains the library from
+    this target. If specified, the generated code will check to see if the
+    ``.xcframework`` exists, and if it does, it will use the ``.xcframework``
+    as its imported location instead of the installed library.

+ 6 - 0
Help/release/dev/install-export-xcframework.rst

@@ -0,0 +1,6 @@
+install-export-xcframework
+--------------------------
+
+* The :command:`export(SETUP)` command gained a new ``XCFRAMEWORK_LOCATION``
+  argument, which can be used to specify the location of a ``.xcframework``
+  that can be substituted for the installed library.

+ 2 - 2
Source/cmExportBuildAndroidMKGenerator.cxx

@@ -57,8 +57,8 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
 }
 
 void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode(
-  std::ostream&, const std::string&, cmGeneratorTarget const*,
-  ImportPropertyMap const&)
+  std::ostream&, const std::string&, const std::string&,
+  cmGeneratorTarget const*, ImportPropertyMap const&, const std::string&)
 {
 }
 

+ 3 - 3
Source/cmExportBuildAndroidMKGenerator.h

@@ -51,9 +51,9 @@ protected:
   void GenerateExpectedTargetsCode(
     std::ostream& os, const std::string& expectedTargets) override;
   void GenerateImportPropertyCode(
-    std::ostream& os, const std::string& config,
-    cmGeneratorTarget const* target,
-    ImportPropertyMap const& properties) override;
+    std::ostream& os, const std::string& config, const std::string& suffix,
+    cmGeneratorTarget const* target, ImportPropertyMap const& properties,
+    const std::string& importedXcFrameworkLocation) override;
   void GenerateMissingTargetsCheckCode(std::ostream& os) override;
   void GenerateFindDependencyCalls(std::ostream&) override {}
   void GenerateInterfaceProperties(

+ 19 - 3
Source/cmExportBuildFileGenerator.cxx

@@ -61,7 +61,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
       expectedTargets += sep + this->Namespace + te->GetExportName();
       sep = " ";
       if (this->ExportedTargets.insert(te).second) {
-        this->Exports.emplace_back(te);
+        this->Exports.emplace_back(te, tei.XcFrameworkLocation);
       } else {
         std::ostringstream e;
         e << "given target \"" << te->GetName() << "\" more than once.";
@@ -202,7 +202,23 @@ void cmExportBuildFileGenerator::GenerateImportTargetsConfig(
       //                              properties);
 
       // Generate code in the export file.
-      this->GenerateImportPropertyCode(os, config, target, properties);
+      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);
     }
   }
 }
@@ -318,7 +334,7 @@ void cmExportBuildFileGenerator::GetTargets(
       if (te->NamelinkOnly) {
         continue;
       }
-      targets.emplace_back(te->TargetName);
+      targets.emplace_back(te->TargetName, te->XcFrameworkLocation);
     }
     return;
   }

+ 7 - 2
Source/cmExportBuildFileGenerator.h

@@ -35,12 +35,14 @@ class cmExportBuildFileGenerator : public cmExportFileGenerator
 public:
   struct TargetExport
   {
-    TargetExport(std::string name)
+    TargetExport(std::string name, std::string xcFrameworkLocation)
       : Name(std::move(name))
+      , XcFrameworkLocation(std::move(xcFrameworkLocation))
     {
     }
 
     std::string Name;
+    std::string XcFrameworkLocation;
   };
 
   cmExportBuildFileGenerator();
@@ -111,12 +113,15 @@ protected:
 
   struct TargetExportPrivate
   {
-    TargetExportPrivate(cmGeneratorTarget* target)
+    TargetExportPrivate(cmGeneratorTarget* target,
+                        std::string xcFrameworkLocation)
       : Target(target)
+      , XcFrameworkLocation(std::move(xcFrameworkLocation))
     {
     }
 
     cmGeneratorTarget* Target;
+    std::string XcFrameworkLocation;
   };
 
   std::vector<TargetExport> Targets;

+ 29 - 1
Source/cmExportCommand.cxx

@@ -72,6 +72,8 @@ bool cmExportCommand(std::vector<std::string> const& args,
 
     std::vector<std::vector<std::string>> PackageDependencyArgs;
     bool ExportPackageDependencies = false;
+
+    std::vector<std::vector<std::string>> TargetArgs;
   };
 
   auto parser =
@@ -87,6 +89,7 @@ bool cmExportCommand(std::vector<std::string> const& args,
   } else if (args[0] == "SETUP") {
     parser.Bind("SETUP"_s, &Arguments::ExportSetName);
     parser.Bind("PACKAGE_DEPENDENCY"_s, &Arguments::PackageDependencyArgs);
+    parser.Bind("TARGET"_s, &Arguments::TargetArgs);
   } else {
     parser.Bind("TARGETS"_s, &Arguments::Targets);
     parser.Bind("ANDROID_MK"_s, &Arguments::AndroidMKFile);
@@ -159,6 +162,31 @@ bool cmExportCommand(std::vector<std::string> const& args,
                  packageDependencyArguments.ExtraArgs);
     }
 
+    struct TargetArguments
+    {
+      std::string XcFrameworkLocation;
+    };
+
+    auto targetParser = cmArgumentParser<TargetArguments>{}.Bind(
+      "XCFRAMEWORK_LOCATION"_s, &TargetArguments::XcFrameworkLocation);
+
+    for (auto const& targetArgs : arguments.TargetArgs) {
+      if (targetArgs.empty()) {
+        continue;
+      }
+
+      TargetArguments const targetArguments =
+        targetParser.Parse(cmMakeRange(targetArgs).advance(1), &unknownArgs);
+
+      if (!unknownArgs.empty()) {
+        status.SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
+        return false;
+      }
+
+      exportSet.SetXcFrameworkLocation(targetArgs.front(),
+                                       targetArguments.XcFrameworkLocation);
+    }
+
     return true;
   }
 
@@ -242,7 +270,7 @@ bool cmExportCommand(std::vector<std::string> const& args,
         status.SetError(e.str());
         return false;
       }
-      targets.emplace_back(currentTarget);
+      targets.emplace_back(currentTarget, std::string{});
     }
     if (arguments.Append) {
       if (cmExportBuildFileGenerator* ebfg =

+ 47 - 17
Source/cmExportFileGenerator.cxx

@@ -1154,8 +1154,9 @@ void cmExportFileGenerator::GenerateImportTargetCode(
 }
 
 void cmExportFileGenerator::GenerateImportPropertyCode(
-  std::ostream& os, const std::string& config, cmGeneratorTarget const* target,
-  ImportPropertyMap const& properties)
+  std::ostream& os, const std::string& config, const std::string& suffix,
+  cmGeneratorTarget const* target, ImportPropertyMap const& properties,
+  const std::string& importedXcFrameworkLocation)
 {
   // Construct the imported target name.
   std::string targetName = this->Namespace;
@@ -1174,12 +1175,31 @@ void cmExportFileGenerator::GenerateImportPropertyCode(
   }
   os << ")\n";
   os << "set_target_properties(" << targetName << " PROPERTIES\n";
+  std::string importedLocationProp = cmStrCat("IMPORTED_LOCATION", suffix);
   for (auto const& property : properties) {
-    os << "  " << property.first << " "
-       << cmExportFileGeneratorEscape(property.second) << "\n";
+    if (importedXcFrameworkLocation.empty() ||
+        property.first != importedLocationProp) {
+      os << "  " << property.first << " "
+         << cmExportFileGeneratorEscape(property.second) << "\n";
+    }
   }
-  os << "  )\n"
-     << "\n";
+  os << "  )\n";
+  if (!importedXcFrameworkLocation.empty()) {
+    auto importedLocationIt = properties.find(importedLocationProp);
+    if (importedLocationIt != properties.end()) {
+      os << "if(NOT CMAKE_VERSION VERSION_LESS \"3.28\" AND IS_DIRECTORY "
+         << cmExportFileGeneratorEscape(importedXcFrameworkLocation)
+         << ")\n"
+            "  set_property(TARGET "
+         << targetName << " PROPERTY " << importedLocationProp << " "
+         << cmExportFileGeneratorEscape(importedXcFrameworkLocation)
+         << ")\nelse()\n  set_property(TARGET " << targetName << " PROPERTY "
+         << importedLocationProp << " "
+         << cmExportFileGeneratorEscape(importedLocationIt->second)
+         << ")\nendif()\n";
+    }
+  }
+  os << "\n";
 }
 
 void cmExportFileGenerator::GenerateFindDependencyCalls(std::ostream& os)
@@ -1310,10 +1330,16 @@ void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
   /* clang-format off */
   os << "# Loop over all imported files and verify that they actually exist\n"
         "foreach(_cmake_target IN LISTS _cmake_import_check_targets)\n"
-        "  foreach(_cmake_file IN LISTS \"_cmake_import_check_files_for_${_cmake_target}\")\n"
-        "    if(NOT EXISTS \"${_cmake_file}\")\n"
-        "      message(FATAL_ERROR \"The imported target \\\"${_cmake_target}\\\""
-        " references the file\n"
+        "  if(CMAKE_VERSION VERSION_LESS \"3.28\"\n"
+        "      OR NOT DEFINED "
+        "_cmake_import_check_xcframework_for_${_cmake_target}\n"
+        "      OR NOT IS_DIRECTORY "
+        "\"${_cmake_import_check_xcframework_for_${_cmake_target}}\")\n"
+        "    foreach(_cmake_file IN LISTS "
+        "\"_cmake_import_check_files_for_${_cmake_target}\")\n"
+        "      if(NOT EXISTS \"${_cmake_file}\")\n"
+        "        message(FATAL_ERROR \"The imported target "
+        "\\\"${_cmake_target}\\\" references the file\n"
         "   \\\"${_cmake_file}\\\"\n"
         "but this file does not exist.  Possible reasons include:\n"
         "* The file was deleted, renamed, or moved to another location.\n"
@@ -1322,8 +1348,9 @@ void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
         "   \\\"${CMAKE_CURRENT_LIST_FILE}\\\"\n"
         "but not all the files it references.\n"
         "\")\n"
-        "    endif()\n"
-        "  endforeach()\n"
+        "      endif()\n"
+        "    endforeach()\n"
+        "  endif()\n"
         "  unset(_cmake_file)\n"
         "  unset(\"_cmake_import_check_files_for_${_cmake_target}\")\n"
         "endforeach()\n"
@@ -1336,15 +1363,18 @@ void cmExportFileGenerator::GenerateImportedFileCheckLoop(std::ostream& os)
 void cmExportFileGenerator::GenerateImportedFileChecksCode(
   std::ostream& os, cmGeneratorTarget* target,
   ImportPropertyMap const& properties,
-  const std::set<std::string>& importedLocations)
+  const std::set<std::string>& importedLocations,
+  const std::string& importedXcFrameworkLocation)
 {
   // Construct the imported target name.
   std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
 
-  os << "list(APPEND _cmake_import_check_targets " << targetName
-     << " )\n"
-        "list(APPEND _cmake_import_check_files_for_"
-     << targetName << " ";
+  os << "list(APPEND _cmake_import_check_targets " << targetName << " )\n";
+  if (!importedXcFrameworkLocation.empty()) {
+    os << "set(_cmake_import_check_xcframework_for_" << targetName << ' '
+       << cmExportFileGeneratorEscape(importedXcFrameworkLocation) << ")\n";
+  }
+  os << "list(APPEND _cmake_import_check_files_for_" << targetName << " ";
 
   for (std::string const& li : importedLocations) {
     auto pi = properties.find(li);

+ 6 - 5
Source/cmExportFileGenerator.h

@@ -84,14 +84,15 @@ protected:
   virtual void GenerateImportTargetCode(std::ostream& os,
                                         cmGeneratorTarget const* target,
                                         cmStateEnums::TargetType targetType);
-  virtual void GenerateImportPropertyCode(std::ostream& os,
-                                          const std::string& config,
-                                          cmGeneratorTarget const* target,
-                                          ImportPropertyMap const& properties);
+  virtual void GenerateImportPropertyCode(
+    std::ostream& os, const std::string& config, const std::string& suffix,
+    cmGeneratorTarget const* target, ImportPropertyMap const& properties,
+    const std::string& importedXcFrameworkLocation);
   virtual void GenerateImportedFileChecksCode(
     std::ostream& os, cmGeneratorTarget* target,
     ImportPropertyMap const& properties,
-    const std::set<std::string>& importedLocations);
+    const std::set<std::string>& importedLocations,
+    const std::string& importedXcFrameworkLocation);
   virtual void GenerateImportedFileCheckLoop(std::ostream& os);
   virtual void GenerateMissingTargetsCheckCode(std::ostream& os);
   virtual void GenerateFindDependencyCalls(std::ostream& os);

+ 3 - 3
Source/cmExportInstallAndroidMKGenerator.cxx

@@ -80,8 +80,8 @@ void cmExportInstallAndroidMKGenerator::GenerateExpectedTargetsCode(
 }
 
 void cmExportInstallAndroidMKGenerator::GenerateImportPropertyCode(
-  std::ostream&, const std::string&, cmGeneratorTarget const*,
-  ImportPropertyMap const&)
+  std::ostream&, const std::string&, const std::string&,
+  cmGeneratorTarget const*, ImportPropertyMap const&, const std::string&)
 {
 }
 
@@ -122,7 +122,7 @@ void cmExportInstallAndroidMKGenerator::GenerateImportedFileCheckLoop(
 
 void cmExportInstallAndroidMKGenerator::GenerateImportedFileChecksCode(
   std::ostream&, cmGeneratorTarget*, ImportPropertyMap const&,
-  const std::set<std::string>&)
+  const std::set<std::string>&, const std::string&)
 {
 }
 

+ 5 - 4
Source/cmExportInstallAndroidMKGenerator.h

@@ -45,9 +45,9 @@ protected:
   void GenerateExpectedTargetsCode(
     std::ostream& os, const std::string& expectedTargets) override;
   void GenerateImportPropertyCode(
-    std::ostream& os, const std::string& config,
-    cmGeneratorTarget const* target,
-    ImportPropertyMap const& properties) override;
+    std::ostream& os, const std::string& config, const std::string& suffix,
+    cmGeneratorTarget const* target, ImportPropertyMap const& properties,
+    const std::string& importedXcFrameworkLocation) override;
   void GenerateMissingTargetsCheckCode(std::ostream& os) override;
   void GenerateFindDependencyCalls(std::ostream&) override {}
   void GenerateInterfaceProperties(
@@ -60,6 +60,7 @@ protected:
   void GenerateImportedFileChecksCode(
     std::ostream& os, cmGeneratorTarget* target,
     ImportPropertyMap const& properties,
-    const std::set<std::string>& importedLocations) override;
+    const std::set<std::string>& importedLocations,
+    const std::string& importedXcFrameworkLocation) override;
   bool GenerateImportFileConfig(const std::string& config) override;
 };

+ 20 - 3
Source/cmExportInstallFileGenerator.cxx

@@ -375,9 +375,26 @@ void cmExportInstallFileGenerator::GenerateImportTargetsConfig(
       //                              properties);
 
       // Generate code in the export file.
-      this->GenerateImportPropertyCode(os, config, gtgt, properties);
-      this->GenerateImportedFileChecksCode(os, gtgt, properties,
-                                           importedLocations);
+      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);
     }
   }
 }

+ 10 - 0
Source/cmExportSet.cxx

@@ -72,6 +72,16 @@ void cmExportSet::AddInstallation(cmInstallExportGenerator const* installation)
   this->Installations.push_back(installation);
 }
 
+void cmExportSet::SetXcFrameworkLocation(const std::string& name,
+                                         const std::string& location)
+{
+  for (auto& te : this->TargetExports) {
+    if (name == te->TargetName) {
+      te->XcFrameworkLocation = location;
+    }
+  }
+}
+
 cmExportSet& cmExportSetMap::operator[](const std::string& name)
 {
   auto it = this->find(name);

+ 3 - 0
Source/cmExportSet.h

@@ -33,6 +33,9 @@ public:
 
   void AddInstallation(cmInstallExportGenerator const* installation);
 
+  void SetXcFrameworkLocation(const std::string& name,
+                              const std::string& location);
+
   std::string const& GetName() const { return this->Name; }
 
   std::vector<std::unique_ptr<cmTargetExport>> const& GetTargetExports() const

+ 1 - 0
Source/cmTargetExport.h

@@ -38,4 +38,5 @@ public:
   ///@}
 
   bool NamelinkOnly = false;
+  std::string XcFrameworkLocation;
 };

+ 103 - 0
Tests/RunCMake/XcFramework/RunCMakeTest.cmake

@@ -119,3 +119,106 @@ unset(RunCMake_TEST_BINARY_DIR)
 
 run_cmake(find-library)
 run_cmake_command(find-library-script ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/find-library.cmake)
+
+file(REMOVE_RECURSE ${RunCMake_BINARY_DIR}/export-install)
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/export-macos-build)
+run_cmake_with_options(export-macos -DCMAKE_SYSTEM_NAME=Darwin -DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/export-install)
+set(RunCMake_TEST_NO_CLEAN 1)
+set(_config_arg)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(_config_arg --config Release)
+endif()
+run_cmake_command(export-macos-build ${CMAKE_COMMAND} --build . ${_config_arg})
+run_cmake_command(export-macos-install ${CMAKE_COMMAND} --install . ${_config_arg})
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/import-macos-install-specific-no-xcframework-build)
+run_cmake_with_options(import-macos-install-specific-no-xcframework -DCMAKE_SYSTEM_NAME=Darwin -Dmylib_DIR=${RunCMake_BINARY_DIR}/export-install/lib/macos/cmake/mylib)
+set(RunCMake_TEST_NO_CLEAN 1)
+set(_config_arg)
+set(_config_dir)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(_config_arg --config Release)
+  set(_config_dir /Release)
+endif()
+run_cmake_command(import-macos-install-specific-no-xcframework-build ${CMAKE_COMMAND} --build . ${_config_arg})
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/export-macos-build)
+set(RunCMake_TEST_NO_CLEAN 1)
+if(CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 15)
+  # 'xcodebuild -create-xcframework' fails on symlinked paths.
+  file(REAL_PATH "${RunCMake_SOURCE_DIR}" src_dir)
+  file(REAL_PATH "${RunCMake_BINARY_DIR}" bld_dir)
+else()
+  set(src_dir "${RunCMake_SOURCE_DIR}")
+  set(bld_dir "${RunCMake_BINARY_DIR}")
+endif()
+run_cmake_command(export-install-xcframework xcodebuild -create-xcframework
+  -output ${bld_dir}/export-install/lib/mylib.xcframework
+  -library ${bld_dir}/export-install/lib/macos/libmylib.a
+  -headers ${src_dir}/mylib/include
+  )
+run_cmake_command(export-build-xcframework xcodebuild -create-xcframework
+  -output ${bld_dir}/export-macos-build/lib/mylib.xcframework
+  -library ${bld_dir}/export-macos-build/lib/macos${_config_dir}/libmylib.a
+  -headers ${src_dir}/mylib/include
+  )
+run_cmake_command(export-install-xcframework-genex xcodebuild -create-xcframework
+  -output ${bld_dir}/export-install/lib2/mylib-genex.xcframework
+  -library ${bld_dir}/export-install/lib/macos/libmylib-genex.a
+  -headers ${src_dir}/mylib/include
+  )
+run_cmake_command(export-build-xcframework-genex xcodebuild -create-xcframework
+  -output ${bld_dir}/export-macos-build/lib/mylib-genex.xcframework
+  -library ${bld_dir}/export-macos-build/lib/macos${_config_dir}/libmylib-genex.a
+  -headers ${src_dir}/mylib/include
+  )
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/import-macos-install-specific-build)
+run_cmake_with_options(import-macos-install-specific -DCMAKE_SYSTEM_NAME=Darwin -Dmylib_DIR=${RunCMake_BINARY_DIR}/export-install/lib/macos/cmake/mylib)
+set(RunCMake_TEST_NO_CLEAN 1)
+set(_config_arg)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(_config_arg --config Release)
+endif()
+run_cmake_command(import-macos-install-specific-build ${CMAKE_COMMAND} --build . ${_config_arg})
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/import-macos-build-specific-build)
+run_cmake_with_options(import-macos-build-specific -DCMAKE_SYSTEM_NAME=Darwin -Dmylib_DIR=${RunCMake_BINARY_DIR}/export-macos-build/lib/macos/cmake/mylib)
+set(RunCMake_TEST_NO_CLEAN 1)
+set(_config_arg)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(_config_arg --config Release)
+endif()
+run_cmake_command(import-macos-build-specific-build ${CMAKE_COMMAND} --build . ${_config_arg})
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/import-macos-install-specific-genex-build)
+run_cmake_with_options(import-macos-install-specific-genex -DCMAKE_SYSTEM_NAME=Darwin -Dmylib_DIR=${RunCMake_BINARY_DIR}/export-install/lib/macos/cmake/mylib)
+set(RunCMake_TEST_NO_CLEAN 1)
+set(_config_arg)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(_config_arg --config Release)
+endif()
+run_cmake_command(import-macos-install-specific-genex-build ${CMAKE_COMMAND} --build . ${_config_arg})
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/import-macos-build-specific-genex-build)
+run_cmake_with_options(import-macos-build-specific-genex -DCMAKE_SYSTEM_NAME=Darwin -Dmylib_DIR=${RunCMake_BINARY_DIR}/export-macos-build/lib/macos/cmake/mylib)
+set(RunCMake_TEST_NO_CLEAN 1)
+set(_config_arg)
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(_config_arg --config Release)
+endif()
+run_cmake_command(import-macos-build-specific-genex-build ${CMAKE_COMMAND} --build . ${_config_arg})
+unset(RunCMake_TEST_NO_CLEAN)
+unset(RunCMake_TEST_BINARY_DIR)

+ 33 - 0
Tests/RunCMake/XcFramework/export-macos.cmake

@@ -0,0 +1,33 @@
+enable_language(C)
+
+include(CMakePackageConfigHelpers)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+  set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO")
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "tvOS" OR CMAKE_SYSTEM_NAME STREQUAL "watchOS" OR CMAKE_SYSTEM_NAME STREQUAL "visionOS")
+  set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES")
+endif()
+
+add_library(mylib STATIC mylib/mylib.c)
+target_include_directories(mylib INTERFACE $<INSTALL_INTERFACE:include>)
+set_property(TARGET mylib PROPERTY ARCHIVE_OUTPUT_DIRECTORY lib/macos)
+
+add_library(mylib-genex STATIC mylib/mylib.c)
+target_include_directories(mylib-genex INTERFACE $<INSTALL_INTERFACE:include>)
+set_property(TARGET mylib-genex PROPERTY ARCHIVE_OUTPUT_DIRECTORY lib/macos)
+
+install(TARGETS mylib mylib-genex DESTINATION lib/macos EXPORT mylib)
+install(FILES mylib/include/mylib/mylib.h DESTINATION include/mylib)
+export(SETUP mylib
+  TARGET mylib XCFRAMEWORK_LOCATION lib/mylib.xcframework
+  TARGET mylib-genex XCFRAMEWORK_LOCATION "$<BUILD_INTERFACE:lib/$<TARGET_PROPERTY:NAME>.xcframework>$<INSTALL_INTERFACE:lib2/$<TARGET_PROPERTY:NAME>.xcframework>"
+  )
+install(EXPORT mylib DESTINATION lib/macos/cmake/mylib FILE mylib-targets.cmake)
+export(EXPORT mylib FILE lib/macos/cmake/mylib/mylib-targets.cmake)
+
+configure_package_config_file(mylib-config.cmake.in mylib-config-sub.cmake INSTALL_DESTINATION lib/macos/cmake/mylib)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mylib-config-sub.cmake DESTINATION lib/macos/cmake/mylib RENAME mylib-config.cmake)
+
+configure_package_config_file(mylib-config.cmake.in lib/macos/cmake/mylib/mylib-config.cmake INSTALL_DESTINATION lib/macos/cmake/mylib)

+ 5 - 0
Tests/RunCMake/XcFramework/import-common.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+find_package(mylib REQUIRED)
+
+add_custom_target(print_loc ALL COMMAND ${CMAKE_COMMAND} -E echo "mylib location: $<TARGET_FILE:mylib>")

+ 5 - 0
Tests/RunCMake/XcFramework/import-genex-common.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+find_package(mylib REQUIRED)
+
+add_custom_target(print_loc ALL COMMAND ${CMAKE_COMMAND} -E echo "mylib-genex location: $<TARGET_FILE:mylib-genex>")

+ 2 - 0
Tests/RunCMake/XcFramework/import-macos-build-specific-build-stdout.txt

@@ -0,0 +1,2 @@
+mylib location: [^
+]*/Tests/RunCMake/XcFramework/export-macos-build/lib/mylib\.xcframework/macos-(arm64|x86_64|arm64_x86_64)/libmylib\.a

+ 2 - 0
Tests/RunCMake/XcFramework/import-macos-build-specific-genex-build-stdout.txt

@@ -0,0 +1,2 @@
+mylib-genex location: [^
+]*/Tests/RunCMake/XcFramework/export-macos-build/lib/mylib-genex\.xcframework/macos-(arm64|x86_64|arm64_x86_64)/libmylib-genex\.a

+ 1 - 0
Tests/RunCMake/XcFramework/import-macos-build-specific-genex.cmake

@@ -0,0 +1 @@
+include(import-genex-common.cmake)

+ 1 - 0
Tests/RunCMake/XcFramework/import-macos-build-specific.cmake

@@ -0,0 +1 @@
+include(import-common.cmake)

+ 2 - 0
Tests/RunCMake/XcFramework/import-macos-install-specific-build-stdout.txt

@@ -0,0 +1,2 @@
+mylib location: [^
+]*/Tests/RunCMake/XcFramework/export-install/lib/mylib\.xcframework/macos-(arm64|x86_64|arm64_x86_64)/libmylib\.a

+ 2 - 0
Tests/RunCMake/XcFramework/import-macos-install-specific-genex-build-stdout.txt

@@ -0,0 +1,2 @@
+mylib-genex location: [^
+]*/Tests/RunCMake/XcFramework/export-install/lib2/mylib-genex\.xcframework/macos-(arm64|x86_64|arm64_x86_64)/libmylib-genex\.a

+ 1 - 0
Tests/RunCMake/XcFramework/import-macos-install-specific-genex.cmake

@@ -0,0 +1 @@
+include(import-genex-common.cmake)

+ 2 - 0
Tests/RunCMake/XcFramework/import-macos-install-specific-no-xcframework-build-stdout.txt

@@ -0,0 +1,2 @@
+mylib location: [^
+]*/Tests/RunCMake/XcFramework/export-install/lib/macos/libmylib\.a

+ 1 - 0
Tests/RunCMake/XcFramework/import-macos-install-specific-no-xcframework.cmake

@@ -0,0 +1 @@
+include(import-common.cmake)

+ 1 - 0
Tests/RunCMake/XcFramework/import-macos-install-specific.cmake

@@ -0,0 +1 @@
+include(import-common.cmake)

+ 3 - 0
Tests/RunCMake/XcFramework/mylib-config.cmake.in

@@ -0,0 +1,3 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/mylib-targets.cmake")