Skip to content

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.

You should have these things in place before you start:

  • JVM 21 or above
  • A Gradle project using Gradle v8.8 or above

This will configure the project to download and use Jextract 25 which is determined from the Java toolchain.

Minimal build script for a Java library
// build.gradle.kts
plugins {
`java-library`
id("de.infolektuell.jextract") version "x.y.z"
}
repositories {
mavenCentral()
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(25)
}
}

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

Configure the plugin via DSL extension, so it can find the library files.

Adding a Jextract library to a Java project
// build.gradle.kts
jextract.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)
}
}

Now the project is ready for its first build.

Building the project
gradlew.bat build

This 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

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.

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.

Configuring a library to load its binaries from the library path
// build.gradle.kts
jextract.libraries {
val greeting by registering {
useSystemLoadLibrary = true
libraryPath.add(layout.projectDirectory.dir("src/main/lib/<os>/<arch>"))
}
}

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.