JNI Library Resource Path Configuration
You can open this sample inside an IDE using the IntelliJ native importer or Eclipse Buildship. |
This sample shows how a Java Native Interface (JNI) library can configure the resource path of the native component inside the JAR. The library has no dependencies, and the build has a minimal configuration.
In this sample, we are configuring the resource path of a JNI library implemented in Java and C++; however, this applies to other JVM and native languages as well.
The resource path is derived from the project’s group by default.
For example, if the project group is com.example.greeter
, the resource path for the shared library will be com/example/greeter
.
Given the following build script:
plugins {
id 'java'
id 'dev.nokee.jni-library'
id 'dev.nokee.cpp-language'
}
group = 'com.example.greeter'
plugins {
id("java")
id("dev.nokee.jni-library")
id("dev.nokee.cpp-language")
}
group = "com.example.greeter"
We can see the effect of configuring the project group:
$ ./gradlew assemble BUILD SUCCESSFUL 4 actionable tasks: 4 executed
$ jar tf ./build/libs/jni-library-with-resource-path.jar META-INF/ META-INF/MANIFEST.MF com/ com/example/ com/example/greeter/ com/example/greeter/NativeLoader.class com/example/greeter/Greeter.class com/example/greeter/libjni-library-with-resource-path.dylib
If is also possible to change the resource path value for each variant as follow:
library {
variants.configureEach {
String osName
if (targetMachine.operatingSystemFamily.windows) {
osName = 'windows'
} else if (targetMachine.operatingSystemFamily.linux) {
osName = 'linux'
} else if (targetMachine.operatingSystemFamily.macOs) {
osName = 'macos'
} else {
throw new GradleException('Unknown operating system family')
}
String architectureName
if (targetMachine.architecture.is32Bit()) {
architectureName = 'x86'
} else if (targetMachine.architecture.is64Bit()) {
architectureName = 'x86-64'
} else {
throw new GradleException('Unknown architecture')
}
resourcePath = "libs/${osName}-${architectureName}"
}
}
library {
variants.configureEach {
val osName = when {
targetMachine.operatingSystemFamily.isWindows -> "windows"
targetMachine.operatingSystemFamily.isLinux -> "linux"
targetMachine.operatingSystemFamily.isMacOs -> "macos"
else -> throw GradleException("Unknown operating system family")
}
val architectureName = when {
targetMachine.architecture.is32Bit -> "x86"
targetMachine.architecture.is64Bit -> "x86-64"
else -> throw GradleException("Unknown architecture")
}
resourcePath.set("libs/${osName}-${architectureName}")
}
}
$ ./gradlew assemble -PconfigureViaDsl BUILD SUCCESSFUL 4 actionable tasks: 1 executed, 3 up-to-date
$ jar tf ./build/libs/jni-library-with-resource-path.jar META-INF/ META-INF/MANIFEST.MF com/ com/example/ com/example/greeter/ com/example/greeter/NativeLoader.class com/example/greeter/Greeter.class libs/ libs/macos-x86-64/ libs/macos-x86-64/libjni-library-with-resource-path.dylib
When the project configures multiple target machines, each native component will be placed inside their own variant aware resource path. See the sample on configuring target machines.
For more information, see JNI Library Plugin and C++ Language Plugin reference chapters.