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 21 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 25 which is determined from the Java toolchain.
// build.gradle.ktsplugins { `java-library` id("de.infolektuell.jextract") version "x.y.z"}
repositories { mavenCentral()}
java { toolchain { languageVersion = JavaLanguageVersion.of(25) }}// build.gradleplugins { 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.
// build.gradle.ktsjextract.libraries { val greeting by registering { header = layout.projectDirectory.file("src/main/public/greeting.h") headerClassName = "Greeting" targetPackage = "com.example.greeting" } sourceSets.main { jextract.libraries.addLater(greeting) }}// build.gradlejextract.libraries { def greeting = register('greeting') { header = layout.projectDirectory.file("src/main/public/greeting.h") headerClassName = "Greeting" targetPackage = "com.example.greeting" } sourceSets.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
Directoryclasses
Directoryjextract
- java
Directorygreeting Generated compiled classes for the library bindings
- …
Directorysources
Directoryjextract
Directoryjava
- greeting the library bindings
- …
- …
- 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 by their name 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 Jextract with the --use-system-load-library command line option and can be configured in a library config in the plugin DSL.
// build.gradle.ktsjextract.libraries { val greeting by registering { useSystemLoadLibrary = true libraryPath.add(layout.projectDirectory.dir("src/main/lib/<os>/<arch>")) }}// build.gradlejextract.libraries { register('greeting') { useSystemLoadLibrary = true libraryPath.add(layout.projectDirectory.dir("src/main/lib/<os>/<arch>")) }}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.
The implementation has to extract and load the binary files using System.load.
The build doesn’t need further configuration.