Skip to content

Commit b264242

Browse files
committed
Add NativeBuildsJvmLoader.overrideLoader for customized JNI lib loading logic
1 parent 308343b commit b264242

2 files changed

Lines changed: 70 additions & 34 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.9.0
4+
5+
* Added `NativeBuildsJvmLoader.overrideLoader` to allow fully customizing the JNI lib loading logic.
6+
37
## 0.8.4
48

59
* Fixed Android JNI loading.

nativebuilds-loader/src/main/kotlin/com/ensody/nativebuilds/loader/NativeBuildsJvmLoader.kt

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ package com.ensody.nativebuilds.loader
33
import java.io.File
44
import kotlin.uuid.Uuid
55

6+
/**
7+
* JNI native .so (shared library) loading mechanism for JVM and Android.
8+
*
9+
* This works with the NativeBuilds project out of the box and can also be customized via [overrideLoader].
10+
*/
611
public object NativeBuildsJvmLoader {
712
private val loadedLibs = mutableSetOf<NativeBuildsJvmLib>()
813
private val tempDir by lazy {
@@ -13,46 +18,73 @@ public object NativeBuildsJvmLoader {
1318
}
1419
}
1520

21+
/**
22+
* Allows customizing the loading mechanism.
23+
*
24+
* The default value is the default loading mechanism. To delegate to the default loading mechanism you can save
25+
* the old value before overriding:
26+
*
27+
* ```kotlin
28+
* val original = NativeBuildsJvmLoader.overrideLoader
29+
* NativeBuildsJvmLoader.overrideLoader = {
30+
* if (...) {
31+
* original(it)
32+
* } else {
33+
* // custom logic
34+
* }
35+
* }
36+
* ```
37+
*/
38+
public var overrideLoader: (lib: NativeBuildsJvmLib) -> Unit = ::realLoad
39+
40+
/**
41+
* Loads the given [lib] for use with JNI code.
42+
*/
1643
public fun load(lib: NativeBuildsJvmLib) {
1744
synchronized(lib) {
1845
if (lib !in loadedLibs) {
19-
val vendor = System.getProperty("java.vendor")
20-
if (vendor == "The Android Project") {
21-
System.loadLibrary(lib.libName.removePrefix("lib"))
22-
loadedLibs.add(lib)
23-
return
24-
}
25-
val osName = System.getProperty("os.name")!!.lowercase()
26-
val osArch = when (val osArch = System.getProperty("os.arch")!!.lowercase()) {
27-
"x86_64", "amd64" -> "X64"
28-
"aarch64", "arm64" -> "Arm64"
29-
else -> error("Unsupported arch: $osArch (os=$osName)")
30-
}
31-
val platform = when {
32-
"windows" in osName -> "mingw$osArch"
33-
"linux" in osName -> "linux$osArch"
34-
"mac" in osName || "darwin" in osName -> "macos$osArch"
35-
else -> error("Unsupported OS: $osName (arch=$osArch)")
36-
}
37-
val libFileName = lib.platformFileName[platform]
38-
?: error("Could not find library ${lib.libName} for platform $platform")
39-
val path = "/jni/$platform/$libFileName"
40-
val tempFile = File(tempDir, libFileName).apply {
41-
deleteOnExit()
42-
}
46+
overrideLoader(lib)
47+
loadedLibs.add(lib)
48+
}
49+
}
50+
}
4351

44-
val resource = checkNotNull(lib::class.java.getResourceAsStream(path)) {
45-
"Could not find shared library: $path"
46-
}
47-
resource.use { inputStream ->
48-
tempFile.outputStream().use {
49-
inputStream.copyTo(it)
50-
}
51-
}
52+
@Suppress("UnsafeDynamicallyLoadedCode")
53+
private fun realLoad(lib: NativeBuildsJvmLib) {
54+
val vendor = System.getProperty("java.vendor")
55+
if (vendor == "The Android Project") {
56+
System.loadLibrary(lib.libName.removePrefix("lib"))
57+
loadedLibs.add(lib)
58+
return
59+
}
60+
val osName = System.getProperty("os.name")!!.lowercase()
61+
val osArch = when (val osArch = System.getProperty("os.arch")!!.lowercase()) {
62+
"x86_64", "amd64" -> "X64"
63+
"aarch64", "arm64" -> "Arm64"
64+
else -> error("Unsupported arch: $osArch (os=$osName)")
65+
}
66+
val platform = when {
67+
"windows" in osName -> "mingw$osArch"
68+
"linux" in osName -> "linux$osArch"
69+
"mac" in osName || "darwin" in osName -> "macos$osArch"
70+
else -> error("Unsupported OS: $osName (arch=$osArch)")
71+
}
72+
val libFileName = lib.platformFileName[platform]
73+
?: error("Could not find library ${lib.libName} for platform $platform")
74+
val path = "/jni/$platform/$libFileName"
75+
val tempFile = File(tempDir, libFileName).apply {
76+
deleteOnExit()
77+
}
5278

53-
System.load(tempFile.absolutePath)
54-
loadedLibs.add(lib)
79+
val resource = checkNotNull(lib::class.java.getResourceAsStream(path)) {
80+
"Could not find shared library: $path"
81+
}
82+
resource.use { inputStream ->
83+
tempFile.outputStream().use {
84+
inputStream.copyTo(it)
5585
}
5686
}
87+
88+
System.load(tempFile.absolutePath)
5789
}
5890
}

0 commit comments

Comments
 (0)