diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 24a2fee0f..3be4e8fdc 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -44,10 +44,12 @@ jobs: test-java: name: Test (Java) (${{ matrix.os_version }} swift:${{ matrix.swift_version }} jdk:${{matrix.jdk_vendor}}) runs-on: ubuntu-latest + # Nightly builds are best-effort + continue-on-error: ${{ contains(matrix.swift_version, 'nightly') }} strategy: fail-fast: true matrix: - swift_version: ['6.2', '6.3'] # FIXME: reenable 'nightly' once snapshot toolchains are stable again + swift_version: ['6.2', '6.3', 'nightly'] os_version: ['jammy'] jdk_vendor: ['corretto'] container: @@ -136,10 +138,12 @@ jobs: test-swift: name: Test (Swift) (${{ matrix.os_version }} swift:${{ matrix.swift_version }} jdk:${{matrix.jdk_vendor}}) runs-on: ubuntu-latest + # Nightly builds are best-effort + continue-on-error: ${{ contains(matrix.swift_version, 'nightly') }} strategy: fail-fast: false matrix: - swift_version: ['6.1.3', '6.2', '6.3'] # FIXME: reenable 'nightly' once snapshot toolchains are stable again + swift_version: ['6.1.3', '6.2', '6.3', 'nightly'] os_version: ['jammy'] jdk_vendor: ['corretto'] container: @@ -186,10 +190,12 @@ jobs: build-swift-android: name: Sample SwiftJavaExtractJNISampleApp (Android) (swift:${{ matrix.swift_version }} android:${{matrix.sdk_triple}} NDK:${{matrix.ndk_version}}) runs-on: ubuntu-22.04 + # Nightly builds are best-effort + continue-on-error: ${{ contains(matrix.swift_version, 'nightly') }} strategy: fail-fast: false matrix: - swift_version: ['nightly-6.3'] # FIXME: reenable 'nightly-main' once snapshot toolchains are stable again + swift_version: ['6.3'] os_version: ['jammy'] jdk_vendor: ['corretto'] sdk_triple: ['aarch64-unknown-linux-android28', 'x86_64-unknown-linux-android28', 'armv7-unknown-linux-android28'] @@ -210,10 +216,12 @@ jobs: verify-samples: name: Sample ${{ matrix.sample_app }} (${{ matrix.os_version }} swift:${{ matrix.swift_version }} jdk:${{matrix.jdk_vendor}}) runs-on: ubuntu-latest + # Nightly builds are best-effort + continue-on-error: ${{ contains(matrix.swift_version, 'nightly') }} strategy: fail-fast: false matrix: - swift_version: ['6.1.3', '6.2', '6.3'] # FIXME: reenable 'nightly' once snapshot toolchains are stable again + swift_version: ['6.1.3', '6.2', '6.3', 'nightly'] os_version: ['jammy'] jdk_vendor: ['corretto'] sample_app: [ # TODO: use a reusable-workflow to generate those names diff --git a/BuildLogic/src/main/kotlin/build-logic.java-common-conventions.gradle.kts b/BuildLogic/src/main/kotlin/build-logic.java-common-conventions.gradle.kts index c70674469..9c82408f3 100644 --- a/BuildLogic/src/main/kotlin/build-logic.java-common-conventions.gradle.kts +++ b/BuildLogic/src/main/kotlin/build-logic.java-common-conventions.gradle.kts @@ -81,9 +81,23 @@ fun javaLibraryPaths(rootDir: File): List { val debugBuildOutputPaths = swiftBuildOutputPaths.map { "$it/debug" } val releaseBuildOutputPaths = swiftBuildOutputPaths.map { "$it/release" } + + // swift-build layout (https://github.com/swiftlang/swift-build/issues/1363): + // .build/out/Products/[-]/ — no triple, different config casing, + // OS suffix on Linux + val swiftBuildSystemConfigs = if (isLinux) { + listOf("Debug-linux", "Release-linux") + } else { + listOf("Debug", "Release") + } + val swiftBuildSystemRoots = listOf("$base.build/out/Products", "../../$base.build/out/Products") + val swiftBuildSystemPaths = swiftBuildSystemRoots.flatMap { root -> + swiftBuildSystemConfigs.map { config -> "$root/$config" } + } + val swiftRuntimePaths = getSwiftRuntimeLibraryPaths() - return debugBuildOutputPaths + releaseBuildOutputPaths + swiftRuntimePaths + return debugBuildOutputPaths + releaseBuildOutputPaths + swiftBuildSystemPaths + swiftRuntimePaths } // Configure paths for native (Swift) libraries diff --git a/BuildLogic/src/main/kotlin/utilities/javaLibraryPaths.kt b/BuildLogic/src/main/kotlin/utilities/javaLibraryPaths.kt index 943ae2434..c3ec0fe92 100644 --- a/BuildLogic/src/main/kotlin/utilities/javaLibraryPaths.kt +++ b/BuildLogic/src/main/kotlin/utilities/javaLibraryPaths.kt @@ -44,10 +44,22 @@ fun Project.javaLibraryPaths(rootDir: File?): List { "${arch}-apple-macosx" } - val paths: List = listOf("release", "debug").map { configuration -> + // Native build system: .build/// + val nativeBuildPaths: List = listOf("release", "debug").map { configuration -> "${base}.build/${triple}/$configuration/" } + + // swift-build: .build/out/Products/[-]/ + val swiftBuildConfigs = if (isLinux) { + listOf("Debug-linux", "Release-linux") + } else { + listOf("Debug", "Release") + } + val swiftBuildPaths: List = swiftBuildConfigs.map { config -> + "${base}.build/out/Products/$config/" + } + val swiftRuntimePaths = swiftRuntimeLibraryPaths() - return paths + swiftRuntimePaths + return nativeBuildPaths + swiftBuildPaths + swiftRuntimePaths } diff --git a/Package.swift b/Package.swift index a26cf3a42..bb7d453ac 100644 --- a/Package.swift +++ b/Package.swift @@ -61,7 +61,7 @@ let package = Package( .executable( name: "swift-java", - targets: ["SwiftJavaTool"] + targets: ["swift-java"] ), .library( @@ -224,7 +224,7 @@ let package = Package( name: "SwiftJavaPlugin", capability: .buildTool(), dependencies: [ - "SwiftJavaTool" + "swift-java" ] ), @@ -289,7 +289,7 @@ let package = Package( ), .executableTarget( - name: "SwiftJavaTool", + name: "swift-java", dependencies: [ .product(name: "SwiftBasicFormat", package: "swift-syntax"), .product(name: "SwiftSyntax", package: "swift-syntax"), @@ -304,6 +304,10 @@ let package = Package( "SwiftJavaShared", "SwiftJavaConfigurationShared", ], + // Keep existing directory name while the target is renamed; see + // https://github.com/swiftlang/swift-java/issues/733 for why the + // target name must match the product name. + path: "Sources/SwiftJavaTool", swiftSettings: [ .swiftLanguageMode(.v5), .enableUpcomingFeature("BareSlashRegexLiterals"), @@ -362,7 +366,7 @@ let package = Package( name: "JExtractSwiftPlugin", capability: .buildTool(), dependencies: [ - "SwiftJavaTool" + "swift-java" ] ), diff --git a/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift b/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift index 3fbfb2316..10f822cbf 100644 --- a/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift +++ b/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift @@ -29,7 +29,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin { var verbose: Bool = getEnvironmentBool("SWIFT_JAVA_VERBOSE") func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { - let toolURL = try context.tool(named: "SwiftJavaTool").url + let toolURL = try context.tool(named: "swift-java").url var commands: [Command] = [] @@ -171,6 +171,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin { displayName: "Generate Java wrappers for Swift types", executable: toolURL, arguments: arguments, + environment: ProcessInfo.processInfo.environment, inputFiles: [configFile] + swiftFiles, outputFiles: jextractOutputFiles, ) @@ -203,9 +204,8 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin { let GradleUserHome = "GRADLE_USER_HOME" let gradleUserHomePath = gradleUserHome.path(percentEncoded: false) log("Prepare command: :SwiftKitCore:build in \(GradleUserHome)=\(gradleUserHomePath)") - var gradlewEnvironment = ProcessInfo.processInfo.environment - gradlewEnvironment[GradleUserHome] = gradleUserHomePath - log("Forward environment: \(gradlewEnvironment)") + var environment = ProcessInfo.processInfo.environment + environment[GradleUserHome] = gradleUserHomePath let gradlewURL = swiftJavaDirectory.appending(path: "gradlew") let gradleExecutable: URL @@ -256,6 +256,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin { displayName: "Build SwiftKitCore, compile Java callbacks, and generate Swift wrappers", executable: toolURL, arguments: javaCallbacksArguments, + environment: environment, inputFiles: outputSwiftFiles + [swiftJavaDirectory], outputFiles: [javaCallbacksSwiftOutput], ) diff --git a/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift b/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift index fb1f22517..ec60ee418 100644 --- a/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift +++ b/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift @@ -31,7 +31,7 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin { log("Create build commands for target '\(target.name)'") guard let sourceModule = target.sourceModule else { return [] } - let executable = try context.tool(named: "SwiftJavaTool").url + let executable = try context.tool(named: "swift-java").url var commands: [Command] = [] // Note: Target doesn't have a directoryURL counterpart to directory, @@ -165,7 +165,7 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin { arguments: ["resolve"] + argumentsOutputDirectory(context: context, generated: false) + argumentsSwiftModule(sourceModule: sourceModule), - environment: [:], + environment: ProcessInfo.processInfo.environment, inputFiles: [configFile], outputFiles: fetchDependenciesOutputFiles ) @@ -192,6 +192,7 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin { executable: executable, arguments: ["wrap-java"] + arguments, + environment: ProcessInfo.processInfo.environment, inputFiles: compiledClassFiles + fetchDependenciesOutputFiles + [configFile], outputFiles: outputSwiftFiles ) diff --git a/SwiftKitCore/build.gradle.kts b/SwiftKitCore/build.gradle.kts index ec5dfd2ae..89d8f5c46 100644 --- a/SwiftKitCore/build.gradle.kts +++ b/SwiftKitCore/build.gradle.kts @@ -86,6 +86,19 @@ val compileSwift = tasks.register("compileSwift") { commandLine("swift") // FIXME: disable prebuilts until swift-syntax isn't broken on 6.2 anymore: https://github.com/swiftlang/swift-java/issues/418 args("build", "--disable-experimental-prebuilts", "--target", "SwiftRuntimeFunctions") + + // When this task runs inside an outer swift-build-driven invocation (e.g. + // JExtractSwiftPlugin -> java-callbacks-build -> gradle -> here) the outer + // build leaks Xcode-style build settings (SDKROOT=/, TOOLCHAINS, SDK_*, + // SWIFTC_PASS_*) into the subprocess environment, which breaks the nested + // swift build with "unable to resolve run destination SDK: '/'". Strip + // them so the inner invocation resolves its own defaults. + listOf( + "SDKROOT", "SDK_DIR", "SDK_DIR_linux", "SDK_NAME", "SDK_NAMES", + "SDK_VERSION", "SDK_VERSION_ACTUAL", "SDK_VERSION_MAJOR", "SDK_VERSION_MINOR", + "SDK_STAT_CACHE_DIR", "SDK_STAT_CACHE_ENABLE", "SDK_STAT_CACHE_PATH", + "SWIFTC_PASS_SDKROOT", "SWIFTC_PASS_SYSROOT", "TOOLCHAINS", + ).forEach { environment.remove(it) } } tasks.build { dependsOn(compileSwift) diff --git a/SwiftKitFFM/build.gradle.kts b/SwiftKitFFM/build.gradle.kts index 1659da750..b9a913a5c 100644 --- a/SwiftKitFFM/build.gradle.kts +++ b/SwiftKitFFM/build.gradle.kts @@ -89,6 +89,19 @@ val compileSwift = tasks.register("compileSwift") { commandLine("swift") // FIXME: disable prebuilts until swift-syntax isn't broken on 6.2 anymore: https://github.com/swiftlang/swift-java/issues/418 args("build", "--disable-experimental-prebuilts", "--target", "SwiftRuntimeFunctions") + + // When this task runs inside an outer swift-build-driven invocation (e.g. + // JExtractSwiftPlugin -> java-callbacks-build -> gradle -> here) the outer + // build leaks Xcode-style build settings (SDKROOT=/, TOOLCHAINS, SDK_*, + // SWIFTC_PASS_*) into the subprocess environment, which breaks the nested + // swift build with "unable to resolve run destination SDK: '/'". Strip + // them so the inner invocation resolves its own defaults. + listOf( + "SDKROOT", "SDK_DIR", "SDK_DIR_linux", "SDK_NAME", "SDK_NAMES", + "SDK_VERSION", "SDK_VERSION_ACTUAL", "SDK_VERSION_MAJOR", "SDK_VERSION_MINOR", + "SDK_STAT_CACHE_DIR", "SDK_STAT_CACHE_ENABLE", "SDK_STAT_CACHE_PATH", + "SWIFTC_PASS_SDKROOT", "SWIFTC_PASS_SYSROOT", "TOOLCHAINS", + ).forEach { environment.remove(it) } } tasks.build { dependsOn(compileSwift)