From 2fdee556da87884638fe955097ac2118b9bb6682 Mon Sep 17 00:00:00 2001 From: Rob Amos Date: Tue, 20 Oct 2020 21:00:30 +1100 Subject: [PATCH 1/4] Added support for macCatalyst as a platform --- Sources/CreateXCFramework/PackageInfo.swift | 9 +-- Sources/CreateXCFramework/Platforms.swift | 35 +++++++++--- .../CreateXCFramework/ProjectGenerator.swift | 5 +- Sources/CreateXCFramework/XcodeBuilder.swift | 57 ++++++++++++------- 4 files changed, 71 insertions(+), 35 deletions(-) diff --git a/Sources/CreateXCFramework/PackageInfo.swift b/Sources/CreateXCFramework/PackageInfo.swift index 69645da..45b6a4a 100644 --- a/Sources/CreateXCFramework/PackageInfo.swift +++ b/Sources/CreateXCFramework/PackageInfo.swift @@ -160,7 +160,8 @@ struct PackageInfo { /// check if our command line platforms are supported by the package definition func supportedPlatforms () throws -> [TargetPlatform] { - let supported = self.options.platform.nonEmpty ?? TargetPlatform.allCases + // if they have specified platforms all good, if not go everything except catalyst + let supported = self.options.platform.nonEmpty ?? TargetPlatform.allCases.filter { $0 != .maccatalyst } // do we have package platforms defined? guard let packagePlatforms = self.manifest.platforms.nonEmpty else { @@ -169,11 +170,11 @@ struct PackageInfo { // filter our package platforms to make sure everything is supported let target = packagePlatforms - .compactMap { platform -> TargetPlatform? in - return supported.first(where: { $0.rawValue == platform.platformName }) + .compactMap { platform -> [TargetPlatform]? in + return supported.filter({ $0.platformName == platform.platformName }) } + .flatMap { $0 } - // are they different then? return target } diff --git a/Sources/CreateXCFramework/Platforms.swift b/Sources/CreateXCFramework/Platforms.swift index 8e77ad6..6473039 100644 --- a/Sources/CreateXCFramework/Platforms.swift +++ b/Sources/CreateXCFramework/Platforms.swift @@ -11,6 +11,7 @@ import PackageModel enum TargetPlatform: String, ExpressibleByArgument, CaseIterable { case ios case macos + case maccatalyst case tvos case watchos @@ -19,36 +20,52 @@ enum TargetPlatform: String, ExpressibleByArgument, CaseIterable { } + var platformName: String { + switch self { + case .ios: return "ios" + case .macos: return "macos" + case .maccatalyst: return "macos" + case .tvos: return "tvos" + case .watchos: return "watchos" + } + } + // MARK: - Target SDKs struct SDK { - let sdkName: String - let directorySuffix: String + let destination: String + let archiveName: String + let buildSettings: [String: String]? } var sdks: [SDK] { switch self { case .ios: return [ - SDK(sdkName: "iphoneos", directorySuffix: "-iphoneos"), - SDK(sdkName: "iphonesimulator", directorySuffix: "-iphonesimulator") + SDK(destination: "generic/platform=iOS", archiveName: "iphoneos.xcarchive", buildSettings: nil), + SDK(destination: "generic/platform=iOS Simulator", archiveName: "iphonesimulator.xcarchive", buildSettings: nil) ] case .macos: return [ - SDK(sdkName: "macosx", directorySuffix: "") + SDK(destination: "platform=macOS", archiveName: "macos.xcarchive", buildSettings: nil) + ] + + case .maccatalyst: + return [ + SDK(destination: "platform=macOS,variant=Mac Catalyst", archiveName: "maccatalyst.xcarchive", buildSettings: [ "SUPPORTS_MACCATALYST": "YES" ]) ] case .tvos: return [ - SDK(sdkName: "appletvos", directorySuffix: "-appletvos"), - SDK(sdkName: "appletvsimulator", directorySuffix: "-appletvsimulator") + SDK(destination: "generic/platform=tvOS", archiveName: "appletvos.xcarchive", buildSettings: nil), + SDK(destination: "generic/platform=tvOS Simulator", archiveName: "appletvsimulator.xcarchive", buildSettings: nil) ] case .watchos: return [ - SDK(sdkName: "watchos", directorySuffix: "-watchos"), - SDK(sdkName: "watchsimulator", directorySuffix: "-watchsimulator") + SDK(destination: "generic/platform=watchOS", archiveName: "watchos.xcarchive", buildSettings: nil), + SDK(destination: "generic/platform=watchOS Simulator", archiveName: "watchsimulator.xcarchive", buildSettings: nil) ] } } diff --git a/Sources/CreateXCFramework/ProjectGenerator.swift b/Sources/CreateXCFramework/ProjectGenerator.swift index 726ab05..f3e660f 100644 --- a/Sources/CreateXCFramework/ProjectGenerator.swift +++ b/Sources/CreateXCFramework/ProjectGenerator.swift @@ -73,7 +73,10 @@ struct ProjectGenerator { graph: self.package.graph, extraDirs: [], extraFiles: [], - options: XcodeprojOptions(xcconfigOverrides: (self.package.overridesXcconfig?.path).flatMap { AbsolutePath($0) }), + options: XcodeprojOptions ( + xcconfigOverrides: (self.package.overridesXcconfig?.path).flatMap { AbsolutePath($0) }, + useLegacySchemeGenerator: true + ), diagnostics: self.package.diagnostics ) diff --git a/Sources/CreateXCFramework/XcodeBuilder.swift b/Sources/CreateXCFramework/XcodeBuilder.swift index 7de30a0..7296a44 100644 --- a/Sources/CreateXCFramework/XcodeBuilder.swift +++ b/Sources/CreateXCFramework/XcodeBuilder.swift @@ -68,21 +68,23 @@ struct XcodeBuilder { // MARK: - Build func build (targets: [String], sdk: TargetPlatform.SDK) throws -> [String: Foundation.URL] { - let process = TSCBasic.Process ( - arguments: try self.buildCommand(targets: targets, sdk: sdk), - outputRedirection: .none - ) - - try process.launch() - let result = try process.waitUntilExit() - - switch result.exitStatus { - case let .terminated(code: code): - if code != 0 { - throw Error.nonZeroExit(code) + for target in targets { + let process = TSCBasic.Process ( + arguments: try self.buildCommand(target: target, sdk: sdk), + outputRedirection: .none + ) + + try process.launch() + let result = try process.waitUntilExit() + + switch result.exitStatus { + case let .terminated(code: code): + if code != 0 { + throw Error.nonZeroExit(code) + } + case let .signalled(signal: signal): + throw Error.signalExit(signal) } - case let .signalled(signal: signal): - throw Error.signalExit(signal) } return targets @@ -91,21 +93,30 @@ struct XcodeBuilder { } } - private func buildCommand (targets: [String], sdk: TargetPlatform.SDK) throws -> [String] { + private func buildCommand (target: String, sdk: TargetPlatform.SDK) throws -> [String] { var command: [String] = [ "xcrun", "xcodebuild", "-project", self.path.pathString, "-configuration", self.options.configuration.xcodeConfigurationName, - "-sdk", sdk.sdkName, - "BUILD_DIR=\(self.buildDirectory.path)" + "-archivePath", self.buildDirectory.appendingPathComponent(self.productName(target: target)).appendingPathComponent(sdk.archiveName).path, + "-destination", sdk.destination, + "BUILD_DIR=\(self.buildDirectory.path)", + "SKIP_INSTALL=NO" ] + // add any build settings + if let settings = sdk.buildSettings { + for setting in settings { + command.append("\(setting.key)=\(setting.value)") + } + } + // add our targets - command += targets.flatMap { [ "-target", $0 ] } + command += [ "-scheme", target ] // and the command - command += [ "build" ] + command += [ "archive" ] return command } @@ -113,7 +124,9 @@ struct XcodeBuilder { // we should probably pull this from the build output but we just make assumptions here private func frameworkPath (target: String, sdk: TargetPlatform.SDK) -> Foundation.URL { return self.buildDirectory - .appendingPathComponent(self.options.configuration.xcodeConfigurationName + sdk.directorySuffix) + .appendingPathComponent(self.productName(target: target)) + .appendingPathComponent(sdk.archiveName) + .appendingPathComponent("Products/Library/Frameworks") .appendingPathComponent("\(self.productName(target: target)).framework") .absoluteURL } @@ -124,6 +137,9 @@ struct XcodeBuilder { func merge (target: String, frameworks: [Foundation.URL]) throws -> Foundation.URL { let outputPath = self.xcframeworkPath(target: target) + // try to remove it if its already there, otherwise we're going to get errors + try? FileManager.default.removeItem(at: outputPath) + let process = TSCBasic.Process ( arguments: self.mergeCommand(outputPath: outputPath, frameworks: frameworks), outputRedirection: .none @@ -156,7 +172,6 @@ struct XcodeBuilder { // and the output command += [ "-output", outputPath.path ] - return command } From 4be75a0d9a1e3c70cc01265ba496e843b3a04073 Mon Sep 17 00:00:00 2001 From: Rob Amos Date: Tue, 20 Oct 2020 21:17:46 +1100 Subject: [PATCH 2/4] Bumped version to 1.3.0 and adjusted default arguments --- Sources/CreateXCFramework/Command+Options.swift | 4 ++-- Sources/CreateXCFramework/Command.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/CreateXCFramework/Command+Options.swift b/Sources/CreateXCFramework/Command+Options.swift index c968098..610a87f 100644 --- a/Sources/CreateXCFramework/Command+Options.swift +++ b/Sources/CreateXCFramework/Command+Options.swift @@ -44,7 +44,7 @@ extension Command { valueName: TargetPlatform.allCases.map({ $0.rawValue }).joined(separator: "|") ) ) - var platform: [TargetPlatform] + var platform: [TargetPlatform] = [] @Option(help: ArgumentHelp("Where to place the compiled .xcframework(s)", valueName: "directory")) var output = "." @@ -69,7 +69,7 @@ extension Command { // MARK: - Targets @Argument(help: "An optional list of products (or targets) to build. Defaults to building all `.library` products") - var products: [String] + var products: [String] = [] } } diff --git a/Sources/CreateXCFramework/Command.swift b/Sources/CreateXCFramework/Command.swift index 7907b8f..32e3d31 100644 --- a/Sources/CreateXCFramework/Command.swift +++ b/Sources/CreateXCFramework/Command.swift @@ -27,7 +27,7 @@ struct Command: ParsableCommand { Supported platforms: \(TargetPlatform.allCases.map({ $0.rawValue }).joined(separator: ", ")) """, - version: "1.2.1" + version: "1.3.0" ) From 95329d4a8f1c2c28b618b6215c640e6985372514 Mon Sep 17 00:00:00 2001 From: Rob Amos Date: Tue, 20 Oct 2020 22:23:25 +1100 Subject: [PATCH 3/4] Updated build tests to support catalyst also --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 83a696a..c878275 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,7 +34,7 @@ jobs: path: Vexil - name: 📦 Package Vexil - run: cd Vexil && ../.build/release/swift-create-xcframework --zip --zip-version 1.2.2 --platform ios --platform macos --platform tvos --platform watchos Vexil Vexillographer + run: cd Vexil && ../.build/release/swift-create-xcframework --zip --zip-version 1.2.2 --platform ios --platform macos --platform tvos --platform watchos tests-xcode-12: name: Test Builds - Xcode 12 @@ -57,4 +57,4 @@ jobs: path: Vexil - name: 📦 Package Vexil - run: cd Vexil && ../.build/release/swift-create-xcframework --zip --zip-version 1.2.2 --platform ios --platform macos --platform tvos --platform watchos Vexil Vexillographer + run: cd Vexil && ../.build/release/swift-create-xcframework --zip --zip-version 1.2.2 --platform ios --platform macos --platform tvos --platform watchos From 78ad9cbff81f7a1cb2a200b35a9fc346d2104a93 Mon Sep 17 00:00:00 2001 From: Rob Amos Date: Tue, 20 Oct 2020 22:47:32 +1100 Subject: [PATCH 4/4] Updated README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 511e8d7..d0145fb 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,10 @@ You can specify a subset of the platforms to build using the `--platform` option swift create-xcframework --platform ios --platform macos ... ``` +#### Catalyst + +You can build your XCFrameworks with support for Mac Catalyst by specifying `--platform maccatalyst` on the command line. As you can't include or exclude Catalyst support in your `Package.swift` we don't try to build it automatically. + ### Choosing Products Because we wrap `xcodebuild`, you can actually build XCFrameworks from anything that will be mapped to an Xcode project as a Framework target. This includes all of the dependencies your Package has. @@ -126,7 +130,7 @@ jobs: - uses: actions/checkout@v2 - name: Create XCFramework - uses: unsignedapps/swift-create-xcframework@v1 + uses: unsignedapps/swift-create-xcframework@v1.3 # Create a release # Upload those artifacts to the release @@ -137,7 +141,7 @@ jobs: You can install using mint: ```shell -mint install unsignedapps/swift-create-xcframework@1.0.5 +mint install unsignedapps/swift-create-xcframework@1.3.0 ``` Or manually: