-
Notifications
You must be signed in to change notification settings - Fork 6
Integrating JniGen
On the most basic level to use JniGen you need to
- Configure its annotation processor to run. This can be either during Java or Kotlin compilation or separately but must happen before C++ compilation
- Use its annotations in your Java code
- Include generated headers in your C++ code
-
Repository:
https://maven.pkg.github.com/gershnik/SimpleJNI
-
Java/KAPT Annotation processor
Group Id:io.github.gershnik
Artifact Id:smjni-jnigen-processor
Version: corresponds to releases on GitHub -
KSP Annotation processor
Group Id:io.github.gershnik
Artifact Id:smjni-jnigen-kprocessor
Version: corresponds to releases on GitHub -
Annotations
Group Id:io.github.gershnik
Artifact Id:smjni-jnigen-annotations
Version: corresponds to releases on GitHub
The instructions below are for Gradle. If you use something else to build your Java code you will need to figure out the equivalent steps.
For a complete example see build.gradle in samples/android/java
repositories {
google()
mavenCentral()
maven { url "https://github.com/gershnik/SimpleJNI/raw/maven" }
}
dependencies {
//JNI annotations
compileOnly("io.github.gershnik:smjni-jnigen-annotations:3.5")
//JNI code generator
annotationProcessor("io.github.gershnik:smjni-jnigen-processor:3.5")
}
//JniGen settings
def jniGenProps = new Object() {
//Where to put the generated files
//Make sure there is nothing else in that folder (it shouldn't even exist).
//This will allow removal of stale files
def generatedPath = "src/main/cpp/generated"
//Name of the file listing all other generated files
def outputListName = "outputs.txt"
//Additional classes to expose
def additionalClasses = ["java.lang.Byte"]
}
android {
//Pass options for JniGen
javaCompileOptions {
annotationProcessorOptions {
arguments = [
"smjni.jnigen.dest.path" : file(jniGenProps.generatedPath).path,
"smjni.jnigen.own.dest.path" : "true",
"smjni.jnigen.output.list.name": jniGenProps.outputListName,
"smjni.jnigen.expose.extra" : jniGenProps.additionalClasses.join(";").toString()
]
}
}
}
//This makes Gradle rebuild Java compilation (and so run annotation processor)
//when any of the generated files are missing
//Use libraryVariants if you are building a library
android.applicationVariants.all { variant ->
variant.javaCompileProvider.get().outputs.upToDateWhen {
def jniGenOutputList = file("${jniGenProps.generatedPath}/${jniGenProps.outputListName}")
if (!jniGenOutputList.exists()) {
return false
}
for(line in jniGenOutputList) {
if (!file("${jniGenProps.generatedPath}/$line").exists()) {
return false
}
}
return true
}
}
//Clean generated headers on project clean
task cleanJNIHeaders(type: Delete) {
delete file("${jniGenProps.generatedPath}")
}
clean.dependsOn cleanJNIHeaders
//Make Java compilation (and JniGen code generation) run before CMake build
tasks.whenTaskAdded { theTask ->
def match = theTask.name =~ ~/^buildCMake(.*)$/
if (match) {
def config;
switch(match.group(1)) {
case "RelWithDebInfo": config = "Release"; break
default: config = match.group(1); break;
}
theTask.dependsOn "compile${config}JavaWithJavac"
}
}
For a complete example see build.gradle in samples/android/kotlin-kapt
repositories {
google()
mavenCentral()
maven { url "https://github.com/gershnik/SimpleJNI/raw/maven" }
}
dependencies {
//JNI annotations
compileOnly("io.github.gershnik:smjni-jnigen-annotations:3.5")
//JNI code generator
kapt("io.github.gershnik:smjni-jnigen-processor:3.5")
}
//JniGen settings
def jniGenProps = new Object() {
//Where to put the generated files
//Make sure there is nothing else in that folder (it shouldn't even exist).
//This will allow removal of stale files
def generatedPath = "src/main/cpp/generated"
//Name of the file listing all other generated files
def outputListName = "outputs.txt"
//Additional classes to expose
def additionalClasses = ["java.lang.Byte"]
}
//Pass options for JniGen via KAPT
kapt {
useBuildCache = false
arguments {
arg("smjni.jnigen.dest.path", jniGenProps.generatedPath)
arg("smjni.jnigen.own.dest.path", "true")
arg("smjni.jnigen.output.list.name", jniGenProps.outputListName)
arg("smjni.jnigen.expose.extra", jniGenProps.additionalClasses.join(";").toString())
}
}
//This makes Gradle rebuild Kotlin compilation (and so run annotation processor)
//when any of the generated files are missing
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
outputs.upToDateWhen {
def jniGenOutputList = file("${jniGenProps.generatedPath}/${jniGenProps.outputListName}")
if (!jniGenOutputList.exists()) {
return false
}
for(line in jniGenOutputList) {
if (!file("${jniGenProps.generatedPath}/$line").exists()) {
return false
}
}
return true
}
}
//Clean generated headers on project clean
task cleanJNIHeaders(type: Delete) {
delete file("${jniGenProps.generatedPath}")
}
clean.dependsOn cleanJNIHeaders
//Make KAPT (and so JniGen code generation) run before CMake build
tasks.whenTaskAdded { theTask ->
def match = theTask.name =~ ~/^buildCMake(.*)$/
if (match) {
def config;
switch(match.group(1)) {
case "RelWithDebInfo": config = "Release"; break
default: config = match.group(1); break;
}
theTask.dependsOn "kapt${config}Kotlin"
}
}
For a complete example see build.gradle in samples/android/kotlin-ksp
repositories {
google()
mavenCentral()
maven { url "https://github.com/gershnik/SimpleJNI/raw/maven" }
}
dependencies {
//JNI annotations
compileOnly("io.github.gershnik:smjni-jnigen-annotations:${gradle.ext.jniGenVersion}")
//JNI code generator
ksp("io.github.gershnik:smjni-jnigen-kprocessor:${gradle.ext.jniGenVersion}")
}
//JniGen settings
def jniGenProps = new Object() {
//Where to put the generated files
//Make sure there is nothing else in that folder (it shouldn't even exist).
//This will allow removal of stale files
def generatedPath = "src/main/cpp/generated"
//Name of the file listing all other generated files
def outputListName = "outputs.txt"
//Additional classes to expose
def additionalClasses = ["java.lang.Byte"]
}
//Pass options for JniGen via KSP
ksp {
arg("smjni.jnigen.dest.path", jniGenProps.generatedPath)
arg("smjni.jnigen.own.dest.path", "true")
arg("smjni.jnigen.output.list.name", jniGenProps.outputListName)
arg("smjni.jnigen.expose.extra", jniGenProps.additionalClasses.join(";").toString())
}
//This makes Gradle rebuild Kotlin compilation (and so run annotation processor)
//when any of the generated files are missing
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
outputs.upToDateWhen {
def jniGenOutputList = file("${jniGenProps.generatedPath}/${jniGenProps.outputListName}")
if (!jniGenOutputList.exists()) {
return false
}
for(line in jniGenOutputList) {
if (!file("${jniGenProps.generatedPath}/$line").exists()) {
return false
}
}
return true
}
}
//Clean generated headers on project clean
task cleanJNIHeaders(type: Delete) {
delete file("${jniGenProps.generatedPath}")
}
clean.dependsOn cleanJNIHeaders
//Make KSP (and so JniGen code generation) run before CMake build
tasks.whenTaskAdded { theTask ->
def match = theTask.name =~ ~/^buildCMake(.*)$/
if (match) {
def config;
switch(match.group(1)) {
case "RelWithDebInfo": config = "Release"; break
default: config = match.group(1); break;
}
theTask.dependsOn "ksp${config}Kotlin"
}
}
- Building
-
User's Guide
Declaring Java Types
Accessing Methods and Fields
Representing Java Classes
Implementing Native Methods
Smart References
Error Handling
Obtaining JNIEnv
Initialization
Strings
Arrays
Direct Buffers
Booleans
Sizes -
JniGen Code Generator
Integrating JniGen
Annotations
Processor Options