Unverified Commit d389d095 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

First step in Android support. (#425)

So far we cannot really build Skiko for Android (as no Android-specific code for rendering integration is made), however it refactor the build system to make this (along with other alternative JVM-based implementations) feasible.
parent 56d6fa7f
...@@ -264,5 +264,6 @@ afterEvaluate { ...@@ -264,5 +264,6 @@ afterEvaluate {
extensions.configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> { extensions.configure<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension> {
versions.webpackDevServer.version = "4.0.0" versions.webpackDevServer.version = "4.0.0"
versions.webpackCli.version = "4.9.0" versions.webpackCli.version = "4.9.0"
nodeVersion = "16.0.0"
} }
} }
...@@ -2,12 +2,8 @@ package org.jetbrains.skiko.sample ...@@ -2,12 +2,8 @@ package org.jetbrains.skiko.sample
import platform.AppKit.* import platform.AppKit.*
import org.jetbrains.skia.*
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import kotlinx.cinterop.*
import platform.Foundation.NSMakeRect import platform.Foundation.NSMakeRect
import platform.Foundation.NSBundle
import platform.Foundation.NSNotification
import platform.Foundation.NSSelectorFromString import platform.Foundation.NSSelectorFromString
import platform.darwin.NSObject import platform.darwin.NSObject
......
...@@ -199,8 +199,6 @@ fun compileNativeBridgesTask(os: OS, arch: Arch): TaskProvider<CompileSkikoCppTa ...@@ -199,8 +199,6 @@ fun compileNativeBridgesTask(os: OS, arch: Arch): TaskProvider<CompileSkikoCppTa
} }
} }
val skiaBinSubdir = "out/${buildType.id}-${targetOs.id}-${targetArch.id}"
internal val Project.isInIdea: Boolean internal val Project.isInIdea: Boolean
get() { get() {
return System.getProperty("idea.active")?.toBoolean() == true return System.getProperty("idea.active")?.toBoolean() == true
...@@ -212,6 +210,9 @@ val Project.supportNative: Boolean ...@@ -212,6 +210,9 @@ val Project.supportNative: Boolean
val Project.supportWasm: Boolean val Project.supportWasm: Boolean
get() = findProperty("skiko.wasm.enabled") == "true" || isInIdea get() = findProperty("skiko.wasm.enabled") == "true" || isInIdea
val Project.supportAndroid: Boolean
get() = findProperty("skiko.android.enabled") == "true"
kotlin { kotlin {
jvm { jvm {
compilations.all { compilations.all {
...@@ -254,9 +255,17 @@ kotlin { ...@@ -254,9 +255,17 @@ kotlin {
implementation(kotlin("test-annotations-common")) implementation(kotlin("test-annotations-common"))
} }
} }
/*
val androidMain by getting {
dependencies {
compileOnly(files(androidJar()))
}
} */
val jvmMain by getting { val jvmMain by getting {
dependencies { dependencies {
implementation(kotlin("stdlib-jdk8")) implementation(kotlin("stdlib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")
} }
...@@ -265,7 +274,6 @@ kotlin { ...@@ -265,7 +274,6 @@ kotlin {
dependencies { dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
implementation(kotlin("test-junit")) implementation(kotlin("test-junit"))
implementation(kotlin("test")) implementation(kotlin("test"))
} }
} }
...@@ -287,7 +295,7 @@ kotlin { ...@@ -287,7 +295,7 @@ kotlin {
val jsTest by getting { val jsTest by getting {
dependsOn(nativeJsTest) dependsOn(nativeJsTest)
dependencies { dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation(kotlin("test-js")) implementation(kotlin("test-js"))
} }
} }
...@@ -298,7 +306,7 @@ kotlin { ...@@ -298,7 +306,7 @@ kotlin {
val nativeMain by creating { val nativeMain by creating {
dependsOn(nativeJsMain) dependsOn(nativeJsMain)
dependencies { dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
} }
} }
val nativeTest by creating { val nativeTest by creating {
...@@ -521,8 +529,62 @@ fun skiaStaticLibraries(skiaDir: String, targetString: String): List<String> { ...@@ -521,8 +529,62 @@ fun skiaStaticLibraries(skiaDir: String, targetString: String): List<String> {
} }
val skiaJvmBindingsDir: Provider<File> = registerOrGetSkiaDirProvider(targetOs, targetArch) val skiaJvmBindingsDir: Provider<File> = registerOrGetSkiaDirProvider(targetOs, targetArch)
val compileJvmBindings = createCompileJvmBindingsTask(targetOs, targetArch, skiaJvmBindingsDir)
val linkJvmBindings = createLinkJvmBindings(targetOs, targetArch, skiaJvmBindingsDir, compileJvmBindings)
val maybeSign = maybeSignTask(targetOs, targetArch, linkJvmBindings)
val createChecksums = createChecksumsTask(targetOs, targetArch, maybeSign, skiaJvmBindingsDir)
val skikoJvmRuntimeJar = skikoJvmRuntimeJarTask(targetOs, targetArch, maybeSign, createChecksums, skiaJvmBindingsDir)
val skikoRuntimeDirForTests = skikoRuntimeDirForTestsTask(targetOs, targetArch, skikoJvmRuntimeJar)
val allJvmRuntimeJars = mutableMapOf((targetOs to targetArch) to skikoJvmRuntimeJar)
if (supportAndroid) {
val os = OS.Android
for (arch in arrayOf(Arch.X64, Arch.Arm64)) {
val skiaAndroidBindingsDir = registerOrGetSkiaDirProvider(os, arch)
val compileAndroidBindings = createCompileJvmBindingsTask(os, arch, skiaAndroidBindingsDir)
val linkAndroidBindings =
createLinkJvmBindings(OS.Android, arch, skiaAndroidBindingsDir, compileAndroidBindings)
val maybeSignAndroid = maybeSignTask(os, arch, linkAndroidBindings)
val createChecksumsAndroid = createChecksumsTask(os, arch, maybeSignAndroid, skiaAndroidBindingsDir)
val skikoJvmRuntimeJarAndroid = skikoJvmRuntimeJarTask(os, arch, maybeSignAndroid, createChecksumsAndroid, skiaAndroidBindingsDir)
allJvmRuntimeJars[os to arch] = skikoJvmRuntimeJarAndroid
}
}
val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings") { fun androidHome() = when (hostOs) {
OS.MacOS -> File("${System.getProperty("user.home")}/Library/Android/sdk")
OS.Linux -> File("${System.getProperty("user.home")}/.android")
else -> throw GradleException("unsupported $hostOs")
}
fun androidClangFor(targetArch: Arch, version: String = "30"): String {
val androidHome = androidHome()
val ndkVersion =
arrayOf("ndk/23.0.7599858", "ndk-bundle").find {
androidHome.resolve(it).exists()
}!!
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"
else -> throw GradleException("unsupported $hostOs")
}
val ndkDir = File(androidHome, "/$ndkVersion/toolchains/llvm/prebuilt/$hostOsArch")
return ndkDir.resolve("bin/$androidArch-linux-android$version-clang++").absolutePath
}
fun androidJar(version: String = "30"): String {
val androidHome = androidHome()
return androidHome.resolve("platforms/android-$version/android.jar").absolutePath
}
fun createCompileJvmBindingsTask(targetOs: OS, targetArch: Arch, skiaJvmBindingsDir: Provider<File>) =
tasks.register<CompileSkikoCppTask>("compileJvmBindings-${targetOs.id}-${targetArch.id}") {
// 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.
if (JavaVersion.current() < JavaVersion.VERSION_11) { if (JavaVersion.current() < JavaVersion.VERSION_11) {
...@@ -542,8 +604,7 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings ...@@ -542,8 +604,7 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
"src/jvmTest/cpp" "src/jvmTest/cpp"
) )
sourceRoots.set(srcDirs) sourceRoots.set(srcDirs)
if (targetOs != OS.Android) includeHeadersNonRecursive(jdkHome.resolve("include"))
includeHeadersNonRecursive(jdkHome.resolve("include"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaJvmBindingsDir.get())) includeHeadersNonRecursive(skiaHeadersDirs(skiaJvmBindingsDir.get()))
includeHeadersNonRecursive(projectDir.resolve("src/jvmMain/cpp/include")) includeHeadersNonRecursive(projectDir.resolve("src/jvmMain/cpp/include"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include")) includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp/common/include"))
...@@ -601,6 +662,17 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings ...@@ -601,6 +662,17 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
// "-DSK_ANGLE", // "-DSK_ANGLE",
) )
} }
OS.Android -> {
compiler.set(androidClangFor(targetArch))
osFlags = arrayOf(
*buildType.clangFlags,
"-fno-rtti",
"-fno-exceptions",
"-fvisibility=hidden",
"-fPIC",
"-DSK_BUILD_FOR_ANDROID"
)
}
OS.Wasm, OS.IOS -> error("Should not reach here") OS.Wasm, OS.IOS -> error("Should not reach here")
} }
...@@ -612,97 +684,109 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings ...@@ -612,97 +684,109 @@ val compileJvmBindings = tasks.register<CompileSkikoCppTask>("compileJvmBindings
) )
} }
val linkJvmBindings = tasks.register<LinkSkikoTask>("linkJvmBindings") { fun createLinkJvmBindings(targetOs: OS, targetArch: Arch,
val skiaBinDir = skiaJvmBindingsDir.get().absolutePath + "/" + skiaBinSubdir skiaJvmBindingsDir: Provider<File>,
val osFlags: Array<String> compileTask: TaskProvider<CompileSkikoCppTask>) =
tasks.register<LinkSkikoTask>("linkJvmBindings-${targetOs.id}-${targetArch.id}") {
val target = targetId(targetOs, targetArch)
val skiaBinSubdir = "out/${buildType.id}-$target"
val skiaBinDir = skiaJvmBindingsDir.get().absolutePath + "/" + skiaBinSubdir
val osFlags: Array<String>
libFiles = fileTree(skiaJvmBindingsDir.map { it.resolve(skiaBinSubdir)}) {
include(if (targetOs.isWindows) "*.lib" else "*.a")
}
libFiles = fileTree(skiaJvmBindingsDir.map { it.resolve(skiaBinSubdir)}) { dependsOn(compileTask)
include(if (targetOs.isWindows) "*.lib" else "*.a") objectFiles = fileTree(compileTask.map { it.outDir.get() }) {
} include("**/*.o")
}
dependsOn(compileJvmBindings) val libNamePrefix = if (targetOs.isWindows) "skiko" else "libskiko"
objectFiles = fileTree(compileJvmBindings.map { it.outDir.get() }) { libOutputFileName.set("$libNamePrefix-${targetOs.id}-${targetArch.id}${targetOs.dynamicLibExt}")
include("**/*.o") buildTargetOS.set(targetOs)
} buildTargetArch.set(targetArch)
buildVariant.set(buildType)
linker.set(linkerForTarget(targetOs, targetArch))
val libNamePrefix = if (targetOs.isWindows) "skiko" else "libskiko" when (targetOs) {
libOutputFileName.set("$libNamePrefix-${targetOs.id}-${targetArch.id}${targetOs.dynamicLibExt}") OS.MacOS -> {
buildTargetOS.set(targetOs) dependsOn("objcCompile")
buildTargetArch.set(targetArch) objectFiles += fileTree("$buildDir/objc/$target") {
buildVariant.set(buildType) include("**/*.o")
linker.set(linkerForTarget(targetOs, targetArch)) }
when (targetOs) { osFlags = arrayOf(
OS.MacOS -> { *targetOs.clangFlags,
dependsOn("objcCompile") "-shared",
objectFiles += fileTree("$buildDir/objc/$target") { "-dead_strip",
include("**/*.o") "-lobjc",
"-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",
"-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 = arrayOf(
*buildType.msvcLinkerFlags,
"/NOLOGO",
"/DLL",
"Advapi32.lib",
"gdi32.lib",
"Dwmapi.lib",
"opengl32.lib",
"shcore.lib",
"user32.lib",
)
}
OS.Android -> {
osFlags = arrayOf(
"-shared"
)
linker.set(androidClangFor(targetArch))
}
OS.Wasm, OS.IOS -> {
throw GradleException("This task shalln't be used with $targetOs")
} }
osFlags = arrayOf(
*targetOs.clangFlags,
"-shared",
"-dead_strip",
"-lobjc",
"-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",
"-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 = arrayOf(
*buildType.msvcLinkerFlags,
"/NOLOGO",
"/DLL",
"Advapi32.lib",
"gdi32.lib",
"Dwmapi.lib",
"opengl32.lib",
"shcore.lib",
"user32.lib",
)
}
OS.Wasm, OS.IOS -> {
throw GradleException("This task shalln't be used with WASM")
} }
flags.set(listOf(*osFlags))
} }
flags.set(listOf(*osFlags))
}
if (hostOs == OS.MacOS) { if (hostOs == OS.MacOS) {
// Very hacky way to compile Objective-C sources and add the // Very hacky way to compile Objective-C sources and add the
// resulting object files into the final library. // resulting object files into the final library.
// TODO: rewrite using SkikoCompileTask
project.tasks.register<Exec>("objcCompile") { project.tasks.register<Exec>("objcCompile") {
val target = targetId(targetOs, targetArch)
val inputDir = "$projectDir/src/jvmMain/objectiveC/${targetOs.id}" val inputDir = "$projectDir/src/jvmMain/objectiveC/${targetOs.id}"
val outDir = "$buildDir/objc/$target" val outDir = "$buildDir/objc/$target"
val names = File(inputDir).listFiles()!!.map { it.name.removeSuffix(".mm") } val names = File(inputDir).listFiles()!!.map { it.name.removeSuffix(".mm") }
...@@ -732,7 +816,9 @@ if (hostOs == OS.MacOS) { ...@@ -732,7 +816,9 @@ if (hostOs == OS.MacOS) {
} }
} }
val generateVersion = project.tasks.register("generateVersion") { val generateVersion = generateVersionTask(targetOs, targetArch)
fun generateVersionTask(targetOs: OS, targetArch: Arch) = project.tasks.register("generateVersion") {
val outDir = generatedKotlin val outDir = generatedKotlin
file(outDir).mkdirs() file(outDir).mkdirs()
val out = "$outDir/Version.kt" val out = "$outDir/Version.kt"
...@@ -750,12 +836,13 @@ val generateVersion = project.tasks.register("generateVersion") { ...@@ -750,12 +836,13 @@ val generateVersion = project.tasks.register("generateVersion") {
} }
} }
val skikoJvmJar: Provider<Jar> by tasks.registering(Jar::class) { val skikoJvmJar by project.tasks.registering(Jar::class) {
archiveBaseName.set("skiko-jvm") archiveBaseName.set("skiko-jvm")
from(kotlin.jvm().compilations["main"].output.allOutputs) from(kotlin.jvm().compilations["main"].output.allOutputs)
} }
val maybeSign by project.tasks.registering(SealAndSignSharedLibraryTask::class) { fun maybeSignTask(targetOs: OS, targetArch: Arch, linkJvmBindings: Provider<LinkSkikoTask>) =
project.tasks.register<SealAndSignSharedLibraryTask>("maybeSign-${targetOs.id}-${targetArch.id}") {
dependsOn(linkJvmBindings) dependsOn(linkJvmBindings)
val linkOutputFile = linkJvmBindings.map { task -> val linkOutputFile = linkJvmBindings.map { task ->
...@@ -783,26 +870,40 @@ val maybeSign by project.tasks.registering(SealAndSignSharedLibraryTask::class) ...@@ -783,26 +870,40 @@ val maybeSign by project.tasks.registering(SealAndSignSharedLibraryTask::class)
signToken.set(skiko.signToken) signToken.set(skiko.signToken)
} }
val createChecksums by project.tasks.registering(org.gradle.crypto.checksum.Checksum::class) { fun createChecksumsTask(targetOs: OS, targetArch: Arch,
dependsOn(maybeSign) maybeSign: Provider<SealAndSignSharedLibraryTask>,
files = project.files(maybeSign.flatMap { it.outputFiles }) + bindingsDir: Provider<File>) =
if (targetOs.isWindows) files(skiaJvmBindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }) else files() project.tasks.register<Checksum>("createChecksums-${targetOs.id}-${targetArch.id}") {
algorithm = Checksum.Algorithm.SHA256 val skiaBinSubdir = "out/${buildType.id}-${targetOs.id}-${targetArch.id}"
outputDir = file("$buildDir/checksums") dependsOn(maybeSign)
} files = project.files(maybeSign.flatMap { it.outputFiles }) +
if (targetOs.isWindows) files(bindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }) else files()
val skikoJvmRuntimeJar by project.tasks.registering(Jar::class) { algorithm = Checksum.Algorithm.SHA256
dependsOn(createChecksums) outputDir = file("$buildDir/checksums")
archiveBaseName.set("skiko-$target")
from(skikoJvmJar.map { zipTree(it.archiveFile) })
from(maybeSign.flatMap { it.outputFiles })
if (targetOs.isWindows) {
from(files(skiaJvmBindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }))
} }
from(createChecksums.map { it.outputs.files })
fun skikoJvmRuntimeJarTask(targetOs: OS, targetArch: Arch,
maybeSign: Provider<SealAndSignSharedLibraryTask>,
createChecksums: Provider<Checksum>,
bindingsDir: Provider<File>) =
project.tasks.register<Jar>("skikoJvmRuntimeJar-${targetOs.id}-${targetArch.id}") {
dependsOn(maybeSign)
dependsOn(createChecksums)
dependsOn(skikoJvmJar)
val target = targetId(targetOs, targetArch)
val skiaBinSubdir = "out/${buildType.id}-$target"
archiveBaseName.set("skiko-$target")
from(skikoJvmJar.map { zipTree(it.archiveFile) })
from(maybeSign.flatMap { it.outputFiles })
if (targetOs.isWindows) {
from(files(bindingsDir.map { it.resolve("${skiaBinSubdir}/icudtl.dat") }))
}
from(createChecksums.map { it.outputs.files })
} }
val skikoRuntimeDirForTests by project.tasks.registering(Copy::class) { fun skikoRuntimeDirForTestsTask(targetOs: OS, targetArch: Arch,
skikoJvmRuntimeJar: Provider<Jar>) =
project.tasks.register<Copy>("skikoRuntimeDirForTests-${targetOs.id}-${targetArch.id}") {
dependsOn(skikoJvmRuntimeJar) dependsOn(skikoJvmRuntimeJar)
from(zipTree(skikoJvmRuntimeJar.flatMap { it.archiveFile })) { from(zipTree(skikoJvmRuntimeJar.flatMap { it.archiveFile })) {
include("*.so") include("*.so")
...@@ -812,6 +913,7 @@ val skikoRuntimeDirForTests by project.tasks.registering(Copy::class) { ...@@ -812,6 +913,7 @@ val skikoRuntimeDirForTests by project.tasks.registering(Copy::class) {
} }
destinationDir = project.buildDir.resolve("skiko-runtime-for-tests") destinationDir = project.buildDir.resolve("skiko-runtime-for-tests")
} }
tasks.withType<Test>().configureEach { tasks.withType<Test>().configureEach {
dependsOn(skikoRuntimeDirForTests) dependsOn(skikoRuntimeDirForTests)
dependsOn(skikoJvmRuntimeJar) dependsOn(skikoJvmRuntimeJar)
...@@ -926,19 +1028,23 @@ publishing { ...@@ -926,19 +1028,23 @@ publishing {
} }
} }
create<MavenPublication>("skikoJvmRuntime") { allJvmRuntimeJars.forEach { entry ->
pomNameForPublication[name] = "Skiko JVM Runtime for ${targetOs.name} ${targetArch.name}" val os = entry.key.first
artifactId = SkikoArtifacts.jvmRuntimeArtifactIdFor(targetOs, targetArch) val arch = entry.key.second
afterEvaluate { create<MavenPublication>("skikoJvmRuntime${targetId(os, arch)}") {
artifact(skikoJvmRuntimeJar.map { it.archiveFile.get() }) pomNameForPublication[name] = "Skiko JVM Runtime for ${os.name} ${arch.name}"
var jvmSourcesArtifact: Any? = null artifactId = SkikoArtifacts.jvmRuntimeArtifactIdFor(os, arch)
kotlin.jvm().mavenPublication { afterEvaluate {
jvmSourcesArtifact = artifacts.find { it.classifier == "sources" } artifact(entry.value.map { it.archiveFile.get() })
} var jvmSourcesArtifact: Any? = null
if (jvmSourcesArtifact == null) { kotlin.jvm().mavenPublication {
error("Could not find sources jar artifact for JVM target") jvmSourcesArtifact = artifacts.find { it.classifier == "sources" }
} else { }
artifact(jvmSourcesArtifact) if (jvmSourcesArtifact == null) {
error("Could not find sources jar artifact for JVM target")
} else {
artifact(jvmSourcesArtifact)
}
} }
} }
} }
......
...@@ -6,6 +6,7 @@ enum class OS( ...@@ -6,6 +6,7 @@ enum class OS(
val clangFlags: Array<String> val clangFlags: Array<String>
) { ) {
Linux("linux", arrayOf()), Linux("linux", arrayOf()),
Android("android", arrayOf()),
Windows("windows", arrayOf()), Windows("windows", arrayOf()),
MacOS("macos", arrayOf("-mmacosx-version-min=10.13")), MacOS("macos", arrayOf("-mmacosx-version-min=10.13")),
Wasm("wasm", arrayOf()), Wasm("wasm", arrayOf()),
...@@ -22,6 +23,7 @@ val OS.isCompatibleWithHost: Boolean ...@@ -22,6 +23,7 @@ val OS.isCompatibleWithHost: Boolean
OS.Windows -> hostOs == OS.Windows OS.Windows -> hostOs == OS.Windows
OS.MacOS, OS.IOS -> hostOs == OS.MacOS OS.MacOS, OS.IOS -> hostOs == OS.MacOS
OS.Wasm -> true OS.Wasm -> true
OS.Android -> true
} }
fun compilerForTarget(os: OS, arch: Arch): String = fun compilerForTarget(os: OS, arch: Arch): String =
...@@ -31,6 +33,7 @@ fun compilerForTarget(os: OS, arch: Arch): String = ...@@ -31,6 +33,7 @@ fun compilerForTarget(os: OS, arch: Arch): String =
Arch.Arm64 -> "clang++" Arch.Arm64 -> "clang++"
Arch.Wasm -> "Unexpected combination: $os & $arch" Arch.Wasm -> "Unexpected combination: $os & $arch"
} }
OS.Android -> "clang++"
OS.Windows -> "cl.exe" OS.Windows -> "cl.exe"
OS.MacOS, OS.IOS -> "clang++" OS.MacOS, OS.IOS -> "clang++"
OS.Wasm -> "emcc" OS.Wasm -> "emcc"
...@@ -41,7 +44,7 @@ fun linkerForTarget(os: OS, arch: Arch): String = ...@@ -41,7 +44,7 @@ fun linkerForTarget(os: OS, arch: Arch): String =
val OS.dynamicLibExt: String val OS.dynamicLibExt: String
get() = when (this) { get() = when (this) {
OS.Linux -> ".so" OS.Linux, OS.Android -> ".so"
OS.Windows -> ".dll" OS.Windows -> ".dll"
OS.MacOS, OS.IOS -> ".dylib" OS.MacOS, OS.IOS -> ".dylib"
OS.Wasm -> ".wasm" OS.Wasm -> ".wasm"
...@@ -115,8 +118,6 @@ fun findTargetArch() = when (System.getProperty("skiko.target.os.arch")) { ...@@ -115,8 +118,6 @@ fun findTargetArch() = when (System.getProperty("skiko.target.os.arch")) {
val targetOs = findTargetOs() ?: hostOs val targetOs = findTargetOs() ?: hostOs
val targetArch = findTargetArch() ?: hostArch val targetArch = findTargetArch() ?: hostArch
val target = targetId(targetOs, targetArch)
fun targetId(os: OS, arch: Arch) = fun targetId(os: OS, arch: Arch) =
"${os.id}-${arch.id}" "${os.id}-${arch.id}"
......
...@@ -11,5 +11,7 @@ dependencies.skia.macos-arm64=m97-0b898c4b8e ...@@ -11,5 +11,7 @@ dependencies.skia.macos-arm64=m97-0b898c4b8e
dependencies.skia.wasm-wasm=m97-0b898c4b8e dependencies.skia.wasm-wasm=m97-0b898c4b8e
dependencies.skia.ios-x64=m97-0b898c4b8e dependencies.skia.ios-x64=m97-0b898c4b8e
dependencies.skia.ios-arm64=m97-0b898c4b8e dependencies.skia.ios-arm64=m97-0b898c4b8e
dependencies.skia.android-x64=m97-0b898c4b8e
dependencies.skia.android-arm64=m97-0b898c4b8e
org.gradle.jvmargs=-Xmx3G org.gradle.jvmargs=-Xmx3G
package org.jetbrains.skiko package org.jetbrains.skiko
enum class OS(val id: String) { enum class OS(val id: String) {
Android("android"),
Linux("linux"), Linux("linux"),
Windows("windows"), Windows("windows"),
MacOS("macos"), MacOS("macos"),
......
...@@ -5,12 +5,11 @@ ...@@ -5,12 +5,11 @@
class SkijaDrawableImpl: public SkDrawable { class SkijaDrawableImpl: public SkDrawable {
public: public:
SkijaDrawableImpl() { SkijaDrawableImpl() {}
}
~SkijaDrawableImpl() { ~SkijaDrawableImpl() {
JNIEnv* env; JNIEnv* env;
if (fJavaVM->GetEnv(AS_JNI_ENV_PTR(&env), SKIKO_JNI_VERSION) == JNI_OK) if (fJavaVM->GetEnv(reinterpret_cast<void**>(&env), SKIKO_JNI_VERSION) == JNI_OK)
env->DeleteGlobalRef(fObject); env->DeleteGlobalRef(fObject);
} }
......
...@@ -440,7 +440,7 @@ public: ...@@ -440,7 +440,7 @@ public:
~JCallback() { ~JCallback() {
if (callback != nullptr) { if (callback != nullptr) {
JNIEnv* localEnv; JNIEnv* localEnv;
if (javaVM->GetEnv(AS_JNI_ENV_PTR(&localEnv), SKIKO_JNI_VERSION) == JNI_OK) { if (javaVM->GetEnv(reinterpret_cast<void**>(&localEnv), SKIKO_JNI_VERSION) == JNI_OK) {
localEnv->DeleteGlobalRef(callback); localEnv->DeleteGlobalRef(callback);
} }
} }
......
...@@ -8,7 +8,7 @@ actual class Library { ...@@ -8,7 +8,7 @@ actual class Library {
var loaded = AtomicBoolean(false) var loaded = AtomicBoolean(false)
@JvmStatic @JvmStatic
actual fun staticLoad() { actual fun staticLoad() {
if (!loaded.compareAndExchange(false, true)) { if (loaded.compareAndSet(false, true)) {
Library.load() Library.load()
} }
} }
......
...@@ -53,7 +53,7 @@ object Library { ...@@ -53,7 +53,7 @@ object Library {
// localization resource on platforms where it is needed. // localization resource on platforms where it is needed.
@Synchronized @Synchronized
fun load() { fun load() {
if (loaded.compareAndExchange(false, true)) return if (!loaded.compareAndSet(false, true)) return
// Find/unpack a usable copy of the native library. // Find/unpack a usable copy of the native library.
findAndLoad() findAndLoad()
......
...@@ -4,8 +4,9 @@ actual val hostOs: OS by lazy { ...@@ -4,8 +4,9 @@ actual val hostOs: OS by lazy {
val osName = System.getProperty("os.name") val osName = System.getProperty("os.name")
when { when {
osName == "Mac OS X" -> OS.MacOS osName == "Mac OS X" -> OS.MacOS
osName == "Linux" -> OS.Linux
osName.startsWith("Win") -> OS.Windows osName.startsWith("Win") -> OS.Windows
"The Android Project" == System.getProperty("java.specification.vendor") -> OS.Android
osName == "Linux" -> OS.Linux
else -> throw Error("Unknown OS $osName") else -> throw Error("Unknown OS $osName")
} }
} }
......
...@@ -119,6 +119,7 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -119,6 +119,7 @@ internal val platformOperations: PlatformOperations by lazy {
} }
} }
} }
OS.Android -> TODO()
OS.JS, OS.Ios -> { OS.JS, OS.Ios -> {
TODO("Commonize me") TODO("Commonize me")
} }
......
...@@ -32,6 +32,7 @@ private fun makeDefaultRenderFactory(): RenderFactory { ...@@ -32,6 +32,7 @@ private fun makeDefaultRenderFactory(): RenderFactory {
GraphicsApi.SOFTWARE_FAST -> LinuxSoftwareRedrawer(layer, properties) GraphicsApi.SOFTWARE_FAST -> LinuxSoftwareRedrawer(layer, properties)
else -> LinuxOpenGLRedrawer(layer, properties) else -> LinuxOpenGLRedrawer(layer, properties)
} }
OS.Android -> TODO()
OS.JS, OS.Ios -> { OS.JS, OS.Ios -> {
TODO("Commonize me") TODO("Commonize me")
} }
......
...@@ -19,8 +19,8 @@ internal fun makeMetalContext() = DirectContext( ...@@ -19,8 +19,8 @@ internal fun makeMetalContext() = DirectContext(
makeMetalContextNative().also { if (it == 0L) TODO("not yet supported") } makeMetalContextNative().also { if (it == 0L) TODO("not yet supported") }
) )
external private fun makeGLRenderTargetNative(width: Int, height: Int, sampleCnt: Int, stencilBits: Int, fbId: Int, fbFormat: Int): Long private external fun makeGLRenderTargetNative(width: Int, height: Int, sampleCnt: Int, stencilBits: Int, fbId: Int, fbFormat: Int): Long
external private fun makeGLContextNative(): Long private external fun makeGLContextNative(): Long
external private fun makeMetalRenderTargetNative(width: Int, height: Int, sampleCnt: Int): Long private external fun makeMetalRenderTargetNative(width: Int, height: Int, sampleCnt: Int): Long
external private fun makeMetalContextNative(): Long private external fun makeMetalContextNative(): Long
...@@ -56,6 +56,7 @@ internal object SkikoProperties { ...@@ -56,6 +56,7 @@ internal object SkikoProperties {
OS.MacOS -> return GraphicsApi.METAL OS.MacOS -> return GraphicsApi.METAL
OS.Linux -> return GraphicsApi.OPENGL OS.Linux -> return GraphicsApi.OPENGL
OS.Windows -> return GraphicsApi.DIRECT3D OS.Windows -> return GraphicsApi.DIRECT3D
OS.Android -> return GraphicsApi.OPENGL
OS.JS, OS.Ios -> TODO("commonize me") OS.JS, OS.Ios -> TODO("commonize me")
} }
} }
...@@ -65,6 +66,7 @@ internal object SkikoProperties { ...@@ -65,6 +66,7 @@ internal object SkikoProperties {
OS.Linux -> listOf(GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT) OS.Linux -> listOf(GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
OS.MacOS -> listOf(GraphicsApi.METAL, GraphicsApi.SOFTWARE_COMPAT) OS.MacOS -> listOf(GraphicsApi.METAL, GraphicsApi.SOFTWARE_COMPAT)
OS.Windows -> listOf(GraphicsApi.DIRECT3D, GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT) OS.Windows -> listOf(GraphicsApi.DIRECT3D, GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
OS.Android -> return listOf(GraphicsApi.OPENGL)
OS.JS, OS.Ios -> TODO("commonize me") OS.JS, OS.Ios -> TODO("commonize me")
} }
......
...@@ -10,7 +10,7 @@ import java.lang.ref.Reference ...@@ -10,7 +10,7 @@ import java.lang.ref.Reference
internal class DirectSoftwareContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) { internal class DirectSoftwareContextHandler(layer: SkiaLayer) : JvmContextHandler(layer) {
var isInited = false var isInited = false
val softwareRedrawer: AbstractDirectSoftwareRedrawer private val softwareRedrawer: AbstractDirectSoftwareRedrawer
get() = layer.redrawer!! as AbstractDirectSoftwareRedrawer get() = layer.redrawer!! as AbstractDirectSoftwareRedrawer
private var currentWidth = 0 private var currentWidth = 0
......
...@@ -3,7 +3,6 @@ package org.jetbrains.skiko.redrawer ...@@ -3,7 +3,6 @@ package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import org.jetbrains.skiko.context.Direct3DContextHandler
import org.jetbrains.skiko.context.OpenGLContextHandler import org.jetbrains.skiko.context.OpenGLContextHandler
internal class LinuxOpenGLRedrawer( internal class LinuxOpenGLRedrawer(
......
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