cmXcFramework.cxx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmXcFramework.h"
  4. #include <string>
  5. #include <cm/string_view>
  6. #include <cmext/string_view>
  7. #include <cm3p/json/value.h>
  8. #include "cmJSONHelpers.h"
  9. #include "cmJSONState.h"
  10. #include "cmMakefile.h"
  11. #include "cmMessageType.h"
  12. #include "cmPlistParser.h"
  13. #include "cmStringAlgorithms.h"
  14. #include "cmake.h"
  15. namespace {
  16. struct PlistMetadata
  17. {
  18. std::string CFBundlePackageType;
  19. std::string XCFrameworkFormatVersion;
  20. };
  21. auto const PlistMetadataHelper =
  22. cmJSONHelperBuilder::Object<PlistMetadata>{}
  23. .Bind("CFBundlePackageType"_s, &PlistMetadata::CFBundlePackageType,
  24. cmJSONHelperBuilder::String())
  25. .Bind("XCFrameworkFormatVersion"_s,
  26. &PlistMetadata::XCFrameworkFormatVersion,
  27. cmJSONHelperBuilder::String());
  28. bool PlistSupportedPlatformHelper(
  29. cmXcFrameworkPlistSupportedPlatform& platform, const Json::Value* value,
  30. cmJSONState* /*state*/)
  31. {
  32. if (!value) {
  33. return false;
  34. }
  35. if (!value->isString()) {
  36. return false;
  37. }
  38. if (value->asString() == "macos"_s) {
  39. platform = cmXcFrameworkPlistSupportedPlatform::macOS;
  40. return true;
  41. }
  42. if (value->asString() == "ios"_s) {
  43. platform = cmXcFrameworkPlistSupportedPlatform::iOS;
  44. return true;
  45. }
  46. if (value->asString() == "tvos"_s) {
  47. platform = cmXcFrameworkPlistSupportedPlatform::tvOS;
  48. return true;
  49. }
  50. if (value->asString() == "watchos"_s) {
  51. platform = cmXcFrameworkPlistSupportedPlatform::watchOS;
  52. return true;
  53. }
  54. if (value->asString() == "xros"_s) {
  55. platform = cmXcFrameworkPlistSupportedPlatform::visionOS;
  56. return true;
  57. }
  58. return false;
  59. }
  60. bool PlistSupportedPlatformVariantHelper(
  61. cmXcFrameworkPlistSupportedPlatformVariant& variant,
  62. const Json::Value* value, cmJSONState* /*state*/)
  63. {
  64. if (!value) {
  65. return false;
  66. }
  67. if (!value->isString()) {
  68. return false;
  69. }
  70. if (value->asString() == "maccatalyst"_s) {
  71. variant = cmXcFrameworkPlistSupportedPlatformVariant::maccatalyst;
  72. return true;
  73. }
  74. if (value->asString() == "simulator"_s) {
  75. variant = cmXcFrameworkPlistSupportedPlatformVariant::simulator;
  76. return true;
  77. }
  78. return false;
  79. }
  80. auto const PlistLibraryHelper =
  81. cmJSONHelperBuilder::Object<cmXcFrameworkPlistLibrary>{}
  82. .Bind("LibraryIdentifier"_s, &cmXcFrameworkPlistLibrary::LibraryIdentifier,
  83. cmJSONHelperBuilder::String())
  84. .Bind("LibraryPath"_s, &cmXcFrameworkPlistLibrary::LibraryPath,
  85. cmJSONHelperBuilder::String())
  86. .Bind("HeadersPath"_s, &cmXcFrameworkPlistLibrary::HeadersPath,
  87. cmJSONHelperBuilder::String(), false)
  88. .Bind("SupportedArchitectures"_s,
  89. &cmXcFrameworkPlistLibrary::SupportedArchitectures,
  90. cmJSONHelperBuilder::Vector<std::string>(
  91. JsonErrors::EXPECTED_TYPE("array"), cmJSONHelperBuilder::String()))
  92. .Bind("SupportedPlatform"_s, &cmXcFrameworkPlistLibrary::SupportedPlatform,
  93. PlistSupportedPlatformHelper)
  94. .Bind("SupportedPlatformVariant"_s,
  95. &cmXcFrameworkPlistLibrary::SupportedPlatformVariant,
  96. cmJSONHelperBuilder::Optional<
  97. cmXcFrameworkPlistSupportedPlatformVariant>(
  98. PlistSupportedPlatformVariantHelper),
  99. false);
  100. auto const PlistHelper =
  101. cmJSONHelperBuilder::Object<cmXcFrameworkPlist>{}.Bind(
  102. "AvailableLibraries"_s, &cmXcFrameworkPlist::AvailableLibraries,
  103. cmJSONHelperBuilder::Vector<cmXcFrameworkPlistLibrary>(
  104. JsonErrors::EXPECTED_TYPE("array"), PlistLibraryHelper));
  105. }
  106. cm::optional<cmXcFrameworkPlist> cmParseXcFrameworkPlist(
  107. const std::string& xcframeworkPath, const cmMakefile& mf,
  108. const cmListFileBacktrace& bt)
  109. {
  110. std::string plistPath = cmStrCat(xcframeworkPath, "/Info.plist");
  111. auto value = cmParsePlist(plistPath);
  112. if (!value) {
  113. mf.GetCMakeInstance()->IssueMessage(
  114. MessageType::FATAL_ERROR,
  115. cmStrCat("Unable to parse plist file:\n ", plistPath), bt);
  116. return cm::nullopt;
  117. }
  118. cmJSONState state;
  119. PlistMetadata metadata;
  120. if (!PlistMetadataHelper(metadata, &*value, &state)) {
  121. mf.GetCMakeInstance()->IssueMessage(
  122. MessageType::FATAL_ERROR,
  123. cmStrCat("Invalid xcframework .plist file:\n ", plistPath), bt);
  124. return cm::nullopt;
  125. }
  126. if (metadata.CFBundlePackageType != "XFWK"_s ||
  127. metadata.XCFrameworkFormatVersion != "1.0"_s) {
  128. mf.GetCMakeInstance()->IssueMessage(
  129. MessageType::FATAL_ERROR,
  130. cmStrCat("Expected:\n ", plistPath,
  131. "\nto have CFBundlePackageType \"XFWK\" and "
  132. "XCFrameworkFormatVersion \"1.0\""),
  133. bt);
  134. return cm::nullopt;
  135. }
  136. cmXcFrameworkPlist plist;
  137. if (!PlistHelper(plist, &*value, &state)) {
  138. mf.GetCMakeInstance()->IssueMessage(
  139. MessageType::FATAL_ERROR,
  140. cmStrCat("Invalid xcframework .plist file:\n ", plistPath), bt);
  141. return cm::nullopt;
  142. }
  143. plist.Path = plistPath;
  144. return cm::optional<cmXcFrameworkPlist>(plist);
  145. }
  146. const cmXcFrameworkPlistLibrary* cmXcFrameworkPlist::SelectSuitableLibrary(
  147. const cmMakefile& mf, const cmListFileBacktrace& bt) const
  148. {
  149. auto systemName = mf.GetSafeDefinition("CMAKE_SYSTEM_NAME");
  150. cm::optional<cmXcFrameworkPlistSupportedPlatformVariant> systemVariant;
  151. if (mf.PlatformIsAppleSimulator()) {
  152. systemVariant = cmXcFrameworkPlistSupportedPlatformVariant::simulator;
  153. }
  154. if (mf.PlatformIsAppleCatalyst()) {
  155. systemVariant = cmXcFrameworkPlistSupportedPlatformVariant::maccatalyst;
  156. }
  157. for (auto const& lib : this->AvailableLibraries) {
  158. std::string supportedSystemName;
  159. switch (lib.SupportedPlatform) {
  160. case cmXcFrameworkPlistSupportedPlatform::macOS:
  161. supportedSystemName = "Darwin";
  162. break;
  163. case cmXcFrameworkPlistSupportedPlatform::iOS:
  164. supportedSystemName = "iOS";
  165. break;
  166. case cmXcFrameworkPlistSupportedPlatform::tvOS:
  167. supportedSystemName = "tvOS";
  168. break;
  169. case cmXcFrameworkPlistSupportedPlatform::watchOS:
  170. supportedSystemName = "watchOS";
  171. break;
  172. case cmXcFrameworkPlistSupportedPlatform::visionOS:
  173. supportedSystemName = "visionOS";
  174. break;
  175. }
  176. if (systemName == supportedSystemName &&
  177. systemVariant == lib.SupportedPlatformVariant) {
  178. return &lib;
  179. }
  180. }
  181. mf.GetCMakeInstance()->IssueMessage(
  182. MessageType::FATAL_ERROR,
  183. cmStrCat("Unable to find suitable library in:\n ", this->Path,
  184. "\nfor system name \"", systemName, '"'),
  185. bt);
  186. return nullptr;
  187. }