Setup Guide
This setup guide covers the standard use-case of generating and integrating native bindings into a Java project with a main source set.
Prerequisites
Section titled “Prerequisites”You should have these things in place before you start:
- JVM 17 or above
- A Gradle project using Gradle v8.8 or above
Including the Plugin
Section titled “Including the Plugin”This will configure the project to download and use Jextract 22 which is determined from the Java toolchain.
plugins { `java-library` id("de.infolektuell.jextract") version "x.y.z"}
repositories { mavenCentral()}
java { toolchain { languageVersion = JavaLanguageVersion.of(25) }}plugins { id 'java-library' id 'de.infolektuell.jextract' version 'x.y.z'}
repositories { mavenCentral()}
java { toolchain { languageVersion = JavaLanguageVersion.of 25 }}Adding a Library
Section titled “Adding a Library”Libraries often consist of a name.h file and binaries like libname.dylib or name.dll.
Put them in your source folder like this:
Directorylib
Directorysrc
Directorymain
Directoryjava
Directorycom
Directoryexample
Directorygreeting
- greeting.java
Directorynative
Directorymacos
- libgreeting.dylib the macOS binary
Directorywindows
- greeting.dll the windows binary
Directorypublic
- greeting.h the header file
- build.gradle.kts
- settings.gradle.kts
Configuring the plugin
Section titled “Configuring the plugin”Configure the plugin via DSL extension, so it can find the library files.
jextract.libraries { val greeting by registering { header = layout.projectDirectory.file("src/main/public/greeting.h") headerClassName = "Greeting" targetPackage = "com.example.greeting" } sourceSets.named("main") { jextract.libraries.addLater(greeting) }}jextract.libraries { def greeting = register('greeting') { header = layout.projectDirectory.file("src/main/public/greeting.h") headerClassName = "Greeting" targetPackage = "com.example.greeting" } sourceSets.named("main") { jextract.libraries.addLater(greeting) }}Build and use
Section titled “Build and use”Now the project is ready for its first build.
gradlew.bat build./gradlew buildThis will result in the following output file structure:
Directory.gradle
Directoryjextract Cache for Jextract downloads and installations
- downloads
- installation
Directorylib
Directorybuild
- …
Directorygenerated
Directorysources
Directoryjextract
Directorygreeting the library bindings
Directorycom
Directoryexample
Directorygreeting
- Greeting.java the bindings to import and use in Java code
- …
- build.gradle.kts
- settings.gradle.kts
Loading libraries
Section titled “Loading libraries”There are mainly two approaches how the generated code can load and access the correct binaries. Please see this stackoverflow question for more details and explanation.
Automatic Loading
Section titled “Automatic Loading”The code searches in the OS-specific paths for the binary files and tries to load them via system.loadLibrary.
The java.library.path property can be augmented to search in more paths or in the deployed app distribution.
This approach is activated in a library config in the plugin DSL.
jextract.libraries { val greeting by registering { useSystemLoadLibrary = true libraries.add("greeting") }}jextract.libraries { def greeting = register('greeting') { useSystemLoadLibrary = true libraries.add("greeting") }}Manual Loading
Section titled “Manual Loading”Instead of configuring the libraries in the DSL, custom logic for loading the files can be implemented. This is a typical approach for bundling natives as resources of a jar file for more portable deployment.