Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions BuildLogic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@
//
//===----------------------------------------------------------------------===//

plugins {
`kotlin-dsl`
embeddedKotlin("plugin.serialization")
}

repositories {
gradlePluginPortal()
mavenCentral()
}

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.3")
}

plugins {
`kotlin-dsl`
}
implementation(libs.kotlinx.serialization.json)
}
1 change: 1 addition & 0 deletions BuildLogic/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fun getSwiftRuntimeLibraryPaths(): List<String> {
/**
* Find library paths for 'java.library.path' when running or testing projects inside this build.
*/
// TODO: can't figure out how to share this code between BuildLogic/ and buildSrc/
// TODO: Deduplicate this code with javaLibraryPaths.kt
fun javaLibraryPaths(rootDir: File): List<String> {
val osName = System.getProperty("os.name").lowercase(Locale.getDefault())
val osArch = System.getProperty("os.arch")
Expand Down
33 changes: 33 additions & 0 deletions BuildLogic/src/main/kotlin/swiftPackageDescribe.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import org.gradle.api.Project
Comment thread
ktoso marked this conversation as resolved.
import org.gradle.api.tasks.Exec
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.ExecOperations
import utilities.SwiftcTargetInfo
import utilities.json
import utilities.swiftPMPackage
import java.io.ByteArrayOutputStream
import java.io.File

fun Project.swiftProductDylibPaths(swiftBuildConfiguration: String): List<String> {
// TODO: require that we depend on swift-java
// TODO: all the products where the targets depend on swift-java plugin
return swiftPMPackage().targets.map {
it.productMemberships
}.flatten().map {
logger.info("[swift-java] Include Swift product: '${it}' in product resource paths.")
"${layout.projectDirectory}/.build/${swiftBuildConfiguration}/lib${it}.dylib"
}
}

fun Project.registerCleanSwift(workingDir: File = layout.projectDirectory.asFile) {
val cleanSwift = tasks.register<Exec>("cleanSwift") {
this.workingDir = workingDir
commandLine("swift")
args("package", "clean")
}
tasks.named("clean").configure {
dependsOn(cleanSwift)
}
}

22 changes: 22 additions & 0 deletions BuildLogic/src/main/kotlin/utilities/SwiftPMPackage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package utilities

import kotlinx.serialization.Serializable
import org.gradle.api.Project
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.ExecOperations
import java.io.ByteArrayOutputStream

@Serializable
internal data class SwiftPMPackage(
val targets: List<SwiftPMTarget>,
)

internal fun Project.swiftPMPackage(): SwiftPMPackage {
val stdout = ByteArrayOutputStream()
serviceOf<ExecOperations>().exec {
workingDir(projectDir)
commandLine("swift", "package", "describe", "--type", "json")
standardOutput = stdout
}
return json.decodeFromString<SwiftPMPackage>(stdout.toString())
}
12 changes: 12 additions & 0 deletions BuildLogic/src/main/kotlin/utilities/SwiftPMTarget.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package utilities

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
internal data class SwiftPMTarget(
@SerialName("product_dependencies")
val productDependencies: List<String> = emptyList(),
@SerialName("product_memberships")
val productMemberships: List<String> = emptyList(),
)
8 changes: 8 additions & 0 deletions BuildLogic/src/main/kotlin/utilities/SwiftcTargetInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package utilities

import kotlinx.serialization.Serializable

@Serializable
internal data class SwiftcTargetInfo(
val paths: SwiftcTargetInfoPaths,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package utilities

import kotlinx.serialization.Serializable

@Serializable
internal data class SwiftcTargetInfoPaths(
val runtimeLibraryPaths: List<String>,
)
42 changes: 42 additions & 0 deletions BuildLogic/src/main/kotlin/utilities/javaLibraryPaths.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package utilities

import org.gradle.api.Project
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.ExecOperations
import java.io.ByteArrayOutputStream
import java.io.File

private fun Project.swiftRuntimeLibraryPaths(): List<String> {
val stdout = ByteArrayOutputStream()
serviceOf<ExecOperations>().exec {
workingDir(projectDir)
commandLine("swiftc", "-print-target-info")
standardOutput = stdout
}
return json.decodeFromString<SwiftcTargetInfo>(stdout.toString()).paths.runtimeLibraryPaths
}

fun Project.javaLibraryPaths(rootDir: File?): List<String> {
val osName = System.getProperty("os.name")
val osArch = System.getProperty("os.arch")
val isLinux = osName.lowercase().contains("linux")
val base = if (rootDir == null) "" else "${rootDir}/"

val triple = if (isLinux) {
val arch = if (osArch == "amd64" || osArch == "x86_64") "x86_64" else osArch
"${arch}-unknown-linux-gnu"
} else {
val arch = if (osArch == "aarch64") "arm64" else osArch
"${arch}-apple-macosx"
}

val paths: List<String> = listOf("release", "debug").flatMap { configuration ->
listOf(
"${base}.build/${triple}/$configuration/",
"${base}../../.build/${triple}/$configuration/",
)
}
val swiftRuntimePaths = swiftRuntimeLibraryPaths()

return paths + swiftRuntimePaths
}
5 changes: 5 additions & 0 deletions BuildLogic/src/main/kotlin/utilities/json.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package utilities

import kotlinx.serialization.json.Json

internal val json = Json { ignoreUnknownKeys = true }
70 changes: 70 additions & 0 deletions BuildLogic/src/main/kotlin/utilities/registerJextractTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package utilities

import org.gradle.api.Project
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.register
import java.io.File
import java.nio.file.Files

private fun Project.swiftProductsWithJExtractPlugin(): List<String> = swiftPMPackage().targets.filter {
it.productDependencies.contains("JExtractSwiftPlugin")
}.flatMap {
it.productMemberships
}

private fun Project.registerSwiftCheckValidTask(): TaskProvider<*> = tasks.register<Exec>("swift-check-valid") {
commandLine("swift")
args("-version")
}

fun Project.registerJextractTask(
arguments: () -> List<String> = {
listOf("build", "--disable-experimental-prebuilts")
}
): TaskProvider<*> {
val swiftCheckValid = registerSwiftCheckValidTask()
return tasks.register<Exec>("jextract") {
description = "Generate Java wrappers for swift target"
dependsOn(swiftCheckValid)

// only because we depend on "live developing" the plugin while using this project to test it
inputs.file(File(rootDir, "Package.swift"))
inputs.dir(File(rootDir, "Sources"))

// If the package description changes, we should execute jextract again, maybe we added jextract to new targets
inputs.file(File(projectDir, "Package.swift"))

// monitor all targets/products which depend on the JExtract plugin
swiftProductsWithJExtractPlugin().forEach {
logger.info("[swift-java:jextract (Gradle)] Swift input target: ${it}")
inputs.dir(File(layout.projectDirectory.asFile, "Sources/${it}"))
}
outputs.dir(layout.buildDirectory.dir("../.build/plugins/outputs/${layout.projectDirectory.asFile.getName().lowercase()}"))

val baseSwiftPluginOutputsDir = layout.buildDirectory.dir("../.build/plugins/outputs/").get().asFile
if (!baseSwiftPluginOutputsDir.exists()) {
baseSwiftPluginOutputsDir.mkdirs()
}
Files.walk(layout.buildDirectory.dir("../.build/plugins/outputs/").get().asFile.toPath()).forEach {
// Add any Java sources generated by the plugin to our sourceSet
if (it.endsWith("JExtractSwiftPlugin/src/generated/java")) {
outputs.dir(it)
}
}

workingDir = layout.projectDirectory.asFile
commandLine("swift")
// FIXME: disable prebuilts until swift-syntax isn't broken on 6.2 anymore: https://github.com/swiftlang/swift-java/issues/418
args(arguments()) // since Swift targets which need to be jextract-ed have the jextract build plugin, we just need to build
// If we wanted to execute a specific subcommand, we can like this:
// args("run",/*
// "swift-java", "jextract",
// "--swift-module", "MySwiftLibrary",
// // java.package is obtained from the swift-java.config in the swift module
// "--output-java", "${layout.buildDirectory.dir(".build/plugins/outputs/${layout.projectDirectory.asFile.getName().toLowerCase()}/JExtractSwiftPlugin/src/generated/java").get()}",
// "--output-swift", "${layout.buildDirectory.dir(".build/plugins/outputs/${layout.projectDirectory.asFile.getName().toLowerCase()}/JExtractSwiftPlugin/Sources").get()}",
// "--log-level", (logging.level <= LogLevel.INFO ? "debug" : */"info")
// )
}
}
Loading
Loading