diff --git a/Package.swift b/Package.swift index 9ea3415..246f990 100644 --- a/Package.swift +++ b/Package.swift @@ -21,7 +21,7 @@ let package = Package( .plugin(name: "skipstone", capability: .buildTool(), dependencies: ["skip"], path: "Plugins/SkipPlugin"), .plugin(name: "Create SkipLink", capability: .command(intent: .custom(verb: "SkipLink", description: "Create local links to transpiled output"), permissions: [.writeToPackageDirectory(reason: "This command will create local links to the skipstone output for the specified package(s), enabling access to the transpiled Kotlin")]), dependencies: ["skip"], path: "Plugins/SkipLink"), .target(name: "SkipDrive", dependencies: ["skipstone", .target(name: "skip")]), - .target(name: "SkipTest", dependencies: [.target(name: "SkipDrive", condition: .when(platforms: [.macOS, .linux]))]), + .target(name: "SkipTest", dependencies: [.target(name: "SkipDrive", condition: .when(platforms: [.macOS, .macCatalyst, .linux]))]), .testTarget(name: "SkipTestTests", dependencies: ["SkipTest"]), .testTarget(name: "SkipDriveTests", dependencies: ["SkipDrive"]), ] diff --git a/Sources/SkipDrive/GradleDriver.swift b/Sources/SkipDrive/GradleDriver.swift index f045dae..f95d60f 100644 --- a/Sources/SkipDrive/GradleDriver.swift +++ b/Sources/SkipDrive/GradleDriver.swift @@ -715,7 +715,7 @@ extension ProcessInfo { } // “The script installs Homebrew to its default, supported, best prefix (/opt/homebrew for Apple Silicon, /usr/local for macOS Intel and /home/linuxbrew/.linuxbrew for Linux)” — https://docs.brew.sh/Installation - #if os(macOS) || os(macCatalyst) + #if os(macOS) || targetEnvironment(macCatalyst) return ProcessInfo.isARM ? "/opt/homebrew" : "/usr/local" #else // Linux @@ -728,7 +728,7 @@ extension ProcessInfo { var env = self.environment let ANDROID_HOME = "ANDROID_HOME" if (env[ANDROID_HOME] ?? "").isEmpty { - #if os(macOS) + #if os(macOS) || targetEnvironment(macCatalyst) env[ANDROID_HOME] = ("~/Library/Android/sdk" as NSString).expandingTildeInPath #elseif os(Windows) env[ANDROID_HOME] = ("~/AppData/Local/Android/Sdk" as NSString).expandingTildeInPath @@ -745,7 +745,7 @@ extension ProcessInfo { let JAVA_HOME = "JAVA_HOME" if (env[JAVA_HOME] ?? "").isEmpty { - #if os(macOS) + #if os(macOS) || targetEnvironment(macCatalyst) // default if JAVA_HOME is unset: /opt/homebrew/opt/java -> ../Cellar/openjdk/21.0.1 env[JAVA_HOME] = "\(Self.homebrewRoot)/opt/java" #endif diff --git a/Sources/SkipDrive/ToolSupport.swift b/Sources/SkipDrive/ToolSupport.swift index b358058..a8be6ea 100644 --- a/Sources/SkipDrive/ToolSupport.swift +++ b/Sources/SkipDrive/ToolSupport.swift @@ -112,7 +112,7 @@ extension Process { extension ProcessInfo { /// True when the current architecture is ARM public static let isARM = { - #if os(macOS) + #if os(macOS) || targetEnvironment(macCatalyst) var size: size_t = 0 sysctlbyname("hw.machine", nil, &size, nil, 0) var machine = [CChar](repeating: 0, count: size) @@ -986,8 +986,8 @@ fileprivate final class PendingResultBox: @unchecked Sendable { // we could do something like this: // https://github.com/swiftlang/swift-tools-support-core/pull/113/changes // - // but for now we simple ignore workingDirectory flag on Linux - #if !os(Linux) + // but for now we simply ignore workingDirectory flag on Linux and Mac Catalyst. + #if !os(Linux) && !targetEnvironment(macCatalyst) posix_spawn_file_actions_addchdir_np(&fileActions, workingDirectory) #endif } diff --git a/Sources/SkipTest/XCGradleHarness.swift b/Sources/SkipTest/XCGradleHarness.swift index c913c80..a80be24 100644 --- a/Sources/SkipTest/XCGradleHarness.swift +++ b/Sources/SkipTest/XCGradleHarness.swift @@ -2,7 +2,7 @@ #if !SKIP #if canImport(SkipDrive) import SkipDrive -#if os(macOS) || os(Linux) +#if os(macOS) || targetEnvironment(macCatalyst) || os(Linux) @_exported import XCTest /// A `XCTestCase` that invokes the `gradle` process. @@ -42,7 +42,7 @@ extension XCGradleHarness where Self : XCTestCase { } return raw.split(separator: "\n", omittingEmptySubsequences: true).map(String.init) }() - try await invokeGradle(actions: [testAction], info: info, deviceID: device, testFilters: testFilters) + try await invokeGradle(actions: [testAction], info: info, deviceID: device, testFilters: testFilters, fromSourceFileRelativeToPackageRoot: file) print("Completed gradle test run for \(device ?? "local")") } catch { XCTFail("\((error as? LocalizedError)?.localizedDescription ?? error.localizedDescription)", file: file, line: line) @@ -99,6 +99,21 @@ extension XCGradleHarness where Self : XCTestCase { var testProcessResult: ProcessResult? = nil var env: [String: String] = ProcessInfo.processInfo.environmentWithDefaultToolPaths + #if targetEnvironment(macCatalyst) + if let packageRootURL = sourcePath.flatMap(packageBaseFolder(forSourceFile:)) { + // Robolectric runs in a macOS JVM, so build host dylibs instead of loading Catalyst frameworks. + let configuration = actions.contains(where: { $0.localizedCaseInsensitiveContains("release") }) ? "release" : "debug" + let swiftBuildArgs = ["/usr/bin/xcrun", "swift", "build", "--package-path", packageRootURL.path, "--target", baseModuleName, "--configuration", configuration, "--disable-sandbox"] + try await Process.checkNonZeroExit(arguments: swiftBuildArgs, environment: env) + let arch = ProcessInfo.isARM ? "arm64-apple-macosx" : "x86_64-apple-macosx" + env["SKIP_FFI_LIBRARY_PATH"] = packageRootURL + .appendingPathComponent(".build", isDirectory: true) + .appendingPathComponent(arch, isDirectory: true) + .appendingPathComponent(configuration, isDirectory: true) + .path + } + #endif + if let deviceID = deviceID, !deviceID.isEmpty { env["ANDROID_SERIAL"] = deviceID } @@ -576,6 +591,6 @@ extension XCTestCase { #endif -#endif // os(macOS) || os(Linux) +#endif // os(macOS) || targetEnvironment(macCatalyst) || os(Linux) #endif // canImport(SkipDrive) #endif // !SKIP