Unverified Commit 6d773d5e authored by Mike Hearn's avatar Mike Hearn Committed by GitHub

Look for the skiko library in the libs directory of the JVM. (#328)

In some packagings, Skiko (+its data file) will be placed alongside
the other shared libraries used by the JVM. This has some advantages
with respect to code signing, and also avoids a .skiko directory
littering the user's home directory. That's especially important on
Windows where dotfiles/dotdirs don't work.

The system property still overrides this.
Co-authored-by: 's avatarMike Hearn <mike@hydraulic.software>
parent 549de5ab
package org.jetbrains.skiko package org.jetbrains.skiko
import org.jetbrains.skia.Bitmap import org.jetbrains.skia.Bitmap
import java.io.BufferedReader
import java.io.File import java.io.File
import java.io.InputStreamReader
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.StandardCopyOption import java.nio.file.StandardCopyOption
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
...@@ -52,52 +50,72 @@ object Library { ...@@ -52,52 +50,72 @@ object Library {
// This function does the following: on request to load given resource, // This function does the following: on request to load given resource,
// it checks if resource with given name is found in content-derived directory // it checks if resource with given name is found in content-derived directory
// in Skiko's home, and if not - unpacks it. Also, it could load additional // in Skiko's home, and if not - unpacks it. Also, it could load additional
// localization resource on platforms wher 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.compareAndExchange(false, true)) return
// Find/unpack a usable copy of the native library.
findAndLoad()
// TODO move properties to SkikoProperties
Setup.init()
try {
// Init code executed after library was loaded.
org.jetbrains.skia.impl.Library._nAfterLoad()
} catch (t: Throwable) {
t.printStackTrace()
}
}
private fun findAndLoad() {
val name = "skiko-$hostId" val name = "skiko-$hostId"
val platformName = System.mapLibraryName(name) val platformName = System.mapLibraryName(name)
val icu = if (hostOs.isWindows) "icudtl.dat" else null val icu = if (hostOs.isWindows) "icudtl.dat" else null
// First try: system property is set.
if (skikoLibraryPath != null) { if (skikoLibraryPath != null) {
val library = File(File(skikoLibraryPath), platformName) val library = File(File(skikoLibraryPath), platformName)
loadLibraryOrCopy(library) loadLibraryOrCopy(library)
if (icu != null && copyDir != null) { if (icu != null && copyDir != null)
unpackIfNeeded(copyDir!!, icu, true) unpackIfNeeded(copyDir!!, icu, true)
return
} }
} else {
// Second try: load it from the bin/ or lib/ directory relative to the JVM home.
// The user might have placed the native files alongside the other JVM libraries
// for signing purposes, so we'll find it here if so.
val jvmFiles = File(System.getProperty("java.home"), if (hostOs.isWindows) "bin" else "lib")
val pathInJvm = jvmFiles.resolve(platformName)
if (pathInJvm.exists() && icu?.let { (jvmFiles.resolve(it)).exists() } != false) {
loadLibraryOrCopy(pathInJvm)
return
}
// Third try: look up in or extract to a local cache directory.
// Key the cache by the hash of the library.
val hashResourceStream = Library::class.java.getResourceAsStream( val hashResourceStream = Library::class.java.getResourceAsStream(
"/$platformName.sha256" "/$platformName.sha256"
) ?: throw LibraryLoadException( ) ?: throw LibraryLoadException(
"Cannot find $platformName.sha256, proper native dependency missing." "Cannot find $platformName.sha256, proper native dependency missing."
) )
val hash = hashResourceStream.use { val hash = hashResourceStream.use { it.bufferedReader().readLine() }
BufferedReader(InputStreamReader(it)).lines().toArray()[0] as String
}
val cacheDir = File(File(cacheRoot), hash) val cacheDir = File(File(cacheRoot), hash)
cacheDir.mkdirs() cacheDir.mkdirs()
val library = unpackIfNeeded(cacheDir, platformName, false) val library = unpackIfNeeded(cacheDir, platformName, false)
loadLibraryOrCopy(library) loadLibraryOrCopy(library)
if (icu != null) { if (icu != null) {
if (copyDir != null) { if (copyDir != null) {
// We made a duplicate to resolve classloader conflicts.
unpackIfNeeded(copyDir!!, icu, true) unpackIfNeeded(copyDir!!, icu, true)
} else { } else {
// Normal path where Skiko is loaded only once.
unpackIfNeeded(cacheDir, icu, false) unpackIfNeeded(cacheDir, icu, false)
} }
} }
} }
// TODO move properties to SkikoProperties
Setup.init()
try {
// Init code executed after library was loaded.
org.jetbrains.skia.impl.Library._nAfterLoad()
} catch (t: Throwable) {
t.printStackTrace()
}
}
} }
// We have to keep this tiny class in Skiko for testing purposes. // We have to keep this tiny class in Skiko for testing purposes.
......
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