| /* 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 <string> |
| |
| #include <cm/string_view> |
| #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"_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, |
| const Json::Value* 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( |
| 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"_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; |
| return cm::optional<cmXcFrameworkPlist>(plist); |
| } |
| |
| const cmXcFrameworkPlistLibrary* cmXcFrameworkPlist::SelectSuitableLibrary( |
| const cmMakefile& mf, const cmListFileBacktrace& 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; |
| } |