|
|
|
/* 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;
|
|
|
|
}
|