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:

build.gradle
plugins {
	id 'java'
	id 'dev.nokee.jni-library'
	id 'dev.nokee.cpp-language'
}

group = 'com.example.greeter'
build.gradle.kts
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:

build.gradle
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}"
	}
}
build.gradle.kts
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.