Unverified Commit 5414141d authored by Oleksandr Karpovich's avatar Oleksandr Karpovich Committed by GitHub

Split build.gradle.kts into smaller files (#845)

Co-authored-by: 's avatarOleksandr.Karpovich <oleksandr.karpovich@jetbrains.com>
parent 5a29cb59
This diff is collapsed.
......@@ -4,9 +4,12 @@ plugins {
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
implementation(kotlin("stdlib"))
compileOnly(gradleApi())
implementation(kotlin("gradle-plugin", "1.9.21"))
implementation("de.undercouch:gradle-download-task:5.4.0")
}
import de.undercouch.gradle.tasks.download.Download
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import java.io.File
class SkikoProjectContext(
val project: Project,
val skiko: SkikoProperties,
val windowsSdkPathProvider: () -> WindowsSdkPaths,
val createChecksumsTask: (OS, Arch, Provider<File>) -> TaskProvider<*>
) {
val buildType = skiko.buildType
val windowsSdkPaths: WindowsSdkPaths by lazy {
windowsSdkPathProvider()
}
val allJvmRuntimeJars = mutableMapOf<Pair<OS, Arch>, TaskProvider<Jar>>()
}
/**
* Do not call inside tasks.register or tasks.call callback
* (tasks' registration during other task's registration is prohibited)
*/
fun SkikoProjectContext.registerOrGetSkiaDirProvider(
os: OS, arch: Arch, isIosSim: Boolean = false
): Provider<File> = with(this.project) {
val taskNameSuffix = joinToTitleCamelCase(buildType.id, os.idWithSuffix(isIosSim = isIosSim), arch.id)
val skiaRelease = skiko.skiaReleaseFor(os, arch, buildType, isIosSim)
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 }
}
}
internal val Project.isInIdea: Boolean
get() {
return System.getProperty("idea.active")?.toBoolean() == true
}
val Project.supportAndroid: Boolean
get() = findProperty("skiko.android.enabled") == "true" // || isInIdea
val Project.supportAwt: Boolean
get() = findProperty("skiko.awt.enabled") == "true" || isInIdea
val Project.supportAllNative: Boolean
get() = findProperty("skiko.native.enabled") == "true" || isInIdea
val Project.supportAllNativeIos: Boolean
get() = supportAllNative || findProperty("skiko.native.ios.enabled") == "true" || isInIdea
val Project.supportNativeIosArm64: Boolean
get() = supportAllNativeIos || findProperty("skiko.native.ios.arm64.enabled") == "true" || isInIdea
val Project.supportNativeIosSimulatorArm64: Boolean
get() = supportAllNativeIos || findProperty("skiko.native.ios.simulatorArm64.enabled") == "true" || isInIdea
val Project.supportNativeIosX64: Boolean
get() = supportAllNativeIos || findProperty("skiko.native.ios.x64.enabled") == "true" || isInIdea
val Project.supportAnyNativeIos: Boolean
get() = supportAllNativeIos || supportNativeIosArm64 || supportNativeIosSimulatorArm64 || supportNativeIosX64
val Project.supportNativeMac: Boolean
get() = supportAllNative || findProperty("skiko.native.mac.enabled") == "true" || isInIdea
val Project.supportNativeLinux: Boolean
get() = supportAllNative || findProperty("skiko.native.linux.enabled") == "true" || isInIdea
val Project.supportAnyNative: Boolean
get() = supportAllNative || supportAnyNativeIos || supportNativeMac || supportNativeLinux
val Project.supportWasm: Boolean
get() = findProperty("skiko.wasm.enabled") == "true" || isInIdea
val Project.supportJs: Boolean
get() = findProperty("skiko.js.enabled") == "true" || supportWasm || isInIdea
\ No newline at end of file
package tasks.configuration
import OS
import SkiaBuildType
import org.gradle.api.Project
import supportAndroid
import supportWasm
import java.io.File
fun skiaHeadersDirs(skiaDir: File): List<File> =
listOf(
skiaDir,
skiaDir.resolve("include"),
skiaDir.resolve("include/core"),
skiaDir.resolve("include/gpu"),
skiaDir.resolve("include/effects"),
skiaDir.resolve("include/pathops"),
skiaDir.resolve("include/utils"),
skiaDir.resolve("include/codec"),
skiaDir.resolve("include/svg"),
skiaDir.resolve("modules/skottie/include"),
skiaDir.resolve("modules/skparagraph/include"),
skiaDir.resolve("modules/skshaper/include"),
skiaDir.resolve("modules/skunicode/include"),
skiaDir.resolve("modules/sksg/include"),
skiaDir.resolve("modules/svg/include"),
skiaDir.resolve("third_party/externals/harfbuzz/src"),
skiaDir.resolve("third_party/icu"),
skiaDir.resolve("third_party/externals/icu/source/common"),
)
fun includeHeadersFlags(headersDirs: List<File>) =
headersDirs.map { "-I${it.absolutePath}" }.toTypedArray()
fun skiaPreprocessorFlags(os: OS, buildType: SkiaBuildType): Array<String> {
val base = listOf(
"-DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=1",
"-DSK_FORCE_DISTANCE_FIELD_TEXT=0",
"-DSK_GAMMA_APPLY_TO_A8",
"-DSK_GAMMA_SRGB",
"-DSK_SCALAR_TO_FLOAT_EXCLUDED",
"-DSK_SUPPORT_GPU=1",
"-DSK_GANESH",
"-DSK_GL",
"-DSK_SHAPER_HARFBUZZ_AVAILABLE",
"-DSK_UNICODE_AVAILABLE",
"-DSK_SUPPORT_OPENCL=0",
"-DSK_UNICODE_AVAILABLE",
"-DU_DISABLE_RENAMING",
"-DSK_USING_THIRD_PARTY_ICU",
*buildType.flags
)
val perOs = when (os) {
OS.MacOS -> listOf(
"-DSK_SHAPER_CORETEXT_AVAILABLE",
"-DSK_BUILD_FOR_MAC",
"-DSK_METAL"
)
OS.IOS -> listOf(
"-DSK_BUILD_FOR_IOS",
"-DSK_SHAPER_CORETEXT_AVAILABLE",
"-DSK_METAL"
)
OS.Windows -> listOf(
"-DSK_BUILD_FOR_WIN",
"-D_CRT_SECURE_NO_WARNINGS",
"-D_HAS_EXCEPTIONS=0",
"-DWIN32_LEAN_AND_MEAN",
"-DNOMINMAX",
"-DSK_GAMMA_APPLY_TO_A8",
"-DSK_DIRECT3D"
)
OS.Linux -> listOf(
"-DSK_BUILD_FOR_LINUX",
"-D_GLIBCXX_USE_CXX11_ABI=0"
)
OS.Wasm -> listOf(
"-DSKIKO_WASM"
)
OS.Android -> listOf(
"-DSK_BUILD_FOR_ANDROID"
)
else -> TODO("unsupported $os")
}
return (base + perOs).toTypedArray()
}
fun Project.configureSignAndPublishDependencies() {
if (supportWasm) {
tasks.forEach { task ->
val name = task.name
val publishJs = "publishJsPublicationTo"
val publishWasm = "publishSkikoWasmRuntimePublicationTo"
val publishWasmPub = "publishWasmJsPublicationTo"
val signWasm = "signSkikoWasmRuntimePublication"
val signJs = "signJsPublication"
val signWasmPub = "signWasmJsPublication"
when {
name.startsWith(publishJs) -> task.dependsOn(signWasm, signWasmPub)
name.startsWith(publishWasm) -> task.dependsOn(signJs)
name.startsWith(publishWasmPub) -> task.dependsOn(signJs)
name.startsWith(signWasmPub) -> task.dependsOn(signWasm)
}
}
}
if (supportAndroid) {
tasks.forEach { task ->
val name = task.name
val signAndroid = "signAndroidPublication"
val generateMetadata = "generateMetadataFileForAndroidPublication"
val publishAndroid = "publishAndroidPublicationTo"
val publishX64 = "publishSkikoJvmRuntimeAndroidX64PublicationTo"
val publishArm64 = "publishSkikoJvmRuntimeAndroidArm64PublicationTo"
val signX64 = "signSkikoJvmRuntimeAndroidX64Publication"
val signArm64 = "signSkikoJvmRuntimeAndroidArm64Publication"
val skikoAndroidJar = "skikoAndroidJar"
when {
name.startsWith(signAndroid) || name.startsWith(generateMetadata) -> {
task.dependsOn(skikoAndroidJar)
}
name.startsWith(publishAndroid) -> {
task.dependsOn(signX64, signArm64)
}
name.startsWith(publishX64) -> {
task.dependsOn(signAndroid, signArm64)
}
name.startsWith(publishArm64) -> {
task.dependsOn(signX64, signAndroid)
}
}
}
}
}
\ No newline at end of file
package tasks.configuration
import Arch
import CompileSkikoCppTask
import CompileSkikoObjCTask
import LinkSkikoTask
import OS
import SealAndSignSharedLibraryTask
import SkiaBuildType
import SkikoProjectContext
import compilerForTarget
import dynamicLibExt
import hostOs
import linkerForTarget
import org.gradle.api.GradleException
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.withType
import projectDirs
import registerOrGetSkiaDirProvider
import registerSkikoTask
import runPkgConfig
import targetId
import java.io.File
fun SkikoProjectContext.createCompileJvmBindingsTask(
targetOs: OS,
targetArch: Arch,
skiaJvmBindingsDir: Provider<File>
) = project.registerSkikoTask<CompileSkikoCppTask>("compileJvmBindings", targetOs, targetArch) {
// Prefer 'java.home' system property to simplify overriding from Intellij.
// When used from command-line, it is effectively equal to JAVA_HOME.
if (JavaVersion.current() < JavaVersion.VERSION_11) {
error("JDK 11+ is required, but Gradle JVM is ${JavaVersion.current()}. " +
"Check JAVA_HOME (CLI) or Gradle settings (Intellij).")
}
val jdkHome = File(System.getProperty("java.home") ?: error("'java.home' is null"))
dependsOn(skiaJvmBindingsDir)
buildTargetOS.set(targetOs)
buildTargetArch.set(targetArch)
buildSuffix.set("jvm")
buildVariant.set(buildType)
val srcDirs = projectDirs(
"src/commonMain/cpp/common",
"src/jvmMain/cpp/common",
"src/awtMain/cpp/common",
"src/awtMain/cpp/${targetOs.id}",
"src/jvmTest/cpp"
)
sourceRoots.set(srcDirs)
if (targetOs != OS.Android) includeHeadersNonRecursive(jdkHome.resolve("include"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaJvmBindingsDir.get()))
val projectDir = project.projectDir
includeHeadersNonRecursive(projectDir.resolve("src/awtMain/cpp/include"))
includeHeadersNonRecursive(projectDir.resolve("src/jvmMain/cpp/include"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include"))
compiler.set(compilerForTarget(targetOs, targetArch))
val osFlags: Array<String>
when (targetOs) {
OS.MacOS -> {
includeHeadersNonRecursive(jdkHome.resolve("include/darwin"))
osFlags = arrayOf(
*targetOs.clangFlags,
*buildType.clangFlags,
"-arch", if (targetArch == Arch.Arm64) "arm64" else "x86_64",
"-fPIC",
"-stdlib=libc++",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden"
)
}
OS.Linux -> {
includeHeadersNonRecursive(jdkHome.resolve("include/linux"))
includeHeadersNonRecursive(runPkgConfig("dbus-1"))
osFlags = arrayOf(
*buildType.clangFlags,
"-DGL_GLEXT_PROTOTYPES",
"-fPIC",
"-fno-rtti",
"-fno-exceptions",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden"
)
}
OS.Windows -> {
compiler.set(windowsSdkPaths.compiler.absolutePath)
includeHeadersNonRecursive(windowsSdkPaths.includeDirs)
includeHeadersNonRecursive(jdkHome.resolve("include/win32"))
osFlags = arrayOf(
"/nologo",
*buildType.msvcCompilerFlags,
"/utf-8",
"/GR-", // no-RTTI.
"/FS", // Due to an error when building in Teamcity. https://docs.microsoft.com/en-us/cpp/build/reference/fs-force-synchronous-pdb-writes
// LATER. Ange rendering arguments:
// "-I$skiaDir/third_party/externals/angle2/include",
// "-I$skiaDir/src/gpu",
// "-DSK_ANGLE",
)
}
OS.Android -> {
compiler.set(project.androidClangFor(targetArch))
osFlags = arrayOf(
*buildType.clangFlags,
"-fno-rtti",
"-fno-exceptions",
"-fvisibility=hidden",
"-fPIC"
)
}
OS.Wasm, OS.IOS -> error("Should not reach here")
}
flags.set(
listOf(
*skiaPreprocessorFlags(targetOs, buildType),
*osFlags
)
)
}
fun Provider<String>.orEmpty(): Provider<String> =
orElse("")
fun Project.androidClangFor(targetArch: Arch, version: String = "30"): Provider<String> {
val androidArch = when (targetArch) {
Arch.Arm64 -> "aarch64"
Arch.X64 -> "x86_64"
else -> throw GradleException("unsupported $targetArch")
}
val hostOsArch = when (hostOs) {
OS.MacOS -> "darwin-x86_64"
OS.Linux -> "linux-x86_64"
OS.Windows -> "windows-x86_64"
else -> throw GradleException("unsupported $hostOs")
}
val ndkPath = project.providers
.environmentVariable("ANDROID_NDK_HOME")
.orEmpty()
.map { ndkHomeEnv ->
ndkHomeEnv.ifEmpty {
val androidHome = androidHomePath().get()
val ndkDir1 = file("$androidHome/ndk")
val candidates1 = if (ndkDir1.exists()) ndkDir1.list() else emptyArray()
val ndkVersion =
arrayOf(*(candidates1.map { "ndk/$it" }.sortedDescending()).toTypedArray(), "ndk-bundle").find {
File(androidHome).resolve(it).exists()
} ?: throw GradleException("Cannot find NDK, is it installed (Tools/SDK Manager)?")
"$androidHome/$ndkVersion"
}
}
return ndkPath.map { ndkPath ->
var clangBinaryName = "$androidArch-linux-android$version-clang++"
if (hostOs.isWindows) {
clangBinaryName += ".cmd"
}
"$ndkPath/toolchains/llvm/prebuilt/$hostOsArch/bin/$clangBinaryName"
}
}
fun SkikoProjectContext.createObjcCompileTask(
os: OS,
arch: Arch,
skiaJvmBindingsDir: Provider<File>
) = project.registerSkikoTask<CompileSkikoObjCTask>("objcCompile", os, arch) {
dependsOn(skiaJvmBindingsDir)
val srcDirs = projectDirs(
"src/awtMain/objectiveC/${os.id}"
)
sourceRoots.set(srcDirs)
val jdkHome = File(System.getProperty("java.home") ?: error("'java.home' is null"))
includeHeadersNonRecursive(jdkHome.resolve("include"))
includeHeadersNonRecursive(jdkHome.resolve("include/darwin"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaJvmBindingsDir.get()))
val projectDir = project.projectDir
includeHeadersNonRecursive(projectDir.resolve("src/awtMain/cpp/include"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include"))
includeHeadersNonRecursive(projectDir.resolve("src/jvmMain/cpp"))
compiler.set("clang")
buildVariant.set(buildType)
buildTargetOS.set(os)
buildTargetArch.set(arch)
flags.set(
listOf(
"-fobjc-arc",
"-arch", if (arch == Arch.Arm64) "arm64" else "x86_64",
*os.clangFlags,
*buildType.clangFlags,
*skiaPreprocessorFlags(os, buildType),
"-fPIC"
)
)
}
fun SkikoProjectContext.createLinkJvmBindings(
targetOs: OS,
targetArch: Arch,
skiaJvmBindingsDir: Provider<File>,
compileTask: TaskProvider<CompileSkikoCppTask>,
objcCompileTask: TaskProvider<CompileSkikoObjCTask>?
) = project.registerSkikoTask<LinkSkikoTask>("linkJvmBindings", targetOs, targetArch) {
val target = targetId(targetOs, targetArch)
val skiaBinSubdir = "out/${buildType.id}-$target"
val skiaBinDir = skiaJvmBindingsDir.get().absolutePath + "/" + skiaBinSubdir
val osFlags: Array<String>
libFiles = project.fileTree(skiaJvmBindingsDir.map { it.resolve(skiaBinSubdir) }) {
include(if (targetOs.isWindows) "*.lib" else "*.a")
}
dependsOn(compileTask)
objectFiles = project.fileTree(compileTask.map { it.outDir.get() }) {
include("**/*.o")
}
val libNamePrefix = if (targetOs.isWindows) "skiko" else "libskiko"
libOutputFileName.set("$libNamePrefix-${targetOs.id}-${targetArch.id}${targetOs.dynamicLibExt}")
buildTargetOS.set(targetOs)
buildSuffix.set("jvm")
buildTargetArch.set(targetArch)
buildVariant.set(buildType)
linker.set(linkerForTarget(targetOs, targetArch))
when (targetOs) {
OS.MacOS -> {
dependsOn(objcCompileTask!!)
objectFiles += project.fileTree(objcCompileTask.map { it.outDir.get() }) {
include("**/*.o")
}
osFlags = arrayOf(
*targetOs.clangFlags,
"-arch", if (targetArch == Arch.Arm64) "arm64" else "x86_64",
"-shared",
"-dead_strip",
"-lobjc",
"-install_name", "./${libOutputFileName.get()}",
"-current_version", skiko.planeDeployVersion,
"-framework", "AppKit",
"-framework", "CoreFoundation",
"-framework", "CoreGraphics",
"-framework", "CoreServices",
"-framework", "CoreText",
"-framework", "Foundation",
"-framework", "IOKit",
"-framework", "Metal",
"-framework", "OpenGL",
"-framework", "QuartzCore" // for CoreAnimation
)
}
OS.Linux -> {
osFlags = arrayOf(
"-shared",
"-static-libstdc++",
"-static-libgcc",
"-lGL",
"-lX11",
"-lfontconfig",
// A fix for https://github.com/JetBrains/compose-jb/issues/413.
// Dynamic position independent linking uses PLT thunks relying on jump targets in GOT (Global Offsets Table).
// GOT entries marked as (for example) R_X86_64_JUMP_SLOT in the relocation table. So, if there's code loading
// platform libstdc++.so, lazy resolve code will resolve GOT entries to platform libstdc++.so on first invocation,
// and so further execution will break, as those two libstdc++ are not compatible.
// To fix it we enforce resolve of all GOT entries at library load time, and make it read-only afterwards.
"-Wl,-z,relro,-z,now",
// Hack to fix problem with linker not always finding certain declarations.
"$skiaBinDir/libsksg.a",
"$skiaBinDir/libskia.a",
"$skiaBinDir/libskunicode.a"
)
}
OS.Windows -> {
linker.set(windowsSdkPaths.linker.absolutePath)
libDirs.set(windowsSdkPaths.libDirs)
osFlags = mutableListOf<String>().apply {
addAll(buildType.msvcLinkerFlags)
addAll(
arrayOf(
// ignore https://learn.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-warning-lnk4217
// because we link OpenGl dynamically, defining functions in our own file in OpenGLLibrary.cc
"/ignore:4217"
)
)
addAll(
arrayOf(
"/NOLOGO",
"/DLL",
"Advapi32.lib",
"gdi32.lib",
"Dwmapi.lib",
"shcore.lib",
"user32.lib",
)
)
if (buildType == SkiaBuildType.DEBUG) add("dxgi.lib")
}.toTypedArray()
}
OS.Android -> {
osFlags = arrayOf(
"-shared",
"-static-libstdc++",
"-lGLESv3",
"-lEGL",
"-llog",
"-landroid",
// Hack to fix problem with linker not always finding certain declarations.
"$skiaBinDir/libskia.a",
)
linker.set(project.androidClangFor(targetArch))
}
OS.Wasm, OS.IOS -> {
throw GradleException("This task shalln't be used with $targetOs")
}
}
flags.set(listOf(*osFlags))
}
fun SkikoProjectContext.maybeSignOrSealTask(
targetOs: OS,
targetArch: Arch,
linkJvmBindings: Provider<LinkSkikoTask>
) = project.registerSkikoTask<SealAndSignSharedLibraryTask>("maybeSign", targetOs, targetArch) {
dependsOn(linkJvmBindings)
val linkOutputFile = linkJvmBindings.map { task ->
task.outDir.get().asFile.walk().single { it.name.endsWith(targetOs.dynamicLibExt) }.absoluteFile
}
libFile.set(project.layout.file(linkOutputFile))
val target = targetId(targetOs, targetArch)
outDir.set(project.layout.buildDirectory.dir("maybe-signed-$target"))
val toolsDir = project.layout.projectDirectory.dir("tools")
if (targetOs == OS.Linux) {
// Linux requires additional sealing to run on wider set of platforms.
// See https://github.com/olonho/sealer.
when (targetArch) {
Arch.X64 -> sealer.set(toolsDir.file("sealer-x64"))
Arch.Arm64 -> sealer.set(toolsDir.file("sealer-arm64"))
else -> error("Unexpected combination of '$targetArch' and '$targetOs'")
}
}
if (hostOs == OS.MacOS) {
codesignClient.set(toolsDir.file("codesign-client-darwin-x64"))
}
signHost.set(skiko.signHost)
signUser.set(skiko.signUser)
signToken.set(skiko.signToken)
}
fun SkikoProjectContext.skikoJvmRuntimeJarTask(
targetOs: OS,
targetArch: Arch,
awtJar: TaskProvider<Jar>,
nativeFiles: List<Provider<File>>
) = project.registerSkikoTask<Jar>("skikoJvmRuntimeJar", targetOs, targetArch) {
dependsOn(awtJar)
val target = targetId(targetOs, targetArch)
archiveBaseName.set("skiko")
archiveClassifier.set(target)
nativeFiles.forEach { provider -> from(provider) }
}
fun SkikoProjectContext.createSkikoJvmJarTask(os: OS, arch: Arch, commonJar: TaskProvider<Jar>): TaskProvider<Jar> = with(this.project) {
val skiaBindingsDir = registerOrGetSkiaDirProvider(os, arch)
val compileBindings = createCompileJvmBindingsTask(os, arch, skiaBindingsDir)
val objcCompile = if (os == OS.MacOS) createObjcCompileTask(os, arch, skiaBindingsDir) else null
val linkBindings =
createLinkJvmBindings(os, arch, skiaBindingsDir, compileBindings, objcCompile)
val maybeSign = maybeSignOrSealTask(os, arch, linkBindings)
val nativeLib = maybeSign.map { it.outputFiles.get().single() }
val createChecksums = createChecksumsTask(os, arch, nativeLib)
val nativeFiles = mutableListOf(
nativeLib,
createChecksums.map { it.outputs.files.singleFile }
)
if (os == OS.Windows) {
val target = targetId(os, arch)
// Add ICU data files.
nativeFiles.add(skiaBindingsDir.map { file(it.resolve("out/${buildType.id}-$target/icudtl.dat")) })
}
// For ARM macOS add x86 native code for compatibility.
if (os == OS.MacOS && arch == Arch.Arm64) {
val altArch = Arch.X64
val skiaBindingsDir2 = registerOrGetSkiaDirProvider(os, altArch)
val compileBindings2 = createCompileJvmBindingsTask(os, altArch, skiaBindingsDir2)
val objcCompile2 = createObjcCompileTask(os, altArch, skiaBindingsDir2)
val linkBindings2 =
createLinkJvmBindings(os, altArch, skiaBindingsDir2, compileBindings2, objcCompile2)
val maybeSign2 = maybeSignOrSealTask(os, altArch, linkBindings2)
val nativeLib2 = maybeSign2.map { it.outputFiles.get().single() }
val createChecksums2 = createChecksumsTask(os, altArch, nativeLib2)
nativeFiles.add(nativeLib2)
nativeFiles.add(createChecksums2.map { it.outputs.files.singleFile })
}
val skikoJvmRuntimeJar = skikoJvmRuntimeJarTask(os, arch, commonJar, nativeFiles)
allJvmRuntimeJars[os to arch] = skikoJvmRuntimeJar
return skikoJvmRuntimeJar
}
fun SkikoProjectContext.skikoRuntimeDirForTestsTask(
targetOs: OS,
targetArch: Arch,
skikoJvmJar: Provider<Jar>,
skikoJvmRuntimeJar: Provider<Jar>
) = project.registerSkikoTask<Copy>("skikoRuntimeDirForTests", targetOs, targetArch) {
dependsOn(skikoJvmJar, skikoJvmRuntimeJar)
from(project.zipTree(skikoJvmJar.flatMap { it.archiveFile }))
from(project.zipTree(skikoJvmRuntimeJar.flatMap { it.archiveFile }))
duplicatesStrategy = DuplicatesStrategy.WARN
destinationDir = project.buildDir.resolve("skiko-runtime-for-tests")
}
fun SkikoProjectContext.skikoJarForTestsTask(
runtimeDirForTestsTask: Provider<Copy>
) = project.registerSkikoTask<Jar>("skikoJvmJarForTests") {
dependsOn(runtimeDirForTestsTask)
from(runtimeDirForTestsTask.map { it.destinationDir })
archiveFileName.set("skiko-runtime-for-tests.jar")
}
fun SkikoProjectContext.setupJvmTestTask(skikoAwtJarForTests: TaskProvider<Jar>, targetOs: OS, targetArch: Arch) = with(project) {
val skikoAwtRuntimeJarForTests = createSkikoJvmJarTask(targetOs, targetArch, skikoAwtJarForTests)
val skikoRuntimeDirForTests = skikoRuntimeDirForTestsTask(targetOs, targetArch, skikoAwtJarForTests, skikoAwtRuntimeJarForTests)
val skikoJarForTests = skikoJarForTestsTask(skikoRuntimeDirForTests)
tasks.withType<Test>().configureEach {
dependsOn(skikoRuntimeDirForTests)
dependsOn(skikoJarForTests)
options {
val dir = skikoRuntimeDirForTests.map { it.destinationDir }.get()
systemProperty("skiko.library.path", dir)
val jar = skikoJarForTests.get().outputs.files.files.single { it.name.endsWith(".jar") }
systemProperty("skiko.jar.path", jar.absolutePath)
systemProperty("skiko.test.screenshots.dir", File(project.projectDir, "src/jvmTest/screenshots").absolutePath)
systemProperty("skiko.test.font.dir", File(project.projectDir, "src/commonTest/resources/fonts").absolutePath)
val testingOnCI = System.getProperty("skiko.test.onci", "false").toBoolean()
val canRunPerformanceTests = testingOnCI
val canRunUiTests = testingOnCI || System.getProperty("os.name") != "Mac OS X"
systemProperty(
"skiko.test.performance.enabled",
System.getProperty("skiko.test.performance.enabled", canRunPerformanceTests.toString())
)
systemProperty("skiko.test.ui.enabled", System.getProperty("skiko.test.ui.enabled", canRunUiTests.toString()))
systemProperty("skiko.test.ui.renderApi", System.getProperty("skiko.test.ui.renderApi", "all"))
systemProperty("skiko.test.debug", buildType == SkiaBuildType.DEBUG)
// Tests should be deterministic, so disable scaling.
// On MacOs we need the actual scale, otherwise we will have aliased screenshots because of scaling.
if (System.getProperty("os.name") != "Mac OS X") {
systemProperty("sun.java2d.dpiaware", "false")
systemProperty("sun.java2d.uiScale", "1")
}
}
jvmArgs = listOf("--add-opens", "java.desktop/sun.font=ALL-UNNAMED")
}
}
fun Project.androidHomePath(): Provider<String> {
val androidHomeFromSdkRoot: Provider<String> =
project.providers.environmentVariable("ANDROID_SDK_ROOT")
val androidHomeFromUserHome: Provider<String> =
project.providers.systemProperty("user.home")
.map { userHome ->
listOf("Library/Android/sdk", ".android/sdk", "Android/sdk")
.map { "$userHome/$it" }
.firstOrNull { File(it).exists() }
?: error("Define Android SDK via ANDROID_SDK_ROOT")
}
return androidHomeFromSdkRoot
.orElse(androidHomeFromUserHome)
}
fun Project.androidJar(askedVersion: String = ""): Provider<File> =
androidHomePath().map { androidHomePath ->
val androidHome = File(androidHomePath)
val version = if (askedVersion.isEmpty()) {
val platformsDir = androidHome.resolve("platforms")
val versions = platformsDir.list().orEmpty()
versions.maxByOrNull { name -> // possible name: "android-32", "android-33-ext4"
name.split("-").getOrNull(1)?.toInt() ?: 0
} ?: error(
buildString {
appendLine("'$platformsDir' does not contain any directories matching expected 'android-NUMBER' format: ${versions}")
}
)
} else {
"android-$askedVersion"
}
androidHome.resolve("platforms/$version/android.jar").also {
println("Skiko task androidJar uses android SDK in $it")
}
}
\ No newline at end of file
package tasks.configuration
import Arch
import CompileSkikoCppTask
import OS
import SkiaBuildType
import SkikoProjectContext
import SkikoProperties
import WriteCInteropDefFile
import compilerForTarget
import isCompatibleWithHost
import joinToTitleCamelCase
import listOfFrameworks
import mutableListOfLinkerOptions
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getByName
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.tasks.CInteropProcess
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTool
import projectDirs
import registerOrGetSkiaDirProvider
import registerSkikoTask
import toTitleCase
import java.io.File
fun String.withSuffix(isIosSim: Boolean = false) =
this + if (isIosSim) "Sim" else ""
fun KotlinTarget.isIosSimArm64() =
name.contains("iosSimulatorArm64", ignoreCase = true)
fun KotlinTarget.generateVersion(
targetOs: OS,
targetArch: Arch,
skikoProperties: SkikoProperties
) {
val targetName = this.name
val isArm64Simulator = isIosSimArm64()
val generatedDir = project.layout.buildDirectory.dir("generated/$targetName")
val generateVersionTask = project.registerSkikoTask<DefaultTask>(
"generateVersion${toTitleCase(platformType.name)}".withSuffix(isIosSim = isArm64Simulator),
targetOs,
targetArch
) {
inputs.property("buildType", skikoProperties.buildType.id)
outputs.dir(generatedDir)
doFirst {
val outDir = generatedDir.get().asFile
outDir.deleteRecursively()
outDir.mkdirs()
val out = "$outDir/Version.kt"
val target = "${targetOs.id}-${targetArch.id}"
val skiaTag = project.property("dependencies.skia.$target") as String
File(out).writeText(
"""
package org.jetbrains.skiko
object Version {
val skiko = "${skikoProperties.deployVersion}"
val skia = "$skiaTag"
}
""".trimIndent()
)
}
}
val compilation = compilations["main"] ?: error("Could not find 'main' compilation for target '$this'")
compilation.compileKotlinTaskProvider.configure {
dependsOn(generateVersionTask)
(this as KotlinCompileTool).source(generatedDir.get().asFile)
}
}
fun SkikoProjectContext.compileNativeBridgesTask(
os: OS, arch: Arch, isArm64Simulator: Boolean
): TaskProvider<CompileSkikoCppTask> = with (this.project) {
val skiaNativeDir = registerOrGetSkiaDirProvider(os, arch, isIosSim = isArm64Simulator)
val actionName = "compileNativeBridges".withSuffix(isIosSim = isArm64Simulator)
return project.registerSkikoTask<CompileSkikoCppTask>(actionName, os, arch) {
dependsOn(skiaNativeDir)
val unpackedSkia = skiaNativeDir.get()
compiler.set(compilerForTarget(os, arch))
buildTargetOS.set(os)
if (isArm64Simulator) {
buildSuffix.set("sim")
}
buildTargetArch.set(arch)
buildVariant.set(buildType)
when (os) {
OS.IOS -> {
val sdkRoot = "/Applications/Xcode.app/Contents/Developer/Platforms"
val iphoneOsSdk = "$sdkRoot/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
val iphoneSimSdk = "$sdkRoot/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
val iosArchFlags = when (arch) {
Arch.Arm64 -> arrayOf(
"-target", if (isArm64Simulator) "arm64-apple-ios-simulator" else "arm64-apple-ios",
"-isysroot", if (isArm64Simulator) iphoneSimSdk else iphoneOsSdk,
"-miphoneos-version-min=12.0"
)
Arch.X64 -> arrayOf(
"-target", "x86_64-apple-ios-simulator",
"-mios-version-min=12.0",
"-isysroot", iphoneSimSdk
)
else -> throw GradleException("Unsupported arch: $arch")
}
flags.set(listOf(
*iosArchFlags,
*buildType.clangFlags,
"-stdlib=libc++",
*skiaPreprocessorFlags(OS.IOS, buildType),
))
}
OS.MacOS -> {
flags.set(listOf(
*buildType.clangFlags,
*skiaPreprocessorFlags(OS.MacOS, buildType)
))
}
OS.Linux -> {
flags.set(listOf(
*buildType.clangFlags,
"-fno-rtti",
"-fno-exceptions",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-D_GLIBCXX_USE_CXX11_ABI=0",
*skiaPreprocessorFlags(OS.Linux, buildType)
))
}
else -> throw GradleException("$os not yet supported")
}
val srcDirs = projectDirs("src/commonMain/cpp/common", "src/nativeNativeJs/cpp", "src/nativeJsMain/cpp") +
if (skiko.includeTestHelpers) projectDirs("src/nativeJsTest/cpp") else emptyList()
sourceRoots.set(srcDirs)
includeHeadersNonRecursive(projectDir.resolve("src/nativeJsMain/cpp"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include"))
includeHeadersNonRecursive(skiaHeadersDirs(unpackedSkia))
}
}
fun configureCinterop(
cinteropName: String,
os: OS,
arch: Arch,
target: KotlinNativeTarget,
targetString: String,
linkerOpts: List<String>,
) {
val tasks = target.project.tasks
val taskNameSuffix = joinToTitleCamelCase(os.idWithSuffix(isIosSim = target.isIosSimArm64()), arch.id)
val writeCInteropDef = tasks.register("writeCInteropDef$taskNameSuffix", WriteCInteropDefFile::class.java) {
this.linkerOpts.set(linkerOpts)
outputFile.set(project.layout.buildDirectory.file("cinterop/$targetString/skiko.def"))
}
tasks.withType(CInteropProcess::class.java).configureEach {
if (konanTarget == target.konanTarget) {
dependsOn(writeCInteropDef)
}
}
target.compilations.getByName("main") {
cinterops.create(cinteropName).apply {
defFileProperty.set(writeCInteropDef.map { it.outputFile.get().asFile })
}
}
}
fun skiaStaticLibraries(skiaDir: String, targetString: String, buildType: SkiaBuildType): List<String> {
val skiaBinSubdir = "$skiaDir/out/${buildType.id}-$targetString"
return listOf(
"libskresources.a",
"libskparagraph.a",
"libskia.a",
"libicu.a",
"libskottie.a",
"libsvg.a",
"libpng.a",
"libwebp_sse41.a",
"libsksg.a",
"libskunicode.a",
"libwebp.a",
"libdng_sdk.a",
"libpiex.a",
"libharfbuzz.a",
"libexpat.a",
"libzlib.a",
"libjpeg.a",
"libskshaper.a"
).map {
"$skiaBinSubdir/$it"
}
}
fun SkikoProjectContext.configureNativeTarget(os: OS, arch: Arch, target: KotlinNativeTarget) = with(this.project) {
if (!os.isCompatibleWithHost) return
target.generateVersion(os, arch, skiko)
val isArm64Simulator = target.isIosSimArm64()
val targetString = "${os.idWithSuffix(isIosSim = isArm64Simulator)}-${arch.id}"
val unzipper = registerOrGetSkiaDirProvider(os, arch, isArm64Simulator)
val unpackedSkia = unzipper.get()
val skiaDir = unpackedSkia.absolutePath
val bridgesLibrary = "$buildDir/nativeBridges/static/$targetString/skiko-native-bridges-$targetString.a"
val allLibraries = skiaStaticLibraries(skiaDir, targetString, buildType) + bridgesLibrary
val skiaBinDir = "$skiaDir/out/${buildType.id}-$targetString"
val linkerFlags = when (os) {
OS.MacOS -> {
val macFrameworks = listOfFrameworks("Metal", "CoreGraphics", "CoreText", "CoreServices")
configureCinterop("skiko", os, arch, target, targetString, macFrameworks)
mutableListOfLinkerOptions(macFrameworks)
}
OS.IOS -> {
val iosFrameworks = listOfFrameworks("Metal", "CoreGraphics", "CoreText", "UIKit")
// list of linker options to be included into klib, which are needed for skiko consumers
// https://github.com/JetBrains/compose-multiplatform/issues/3178
// Important! Removing or renaming cinterop-uikit publication might cause compile error
// for projects depending on older Compose/Skiko transitively https://youtrack.jetbrains.com/issue/KT-60399
configureCinterop("uikit", os, arch, target, targetString, iosFrameworks)
mutableListOfLinkerOptions(iosFrameworks)
}
OS.Linux -> mutableListOfLinkerOptions(
"-L/usr/lib/x86_64-linux-gnu",
"-lfontconfig",
"-lGL",
// TODO: an ugly hack, Linux linker searches only unresolved symbols.
"$skiaBinDir/libsksg.a",
"$skiaBinDir/libskshaper.a",
"$skiaBinDir/libskunicode.a",
"$skiaBinDir/libskia.a"
)
else -> mutableListOf()
}
if (skiko.includeTestHelpers) {
linkerFlags.addAll(when (os) {
OS.Linux -> listOf(
"-linker-option", "-lX11",
"-linker-option", "-lGLX",
)
else -> emptyList()
})
}
// For some reason since 1.8.0 we need to set freeCompilerArgs for binaries AND for compilations
target.binaries.all {
freeCompilerArgs += allLibraries.map { listOf("-include-binary", it) }.flatten() + linkerFlags
}
target.compilations.all {
kotlinOptions {
freeCompilerArgs += allLibraries.map { listOf("-include-binary", it) }.flatten() + linkerFlags
}
}
val crossCompileTask = compileNativeBridgesTask(os, arch, isArm64Simulator = isArm64Simulator)
// TODO: move to LinkSkikoTask.
val actionName = "linkNativeBridges".withSuffix(isIosSim = isArm64Simulator)
val linkTask = project.registerSkikoTask<Exec>(actionName, os, arch) {
dependsOn(crossCompileTask)
val objectFilesDir = crossCompileTask.map { it.outDir.get() }
val objectFiles = project.fileTree(objectFilesDir) {
include("**/*.o")
}
inputs.files(objectFiles)
val outDir = "$buildDir/nativeBridges/static/$targetString"
val staticLib = "$outDir/skiko-native-bridges-$targetString.a"
workingDir = File(outDir)
when (os) {
OS.Linux -> {
executable = "ar"
argumentProviders.add { listOf("-crs", staticLib) }
}
OS.MacOS, OS.IOS -> {
executable = "libtool"
argumentProviders.add { listOf("-static", "-o", staticLib) }
}
else -> error("Unexpected OS for native bridges linking: $os")
}
argumentProviders.add { objectFiles.files.map { it.absolutePath } }
file(outDir).mkdirs()
outputs.dir(outDir)
}
target.compilations.all {
compileTaskProvider.configure {
dependsOn(linkTask)
}
}
}
fun KotlinMultiplatformExtension.configureIOSTestsWithMetal(project: Project) {
val metalTestTargets = listOf("iosX64", "iosSimulatorArm64")
metalTestTargets.forEach { target: String ->
if (targets.names.contains(target)) {
val testBinary = targets.getByName<KotlinNativeTarget>(target).binaries.getTest("DEBUG")
project.tasks.create(target + "TestWithMetal") {
dependsOn(testBinary.linkTask)
doLast {
val simulatorIdPropertyKey = "skiko.iosSimulatorUUID"
val simulatorId = project.findProperty(simulatorIdPropertyKey)?.toString()
?: error("Property '$simulatorIdPropertyKey' not found. Pass it with -P$simulatorIdPropertyKey=...")
project.exec { commandLine("xcrun", "simctl", "boot", simulatorId) }
try {
project.exec { commandLine("xcrun", "simctl", "spawn", simulatorId, testBinary.outputFile) }
} finally {
project.exec { commandLine("xcrun", "simctl", "shutdown", simulatorId) }
}
}
}
}
}
}
\ No newline at end of file
package tasks.configuration
import Arch
import CompileSkikoCppTask
import LinkSkikoWasmTask
import OS
import SkikoProjectContext
import compilerForTarget
import linkerForTarget
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.registering
import projectDirs
import registerOrGetSkiaDirProvider
import supportJs
import supportWasm
data class LinkWasmTasks(
val linkWasm: TaskProvider<LinkSkikoWasmTask>?,
val linkWasmWithES6: TaskProvider<LinkSkikoWasmTask>?
)
fun SkikoProjectContext.createWasmLinkTasks(): LinkWasmTasks = with(this.project) {
if (!supportWasm && !supportJs) {
return LinkWasmTasks(null, null)
}
val skiaWasmDir = registerOrGetSkiaDirProvider(OS.Wasm, Arch.Wasm, false)
val compileWasm by tasks.registering(CompileSkikoCppTask::class) {
val osArch = OS.Wasm to Arch.Wasm
dependsOn(skiaWasmDir)
compiler.set(compilerForTarget(OS.Wasm, Arch.Wasm))
buildTargetOS.set(osArch.first)
buildTargetArch.set(osArch.second)
buildVariant.set(buildType)
val srcDirs = projectDirs("src/commonMain/cpp/common", "src/jsWasmMain/cpp", "src/nativeJsMain/cpp") +
if (skiko.includeTestHelpers) projectDirs("src/nativeJsTest/cpp") else emptyList()
sourceRoots.set(srcDirs)
includeHeadersNonRecursive(projectDir.resolve("src/nativeJsMain/cpp"))
includeHeadersNonRecursive(projectDir.resolve("src/jsWasmMain/cpp"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaWasmDir.get()))
flags.set(
listOf(
*skiaPreprocessorFlags(OS.Wasm, buildType),
*buildType.clangFlags,
"-fno-rtti",
"-fno-exceptions",
)
)
}
val configureCommon: LinkSkikoWasmTask.(outputES6: Boolean) -> Unit = { outputES6 ->
val osArch = OS.Wasm to Arch.Wasm
dependsOn(compileWasm)
dependsOn(skiaWasmDir)
val unpackedSkia = skiaWasmDir.get()
linker.set(linkerForTarget(OS.Wasm, Arch.Wasm))
buildTargetOS.set(osArch.first)
buildTargetArch.set(osArch.second)
buildVariant.set(buildType)
if (outputES6) buildSuffix.set("es6")
libFiles = project.fileTree(unpackedSkia) { include("**/*.a") }
objectFiles = project.fileTree(compileWasm.map { it.outDir.get() }) {
include("**/*.o")
}
val jsFileExtension = if (outputES6) "mjs" else "js"
val wasmFileName = if (outputES6) {
"skikomjs.wasm"
} else {
"skiko.wasm" // to keep it compatible with older apps
}
val jsFileName = if (outputES6) {
"skikomjs.mjs"
} else {
"skiko.js" // to keep it compatible with older apps
}
libOutputFileName.set(wasmFileName) // emcc ignores this, it names .wasm file identically to js output
jsOutputFileName.set(jsFileName) // this determines the name .wasm file too
skikoJsPrefix.from(
// the order matters
project.layout.projectDirectory.file("src/jsWasmMain/resources/skikoCallbacks.js"),
project.layout.projectDirectory.file("src/jsWasmMain/resources/setup.$jsFileExtension")
)
@OptIn(kotlin.ExperimentalStdlibApi::class)
flags.set(buildList {
addAll(
listOf(
"-l", "GL",
"-s", "MAX_WEBGL_VERSION=2",
"-s", "MIN_WEBGL_VERSION=2",
"-s", "OFFSCREEN_FRAMEBUFFER=1",
"-s", "ALLOW_MEMORY_GROWTH=1", // TODO: Is there a better way? Should we use `-s INITIAL_MEMORY=X`?
"--bind",
// -O2 saves 800kB for the output file, and ~100kB for transferred size.
// -O3 breaks the exports in js/mjs files. skiko.wasm size is the same though
"-O2"
)
)
if (outputES6) {
addAll(
listOf(
"-s", "EXPORT_ES6=1",
"-s", "MODULARIZE=1",
"-s", "EXPORT_NAME=loadSkikoWASM",
"-s", "EXPORTED_RUNTIME_METHODS=\"[GL, wasmExports]\"",
// "-s", "EXPORT_ALL=1",
)
)
}
})
doLast {
// skiko.js (and skiko.mjs) files are directly referenced in karma.config.d/*/config.js
// so symbols must be replaced right after linking
val jsFiles = outDir.asFile.get().walk()
.filter { it.isFile && (it.name.endsWith(".js") || it.name.endsWith(".mjs")) }
for (jsFile in jsFiles) {
val originalContent = jsFile.readText()
val newContent = originalContent.replace("_org_jetbrains", "org_jetbrains")
.replace("skikomjs.wasm", "skiko.wasm")
.replace("if(ENVIRONMENT_IS_NODE){", "if (false) {") // to make webpack erase this part
jsFile.writeText(newContent)
if (outputES6) {
// delete this file as its presence can be confusing.
// It's identical to skiko.wasm and we use skiko.wasm in `skikoWasmJar`task
outDir.file(wasmFileName).get().asFile.delete()
outDir.file(jsFileName).get().asFile.renameTo(outDir.asFile.get().resolve("skiko.mjs"))
}
}
}
}
val linkWasmWithES6 by tasks.registering(LinkSkikoWasmTask::class) {
configureCommon(true)
}
val linkWasm by tasks.registering(LinkSkikoWasmTask::class) {
dependsOn(linkWasmWithES6)
configureCommon(false)
}
// skikoWasmJar is used by task name
val skikoWasmJar by project.tasks.registering(Jar::class) {
dependsOn(linkWasm)
// We produce jar that contains .js of wrapper/bindings and .wasm with Skia + bindings.
val wasmOutDir = linkWasm.map { it.outDir }
val wasmEsOutDir = linkWasmWithES6.map { it.outDir }
from(wasmOutDir) {
include("*.wasm")
include("*.js")
include("*.mjs")
}
from(wasmEsOutDir) {
include("*.mjs")
}
archiveBaseName.set("skiko-wasm")
doLast {
println("Wasm and JS at: ${archiveFile.get().asFile.absolutePath}")
}
}
return LinkWasmTasks(linkWasm, linkWasmWithES6)
}
\ No newline at end of file
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
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