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