diff --git a/BuildLogic/src/main/kotlin/utilities/registerJextractTask.kt b/BuildLogic/src/main/kotlin/utilities/registerJextractTask.kt index f2f6605d1..40f8051a1 100644 --- a/BuildLogic/src/main/kotlin/utilities/registerJextractTask.kt +++ b/BuildLogic/src/main/kotlin/utilities/registerJextractTask.kt @@ -15,6 +15,8 @@ package utilities import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.provider.Provider import org.gradle.api.tasks.Exec import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.register @@ -26,6 +28,27 @@ private fun Project.swiftTargetsWithJExtractPlugin(): List = swiftPMPack it.name } +/** + * The directory into which the SwiftPM JExtractSwiftPlugin emits generated Java sources + * for a given Swift target. + * + * The path is computed lazily as a `Provider`, so callers can register it as a + * `srcDir` even before the `jextract` task has executed. We need that explicit registration + * so e.g. vscode or other IDEs can index the generated sources without first running the build. + */ +fun Project.jextractGeneratedJavaDir(targetName: String): Provider = + layout.buildDirectory.dir( + "../.build/plugins/outputs/${layout.projectDirectory.asFile.name.lowercase()}/${targetName}/destination/JExtractSwiftPlugin/src/generated/java" + ) + +/** + * One generated-Java source directory per Swift target that uses the JExtractSwiftPlugin. + * Use this in `sourceSets { main { java { srcDir(...) } } }` alongside `srcDir(jextract)` + * so the dir is visible to IDEs regardless of task-execution order. + */ +fun Project.jextractGeneratedJavaDirs(): List> = + swiftTargetsWithJExtractPlugin().map { jextractGeneratedJavaDir(it) } + private fun Project.registerSwiftCheckValidTask(): TaskProvider<*> = tasks.register("swift-check-valid") { commandLine("swift") args("-version") @@ -52,11 +75,7 @@ fun Project.registerJextractTask( swiftTargetsWithJExtractPlugin().forEach { targetName -> logger.info("[swift-java:jextract (Gradle)] Swift input target: ${targetName}") inputs.dir(File(layout.projectDirectory.asFile, "Sources/${targetName}")) - outputs.dir( - layout.buildDirectory.dir( - "../.build/plugins/outputs/${layout.projectDirectory.asFile.getName().lowercase()}/${targetName}/destination/JExtractSwiftPlugin/src/generated/java" - ) - ) + outputs.dir(jextractGeneratedJavaDir(targetName)) } workingDir = layout.projectDirectory.asFile diff --git a/Samples/SwiftAndJavaJarFFMSampleLib/build.gradle.kts b/Samples/SwiftAndJavaJarFFMSampleLib/build.gradle.kts index 6912f51be..4bb342e5f 100644 --- a/Samples/SwiftAndJavaJarFFMSampleLib/build.gradle.kts +++ b/Samples/SwiftAndJavaJarFFMSampleLib/build.gradle.kts @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +import utilities.jextractGeneratedJavaDirs import utilities.registerJextractTask plugins { @@ -47,16 +48,20 @@ dependencies { val jextract = registerJextractTask() -// Add the java-swift generated Java sources +// Add the java-swift generated Java sources. +// `srcDir(jextract)` wires the build dependency; the explicit dir registration +// below makes the source root visible to IDE project importers (vscode-java). sourceSets { main { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } test { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } } diff --git a/Samples/SwiftJavaExtractFFMSampleApp/build.gradle.kts b/Samples/SwiftJavaExtractFFMSampleApp/build.gradle.kts index 6a4d752a2..d34afb7ea 100644 --- a/Samples/SwiftJavaExtractFFMSampleApp/build.gradle.kts +++ b/Samples/SwiftJavaExtractFFMSampleApp/build.gradle.kts @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// import utilities.javaLibraryPaths +import utilities.jextractGeneratedJavaDirs import utilities.registerJextractTask plugins { @@ -36,21 +37,26 @@ java { val jextract = registerJextractTask() -// Add the java-swift generated Java sources +// Add the java-swift generated Java sources. +// `srcDir(jextract)` wires the build dependency; the explicit dir registration +// below makes the source root visible to IDE project importers (vscode-java). sourceSets { main { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } test { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } this.jmh { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } } diff --git a/Samples/SwiftJavaExtractJNISampleApp/build.gradle.kts b/Samples/SwiftJavaExtractJNISampleApp/build.gradle.kts index d6416bafb..72b1eb203 100644 --- a/Samples/SwiftJavaExtractJNISampleApp/build.gradle.kts +++ b/Samples/SwiftJavaExtractJNISampleApp/build.gradle.kts @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// import utilities.javaLibraryPaths +import utilities.jextractGeneratedJavaDirs import utilities.registerJextractTask plugins { @@ -44,21 +45,27 @@ val jextract = registerJextractTask { cmdArgs } -// Add the java-swift generated Java sources +// Add the java-swift generated Java sources. +// `srcDir(jextract)` wires the build dependency (compile depends on jextract); +// `srcDir(it)` for each generated dir registers the path explicitly so IDEs +// (notably vscode-java) index the generated sources without having to run jextract first. sourceSets { main { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } test { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } this.jmh { java { srcDir(jextract) + jextractGeneratedJavaDirs().forEach { srcDir(it) } } } }