Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xcframework prebuilt binaries #3123

Merged
15 changes: 15 additions & 0 deletions Source/CarthageKit/FrameworkSuffix.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Result

/// Framework Suffix
public enum FrameworkSuffix: String {
/// Framework
case framework = "framework"

/// XCFramework
case xcframework = "xcframework"

/// Attempts to parse a product type from a string path component
public static func from(string: String) -> Result<FrameworkSuffix, CarthageError> {
return Result(self.init(rawValue: string), failWith: .parseError(description: "unexpected framework suffix \"\(string)\""))
}
}
34 changes: 23 additions & 11 deletions Source/CarthageKit/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -599,17 +599,12 @@ public final class Project { // swiftlint:disable:this type_body_length
.then(shouldCheckout ? checkoutResolvedDependencies(dependenciesToUpdate, buildOptions: buildOptions) : .empty)
}

/// Constructs the file:// URL at which a given .framework
/// Constructs the file:// URL at which a given .framework or .xcframework
/// will be found. Depends on the location of the current project.
private func frameworkURLInCarthageBuildFolder(
forSDK sdk: SDK,
frameworkNameAndExtension: String
) -> Result<URL, CarthageError> {
guard let lastComponent = URL(string: frameworkNameAndExtension)?.pathExtension,
lastComponent == "framework" else {
return .failure(.internalError(description: "\(frameworkNameAndExtension) is not a valid framework identifier"))
}

guard let destinationURLInWorkingDir = sdk
.relativeURL?
.appendingPathComponent(frameworkNameAndExtension, isDirectory: true) else {
Expand Down Expand Up @@ -674,9 +669,7 @@ public final class Project { // swiftlint:disable:this type_body_length
.flatMap(.merge) { frameworksUrls -> SignalProducer<SourceURLAndDestinationURL, CarthageError> in
return SignalProducer<URL, CarthageError>(frameworksUrls)
.flatMap(.merge) { url -> SignalProducer<URL, CarthageError> in
return platformForFramework(url)
.attemptMap { self.frameworkURLInCarthageBuildFolder(forSDK: $0,
frameworkNameAndExtension: url.lastPathComponent) }
return self.getBinaryFrameworkURL(url: url)
}
.collect()
.flatMap(.merge) { destinationUrls -> SignalProducer<SourceURLAndDestinationURL, CarthageError> in
Expand Down Expand Up @@ -721,6 +714,23 @@ public final class Project { // swiftlint:disable:this type_body_length
.then(SignalProducer<URL, CarthageError>(value: directoryURL))
}
}

/// Ensures binary framework has a valid extension and returns url in build folder
private func getBinaryFrameworkURL(url: URL) -> SignalProducer<URL, CarthageError> {
return SignalProducer(result: FrameworkSuffix.from(string: url.pathExtension))
.flatMap(.merge) { frameworkSuffix -> SignalProducer<URL, CarthageError> in
switch frameworkSuffix {
case .xcframework:
return SignalProducer<URL, CarthageError>(value: url)
.attemptMap { self.frameworkURLInCarthageBuildFolder(forSDK: SDK(name: "", simulatorHeuristic: ""),
frameworkNameAndExtension: $0.lastPathComponent) }
case .framework:
return platformForFramework(url)
.attemptMap { self.frameworkURLInCarthageBuildFolder(forSDK: $0,
frameworkNameAndExtension: url.lastPathComponent) }
}
}
}

/// Removes the file located at the given URL
///
Expand Down Expand Up @@ -1447,11 +1457,13 @@ func platformForFramework(_ frameworkURL: URL) -> SignalProducer<SDK, CarthageEr
/// Sends the URL to each framework bundle found in the given directory.
internal func frameworksInDirectory(_ directoryURL: URL) -> SignalProducer<URL, CarthageError> {
return filesInDirectory(directoryURL, kUTTypeFramework as String)
.concat(filesInDirectory(directoryURL, "com.apple.xcframework"))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation fix needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

.filter { !$0.pathComponents.contains("__MACOSX") }
.filter { url in
// Skip nested frameworks
let frameworksInURL = url.pathComponents.filter { pathComponent in
return (pathComponent as NSString).pathExtension == "framework"
let pathExtension = (pathComponent as NSString).pathExtension
return FrameworkSuffix.from(string: pathExtension).error == nil
}
return frameworksInURL.count == 1
}.filter { url in
Expand All @@ -1461,7 +1473,7 @@ internal func frameworksInDirectory(_ directoryURL: URL) -> SignalProducer<URL,
let packageType: PackageType? = bundle?.packageType

switch packageType {
case .framework?, .bundle?:
case .xcframework?, .framework?, .bundle?:
return true
default:
// In case no Info.plist exists check the Mach-O fileType
Expand Down
22 changes: 22 additions & 0 deletions Source/CarthageKit/Xcode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@ public enum FrameworkType: String, Codable {
internal enum PackageType: String {
/// A .framework package.
case framework = "FMWK"

/// A .xcframework package
case xcframework = "XFWK"

/// A .bundle package. Some frameworks might have this package type code
/// (e.g. https://github.com/ResearchKit/ResearchKit/blob/1.3.0/ResearchKit/Info.plist#L15-L16).
Expand Down Expand Up @@ -1357,6 +1360,9 @@ extension Signal where Value: TaskEventType {
}

public func nonDestructivelyStripArchitectures(_ frameworkURL: URL, _ architectures: Set<String>) -> SignalProducer<(Data, URL), CarthageError> {
guard isNotXCFramework(frameworkURL) else {
return SignalProducer<(Data, URL), CarthageError>.empty
}
return SignalProducer(value: frameworkURL)
.attemptMap(binaryURL)
.attemptMap {
Expand Down Expand Up @@ -1413,6 +1419,9 @@ public func nonDestructivelyStripArchitectures(_ frameworkURL: URL, _ architectu

/// Strips the given architectures from a framework.
private func stripArchitectures(_ packageURL: URL, _ architectures: Set<String>) -> SignalProducer<(), CarthageError> {
guard isNotXCFramework(packageURL) else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation fix needed. Please check the indentation of return statement below it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

return SignalProducer<(), CarthageError>.empty
}
return SignalProducer<URL, CarthageError> { () -> Result<URL, CarthageError> in binaryURL(packageURL) }
.flatMap(.merge) { binaryURL -> SignalProducer<(), CarthageError> in
let arguments = [
Expand All @@ -1431,6 +1440,9 @@ private func stripArchitectures(_ packageURL: URL, _ architectures: Set<String>)

// Returns a signal of all architectures present in a given package.
public func architecturesInPackage(_ packageURL: URL, xcrunQuery: [String] = ["lipo", "-info"]) -> SignalProducer<[String], CarthageError> {
guard isNotXCFramework(packageURL) else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation fix needed. Please check the indentation of return statement below it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done for all changes made in the PR 👍

return SignalProducer(value: [])
}
let binaryURLResult = binaryURL(packageURL)
guard let binaryURL = binaryURLResult.value else { return SignalProducer(error: binaryURLResult.error!) }

Expand Down Expand Up @@ -1491,6 +1503,9 @@ public func architecturesInPackage(_ packageURL: URL, xcrunQuery: [String] = ["l

/// Strips debug symbols from the given framework
public func stripDebugSymbols(_ frameworkURL: URL) -> SignalProducer<(), CarthageError> {
guard isNotXCFramework(frameworkURL) else {
return SignalProducer<(), CarthageError>.empty
}
return SignalProducer<URL, CarthageError> { () -> Result<URL, CarthageError> in binaryURL(frameworkURL) }
.flatMap(.merge) { binaryURL -> SignalProducer<TaskEvent<Data>, CarthageError> in
let stripTask = Task("/usr/bin/xcrun", arguments: [ "strip", "-S", "-o", binaryURL.path, binaryURL.path])
Expand Down Expand Up @@ -1532,6 +1547,9 @@ private func stripDirectory(named directory: String, of frameworkURL: URL) -> Si

/// Sends a set of UUIDs for each architecture present in the given framework.
public func UUIDsForFramework(_ frameworkURL: URL) -> SignalProducer<Set<UUID>, CarthageError> {
guard isNotXCFramework(frameworkURL) else {
return SignalProducer(value: Set<UUID>())
}
return SignalProducer { () -> Result<URL, CarthageError> in binaryURL(frameworkURL) }
.flatMap(.merge, UUIDsFromDwarfdump)
}
Expand Down Expand Up @@ -1649,3 +1667,7 @@ private func codesign(_ frameworkURL: URL, _ expandedIdentity: String) -> Signal
.mapError(CarthageError.taskError)
.then(SignalProducer<(), CarthageError>.empty)
}

private func isNotXCFramework(_ frameworkUrl: URL) -> Bool {
return FrameworkSuffix.from(string: frameworkUrl.pathExtension).value != .xcframework
}