From d57c677a1d42645b25b5a6909dd692dcd554c526 Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Wed, 13 May 2026 13:44:28 +0900 Subject: [PATCH 1/4] adjust product name to survive new build system The way we're looking up the swift-java "tool" in plugins uses the target name "SwiftJavaTool" and that is correct in the natrive build system. In swift 6.4, and in Xcode, the swift-build build system is actually naming them using product names: so swift-java. In order to have the build work in BOTH build systems, we have to make the name be the same... It's a workaround, but it seems to work. This should resolve the failure ``` error: Build input file cannot be found: '/Users/ktoso/code/swift-java/Samples/JavaKitSampleApp/.build/out/Products/Debug/SwiftJavaTool'. Did you forget to declare this file as an output of a script phase or custom build rule which produces it? ``` that folks were reporting in #733 and in https://github.com/swiftlang/swift-java/issues/281 --- Package.swift | 12 ++++++++---- .../JExtractSwiftPlugin/JExtractSwiftPlugin.swift | 2 +- Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) 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..535b629f0 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] = [] diff --git a/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift b/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift index fb1f22517..7f48e383f 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, From ab757db4ddd9cef69f192eeef4c763f91551274e Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Wed, 13 May 2026 13:58:32 +0900 Subject: [PATCH 2/4] forward env to tool uses --- .github/workflows/pull_request.yml | 14 ++++++++++---- .../JExtractSwiftPlugin/JExtractSwiftPlugin.swift | 7 ++++--- Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift | 3 ++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 24a2fee0f..242e2d5ab 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: @@ -189,7 +193,7 @@ jobs: strategy: fail-fast: false matrix: - swift_version: ['nightly-6.3'] # FIXME: reenable 'nightly-main' once snapshot toolchains are stable again + swift_version: ['nightly'] os_version: ['jammy'] jdk_vendor: ['corretto'] sdk_triple: ['aarch64-unknown-linux-android28', 'x86_64-unknown-linux-android28', 'armv7-unknown-linux-android28'] @@ -210,10 +214,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/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift b/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift index 535b629f0..10f822cbf 100644 --- a/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift +++ b/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift @@ -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 7f48e383f..ec60ee418 100644 --- a/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift +++ b/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift @@ -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 ) From e680ada5b0b23b513770444e99550ef2721df863 Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Wed, 13 May 2026 18:49:32 +0900 Subject: [PATCH 3/4] include swift-build paths in search paths --- .github/workflows/pull_request.yml | 4 +++- ...uild-logic.java-common-conventions.gradle.kts | 16 +++++++++++++++- .../main/kotlin/utilities/javaLibraryPaths.kt | 16 ++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 242e2d5ab..3be4e8fdc 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -190,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'] + 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'] 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 } From 06947f18f77827835a4a446f843d4a04a386e7bf Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Thu, 14 May 2026 09:19:45 +0900 Subject: [PATCH 4/4] more workarounds for nested swift-builds --- SwiftKitCore/build.gradle.kts | 13 +++++++++++++ SwiftKitFFM/build.gradle.kts | 13 +++++++++++++ 2 files changed, 26 insertions(+) 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)