@@ -40,7 +40,8 @@ enum CocoaPodUtils {
40
40
}
41
41
42
42
/// Information associated with an installed pod.
43
- struct PodInfo {
43
+ /// This is a class so that moduleMapContents can be updated via reference.
44
+ class PodInfo {
44
45
/// The version of the generated pod.
45
46
let version : String
46
47
@@ -49,6 +50,39 @@ enum CocoaPodUtils {
49
50
50
51
/// The location of the pod on disk.
51
52
let installedLocation : URL
53
+
54
+ /// Source pod flag.
55
+ let isSourcePod : Bool
56
+
57
+ /// Binary frameworks in this pod.
58
+ let binaryFrameworks : [ URL ]
59
+
60
+ /// Subspecs installed for this pod.
61
+ let subspecs : Set < String >
62
+
63
+ /// The contents of the module map for all frameworks associated with the pod.
64
+ var moduleMapContents : ModuleMapBuilder . ModuleMapContents ?
65
+
66
+ init ( version: String , dependencies: [ String ] , installedLocation: URL , subspecs: Set < String > ) {
67
+ self . version = version
68
+ self . dependencies = dependencies
69
+ self . installedLocation = installedLocation
70
+ self . subspecs = subspecs
71
+
72
+ // Get all the frameworks contained in this directory.
73
+ var binaryFrameworks : [ URL ] = [ ]
74
+ if installedLocation != LaunchArgs . shared. localPodspecPath {
75
+ do {
76
+ binaryFrameworks = try FileManager . default. recursivelySearch ( for: . frameworks,
77
+ in: installedLocation)
78
+ } catch {
79
+ fatalError ( " Cannot search for .framework files in Pods directory " +
80
+ " \( installedLocation) : \( error) " )
81
+ }
82
+ }
83
+ self . binaryFrameworks = binaryFrameworks
84
+ isSourcePod = binaryFrameworks == [ ]
85
+ }
52
86
}
53
87
54
88
/// Executes the `pod cache clean --all` command to remove any cached CocoaPods.
@@ -86,11 +120,14 @@ enum CocoaPodUtils {
86
120
/// - pods: List of VersionedPods to install
87
121
/// - directory: Destination directory for the pods.
88
122
/// - customSpecRepos: Additional spec repos to check for installation.
123
+ /// - forceStaticLibs: Force a static library pod install. For the module map construction, we want pod names not module
124
+ /// names in the generated OTHER_LD_FLAGS options.
89
125
/// - Returns: A dictionary of PodInfo's keyed by the pod name.
90
126
@discardableResult
91
127
static func installPods( _ pods: [ VersionedPod ] ,
92
128
inDir directory: URL ,
93
- customSpecRepos: [ URL ] ? = nil ) -> [ String : PodInfo ] {
129
+ customSpecRepos: [ URL ] ? ,
130
+ forceStaticLibs: Bool = false ) -> [ String : PodInfo ] {
94
131
let fileManager = FileManager . default
95
132
// Ensure the directory exists, otherwise we can't install all subspecs.
96
133
guard fileManager. directoryExists ( at: directory) else {
@@ -105,7 +142,10 @@ enum CocoaPodUtils {
105
142
106
143
// Attempt to write the Podfile to disk.
107
144
do {
108
- try writePodfile ( for: pods, toDirectory: directory, customSpecRepos: customSpecRepos)
145
+ try writePodfile ( for: pods,
146
+ toDirectory: directory,
147
+ customSpecRepos: customSpecRepos,
148
+ forceStaticLibs: forceStaticLibs)
109
149
} catch let FileManager . FileError . directoryNotFound( path) {
110
150
fatalError ( " Failed to write Podfile with pods \( pods) at path \( path) " )
111
151
} catch let FileManager . FileError . writeToFileFailed( path, error) {
@@ -156,30 +196,49 @@ enum CocoaPodUtils {
156
196
break
157
197
}
158
198
if let ( pod, version) = detectVersion ( fromLine: line) {
159
- let corePod = pod. components ( separatedBy: " / " ) [ 0 ]
160
- currentPod = corePod. trimmingCharacters ( in: quotes)
199
+ currentPod = pod. trimmingCharacters ( in: quotes)
161
200
pods [ currentPod!] = version
162
201
} else if let currentPod = currentPod {
163
202
let matches = depRegex. matches ( in: line, range: NSRange ( location: 0 , length: line. utf8. count) )
164
203
// Match something like - GTMSessionFetcher/Full (= 1.3.0)
165
204
if let match = matches. first {
166
205
let depLine = ( line as NSString ) . substring ( with: match. range ( at: 0 ) ) as String
167
206
// Split spaces and subspecs.
168
- let dep = depLine. components ( separatedBy: [ " " , " / " ] ) [ 2 ] . trimmingCharacters ( in: quotes)
207
+ let dep = depLine. components ( separatedBy: [ " " ] ) [ 2 ] . trimmingCharacters ( in: quotes)
169
208
if dep != currentPod {
170
- if deps [ currentPod] == nil {
171
- deps [ currentPod] = Set ( )
172
- }
173
- deps [ currentPod] ? . insert ( dep)
209
+ deps [ currentPod, default: Set ( ) ] . insert ( dep)
174
210
}
175
211
}
176
212
}
177
213
}
214
+ // Organize the subspecs
215
+ var versions : [ String : String ] = [ : ]
216
+ var subspecs : [ String : Set < String > ] = [ : ]
217
+
218
+ for (podName, version) in pods {
219
+ let subspecArray = podName. components ( separatedBy: " / " )
220
+ if subspecArray. count == 1 || subspecArray [ 0 ] == " abseil " {
221
+ // Special case for abseil since it has two layers and no external deps.
222
+ versions [ subspecArray [ 0 ] ] = version
223
+ } else if subspecArray. count > 2 {
224
+ fatalError ( " Multi-layered subspecs are not supported - \( podName) " )
225
+ } else {
226
+ if let previousVersion = versions [ podName] , version != previousVersion {
227
+ fatalError ( " Different installed versions for \( podName) . " +
228
+ " \( version) versus \( previousVersion) " )
229
+ } else {
230
+ let basePodName = subspecArray [ 0 ]
231
+ versions [ basePodName] = version
232
+ subspecs [ basePodName, default: Set ( ) ] . insert ( subspecArray [ 1 ] )
233
+ deps [ basePodName] = deps [ basePodName, default: Set ( ) ] . union ( deps [ podName] ?? Set ( ) )
234
+ }
235
+ }
236
+ }
178
237
179
238
// Generate an InstalledPod for each Pod found.
180
239
let podsDir = projectDir. appendingPathComponent ( " Pods " )
181
240
var installedPods : [ String : PodInfo ] = [ : ]
182
- for (podName, version) in pods {
241
+ for (podName, version) in versions {
183
242
var podDir = podsDir. appendingPathComponent ( podName)
184
243
// Make sure that pod got installed if it's not coming from a local podspec.
185
244
if !FileManager. default. directoryExists ( at: podDir) {
@@ -190,7 +249,8 @@ enum CocoaPodUtils {
190
249
podDir = repoDir
191
250
}
192
251
let dependencies = [ String] ( deps [ podName] ?? [ ] )
193
- let podInfo = PodInfo ( version: version, dependencies: dependencies, installedLocation: podDir)
252
+ let podInfo = PodInfo ( version: version, dependencies: dependencies, installedLocation: podDir,
253
+ subspecs: subspecs [ podName] ?? Set ( ) )
194
254
installedPods [ podName] = podInfo
195
255
}
196
256
return installedPods
@@ -251,6 +311,15 @@ enum CocoaPodUtils {
251
311
return Array ( returnDeps)
252
312
}
253
313
314
+ /// Get all transitive pod dependencies for a pod with subspecs merged.
315
+ /// - Returns: An array of Strings of pod names.
316
+ static func transitiveMasterPodDependencies( for podName: String ,
317
+ in installedPods: [ String : PodInfo ] ) -> [ String ] {
318
+ return Array ( Set ( transitivePodDependencies ( for: podName, in: installedPods) . map {
319
+ $0. components ( separatedBy: " / " ) [ 0 ]
320
+ } ) )
321
+ }
322
+
254
323
/// Get all transitive pod dependencies for a pod.
255
324
/// - Returns: An array of dependencies with versions for a given pod.
256
325
static func transitiveVersionedPodDependencies( for podName: String ,
@@ -300,7 +369,8 @@ enum CocoaPodUtils {
300
369
/// Create the contents of a Podfile for an array of subspecs. This assumes the array of subspecs
301
370
/// is not empty.
302
371
private static func generatePodfile( for pods: [ VersionedPod ] ,
303
- customSpecsRepos: [ URL ] ? = nil ) -> String {
372
+ customSpecsRepos: [ URL ] ? ,
373
+ forceStaticLibs: Bool ) -> String {
304
374
// Start assembling the Podfile.
305
375
var podfile : String = " "
306
376
@@ -315,6 +385,13 @@ enum CocoaPodUtils {
315
385
""" // Explicit newline above to ensure it's included in the String.
316
386
}
317
387
388
+ if forceStaticLibs {
389
+ podfile += " use_modular_headers! \n "
390
+ } else if LaunchArgs . shared. dynamic {
391
+ podfile += " use_frameworks! \n "
392
+ } else {
393
+ podfile += " use_frameworks! :linkage => :static \n "
394
+ }
318
395
// Include the minimum iOS version.
319
396
podfile += """
320
397
platform :ios, ' \( LaunchArgs . shared. minimumIOSVersion) '
@@ -367,15 +444,16 @@ enum CocoaPodUtils {
367
444
/// "Podfile".
368
445
private static func writePodfile( for pods: [ VersionedPod ] ,
369
446
toDirectory directory: URL ,
370
- customSpecRepos: [ URL ] ? ) throws {
447
+ customSpecRepos: [ URL ] ? ,
448
+ forceStaticLibs: Bool ) throws {
371
449
guard FileManager . default. directoryExists ( at: directory) else {
372
450
// Throw an error so the caller can provide a better error message.
373
451
throw FileManager . FileError. directoryNotFound ( path: directory. path)
374
452
}
375
453
376
454
// Generate the full path of the Podfile and attempt to write it to disk.
377
455
let path = directory. appendingPathComponent ( " Podfile " )
378
- let podfile = generatePodfile ( for: pods, customSpecsRepos: customSpecRepos)
456
+ let podfile = generatePodfile ( for: pods, customSpecsRepos: customSpecRepos, forceStaticLibs : forceStaticLibs )
379
457
do {
380
458
try podfile. write ( toFile: path. path, atomically: true , encoding: . utf8)
381
459
} catch {
0 commit comments