summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2023-05-17 17:50:32 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2023-07-26 21:00:01 (GMT)
commit7050ac56a11768c90f55654aa3f63d02bb549243 (patch)
treea436ee5be767bfd776dc93d747abd122a94f3a34
parent93ed53790cb1e2d5f25f26156ee5c6590b0d3150 (diff)
downloadCMake-7050ac56a11768c90f55654aa3f63d02bb549243.zip
CMake-7050ac56a11768c90f55654aa3f63d02bb549243.tar.gz
CMake-7050ac56a11768c90f55654aa3f63d02bb549243.tar.bz2
macOS: Add support for linking against .xcframework folders
Issue: #21752
-rw-r--r--Help/command/target_link_libraries.rst6
-rw-r--r--Help/prop_tgt/IMPORTED_LOCATION.rst6
-rw-r--r--Help/release/dev/xcframework-target-link-libraries.rst7
-rw-r--r--Source/CMakeLists.txt4
-rw-r--r--Source/cmComputeLinkInformation.cxx88
-rw-r--r--Source/cmComputeLinkInformation.h5
-rw-r--r--Source/cmGeneratorTarget.cxx41
-rw-r--r--Source/cmGeneratorTarget.h2
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx63
-rw-r--r--Source/cmLocalGenerator.cxx39
-rw-r--r--Source/cmLocalGenerator.h3
-rw-r--r--Source/cmPlistParser.cxx33
-rw-r--r--Source/cmPlistParser.h13
-rw-r--r--Source/cmSystemTools.cxx6
-rw-r--r--Source/cmSystemTools.h3
-rw-r--r--Source/cmTarget.cxx20
-rw-r--r--Source/cmXcFramework.cxx174
-rw-r--r--Source/cmXcFramework.h44
-rw-r--r--Tests/RunCMake/CMakeLists.txt17
-rw-r--r--Tests/RunCMake/XcFramework/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/XcFramework/RunCMakeTest.cmake83
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-link-phase-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-link-phase-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-link-phase-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-link-phase-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-link-phase-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-framework-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-result.txt1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-stderr.txt11
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-incomplete-result.txt1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-incomplete-stderr.txt10
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-incomplete.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-link-phase-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-link-phase-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-link-phase-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-link-phase-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-link-phase-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-library-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-link-phase.cmake2
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-framework-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-result.txt1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-stderr.txt11
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-incomplete-result.txt1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-incomplete-stderr.txt10
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-incomplete.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-library-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target-link-phase.cmake2
-rw-r--r--Tests/RunCMake/XcFramework/create-executable-target.cmake21
-rw-r--r--Tests/RunCMake/XcFramework/create-executable.cmake18
-rw-r--r--Tests/RunCMake/XcFramework/create-framework-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-framework-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-framework-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-framework-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-framework-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-framework.cmake3
-rw-r--r--Tests/RunCMake/XcFramework/create-library-common.cmake12
-rw-r--r--Tests/RunCMake/XcFramework/create-library-ios.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-library-macos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-library-tvos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-library-visionos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-library-watchos.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/create-library.cmake1
-rw-r--r--Tests/RunCMake/XcFramework/myexe/myexe.c7
-rw-r--r--Tests/RunCMake/XcFramework/mylib/include/mylib/mylib.h3
-rw-r--r--Tests/RunCMake/XcFramework/mylib/mylib.c3
-rwxr-xr-xbootstrap2
94 files changed, 828 insertions, 6 deletions
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index 1d27660..cc6bc0f 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -66,6 +66,12 @@ Each ``<item>`` may be:
:ref:`usage requirement <Target Usage Requirements>`. This has the same
effect as passing the framework directory as an include directory.
+ .. versionadded:: 3.28
+
+ The library file may point to a ``.xcframework`` folder on macOS. If it
+ does, the target will get the selected library's ``Headers`` directory as
+ a usage requirement.
+
.. versionadded:: 3.8
On :ref:`Visual Studio Generators` for VS 2010 and above, library files
ending in ``.targets`` will be treated as MSBuild targets files and
diff --git a/Help/prop_tgt/IMPORTED_LOCATION.rst b/Help/prop_tgt/IMPORTED_LOCATION.rst
index 50c3658..915085b 100644
--- a/Help/prop_tgt/IMPORTED_LOCATION.rst
+++ b/Help/prop_tgt/IMPORTED_LOCATION.rst
@@ -20,6 +20,12 @@ non-imported targets.
For frameworks on macOS, this may be the location of the framework folder
itself.
+.. versionadded:: 3.28
+
+ This may be the location of a ``.xcframework`` folder on macOS. If it is,
+ any target that links against it will get the selected library's ``Headers``
+ directory as a usage requirement.
+
The ``IMPORTED_LOCATION`` target property may be overridden for a
given configuration ``<CONFIG>`` by the configuration-specific
:prop_tgt:`IMPORTED_LOCATION_<CONFIG>` target property. Furthermore,
diff --git a/Help/release/dev/xcframework-target-link-libraries.rst b/Help/release/dev/xcframework-target-link-libraries.rst
new file mode 100644
index 0000000..7edded5
--- /dev/null
+++ b/Help/release/dev/xcframework-target-link-libraries.rst
@@ -0,0 +1,7 @@
+xcframework-target-link-libraries
+---------------------------------
+
+* Targets may now link against an ``.xcframework`` folder in
+ :command:`target_link_libraries`.
+* The :prop_tgt:`IMPORTED_LOCATION` property of a target may now be an
+ ``.xcframework`` folder.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 708aec7..a067766 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -371,6 +371,8 @@ add_library(
cmNewLineStyle.cxx
cmOrderDirectories.cxx
cmOrderDirectories.h
+ cmPlistParser.cxx
+ cmPlistParser.h
cmPolicies.h
cmPolicies.cxx
cmProcessOutput.cxx
@@ -451,6 +453,8 @@ add_library(
cmWorkerPool.h
cmWorkingDirectory.cxx
cmWorkingDirectory.h
+ cmXcFramework.cxx
+ cmXcFramework.h
cmXMLParser.cxx
cmXMLParser.h
cmXMLSafe.cxx
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index a50ce11..be73fa3 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -29,6 +29,7 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmValue.h"
+#include "cmXcFramework.h"
#include "cmake.h"
// #define CM_COMPUTE_LINK_INFO_DEBUG
@@ -373,6 +374,10 @@ cmComputeLinkInformation::cmComputeLinkInformation(
this->LibraryFeatureDescriptors.emplace(
"__CMAKE_LINK_FRAMEWORK",
LibraryFeatureDescriptor{ "__CMAKE_LINK_FRAMEWORK", "<LIBRARY>" });
+ // To link xcframework using a full path
+ this->LibraryFeatureDescriptors.emplace(
+ "__CMAKE_LINK_XCFRAMEWORK",
+ LibraryFeatureDescriptor{ "__CMAKE_LINK_XCFRAMEWORK", "<LIBRARY>" });
// Check the platform policy for missing soname case.
this->NoSONameUsesPath =
@@ -519,6 +524,12 @@ cmComputeLinkInformation::GetFrameworkPathsEmitted() const
return this->FrameworkPathsEmitted;
}
+std::vector<std::string> const&
+cmComputeLinkInformation::GetXcFrameworkHeaderPaths() const
+{
+ return this->XcFrameworkHeaderPaths;
+}
+
const std::set<const cmGeneratorTarget*>&
cmComputeLinkInformation::GetSharedLibrariesLinked() const
{
@@ -1159,6 +1170,13 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
} else {
this->ObjectLibrariesLinked.push_back(entry.Target);
}
+ } else if (this->GlobalGenerator->IsXcode() &&
+ !tgt->GetImportedXcFrameworkPath(config).empty()) {
+ this->Items.emplace_back(
+ tgt->GetImportedXcFrameworkPath(config), ItemIsPath::Yes, tgt,
+ this->FindLibraryFeature(entry.Feature == DEFAULT
+ ? "__CMAKE_LINK_XCFRAMEWORK"
+ : entry.Feature));
} else {
// Decide whether to use an import library.
cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
@@ -1198,6 +1216,25 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
this->AddRuntimeDLL(tgt);
}
}
+
+ auto xcFrameworkPath = tgt->GetImportedXcFrameworkPath(config);
+ if (!xcFrameworkPath.empty()) {
+ auto plist = cmParseXcFrameworkPlist(xcFrameworkPath, *this->Makefile,
+ item.Backtrace);
+ if (!plist) {
+ return;
+ }
+ if (auto const* library =
+ plist->SelectSuitableLibrary(*this->Makefile, item.Backtrace)) {
+ if (!library->HeadersPath.empty()) {
+ this->AddXcFrameworkHeaderPath(cmStrCat(xcFrameworkPath, '/',
+ library->LibraryIdentifier,
+ '/', library->HeadersPath));
+ }
+ } else {
+ return;
+ }
+ }
} else {
// This is not a CMake target. Use the name given.
if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) ||
@@ -1206,6 +1243,12 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
this->Target->IsApple())) {
// This is a framework.
this->AddFrameworkItem(entry);
+ } else if (cmHasSuffix(entry.Feature, "XCFRAMEWORK"_s) ||
+ (entry.Feature == DEFAULT &&
+ cmSystemTools::IsPathToXcFramework(item.Value) &&
+ this->Target->IsApple())) {
+ // This is a framework.
+ this->AddXcFrameworkItem(entry);
} else if (cmSystemTools::FileIsFullPath(item.Value)) {
if (cmSystemTools::FileIsDirectory(item.Value)) {
// This is a directory.
@@ -1945,6 +1988,46 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
}
}
+void cmComputeLinkInformation::AddXcFrameworkItem(LinkEntry const& entry)
+{
+ auto plist = cmParseXcFrameworkPlist(entry.Item.Value, *this->Makefile,
+ entry.Item.Backtrace);
+ if (!plist) {
+ return;
+ }
+
+ if (auto const* lib =
+ plist->SelectSuitableLibrary(*this->Makefile, entry.Item.Backtrace)) {
+ if (this->GlobalGenerator->IsXcode()) {
+ this->Items.emplace_back(
+ entry.Item.Value, ItemIsPath::Yes, nullptr,
+ this->FindLibraryFeature(entry.Feature == DEFAULT
+ ? "__CMAKE_LINK_XCFRAMEWORK"
+ : entry.Feature));
+ } else {
+ auto libraryPath = cmStrCat(
+ entry.Item.Value, '/', lib->LibraryIdentifier, '/', lib->LibraryPath);
+ LinkEntry libraryEntry(
+ BT<std::string>(libraryPath, entry.Item.Backtrace), entry.Target);
+
+ if (cmSystemTools::IsPathToFramework(libraryPath) &&
+ this->Target->IsApple()) {
+ // This is a framework.
+ this->AddFrameworkItem(libraryEntry);
+ } else {
+ this->Depends.push_back(libraryPath);
+ this->AddFullItem(libraryEntry);
+ this->AddLibraryRuntimeInfo(libraryPath);
+ if (!lib->HeadersPath.empty()) {
+ this->AddXcFrameworkHeaderPath(cmStrCat(entry.Item.Value, '/',
+ lib->LibraryIdentifier, '/',
+ lib->HeadersPath));
+ }
+ }
+ }
+ }
+}
+
void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item)
{
// A full path to a directory was found as a link item. Warn the
@@ -1982,6 +2065,11 @@ void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
}
}
+void cmComputeLinkInformation::AddXcFrameworkHeaderPath(std::string const& p)
+{
+ this->XcFrameworkHeaderPaths.push_back(p);
+}
+
bool cmComputeLinkInformation::CheckSharedLibNoSOName(LinkEntry const& entry)
{
// This platform will use the path to a library as its soname if the
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index 8393a29..e75423f 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -88,6 +88,7 @@ public:
std::vector<std::string> const& GetDepends() const;
std::vector<std::string> const& GetFrameworkPaths() const;
std::set<std::string> const& GetFrameworkPathsEmitted() const;
+ std::vector<std::string> const& GetXcFrameworkHeaderPaths() const;
std::string GetLinkLanguage() const { return this->LinkLanguage; }
std::vector<std::string> const& GetRuntimeSearchPath() const;
std::string const& GetRuntimeFlag() const { return this->RuntimeFlag; }
@@ -132,6 +133,7 @@ private:
std::vector<std::string> Directories;
std::vector<std::string> Depends;
std::vector<std::string> FrameworkPaths;
+ std::vector<std::string> XcFrameworkHeaderPaths;
std::vector<std::string> RuntimeSearchPath;
std::set<cmGeneratorTarget const*> SharedLibrariesLinked;
std::vector<cmGeneratorTarget const*> ObjectLibrariesLinked;
@@ -204,6 +206,7 @@ private:
bool CheckImplicitDirItem(LinkEntry const& entry);
void AddUserItem(LinkEntry const& entry, bool pathNotKnown);
void AddFrameworkItem(LinkEntry const& entry);
+ void AddXcFrameworkItem(LinkEntry const& entry);
void DropDirectoryItem(BT<std::string> const& item);
bool CheckSharedLibNoSOName(LinkEntry const& entry);
void AddSharedLibNoSOName(LinkEntry const& entry);
@@ -214,6 +217,8 @@ private:
void AddFrameworkPath(std::string const& p);
std::set<std::string> FrameworkPathsEmitted;
+ void AddXcFrameworkHeaderPath(std::string const& p);
+
// Linker search path computation.
std::unique_ptr<cmOrderDirectories> OrderLinkerSearchPath;
bool FinishLinkerSearchDirectories();
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 42be082..cff1574 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -8874,6 +8874,47 @@ std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
return filename;
}
+std::string cmGeneratorTarget::GetImportedXcFrameworkPath(
+ const std::string& config) const
+{
+ if (!(this->IsApple() && this->IsImported() &&
+ (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->GetType() == cmStateEnums::UNKNOWN_LIBRARY))) {
+ return {};
+ }
+
+ std::string desiredConfig = config;
+ if (config.empty()) {
+ desiredConfig = "NOCONFIG";
+ }
+
+ std::string result;
+
+ cmValue loc = nullptr;
+ cmValue imp = nullptr;
+ std::string suffix;
+
+ if (this->Target->GetMappedConfig(desiredConfig, loc, imp, suffix)) {
+ if (loc) {
+ result = *loc;
+ } else {
+ std::string impProp = cmStrCat("IMPORTED_LOCATION", suffix);
+ if (cmValue configLocation = this->GetProperty(impProp)) {
+ result = *configLocation;
+ } else if (cmValue location = this->GetProperty("IMPORTED_LOCATION")) {
+ result = *location;
+ }
+ }
+
+ if (cmSystemTools::IsPathToXcFramework(result)) {
+ return result;
+ }
+ }
+
+ return {};
+}
+
bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
{
auto sources = cmGeneratorTarget::GetSourceFiles(config);
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index a03513d..753d6f3 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -926,6 +926,8 @@ public:
cmSourceFile& source, const std::string& dir,
cm::optional<std::set<std::string>>& languages) const;
+ std::string GetImportedXcFrameworkPath(const std::string& config) const;
+
private:
void AddSourceCommon(const std::string& src, bool before = false);
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 0472631..247d4fc 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -53,6 +53,7 @@
#include "cmXCodeObject.h"
#include "cmXCodeScheme.h"
#include "cmXMLWriter.h"
+#include "cmXcFramework.h"
#include "cmake.h"
#if !defined(CMAKE_BOOTSTRAP) && defined(__APPLE__)
@@ -1061,12 +1062,14 @@ bool IsLinkPhaseLibraryExtension(const std::string& fileExt)
{
// Empty file extension is a special case for paths to framework's
// internal binary which could be MyFw.framework/Versions/*/MyFw
- return (fileExt == ".framework" || fileExt == ".a" || fileExt == ".o" ||
- fileExt == ".dylib" || fileExt == ".tbd" || fileExt.empty());
+ return (fileExt == ".framework" || fileExt == ".xcframework" ||
+ fileExt == ".a" || fileExt == ".o" || fileExt == ".dylib" ||
+ fileExt == ".tbd" || fileExt.empty());
}
bool IsLibraryType(const std::string& fileType)
{
- return (fileType == "wrapper.framework" || fileType == "archive.ar" ||
+ return (fileType == "wrapper.framework" ||
+ fileType == "wrapper.xcframework" || fileType == "archive.ar" ||
fileType == "compiled.mach-o.objfile" ||
fileType == "compiled.mach-o.dylib" ||
fileType == "compiled.mach-o.executable" ||
@@ -1079,6 +1082,9 @@ std::string GetDirectoryValueFromFileExtension(const std::string& dirExt)
if (ext == "framework") {
return "wrapper.framework";
}
+ if (ext == "xcframework") {
+ return "wrapper.xcframework";
+ }
if (ext == "xcassets") {
return "folder.assetcatalog";
}
@@ -3607,6 +3613,8 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
bool canUseLinkPhase = !libItem.HasFeature() ||
libItem.GetFeatureName() == "__CMAKE_LINK_FRAMEWORK"_s ||
libItem.GetFeatureName() == "FRAMEWORK"_s ||
+ libItem.GetFeatureName() == "__CMAKE_LINK_XCFRAMEWORK"_s ||
+ libItem.GetFeatureName() == "XCFRAMEWORK"_s ||
libItem.GetFeatureName() == "WEAK_FRAMEWORK"_s ||
libItem.GetFeatureName() == "WEAK_LIBRARY"_s;
if (canUseLinkPhase) {
@@ -3917,12 +3925,14 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
if (cmSystemTools::FileIsFullPath(cleanPath)) {
cleanPath = cmSystemTools::CollapseFullPath(cleanPath);
}
- bool isFramework =
+ bool isXcFramework =
+ cmHasSuffix(libName.GetFeatureName(), "XCFRAMEWORK"_s);
+ bool isFramework = !isXcFramework &&
cmHasSuffix(libName.GetFeatureName(), "FRAMEWORK"_s);
if (isFramework) {
const auto fwDescriptor = this->SplitFrameworkPath(
cleanPath, cmGlobalGenerator::FrameworkFormat::Extended);
- if (!fwDescriptor->Directory.empty() &&
+ if (isFramework && !fwDescriptor->Directory.empty() &&
emitted.insert(fwDescriptor->Directory).second) {
// This is a search path we had not added before and it isn't
// an implicit search path, so we need it
@@ -3940,13 +3950,54 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
fwDescriptor->GetLinkName()))
.Value);
}
+ } else if (isXcFramework) {
+ auto plist = cmParseXcFrameworkPlist(
+ cleanPath, *this->Makefiles.front(), libName.Value.Backtrace);
+ if (!plist) {
+ return;
+ }
+ if (auto const* library = plist->SelectSuitableLibrary(
+ *this->Makefiles.front(), libName.Value.Backtrace)) {
+ auto libraryPath =
+ cmStrCat(cleanPath, '/', library->LibraryIdentifier, '/',
+ library->LibraryPath);
+ if (auto const fwDescriptor = this->SplitFrameworkPath(
+ libraryPath,
+ cmGlobalGenerator::FrameworkFormat::Relaxed)) {
+ if (!fwDescriptor->Directory.empty() &&
+ emitted.insert(fwDescriptor->Directory).second) {
+ // This is a search path we had not added before and it
+ // isn't an implicit search path, so we need it
+ fwSearchPaths.Add(
+ this->XCodeEscapePath(fwDescriptor->Directory));
+ }
+ libPaths.Add(cmStrCat(
+ "-framework ",
+ this->XCodeEscapePath(fwDescriptor->GetLinkName())));
+ } else {
+ libPaths.Add(
+ libName.GetFormattedItem(this->XCodeEscapePath(libraryPath))
+ .Value);
+ if (!library->HeadersPath.empty()) {
+ this->AppendBuildSettingAttribute(
+ target, "HEADER_SEARCH_PATHS",
+ this->CreateString(this->XCodeEscapePath(
+ cmStrCat(cleanPath, '/', library->LibraryIdentifier, '/',
+ library->HeadersPath))),
+ configName);
+ }
+ }
+ } else {
+ return;
+ }
} else {
libPaths.Add(
libName.GetFormattedItem(this->XCodeEscapePath(cleanPath))
.Value);
}
if ((!libName.Target || libName.Target->IsImported()) &&
- (isFramework || IsLinkPhaseLibraryExtension(cleanPath))) {
+ (isFramework || isXcFramework ||
+ IsLinkPhaseLibraryExtension(cleanPath))) {
// Create file reference for embedding
auto it = this->ExternalLibRefs.find(cleanPath);
if (it == this->ExternalLibRefs.end()) {
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index cf1eb96..acefedc 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1659,6 +1659,8 @@ std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags(
this->AppendFlags(compileFlags, mf->GetDefineFlags());
this->AppendFlags(compileFlags,
this->GetFrameworkFlags(lang, config, target));
+ this->AppendFlags(compileFlags,
+ this->GetXcFrameworkFlags(lang, config, target));
if (!compileFlags.empty()) {
flags.emplace_back(std::move(compileFlags));
@@ -1724,6 +1726,43 @@ std::string cmLocalGenerator::GetFrameworkFlags(std::string const& lang,
return flags;
}
+std::string cmLocalGenerator::GetXcFrameworkFlags(std::string const& lang,
+ std::string const& config,
+ cmGeneratorTarget* target)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmMakefile* mf = lg->GetMakefile();
+
+ if (!target->IsApple()) {
+ return std::string();
+ }
+
+ cmValue includeSearchFlag =
+ mf->GetDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang));
+ cmValue sysIncludeSearchFlag =
+ mf->GetDefinition(cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
+
+ if (!includeSearchFlag && !sysIncludeSearchFlag) {
+ return std::string{};
+ }
+
+ std::string flags;
+ if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) {
+ std::vector<std::string> const& paths = cli->GetXcFrameworkHeaderPaths();
+ for (std::string const& path : paths) {
+ if (sysIncludeSearchFlag &&
+ target->IsSystemIncludeDirectory(path, config, lang)) {
+ flags += *sysIncludeSearchFlag;
+ } else {
+ flags += *includeSearchFlag;
+ }
+ flags += lg->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
+ flags += " ";
+ }
+ }
+ return flags;
+}
+
void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target,
std::string const& config,
std::string const& lang,
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index c811408..7734cbe 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -520,6 +520,9 @@ public:
std::string GetFrameworkFlags(std::string const& l,
std::string const& config,
cmGeneratorTarget* target);
+ std::string GetXcFrameworkFlags(std::string const& l,
+ std::string const& config,
+ cmGeneratorTarget* target);
virtual std::string GetTargetFortranFlags(cmGeneratorTarget const* target,
std::string const& config);
diff --git a/Source/cmPlistParser.cxx b/Source/cmPlistParser.cxx
new file mode 100644
index 0000000..ce3c171
--- /dev/null
+++ b/Source/cmPlistParser.cxx
@@ -0,0 +1,33 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmPlistParser.h"
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
+
+cm::optional<Json::Value> cmParsePlist(const std::string& filename)
+{
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(
+ { "/usr/bin/plutil", "-convert", "json", "-o", "-", filename });
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+ auto chain = builder.Start();
+ chain.Wait();
+
+ auto const& status = chain.GetStatus(0);
+ if (status.ExitStatus != 0) {
+ return cm::nullopt;
+ }
+
+ Json::Reader reader;
+ Json::Value value;
+ cmUVPipeIStream outputStream(chain.GetLoop(), chain.OutputStream());
+ if (!reader.parse(outputStream, value)) {
+ return cm::nullopt;
+ }
+ return cm::optional<Json::Value>(value);
+}
diff --git a/Source/cmPlistParser.h b/Source/cmPlistParser.h
new file mode 100644
index 0000000..2ace254
--- /dev/null
+++ b/Source/cmPlistParser.h
@@ -0,0 +1,13 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+#include <cm/optional>
+
+namespace Json {
+class Value;
+}
+
+cm::optional<Json::Value> cmParsePlist(const std::string& filename);
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 1fb0079..f014de9 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1900,6 +1900,12 @@ bool cmSystemTools::IsPathToFramework(const std::string& path)
cmHasLiteralSuffix(path, ".framework"));
}
+bool cmSystemTools::IsPathToXcFramework(const std::string& path)
+{
+ return (cmSystemTools::FileIsFullPath(path) &&
+ cmHasLiteralSuffix(path, ".xcframework"));
+}
+
bool cmSystemTools::IsPathToMacOSSharedLibrary(const std::string& path)
{
return (cmSystemTools::FileIsFullPath(path) &&
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 7d55d4b..6592f84 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -111,6 +111,9 @@ public:
//! Return true if the path is a framework
static bool IsPathToFramework(const std::string& path);
+ //! Return true if the path is a xcframework
+ static bool IsPathToXcFramework(const std::string& path);
+
//! Return true if the path is a macOS non-framework shared library (aka
//! .dylib)
static bool IsPathToMacOSSharedLibrary(const std::string& path);
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 1281bc6..76a14b8 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -40,6 +40,7 @@
#include "cmSystemTools.h"
#include "cmTargetPropertyComputer.h"
#include "cmValue.h"
+#include "cmXcFramework.h"
#include "cmake.h"
template <>
@@ -2800,6 +2801,25 @@ std::string cmTarget::ImportedGetFullPath(
}
}
}
+ if (this->IsApple() &&
+ (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
+ this->impl->TargetType == cmStateEnums::STATIC_LIBRARY ||
+ this->impl->TargetType == cmStateEnums::UNKNOWN_LIBRARY) &&
+ cmSystemTools::IsPathToXcFramework(result)) {
+ auto plist = cmParseXcFrameworkPlist(result, *this->impl->Makefile,
+ this->impl->Backtrace);
+ if (!plist) {
+ return "";
+ }
+ auto const* library = plist->SelectSuitableLibrary(
+ *this->impl->Makefile, this->impl->Backtrace);
+ if (library) {
+ result = cmStrCat(result, '/', library->LibraryIdentifier, '/',
+ library->LibraryPath);
+ } else {
+ return "";
+ }
+ }
break;
case cmStateEnums::ImportLibraryArtifact:
diff --git a/Source/cmXcFramework.cxx b/Source/cmXcFramework.cxx
new file mode 100644
index 0000000..c91e7f2
--- /dev/null
+++ b/Source/cmXcFramework.cxx
@@ -0,0 +1,174 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmXcFramework.h"
+
+#include <functional>
+#include <string>
+
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+
+#include "cmJSONHelpers.h"
+#include "cmJSONState.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPlistParser.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+namespace {
+struct PlistMetadata
+{
+ std::string CFBundlePackageType;
+ std::string XCFrameworkFormatVersion;
+};
+
+auto const PlistMetadataHelper =
+ cmJSONHelperBuilder::Object<PlistMetadata>{}
+ .Bind("CFBundlePackageType"_s, &PlistMetadata::CFBundlePackageType,
+ cmJSONHelperBuilder::String())
+ .Bind("XCFrameworkFormatVersion"_s,
+ &PlistMetadata::XCFrameworkFormatVersion,
+ cmJSONHelperBuilder::String());
+
+bool PlistSupportedPlatformHelper(
+ cmXcFrameworkPlistSupportedPlatform& platform, const Json::Value* value,
+ cmJSONState* /*state*/)
+{
+ if (!value) {
+ return false;
+ }
+
+ if (!value->isString()) {
+ return false;
+ }
+
+ if (value->asString() == "macos") {
+ platform = cmXcFrameworkPlistSupportedPlatform::macOS;
+ return true;
+ }
+ if (value->asString() == "ios") {
+ platform = cmXcFrameworkPlistSupportedPlatform::iOS;
+ return true;
+ }
+ if (value->asString() == "tvos") {
+ platform = cmXcFrameworkPlistSupportedPlatform::tvOS;
+ return true;
+ }
+ if (value->asString() == "watchos") {
+ platform = cmXcFrameworkPlistSupportedPlatform::watchOS;
+ return true;
+ }
+ if (value->asString() == "xros") {
+ platform = cmXcFrameworkPlistSupportedPlatform::visionOS;
+ return true;
+ }
+
+ return false;
+}
+
+auto const PlistLibraryHelper =
+ cmJSONHelperBuilder::Object<cmXcFrameworkPlistLibrary>{}
+ .Bind("LibraryIdentifier"_s, &cmXcFrameworkPlistLibrary::LibraryIdentifier,
+ cmJSONHelperBuilder::String())
+ .Bind("LibraryPath"_s, &cmXcFrameworkPlistLibrary::LibraryPath,
+ cmJSONHelperBuilder::String())
+ .Bind("HeadersPath"_s, &cmXcFrameworkPlistLibrary::HeadersPath,
+ cmJSONHelperBuilder::String(), false)
+ .Bind("SupportedArchitectures"_s,
+ &cmXcFrameworkPlistLibrary::SupportedArchitectures,
+ cmJSONHelperBuilder::Vector<std::string>(
+ JsonErrors::EXPECTED_TYPE("array"), cmJSONHelperBuilder::String()))
+ .Bind("SupportedPlatform"_s, &cmXcFrameworkPlistLibrary::SupportedPlatform,
+ PlistSupportedPlatformHelper);
+
+auto const PlistHelper =
+ cmJSONHelperBuilder::Object<cmXcFrameworkPlist>{}.Bind(
+ "AvailableLibraries"_s, &cmXcFrameworkPlist::AvailableLibraries,
+ cmJSONHelperBuilder::Vector<cmXcFrameworkPlistLibrary>(
+ JsonErrors::EXPECTED_TYPE("array"), PlistLibraryHelper));
+}
+
+cm::optional<cmXcFrameworkPlist> cmParseXcFrameworkPlist(
+ const std::string& xcframeworkPath, const cmMakefile& mf,
+ const cmListFileBacktrace& bt)
+{
+ std::string plistPath = cmStrCat(xcframeworkPath, "/Info.plist");
+
+ auto value = cmParsePlist(plistPath);
+ if (!value) {
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Unable to parse plist file:\n ", plistPath), bt);
+ return cm::nullopt;
+ }
+
+ cmJSONState state;
+
+ PlistMetadata metadata;
+ if (!PlistMetadataHelper(metadata, &*value, &state)) {
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Invalid xcframework .plist file:\n ", plistPath), bt);
+ return cm::nullopt;
+ }
+ if (metadata.CFBundlePackageType != "XFWK" ||
+ metadata.XCFrameworkFormatVersion != "1.0") {
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Expected:\n ", plistPath,
+ "\nto have CFBundlePackageType \"XFWK\" and "
+ "XCFrameworkFormatVersion \"1.0\""),
+ bt);
+ return cm::nullopt;
+ }
+
+ cmXcFrameworkPlist plist;
+ if (!PlistHelper(plist, &*value, &state)) {
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Invalid xcframework .plist file:\n ", plistPath), bt);
+ return cm::nullopt;
+ }
+ plist.Path = plistPath;
+ return cm::optional<cmXcFrameworkPlist>(plist);
+}
+
+const cmXcFrameworkPlistLibrary* cmXcFrameworkPlist::SelectSuitableLibrary(
+ const cmMakefile& mf, const cmListFileBacktrace& bt) const
+{
+ auto systemName = mf.GetSafeDefinition("CMAKE_SYSTEM_NAME");
+
+ for (auto const& lib : this->AvailableLibraries) {
+ std::string supportedSystemName;
+ switch (lib.SupportedPlatform) {
+ case cmXcFrameworkPlistSupportedPlatform::macOS:
+ supportedSystemName = "Darwin";
+ break;
+ case cmXcFrameworkPlistSupportedPlatform::iOS:
+ supportedSystemName = "iOS";
+ break;
+ case cmXcFrameworkPlistSupportedPlatform::tvOS:
+ supportedSystemName = "tvOS";
+ break;
+ case cmXcFrameworkPlistSupportedPlatform::watchOS:
+ supportedSystemName = "watchOS";
+ break;
+ case cmXcFrameworkPlistSupportedPlatform::visionOS:
+ supportedSystemName = "visionOS";
+ break;
+ }
+
+ if (systemName == supportedSystemName) {
+ return &lib;
+ }
+ }
+
+ mf.GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Unable to find suitable library in:\n ", this->Path,
+ "\nfor system name \"", systemName, '"'),
+ bt);
+ return nullptr;
+}
diff --git a/Source/cmXcFramework.h b/Source/cmXcFramework.h
new file mode 100644
index 0000000..c35df11
--- /dev/null
+++ b/Source/cmXcFramework.h
@@ -0,0 +1,44 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmListFileCache.h"
+
+class cmMakefile;
+
+enum class cmXcFrameworkPlistSupportedPlatform
+{
+ macOS,
+ iOS,
+ tvOS,
+ watchOS,
+ visionOS,
+};
+
+struct cmXcFrameworkPlistLibrary
+{
+ std::string LibraryIdentifier;
+ std::string LibraryPath;
+ std::string HeadersPath;
+ std::vector<std::string> SupportedArchitectures;
+ cmXcFrameworkPlistSupportedPlatform SupportedPlatform;
+};
+
+struct cmXcFrameworkPlist
+{
+ std::string Path;
+ std::vector<cmXcFrameworkPlistLibrary> AvailableLibraries;
+
+ const cmXcFrameworkPlistLibrary* SelectSuitableLibrary(
+ const cmMakefile& mf,
+ const cmListFileBacktrace& bt = cmListFileBacktrace{}) const;
+};
+
+cm::optional<cmXcFrameworkPlist> cmParseXcFrameworkPlist(
+ const std::string& xcframeworkPath, const cmMakefile& mf,
+ const cmListFileBacktrace& bt = cmListFileBacktrace{});
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index d20af29..280b81e 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -703,6 +703,23 @@ endif()
if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.0)
add_RunCMake_test(Framework)
+ if(NOT DEFINED CMake_TEST_XcFramework)
+ set(CMake_TEST_XcFramework ON)
+ endif()
+ if(CMake_TEST_XcFramework AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 11.0)
+ set(XcFramework_ARGS -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
+ add_RunCMake_test(XcFramework)
+
+ # This test can take a very long time due to lots of combinations.
+ # Use a long default timeout and provide an option to customize it.
+ if(NOT DEFINED CMake_TEST_XcFramework_TIMEOUT)
+ set(CMake_TEST_XcFramework_TIMEOUT 3000)
+ endif()
+ set_tests_properties(RunCMake.XcFramework PROPERTIES
+ TIMEOUT "${CMake_TEST_XcFramework_TIMEOUT}"
+ RUN_SERIAL TRUE
+ )
+ endif()
endif()
add_RunCMake_test(File_Archive)
diff --git a/Tests/RunCMake/XcFramework/CMakeLists.txt b/Tests/RunCMake/XcFramework/CMakeLists.txt
new file mode 100644
index 0000000..54a4d62
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.26)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/XcFramework/RunCMakeTest.cmake b/Tests/RunCMake/XcFramework/RunCMakeTest.cmake
new file mode 100644
index 0000000..dcfaad4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/RunCMakeTest.cmake
@@ -0,0 +1,83 @@
+include(RunCMake)
+
+function(create_library type platform system_name archs)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/create-${type}-${platform}-build)
+ run_cmake_with_options(create-${type}-${platform} -DCMAKE_SYSTEM_NAME=${system_name} -DCMAKE_OSX_ARCHITECTURES=${archs} -DCMAKE_INSTALL_PREFIX=${RunCMake_TEST_BINARY_DIR}/install)
+
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(create-${type}-${platform}-build ${CMAKE_COMMAND} --build . --config Release)
+ run_cmake_command(create-${type}-${platform}-install ${CMAKE_COMMAND} --install . --config Release)
+endfunction()
+
+function(create_libraries type)
+ create_library(${type} macos Darwin "${macos_archs_2}")
+ create_library(${type} ios iOS "arm64")
+ create_library(${type} tvos tvOS "arm64")
+ create_library(${type} watchos watchOS "armv7k\\\\;arm64_32")
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15)
+ create_library(${type} visionos visionOS "arm64")
+ endif()
+endfunction()
+
+function(create_xcframework name type platforms)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/create-xcframework-${name}-build)
+ set(args)
+ foreach(platform IN LISTS platforms)
+ if(type STREQUAL "framework")
+ list(APPEND args -framework ${RunCMake_BINARY_DIR}/create-${type}-${platform}-build/install/lib/mylib.framework)
+ else()
+ list(APPEND args -library ${RunCMake_BINARY_DIR}/create-${type}-${platform}-build/install/lib/libmylib.a -headers ${RunCMake_SOURCE_DIR}/mylib/include)
+ endif()
+ endforeach()
+ run_cmake_command(create-xcframework-${name} xcodebuild -create-xcframework ${args} -output ${RunCMake_TEST_BINARY_DIR}/mylib.xcframework)
+endfunction()
+
+function(create_executable name xcfname system_name archs)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/create-executable-${name}-build)
+ run_cmake_with_options(create-executable-${name} -DCMAKE_SYSTEM_NAME=${system_name} -DCMAKE_OSX_ARCHITECTURES=${archs} -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-${xcfname}-build/mylib.xcframework)
+
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(create-executable-${name}-build ${CMAKE_COMMAND} --build . --config Release)
+endfunction()
+
+function(create_executables name type)
+ create_executable(${name}-macos ${type} Darwin "${macos_archs_2}")
+ create_executable(${name}-ios ${type} iOS "arm64")
+ create_executable(${name}-tvos ${type} tvOS "arm64")
+ create_executable(${name}-watchos ${type} watchOS "armv7k\\\\;arm64_32")
+ if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15)
+ create_executable(${name}-visionos ${type} visionOS "arm64")
+ endif()
+endfunction()
+
+set(xcframework_platforms macos ios tvos watchos)
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 15)
+ list(APPEND xcframework_platforms visionos)
+endif()
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12)
+ set(macos_archs_1 "x86_64\\;arm64")
+ set(macos_archs_2 "x86_64\\\\;arm64")
+else()
+ set(macos_archs_1 "x86_64")
+ set(macos_archs_2 "x86_64")
+endif()
+
+create_libraries(library)
+create_libraries(framework)
+create_xcframework(library library "${xcframework_platforms}")
+create_xcframework(framework framework "${xcframework_platforms}")
+create_xcframework(incomplete framework "tvos;watchos")
+create_executables(library library)
+create_executables(framework framework)
+run_cmake_with_options(create-executable-incomplete -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+create_executables(target-library library)
+create_executables(target-framework framework)
+run_cmake_with_options(create-executable-target-incomplete -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+if(RunCMake_GENERATOR STREQUAL "Xcode" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12)
+ create_executables(library-link-phase library)
+ create_executables(framework-link-phase framework)
+ run_cmake_with_options(create-executable-incomplete-link-phase -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+ create_executables(target-library-link-phase library)
+ create_executables(target-framework-link-phase framework)
+ run_cmake_with_options(create-executable-target-incomplete-link-phase -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+endif()
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-ios.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-ios.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-ios.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-ios.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-macos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-macos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-tvos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-visionos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-watchos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-link-phase-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-macos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-macos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-tvos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-visionos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-framework-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-framework-watchos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-framework-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-result.txt b/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-stderr.txt b/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-stderr.txt
new file mode 100644
index 0000000..5b43e19
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at create-executable\.cmake:[0-9]+ \(target_link_libraries\):
+ Unable to find suitable library in:
+
+ [^
+]*/Tests/RunCMake/XcFramework/create-xcframework-incomplete-build/mylib\.xcframework/Info\.plist
+
+ for system name "Darwin"
+Call Stack \(most recent call first\):
+ create-executable-link-phase\.cmake:[0-9]+ \(include\)
+ create-executable-incomplete-link-phase\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase.cmake b/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-incomplete-link-phase.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-incomplete-result.txt b/Tests/RunCMake/XcFramework/create-executable-incomplete-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-incomplete-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/XcFramework/create-executable-incomplete-stderr.txt b/Tests/RunCMake/XcFramework/create-executable-incomplete-stderr.txt
new file mode 100644
index 0000000..66b7d62
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-incomplete-stderr.txt
@@ -0,0 +1,10 @@
+CMake Error at create-executable\.cmake:[0-9]+ \(target_link_libraries\):
+ Unable to find suitable library in:
+
+ [^
+]*/Tests/RunCMake/XcFramework/create-xcframework-incomplete-build/mylib\.xcframework/Info\.plist
+
+ for system name "Darwin"
+Call Stack \(most recent call first\):
+ create-executable-incomplete\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/XcFramework/create-executable-incomplete.cmake b/Tests/RunCMake/XcFramework/create-executable-incomplete.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-incomplete.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-library-ios.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-ios.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-link-phase-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-ios.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-ios.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-link-phase-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-macos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-macos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-link-phase-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-tvos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-link-phase-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-visionos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-link-phase-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-watchos.cmake
new file mode 100644
index 0000000..2888c85
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-link-phase-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-macos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-macos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-tvos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-visionos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-library-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-library-watchos.cmake
new file mode 100644
index 0000000..760d9d4
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-library-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-link-phase.cmake b/Tests/RunCMake/XcFramework/create-executable-link-phase.cmake
new file mode 100644
index 0000000..9884781
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-link-phase.cmake
@@ -0,0 +1,2 @@
+include(create-executable.cmake)
+set_property(TARGET myexe PROPERTY XCODE_LINK_BUILD_PHASE_MODE "KNOWN_LOCATION")
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-ios.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-ios.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-ios.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-ios.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-macos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-macos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-tvos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-visionos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-watchos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-link-phase-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-macos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-macos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-tvos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-visionos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-framework-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-framework-watchos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-framework-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-result.txt b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-stderr.txt b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-stderr.txt
new file mode 100644
index 0000000..1308933
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at create-executable-target\.cmake:[0-9]+ \(target_link_libraries\):
+ Unable to find suitable library in:
+
+ [^
+]*/Tests/RunCMake/XcFramework/create-xcframework-incomplete-build/mylib\.xcframework/Info\.plist
+
+ for system name "Darwin"
+Call Stack \(most recent call first\):
+ create-executable-target-link-phase\.cmake:[0-9]+ \(include\)
+ create-executable-target-incomplete-link-phase\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase.cmake b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-link-phase.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-incomplete-result.txt b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-incomplete-stderr.txt b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-stderr.txt
new file mode 100644
index 0000000..716b17d
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-incomplete-stderr.txt
@@ -0,0 +1,10 @@
+CMake Error at create-executable-target\.cmake:[0-9]+ \(target_link_libraries\):
+ Unable to find suitable library in:
+
+ [^
+]*/Tests/RunCMake/XcFramework/create-xcframework-incomplete-build/mylib\.xcframework/Info\.plist
+
+ for system name "Darwin"
+Call Stack \(most recent call first\):
+ create-executable-target-incomplete\.cmake:[0-9]+ \(include\)
+ CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-incomplete.cmake b/Tests/RunCMake/XcFramework/create-executable-target-incomplete.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-incomplete.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-ios.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-ios.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-ios.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-ios.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-ios.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-macos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-macos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-tvos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-visionos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-watchos.cmake
new file mode 100644
index 0000000..dfeccb9
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-link-phase-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable-target-link-phase.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-macos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-macos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-macos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-tvos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-tvos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-tvos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-visionos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-visionos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-visionos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-library-watchos.cmake b/Tests/RunCMake/XcFramework/create-executable-target-library-watchos.cmake
new file mode 100644
index 0000000..b2e3469
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-library-watchos.cmake
@@ -0,0 +1 @@
+include(create-executable-target.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-executable-target-link-phase.cmake b/Tests/RunCMake/XcFramework/create-executable-target-link-phase.cmake
new file mode 100644
index 0000000..9c0b0d5
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target-link-phase.cmake
@@ -0,0 +1,2 @@
+include(create-executable-target.cmake)
+set_property(TARGET myexe PROPERTY XCODE_LINK_BUILD_PHASE_MODE "KNOWN_LOCATION")
diff --git a/Tests/RunCMake/XcFramework/create-executable-target.cmake b/Tests/RunCMake/XcFramework/create-executable-target.cmake
new file mode 100644
index 0000000..0cc356c
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable-target.cmake
@@ -0,0 +1,21 @@
+enable_language(C)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
+ 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_CODE_SIGNING_ALLOWED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
+ set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES")
+endif()
+
+add_library(mylib IMPORTED STATIC)
+set_property(TARGET mylib PROPERTY IMPORTED_LOCATION ${MYLIB_LIBRARY})
+
+add_executable(myexe myexe/myexe.c)
+target_link_libraries(myexe PRIVATE mylib)
diff --git a/Tests/RunCMake/XcFramework/create-executable.cmake b/Tests/RunCMake/XcFramework/create-executable.cmake
new file mode 100644
index 0000000..6706b9f
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-executable.cmake
@@ -0,0 +1,18 @@
+enable_language(C)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
+ 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_CODE_SIGNING_ALLOWED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
+ set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES")
+endif()
+
+add_executable(myexe myexe/myexe.c)
+target_link_libraries(myexe PRIVATE ${MYLIB_LIBRARY})
diff --git a/Tests/RunCMake/XcFramework/create-framework-ios.cmake b/Tests/RunCMake/XcFramework/create-framework-ios.cmake
new file mode 100644
index 0000000..8b7df9b
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-framework-ios.cmake
@@ -0,0 +1 @@
+include(create-framework.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-framework-macos.cmake b/Tests/RunCMake/XcFramework/create-framework-macos.cmake
new file mode 100644
index 0000000..8b7df9b
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-framework-macos.cmake
@@ -0,0 +1 @@
+include(create-framework.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-framework-tvos.cmake b/Tests/RunCMake/XcFramework/create-framework-tvos.cmake
new file mode 100644
index 0000000..8b7df9b
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-framework-tvos.cmake
@@ -0,0 +1 @@
+include(create-framework.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-framework-visionos.cmake b/Tests/RunCMake/XcFramework/create-framework-visionos.cmake
new file mode 100644
index 0000000..8b7df9b
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-framework-visionos.cmake
@@ -0,0 +1 @@
+include(create-framework.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-framework-watchos.cmake b/Tests/RunCMake/XcFramework/create-framework-watchos.cmake
new file mode 100644
index 0000000..8b7df9b
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-framework-watchos.cmake
@@ -0,0 +1 @@
+include(create-framework.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-framework.cmake b/Tests/RunCMake/XcFramework/create-framework.cmake
new file mode 100644
index 0000000..f4406e6
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-framework.cmake
@@ -0,0 +1,3 @@
+set(CMAKE_FRAMEWORK ON)
+include(create-library-common.cmake)
+install(FILES mylib/include/mylib/mylib.h DESTINATION lib/mylib.framework/Headers)
diff --git a/Tests/RunCMake/XcFramework/create-library-common.cmake b/Tests/RunCMake/XcFramework/create-library-common.cmake
new file mode 100644
index 0000000..958660d
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-library-common.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+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)
+install(TARGETS mylib DESTINATION lib)
diff --git a/Tests/RunCMake/XcFramework/create-library-ios.cmake b/Tests/RunCMake/XcFramework/create-library-ios.cmake
new file mode 100644
index 0000000..a9f5dee
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-library-ios.cmake
@@ -0,0 +1 @@
+include(create-library.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-library-macos.cmake b/Tests/RunCMake/XcFramework/create-library-macos.cmake
new file mode 100644
index 0000000..a9f5dee
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-library-macos.cmake
@@ -0,0 +1 @@
+include(create-library.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-library-tvos.cmake b/Tests/RunCMake/XcFramework/create-library-tvos.cmake
new file mode 100644
index 0000000..a9f5dee
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-library-tvos.cmake
@@ -0,0 +1 @@
+include(create-library.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-library-visionos.cmake b/Tests/RunCMake/XcFramework/create-library-visionos.cmake
new file mode 100644
index 0000000..a9f5dee
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-library-visionos.cmake
@@ -0,0 +1 @@
+include(create-library.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-library-watchos.cmake b/Tests/RunCMake/XcFramework/create-library-watchos.cmake
new file mode 100644
index 0000000..a9f5dee
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-library-watchos.cmake
@@ -0,0 +1 @@
+include(create-library.cmake)
diff --git a/Tests/RunCMake/XcFramework/create-library.cmake b/Tests/RunCMake/XcFramework/create-library.cmake
new file mode 100644
index 0000000..f2a5249
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/create-library.cmake
@@ -0,0 +1 @@
+include(create-library-common.cmake)
diff --git a/Tests/RunCMake/XcFramework/myexe/myexe.c b/Tests/RunCMake/XcFramework/myexe/myexe.c
new file mode 100644
index 0000000..d04efbd
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/myexe/myexe.c
@@ -0,0 +1,7 @@
+#include <mylib/mylib.h>
+
+int main(void)
+{
+ mylib();
+ return 0;
+}
diff --git a/Tests/RunCMake/XcFramework/mylib/include/mylib/mylib.h b/Tests/RunCMake/XcFramework/mylib/include/mylib/mylib.h
new file mode 100644
index 0000000..1de07aa
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/mylib/include/mylib/mylib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+extern void mylib(void);
diff --git a/Tests/RunCMake/XcFramework/mylib/mylib.c b/Tests/RunCMake/XcFramework/mylib/mylib.c
new file mode 100644
index 0000000..4489684
--- /dev/null
+++ b/Tests/RunCMake/XcFramework/mylib/mylib.c
@@ -0,0 +1,3 @@
+void mylib(void)
+{
+}
diff --git a/bootstrap b/bootstrap
index 82c5957..8b43d20 100755
--- a/bootstrap
+++ b/bootstrap
@@ -451,6 +451,7 @@ CMAKE_CXX_SOURCES="\
cmGccDepfileReader \
cmReturnCommand \
cmPlaceholderExpander \
+ cmPlistParser \
cmRulePlaceholderExpander \
cmRuntimeDependencyArchive \
cmScriptGenerator \
@@ -500,6 +501,7 @@ CMAKE_CXX_SOURCES="\
cmWhileCommand \
cmWindowsRegistry \
cmWorkingDirectory \
+ cmXcFramework \
cmake \
cmakemain \
cmcmd \