Unverified Commit 920a24cf authored by Alexey Tsvetkov's avatar Alexey Tsvetkov Committed by GitHub

Unify configuration of skia related tasks (#254)

* Unify configuration of skia related tasks

Also fixes the issue, where a new version of Skia
was not downloaded for cross-platform targets
parent 848a57cd
...@@ -2,7 +2,6 @@ import de.undercouch.gradle.tasks.download.Download ...@@ -2,7 +2,6 @@ import de.undercouch.gradle.tasks.download.Download
import org.gradle.crypto.checksum.Checksum import org.gradle.crypto.checksum.Checksum
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.utils.keysToMap
plugins { plugins {
kotlin("multiplatform") version "1.5.31" // "1.6.0-M1" kotlin("multiplatform") version "1.5.31" // "1.6.0-M1"
...@@ -39,19 +38,6 @@ repositories { ...@@ -39,19 +38,6 @@ repositories {
mavenCentral() mavenCentral()
} }
val skiaZip = run {
val zipName = skiko.skiaReleaseFor(targetOs, targetArch, buildType) + ".zip"
val zipFile = skiko.dependenciesDir.resolve("skia/${zipName.substringAfterLast('/')}")
tasks.register("downloadSkia", Download::class) {
onlyIf { skiko.skiaDir == null && !zipFile.exists() }
inputs.property("skia.release.for.target.os", skiko.skiaReleaseFor(targetOs, targetArch, buildType))
src("https://github.com/JetBrains/skia-pack/releases/download/$zipName")
dest(zipFile)
onlyIfModified(true)
}.map { zipFile }
}
val windowsSdkPaths: WindowsSdkPaths by lazy { val windowsSdkPaths: WindowsSdkPaths by lazy {
findWindowsSdkPathsForCurrentOS(gradle) findWindowsSdkPathsForCurrentOS(gradle)
} }
...@@ -71,49 +57,12 @@ class NativeCompilationInfo(val target: org.jetbrains.kotlin.gradle.plugin.mpp.K ...@@ -71,49 +57,12 @@ class NativeCompilationInfo(val target: org.jetbrains.kotlin.gradle.plugin.mpp.K
val allNativeTargets = mutableMapOf<Pair<OS, Arch>, NativeCompilationInfo>() val allNativeTargets = mutableMapOf<Pair<OS, Arch>, NativeCompilationInfo>()
val skiaCrossDownloadTasks: Map<Pair<OS, Arch>, Provider<File>> = crossTargets.keysToMap { osArch -> val skiaWasmDir = registerOrGetSkiaDirProvider(OS.Wasm, Arch.Wasm)
val suffix = targetSuffix(osArch.first, osArch.second)
val out = skiko.dependenciesDir.resolve("skia/skia-$suffix.zip")
tasks.register<Download>("skiaCrossDownload$suffix") {
onlyIf { skiko.skiaDir == null && !out.exists() }
val release = skiko.skiaReleaseFor(osArch.first, osArch.second, buildType)
src("https://github.com/JetBrains/skia-pack/releases/download/$release.zip")
dest(out.absolutePath)
onlyIfModified(true)
}.map { out.absoluteFile }
}
val skiaDirProviderForCrossTargets: Map<Pair<OS, Arch>, Provider<File>> = crossTargets.keysToMap { osArch ->
val suffix = targetSuffix(osArch.first, osArch.second)
if (skiko.skiaDir != null) {
tasks.register("skiaCrossDir$suffix", DefaultTask::class) {
// dummy task to simplify usage of the resulting provider (see `else` branch)
// if a file provider is not created from a task provider,
// then it cannot be used instead of a task in `dependsOn` clauses of other tasks.
// e.g. the resulting `skiaDir` could not be used in `dependsOn` of CppCompile configuration
enabled = false
}.map { skiko.skiaDir!!.absoluteFile }
} else {
val targetDir = skiko.dependenciesDir.resolve("skia/skia-$suffix")
tasks.register("skiaCrossUnzip$suffix", Copy::class) {
val downloader = skiaCrossDownloadTasks[osArch]!!
dependsOn(downloader)
from(downloader.map { zipTree(it) })
into(targetDir)
destinationDir = targetDir.absoluteFile
}.map { it.destinationDir.absoluteFile }
}
}
val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") { val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") {
val osArch = OS.Wasm to Arch.Wasm val osArch = OS.Wasm to Arch.Wasm
val unzipper = skiaDirProviderForCrossTargets[osArch]!! dependsOn(skiaWasmDir)
dependsOn(unzipper)
val unpackedSkia = unzipper.get()
compiler.set(compilerForTarget(OS.Wasm, Arch.Wasm)) compiler.set(compilerForTarget(OS.Wasm, Arch.Wasm))
buildTargetOS.set(osArch.first) buildTargetOS.set(osArch.first)
...@@ -125,7 +74,7 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") { ...@@ -125,7 +74,7 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") {
sourceRoots.set(srcDirs) sourceRoots.set(srcDirs)
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp")) includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp"))
includeHeadersNonRecursive(skiaHeadersDirs(unpackedSkia)) includeHeadersNonRecursive(skiaHeadersDirs(skiaWasmDir.get()))
flags.set(listOf( flags.set(listOf(
*skiaPreprocessorFlags(), *skiaPreprocessorFlags(),
...@@ -134,16 +83,15 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") { ...@@ -134,16 +83,15 @@ val compileWasm = tasks.register<CompileSkikoCppTask>("compileWasm") {
} }
fun registerNativeBridgesTask(os: OS, arch: Arch): TaskProvider<CompileSkikoCppTask> { fun registerNativeBridgesTask(os: OS, arch: Arch): TaskProvider<CompileSkikoCppTask> {
return tasks.register<CompileSkikoCppTask>("${os.id}_${arch.id}_CrossCompile") { val skiaNativeDir = registerOrGetSkiaDirProvider(os, arch)
val osArch = os to arch
val unzipper = skiaDirProviderForCrossTargets[osArch]!! return tasks.register<CompileSkikoCppTask>("${os.id}_${arch.id}_CrossCompile") {
dependsOn(unzipper) dependsOn(skiaNativeDir)
val unpackedSkia = unzipper.get() val unpackedSkia = skiaNativeDir.get()
compiler.set(compilerForTarget(os, arch)) compiler.set(compilerForTarget(os, arch))
buildTargetOS.set(osArch.first) buildTargetOS.set(os)
buildTargetArch.set(osArch.second) buildTargetArch.set(arch)
buildVariant.set(buildType) buildVariant.set(buildType)
when (os) { when (os) {
...@@ -213,10 +161,8 @@ val linkWasm = tasks.register<LinkSkikoWasmTask>("linkWasm") { ...@@ -213,10 +161,8 @@ val linkWasm = tasks.register<LinkSkikoWasmTask>("linkWasm") {
val osArch = OS.Wasm to Arch.Wasm val osArch = OS.Wasm to Arch.Wasm
dependsOn(compileWasm) dependsOn(compileWasm)
dependsOn(skiaWasmDir)
val unzipper = skiaDirProviderForCrossTargets[osArch]!! val unpackedSkia = skiaWasmDir.get()
dependsOn(unzipper)
val unpackedSkia = unzipper.get()
linker.set(linkerForTarget(OS.Wasm, Arch.Wasm)) linker.set(linkerForTarget(OS.Wasm, Arch.Wasm))
buildTargetOS.set(osArch.first) buildTargetOS.set(osArch.first)
...@@ -254,24 +200,6 @@ val linkWasm = tasks.register<LinkSkikoWasmTask>("linkWasm") { ...@@ -254,24 +200,6 @@ val linkWasm = tasks.register<LinkSkikoWasmTask>("linkWasm") {
} }
} }
val skiaDir: Provider<File> = run {
if (skiko.skiaDir != null) {
tasks.register("skiaDir", DefaultTask::class) {
// dummy task to simplify usage of the resulting provider (see `else` branch)
// if a file provider is not created from a task provider,
// then it cannot be used instead of a task in `dependsOn` clauses of other tasks.
// e.g. the resulting `skiaDir` could not be used in `dependsOn` of CppCompile configuration
enabled = false
}.map { skiko.skiaDir!! }
} else {
val targetDir = skiko.dependenciesDir.resolve("skia/skia")
tasks.register("unzipSkia", Copy::class) {
from(skiaZip.map { zipTree(it) })
into(targetDir)
}.map { targetDir }
}
}
val skiaBinSubdir = "out/${buildType.id}-${targetOs.id}-${targetArch.id}" val skiaBinSubdir = "out/${buildType.id}-${targetOs.id}-${targetArch.id}"
val Project.supportNative: Boolean val Project.supportNative: Boolean
...@@ -315,8 +243,7 @@ kotlin { ...@@ -315,8 +243,7 @@ kotlin {
for ((osArch, compilation) in allNativeTargets) { for ((osArch, compilation) in allNativeTargets) {
val targetString = "${osArch.first.id}-${osArch.second.id}" val targetString = "${osArch.first.id}-${osArch.second.id}"
val unzipper = skiaDirProviderForCrossTargets[osArch] ?: val unzipper = registerOrGetSkiaDirProvider(osArch.first, osArch.second)
throw GradleException("add $osArch to the list of cross-targets")
val unpackedSkia = unzipper.get() val unpackedSkia = unzipper.get()
val skiaDir = unpackedSkia.absolutePath val skiaDir = unpackedSkia.absolutePath
...@@ -575,6 +502,8 @@ fun skiaStaticLibraries(skiaDir: String, targetString: String): List<String> { ...@@ -575,6 +502,8 @@ fun skiaStaticLibraries(skiaDir: String, targetString: String): List<String> {
} }
} }
val skiaJvmBindingsDir: Provider<File> = registerOrGetSkiaDirProvider(targetOs, targetArch)
val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings") { val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings") {
// Prefer 'java.home' system property to simplify overriding from Intellij. // Prefer 'java.home' system property to simplify overriding from Intellij.
// When used from command-line, it is effectively equal to JAVA_HOME. // When used from command-line, it is effectively equal to JAVA_HOME.
...@@ -583,7 +512,7 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings ...@@ -583,7 +512,7 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
"Check JAVA_HOME (CLI) or Gradle settings (Intellij).") "Check JAVA_HOME (CLI) or Gradle settings (Intellij).")
} }
val jdkHome = File(System.getProperty("java.home") ?: error("'java.home' is null")) val jdkHome = File(System.getProperty("java.home") ?: error("'java.home' is null"))
dependsOn(skiaDir) dependsOn(skiaJvmBindingsDir)
buildTargetOS.set(targetOs) buildTargetOS.set(targetOs)
buildTargetArch.set(targetArch) buildTargetArch.set(targetArch)
buildVariant.set(buildType) buildVariant.set(buildType)
...@@ -596,7 +525,7 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings ...@@ -596,7 +525,7 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
sourceRoots.set(srcDirs) sourceRoots.set(srcDirs)
includeHeadersNonRecursive(jdkHome.resolve("include")) includeHeadersNonRecursive(jdkHome.resolve("include"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaDir.get())) includeHeadersNonRecursive(skiaHeadersDirs(skiaJvmBindingsDir.get()))
includeHeadersNonRecursive(projectDir.resolve("src/jvmMain/cpp/include")) includeHeadersNonRecursive(projectDir.resolve("src/jvmMain/cpp/include"))
compiler.set(compilerForTarget(targetOs, targetArch)) compiler.set(compilerForTarget(targetOs, targetArch))
...@@ -664,10 +593,10 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings ...@@ -664,10 +593,10 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
} }
val linkJvmBindings = tasks.register<LinkSkikoTask>("linkJvmBindings") { val linkJvmBindings = tasks.register<LinkSkikoTask>("linkJvmBindings") {
val skiaBinDir = skiaDir.get().absolutePath + "/" + skiaBinSubdir val skiaBinDir = skiaJvmBindingsDir.get().absolutePath + "/" + skiaBinSubdir
val osFlags: Array<String> val osFlags: Array<String>
libFiles = fileTree(skiaDir.map { it.resolve(skiaBinSubdir)}) { libFiles = fileTree(skiaJvmBindingsDir.map { it.resolve(skiaBinSubdir)}) {
include(if (targetOs.isWindows) "*.lib" else "*.a") include(if (targetOs.isWindows) "*.lib" else "*.a")
} }
...@@ -759,7 +688,7 @@ project.tasks.register<Exec>("objcCompile") { ...@@ -759,7 +688,7 @@ project.tasks.register<Exec>("objcCompile") {
val srcs = names.map { "$inputDir/$it.mm" }.toTypedArray() val srcs = names.map { "$inputDir/$it.mm" }.toTypedArray()
val outs = names.map { "$outDir/$it.o" }.toTypedArray() val outs = names.map { "$outDir/$it.o" }.toTypedArray()
workingDir = File(outDir) workingDir = File(outDir)
val skiaDir = skiaDir.get().absolutePath val skiaDir = skiaJvmBindingsDir.get().absolutePath
commandLine = listOf( commandLine = listOf(
"clang", "clang",
*targetOs.clangFlags, *targetOs.clangFlags,
...@@ -930,7 +859,7 @@ val maybeSign by project.tasks.registering { ...@@ -930,7 +859,7 @@ val maybeSign by project.tasks.registering {
val createChecksums by project.tasks.registering(org.gradle.crypto.checksum.Checksum::class) { val createChecksums by project.tasks.registering(org.gradle.crypto.checksum.Checksum::class) {
dependsOn(maybeSign) dependsOn(maybeSign)
files = project.files(maybeSign.map { it.outputs.files }) + files = project.files(maybeSign.map { it.outputs.files }) +
if (targetOs.isWindows) files(skiaDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }) else files() if (targetOs.isWindows) files(skiaJvmBindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }) else files()
algorithm = Checksum.Algorithm.SHA256 algorithm = Checksum.Algorithm.SHA256
outputDir = file("$buildDir/checksums") outputDir = file("$buildDir/checksums")
} }
...@@ -945,7 +874,7 @@ val skikoJvmRuntimeJar by project.tasks.registering(Jar::class) { ...@@ -945,7 +874,7 @@ val skikoJvmRuntimeJar by project.tasks.registering(Jar::class) {
it.replace(".maybesigned", "") it.replace(".maybesigned", "")
} }
if (targetOs.isWindows) { if (targetOs.isWindows) {
from(files(skiaDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") })) from(files(skiaJvmBindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }))
} }
from(createChecksums.map { it.outputs.files }) from(createChecksums.map { it.outputs.files })
} }
...@@ -997,11 +926,6 @@ tasks.withType<Test>().configureEach { ...@@ -997,11 +926,6 @@ tasks.withType<Test>().configureEach {
} }
} }
fun Task.disable() {
enabled = false
group = "Disabled tasks"
}
afterEvaluate { afterEvaluate {
tasks.configureEach { tasks.configureEach {
if (group == "publishing") { if (group == "publishing") {
...@@ -1114,3 +1038,36 @@ fun Task.projectDirs(vararg relativePaths: String): List<Directory> { ...@@ -1114,3 +1038,36 @@ fun Task.projectDirs(vararg relativePaths: String): List<Directory> {
val projectDir = project.layout.projectDirectory val projectDir = project.layout.projectDirectory
return relativePaths.map { path -> projectDir.dir(path) } return relativePaths.map { path -> projectDir.dir(path) }
} }
/**
* Do not call inside tasks.register or tasks.call callback
* (tasks' registration during other task's registration is prohibited)
*/
fun registerOrGetSkiaDirProvider(os: OS, arch: Arch): Provider<File> {
val taskNameSuffix = joinToTitleCamelCase(buildType.id, os.id, arch.id)
val skiaRelease = skiko.skiaReleaseFor(os, arch, buildType)
val downloadSkia = tasks.registerOrGetTask<Download>("downloadSkia$taskNameSuffix") {
onlyIf { !dest.exists() }
onlyIfModified(true)
val skiaUrl = "https://github.com/JetBrains/skia-pack/releases/download/$skiaRelease.zip"
inputs.property("skia.url", skiaUrl)
src(skiaUrl)
dest(skiko.dependenciesDir.resolve("skia/$skiaRelease.zip"))
}.map { it.dest.absoluteFile }
return if (skiko.skiaDir != null) {
tasks.registerOrGetTask<DefaultTask>("skiaDir$taskNameSuffix") {
// dummy task to simplify usage of the resulting provider (see `else` branch)
// if a file provider is not created from a task provider,
// then it cannot be used instead of a task in `dependsOn` clauses of other tasks.
// e.g. the resulting `skiaDir` could not be used in `dependsOn` of CppCompile configuration
enabled = false
}.map { skiko.skiaDir!!.absoluteFile }
} else {
tasks.registerOrGetTask<Copy>("unzipSkia$taskNameSuffix") {
dependsOn(downloadSkia)
from(downloadSkia.map { zipTree(it) })
into(skiko.dependenciesDir.resolve("skia/$skiaRelease"))
}.map { it.destinationDir.absoluteFile }
}
}
\ No newline at end of file
val OS.dynamicLibExt: String
get() = when (this) {
OS.Linux -> ".so"
OS.Windows -> ".dll"
OS.MacOS, OS.IOS -> ".dylib"
OS.Wasm -> ".wasm"
}
...@@ -31,6 +31,15 @@ fun compilerForTarget(os: OS, arch: Arch): String = ...@@ -31,6 +31,15 @@ fun compilerForTarget(os: OS, arch: Arch): String =
fun linkerForTarget(os: OS, arch: Arch): String = fun linkerForTarget(os: OS, arch: Arch): String =
if (os.isWindows) "link.exe" else compilerForTarget(os, arch) if (os.isWindows) "link.exe" else compilerForTarget(os, arch)
val OS.dynamicLibExt: String
get() = when (this) {
OS.Linux -> ".so"
OS.Windows -> ".dll"
OS.MacOS, OS.IOS -> ".dylib"
OS.Wasm -> ".wasm"
}
enum class Arch(val id: String) { enum class Arch(val id: String) {
X64("x64"), X64("x64"),
Arm64("arm64"), Arm64("arm64"),
......
import org.gradle.api.Task
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskContainer
import org.gradle.kotlin.dsl.register
// Utils, that are not needed in scripts can be placed to internal/utils
inline fun <reified T : Task> TaskContainer.registerOrGetTask(
name: String, crossinline fn: T.() -> Unit
): Provider<T> {
val taskProvider =
if (name in names) named(name)
else register(name, T::class) { fn(this) }
return taskProvider.map { it as T }
}
fun joinToTitleCamelCase(vararg parts: String): String =
parts.joinToString(separator = "") { part ->
if (part.isEmpty()) part
else buildString {
append(part.first().toTitleCase())
append(part.substring(1))
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment