| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmXcFramework.h" | |
| #include <string> | |
| #include <cm/string_view> | |
| #include <cmext/string_view> | |
| #include <cm3p/json/value.h> | |
| #include "cmGlobalGenerator.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, Json::Value const* value, | |
| cmJSONState* /*state*/) | |
| { | |
| if (!value) { | |
| return false; | |
| } | |
| if (!value->isString()) { | |
| return false; | |
| } | |
| if (value->asString() == "macos"_s) { | |
| platform = cmXcFrameworkPlistSupportedPlatform::macOS; | |
| return true; | |
| } | |
| if (value->asString() == "ios"_s) { | |
| platform = cmXcFrameworkPlistSupportedPlatform::iOS; | |
| return true; | |
| } | |
| if (value->asString() == "tvos"_s) { | |
| platform = cmXcFrameworkPlistSupportedPlatform::tvOS; | |
| return true; | |
| } | |
| if (value->asString() == "watchos"_s) { | |
| platform = cmXcFrameworkPlistSupportedPlatform::watchOS; | |
| return true; | |
| } | |
| if (value->asString() == "xros"_s) { | |
| platform = cmXcFrameworkPlistSupportedPlatform::visionOS; | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool PlistSupportedPlatformVariantHelper( | |
| cmXcFrameworkPlistSupportedPlatformVariant& variant, | |
| Json::Value const* value, cmJSONState* /*state*/) | |
| { | |
| if (!value) { | |
| return false; | |
| } | |
| if (!value->isString()) { | |
| return false; | |
| } | |
| if (value->asString() == "maccatalyst"_s) { | |
| variant = cmXcFrameworkPlistSupportedPlatformVariant::maccatalyst; | |
| return true; | |
| } | |
| if (value->asString() == "simulator"_s) { | |
| variant = cmXcFrameworkPlistSupportedPlatformVariant::simulator; | |
| 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) | |
| .Bind("SupportedPlatformVariant"_s, | |
| &cmXcFrameworkPlistLibrary::SupportedPlatformVariant, | |
| cmJSONHelperBuilder::Optional< | |
| cmXcFrameworkPlistSupportedPlatformVariant>( | |
| PlistSupportedPlatformVariantHelper), | |
| false); | |
| auto const PlistHelper = | |
| cmJSONHelperBuilder::Object<cmXcFrameworkPlist>{}.Bind( | |
| "AvailableLibraries"_s, &cmXcFrameworkPlist::AvailableLibraries, | |
| cmJSONHelperBuilder::Vector<cmXcFrameworkPlistLibrary>( | |
| JsonErrors::EXPECTED_TYPE("array"), PlistLibraryHelper)); | |
| } | |
| cm::optional<cmXcFrameworkPlist> cmParseXcFrameworkPlist( | |
| std::string const& xcframeworkPath, cmMakefile const& mf, | |
| cmListFileBacktrace const& bt) | |
| { | |
| cmGlobalGenerator* gen = mf.GetGlobalGenerator(); | |
| if (cm::optional<cmXcFrameworkPlist> cached = | |
| gen->GetXcFrameworkPListContent(xcframeworkPath)) { | |
| return cached; | |
| } | |
| 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"_s || | |
| metadata.XCFrameworkFormatVersion != "1.0"_s) { | |
| 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; | |
| gen->SetXcFrameworkPListContent(xcframeworkPath, plist); | |
| return cm::optional<cmXcFrameworkPlist>(plist); | |
| } | |
| cmXcFrameworkPlistLibrary const* cmXcFrameworkPlist::SelectSuitableLibrary( | |
| cmMakefile const& mf, cmListFileBacktrace const& bt) const | |
| { | |
| auto systemName = mf.GetSafeDefinition("CMAKE_SYSTEM_NAME"); | |
| cm::optional<cmXcFrameworkPlistSupportedPlatformVariant> systemVariant; | |
| if (mf.PlatformIsAppleSimulator()) { | |
| systemVariant = cmXcFrameworkPlistSupportedPlatformVariant::simulator; | |
| } | |
| if (mf.PlatformIsAppleCatalyst()) { | |
| systemVariant = cmXcFrameworkPlistSupportedPlatformVariant::maccatalyst; | |
| } | |
| 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 && | |
| systemVariant == lib.SupportedPlatformVariant) { | |
| 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; | |
| } |