@@ -28,20 +28,15 @@ struct FrameworkBuilder {
2828 /// Flag for building dynamic frameworks instead of static frameworks.
2929 private let dynamicFrameworks : Bool
3030
31- /// Flag for whether or not Carthage artifacts should be built as well.
32- private let buildCarthage : Bool
33-
3431 /// The Pods directory for building the framework.
3532 private var podsDir : URL {
3633 return projectDir. appendingPathComponent ( " Pods " , isDirectory: true )
3734 }
3835
3936 /// Default initializer.
40- init ( projectDir: URL , platform: Platform , includeCarthage: Bool ,
41- dynamicFrameworks: Bool ) {
37+ init ( projectDir: URL , platform: Platform , dynamicFrameworks: Bool ) {
4238 self . projectDir = projectDir
4339 targetPlatforms = platform. platformTargets
44- buildCarthage = includeCarthage && platform == . iOS
4540 self . dynamicFrameworks = dynamicFrameworks
4641 }
4742
@@ -52,11 +47,13 @@ struct FrameworkBuilder {
5247 ///
5348 /// - Parameter framework: The name of the framework to be built.
5449 /// - Parameter logsOutputDir: The path to the directory to place build logs.
50+ /// - Parameter setCarthage: Set Carthage diagnostics flag in build.
5551 /// - Parameter moduleMapContents: Module map contents for all frameworks in this pod.
56- /// - Returns: A path to the newly compiled frameworks, the Carthage frameworks, and Resources.
52+ /// - Returns: A path to the newly compiled frameworks, and Resources.
5753 func compileFrameworkAndResources( withName framework: String ,
5854 logsOutputDir: URL ? = nil ,
59- podInfo: CocoaPodUtils . PodInfo ) -> ( [ URL ] , URL ? , URL ? ) {
55+ setCarthage: Bool ,
56+ podInfo: CocoaPodUtils . PodInfo ) -> ( [ URL ] , URL ? ) {
6057 let fileManager = FileManager . default
6158 let outputDir = fileManager. temporaryDirectory ( withName: " frameworks_being_built " )
6259 let logsDir = logsOutputDir ?? fileManager. temporaryDirectory ( withName: " build_logs " )
@@ -78,10 +75,15 @@ struct FrameworkBuilder {
7875
7976 if dynamicFrameworks {
8077 return ( buildDynamicFrameworks ( withName: framework, logsDir: logsDir, outputDir: outputDir) ,
81- nil , nil )
78+ nil )
8279 } else {
83- return buildStaticFrameworks ( withName: framework, logsDir: logsDir, outputDir: outputDir,
84- podInfo: podInfo)
80+ return buildStaticFrameworks (
81+ withName: framework,
82+ logsDir: logsDir,
83+ outputDir: outputDir,
84+ setCarthage: setCarthage,
85+ podInfo: podInfo
86+ )
8587 }
8688 }
8789
@@ -149,7 +151,7 @@ struct FrameworkBuilder {
149151 /// - Returns: A dictionary of URLs to the built thin libraries keyed by platform.
150152 private func buildFrameworksForAllPlatforms( withName framework: String ,
151153 logsDir: URL ,
152- setCarthage: Bool = false ) -> [ TargetPlatform : URL ] {
154+ setCarthage: Bool ) -> [ TargetPlatform : URL ] {
153155 // Build every architecture and save the locations in an array to be assembled.
154156 var slicedFrameworks = [ TargetPlatform: URL] ( )
155157 for targetPlatform in targetPlatforms {
@@ -327,13 +329,15 @@ struct FrameworkBuilder {
327329 /// - Parameter framework: The name of the framework to be built.
328330 /// - Parameter logsDir: The path to the directory to place build logs.
329331 /// - Parameter moduleMapContents: Module map contents for all frameworks in this pod.
330- /// - Returns: A path to the newly compiled framework, the Carthage version, and the Resource URL.
332+ /// - Returns: A path to the newly compiled framework, and the Resource URL.
331333 private func buildStaticFrameworks( withName framework: String ,
332334 logsDir: URL ,
333335 outputDir: URL ,
334- podInfo: CocoaPodUtils . PodInfo ) -> ( [ URL ] , URL ? , URL ) {
336+ setCarthage: Bool ,
337+ podInfo: CocoaPodUtils . PodInfo ) -> ( [ URL ] , URL ) {
335338 // Build every architecture and save the locations in an array to be assembled.
336- let slicedFrameworks = buildFrameworksForAllPlatforms ( withName: framework, logsDir: logsDir)
339+ let slicedFrameworks = buildFrameworksForAllPlatforms ( withName: framework, logsDir: logsDir,
340+ setCarthage: setCarthage)
337341
338342 // Create the framework directory in the filesystem for the thin archives to go.
339343 let fileManager = FileManager . default
@@ -354,6 +358,17 @@ struct FrameworkBuilder {
354358 // Get the framework Headers directory. On macOS, it's a symbolic link.
355359 let headersDir = archivePath. appendingPathComponent ( " Headers " ) . resolvingSymlinksInPath ( )
356360
361+ // The macOS Headers directory can have a Headers file in it symbolically linked to nowhere.
362+ // Delete it here to avoid putting it in the zip or crashing the Carthage hash generation.
363+ // For example,in the 8.0.0 zip distribution see
364+ // Firebase/FirebaseAnalytics/PromisesObjC.xcframework/macos-arm64_x86_64/PromisesObjc
365+ // .framework/Headers/Headers
366+ do {
367+ try fileManager. removeItem ( at: headersDir. appendingPathComponent ( " Headers " ) )
368+ } catch {
369+ // Ignore
370+ }
371+
357372 // Find CocoaPods generated umbrella header.
358373 var umbrellaHeader = " "
359374 if framework == " gRPC-Core " || framework == " TensorFlowLiteObjC " {
@@ -427,27 +442,11 @@ struct FrameworkBuilder {
427442 }
428443 let moduleMapContents = moduleMapContentsTemplate. get ( umbrellaHeader: umbrellaHeader)
429444 let frameworks = groupFrameworks ( withName: framework,
445+ isCarthage: setCarthage,
430446 fromFolder: frameworkDir,
431447 slicedFrameworks: slicedFrameworks,
432448 moduleMapContents: moduleMapContents)
433449
434- var carthageFramework : URL ?
435- if buildCarthage {
436- var carthageThinArchives : [ TargetPlatform : URL ]
437- if framework == " FirebaseCoreDiagnostics " {
438- // FirebaseCoreDiagnostics needs to be built with a different ifdef for the Carthage distro.
439- carthageThinArchives = buildFrameworksForAllPlatforms ( withName: framework,
440- logsDir: logsDir,
441- setCarthage: true )
442- } else {
443- carthageThinArchives = slicedFrameworks
444- }
445- carthageFramework = packageCarthageFramework ( withName: framework,
446- fromFolder: frameworkDir,
447- slicedFrameworks: carthageThinArchives,
448- resourceContents: resourceContents,
449- moduleMapContents: moduleMapContents)
450- }
451450 // Remove the temporary thin archives.
452451 for slicedFramework in slicedFrameworks. values {
453452 do {
@@ -463,7 +462,7 @@ struct FrameworkBuilder {
463462 """ )
464463 }
465464 }
466- return ( frameworks, carthageFramework , resourceContents)
465+ return ( frameworks, resourceContents)
467466 }
468467
469468 /// Parses CocoaPods config files or uses the passed in `moduleMapContents` to write the
@@ -478,7 +477,7 @@ struct FrameworkBuilder {
478477 // Instead it use build options to specify them. For the zip build, we need the module maps to
479478 // include the dependent frameworks and libraries. Therefore we reconstruct them by parsing
480479 // the CocoaPods config files and add them here.
481- // Currently we only to the construction for Objective C since Swift Module directories require
480+ // Currently we only do the construction for Objective C since Swift Module directories require
482481 // several other files. See https://github.com/firebase/firebase-ios-sdk/pull/5040.
483482 // Therefore, for Swift we do a simple copy of the Modules files from an Xcode build.
484483 // This is sufficient for the testing done so far, but more testing is required to determine
@@ -594,19 +593,22 @@ struct FrameworkBuilder {
594593
595594 /// Groups slices for each platform into a minimal set of frameworks.
596595 /// - Parameter withName: The framework name.
596+ /// - Parameter isCarthage: Name the temp directory differently for Carthage.
597597 /// - Parameter fromFolder: The almost complete framework folder. Includes Headers, Info.plist,
598598 /// and Resources.
599599 /// - Parameter slicedFrameworks: All the frameworks sliced by platform.
600600 /// - Parameter moduleMapContents: Module map contents for all frameworks in this pod.
601601 private func groupFrameworks( withName framework: String ,
602+ isCarthage: Bool ,
602603 fromFolder: URL ,
603604 slicedFrameworks: [ TargetPlatform : URL ] ,
604605 moduleMapContents: String ) -> ( [ URL ] ) {
605606 let fileManager = FileManager . default
606607
607608 // Create a `.framework` for each of the thinArchives using the `fromFolder` as the base.
608- let platformFrameworksDir =
609- fileManager. temporaryDirectory ( withName: " platform_frameworks " )
609+ let platformFrameworksDir = fileManager. temporaryDirectory (
610+ withName: isCarthage ? " carthage_frameworks " : " platform_frameworks "
611+ )
610612 if !fileManager. directoryExists ( at: platformFrameworksDir) {
611613 do {
612614 try fileManager. createDirectory ( at: platformFrameworksDir,
@@ -704,172 +706,4 @@ struct FrameworkBuilder {
704706 }
705707 return xcframework
706708 }
707-
708- /// Packages a Carthage framework. Carthage does not yet support xcframeworks, so we exclude the
709- /// Catalyst slice.
710- /// - Parameter withName: The framework name.
711- /// - Parameter fromFolder: The almost complete framework folder. Includes Headers, Info.plist,
712- /// and Resources.
713- /// - Parameter slicedFrameworks: All the frameworks sliced by platform.
714- /// - Parameter resourceContents: Location of the resources for this Carthage framework.
715- /// - Parameter moduleMapContents: Module map contents for all frameworks in this pod.
716- private func packageCarthageFramework( withName framework: String ,
717- fromFolder: URL ,
718- slicedFrameworks: [ TargetPlatform : URL ] ,
719- resourceContents: URL ,
720- moduleMapContents: String ) -> URL ? {
721- let fileManager = FileManager . default
722-
723- // Create a `.framework` for each of the thinArchives using the `fromFolder` as the base.
724- let platformFrameworksDir = fileManager. temporaryDirectory ( withName: " carthage_frameworks " )
725- if !fileManager. directoryExists ( at: platformFrameworksDir) {
726- do {
727- try fileManager. createDirectory ( at: platformFrameworksDir,
728- withIntermediateDirectories: true )
729- } catch {
730- fatalError ( " Could not create a temp directory to store all thin frameworks: \( error) " )
731- }
732- }
733-
734- // The frameworks include the arm64 simulator slice which will conflict with the arm64 device
735- // slice. Until Carthage can use XCFrameworks natively, extract the supported thin slices.
736- let thinSlices : [ Architecture : URL ] =
737- slicedBinariesForCarthage ( fromFrameworks: slicedFrameworks,
738- workingDir: platformFrameworksDir)
739-
740- // Copy the framework in the appropriate directory structure.
741- let frameworkDir = platformFrameworksDir. appendingPathComponent ( fromFolder. lastPathComponent)
742- do {
743- try fileManager. copyItem ( at: fromFolder, to: frameworkDir)
744- } catch {
745- fatalError ( " Could not create .framework needed to build \( framework) for Carthage: \( error) " )
746- }
747-
748- // Build the fat archive using the `lipo` command to make one fat binary that Carthage can use
749- // in the framework. We need the full archive path.
750- let fatArchive = frameworkDir. appendingPathComponent ( framework)
751- let result = FrameworkBuilder . syncExec (
752- command: " /usr/bin/lipo " ,
753- args: [ " -create " , " -output " , fatArchive. path] + thinSlices. map { $0. value. path }
754- )
755- switch result {
756- case let . error( code, output) :
757- fatalError ( """
758- lipo command exited with \( code) when trying to build \( framework) . Output:
759- \( output)
760- """ )
761- case . success:
762- print ( " lipo command for \( framework) succeeded. " )
763- }
764-
765- // Package the modulemaps. The build architecture does not support constructing Swift module
766- // maps for the Carthage distribution, so skip this pod if there is any Swift.
767- let foundSwift = packageModuleMaps ( inFrameworks: slicedFrameworks. map { $0. value } ,
768- moduleMapContents: moduleMapContents,
769- destination: frameworkDir,
770- buildingCarthage: true )
771- if foundSwift {
772- do {
773- try fileManager. removeItem ( at: frameworkDir)
774- } catch {
775- fatalError ( " Could not remove \( frameworkDir) \( error) " )
776- }
777- return nil
778- }
779-
780- // Carthage Resources are packaged in the framework.
781- // Copy them instead of moving them, since they'll still need to be copied into the xcframework.
782- let resourceDir = frameworkDir. appendingPathComponent ( " Resources " )
783- do {
784- try ResourcesManager . moveAllBundles ( inDirectory: resourceContents,
785- to: resourceDir,
786- keepOriginal: true )
787- } catch {
788- fatalError ( " Could not move bundles into Resources directory while building \( framework) : " +
789- " \( error) " )
790- }
791- return frameworkDir
792- }
793-
794- /// Takes existing fat frameworks (sliced per platform) and returns thin slices, excluding arm64
795- /// simulator slices since Carthage can only create a regular framework.
796- private func slicedBinariesForCarthage( fromFrameworks frameworks: [ TargetPlatform : URL ] ,
797- workingDir: URL ) -> [ Architecture : URL ] {
798- // Exclude Catalyst.
799- let platformsToInclude : [ TargetPlatform ] = frameworks. keys. filter { $0 != . catalyst }
800- let builtSlices : [ TargetPlatform : URL ] = frameworks
801- . filter { platformsToInclude. contains ( $0. key) }
802- . mapValues { frameworkURL in
803- // Get the path to the sliced binary instead of the framework.
804- let frameworkName = frameworkURL. lastPathComponent
805- let binaryName = frameworkName. replacingOccurrences ( of: " .framework " , with: " " )
806- return frameworkURL. appendingPathComponent ( binaryName)
807- }
808-
809- let fileManager = FileManager . default
810- let individualSlices = workingDir. appendingPathComponent ( " slices " )
811- if !fileManager. directoryExists ( at: individualSlices) {
812- do {
813- try fileManager. createDirectory ( at: individualSlices,
814- withIntermediateDirectories: true )
815- } catch {
816- fatalError ( " Could not create a temp directory to store sliced binaries: \( error) " )
817- }
818- }
819-
820- // Loop through and extract the necessary architectures.
821- var slices : [ Architecture : URL ] = [ : ]
822- for (platform, binary) in builtSlices {
823- var archs = platform. archs
824- var forceLipoOnOneArch = false
825- if platform == . iOSSimulator {
826- // Exclude the arm64 slice for simulator since Carthage can't package as an XCFramework.
827- archs. removeAll ( where: { $0 == . arm64 } )
828- if binary. lastPathComponent == " FirebaseAppCheck " {
829- // Exclude i386 slice for iOS 11+ frameworks.
830- archs. removeAll ( where: { $0 == . i386 } )
831- forceLipoOnOneArch = true // Still need to run lipo because .x86_64 and arm64 were built.
832- }
833- }
834- if platform == . iOSDevice {
835- if binary. lastPathComponent == " FirebaseAppCheck " {
836- // Exclude armv7 slice for iOS 11+ frameworks.
837- archs. removeAll ( where: { $0 == . armv7 } )
838- }
839- }
840-
841- // lipo doesn't work if only one architecture.
842- if archs. count == 1 , !forceLipoOnOneArch {
843- slices [ archs. first!] = binary
844- continue
845- }
846-
847- // Loop through the architectures and strip out each by using `lipo`.
848- for arch in archs {
849- // Create the path where the thin slice will reside, ensure it's non-existent.
850- let destination = individualSlices. appendingPathComponent ( " \( arch. rawValue) .a " )
851- fileManager. removeIfExists ( at: destination)
852-
853- // Use lipo to extract the architecture we're looking for.
854- let result = FrameworkBuilder . syncExec ( command: " /usr/bin/lipo " ,
855- args: [ binary. path,
856- " -thin " , arch. rawValue,
857- " -output " , destination. path] )
858- switch result {
859- case let . error( code, output) :
860- fatalError ( """
861- lipo command exited with \( code) when trying to extract the \( arch. rawValue) slice \
862- from \( binary. path) . Output:
863- \( output)
864- """ )
865- case . success:
866- print ( " lipo successfully extracted the \( arch. rawValue) slice from \( binary. path) " )
867- }
868-
869- slices [ arch] = destination
870- }
871- }
872-
873- return slices
874- }
875709}
0 commit comments