# Loading native things not twice

**URL:** <https://discuss.gradle.org/t/loading-native-things-not-twice/15180>\
**Category:** Help/Discuss\
**Created:** [March 15, 2016, 7:58am UTC](https://discuss.gradle.org/t/loading-native-things-not-twice/15180 "2016-03-15T07:58:56Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![moley](https://avatars.discourse-cdn.com/v4/letter/m/3d9bf3/32.png) [@moley](https://discuss.gradle.org/u/moley)\
**Post date:** [March 15, 2016, 7:58am UTC](https://discuss.gradle.org/t/loading-native-things-not-twice/15180/1 "2016-03-15T07:58:56Z")

</div>

Hi anyone,

we wrote a plugin to handle sever lifecycles (e.g. database and so on). For the windows part we use winp library of jenkins to determine the list of processes in windows. This lib contains native parts so we get the following error when using it:

Caused by: java.lang.UnsatisfiedLinkError: Native Library C:…gradle\caches\modules-2\files-2.1\org.jvnet.winp\winp\1.23\7ea543f14a8108a0e20491202d7e25a2f72859c5\winp.59602D8CF2F93C3D220D46F4C7564C94.dll already loaded in another classloader

So far it is pretty clear. My question: Is there a mechanism in gradle, that can handle such things, especially when we want to use the gradle daemon?

Looking forward to your replies.  
Cheers  
Markus

---

<div class="post-metadata">

**Author:** ![Ealrann](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/ealrann/32/8268_2.png) [@Ealrann](https://discuss.gradle.org/u/Ealrann)\
**Post date:** [January 17, 2020, 8:37pm UTC](https://discuss.gradle.org/t/loading-native-things-not-twice/15180/2 "2020-01-17T20:37:29Z")

</div>

Hello,  
I ran into the same problem. I try to make a custom task which depends on a native jar, so I get the message “Library is already loaded in another ClassLoader”.  
Did you find any solution to this problem? (except than disabling the daemon mode?)

---

<div class="post-metadata">

**Author:** ![jendrik](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/jendrik/32/7964_2.png) [@jendrik](https://discuss.gradle.org/u/jendrik)\
**Post date:** [January 24, 2020, 7:49am UTC](https://discuss.gradle.org/t/loading-native-things-not-twice/15180/3 "2020-01-24T07:49:51Z")

</div>

@Ealrann if I understand correctly, this should be solved by only putting only one “native jar” on the classpath depending on the operating system used. The best way to do that is to make sure the module you depend on provides different _variants_ for different operating systems so that Gradle can automatically select the right one. You can add the variants to libraries with POM metadata using a component metadata rule. In the docs, we even use LWGJ as an example. Maybe you can use that directly. 🙂

[https://docs.gradle.org/current/userguide/component\_metadata\_rules.html#adding\_variants\_for\_native\_jars](https://docs.gradle.org/current/userguide/component_metadata_rules.html#adding_variants_for_native_jars)

---

<div class="post-metadata">

**Author:** ![Ealrann](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/ealrann/32/8268_2.png) [@Ealrann](https://discuss.gradle.org/u/Ealrann)\
**Post date:** [January 24, 2020, 10:15am UTC](https://discuss.gradle.org/t/loading-native-things-not-twice/15180/4 "2020-01-24T10:15:12Z")

</div>

@jendrik  
Indeed, it’s working! Thank you very much.

However, I’m not sure we talked about the same problem (well, maybe I don’t understand everything haha):  
We don’t declare the natives for different platforms in our dependencies (otherwise our code would simply crash). The task works the first time we launch it, but when we run it again, Gradle try to reload the dependencies, so the task fail: “Library is already loaded in another ClassLoader”.  
A temporary solution was to:

- `gradle --stop`
- disable the gradle daemon mode

* * *

For the log (could help somebody else): I replaced this code:

```gradle
project.ext.lwjglVersion = "3.2.3"

switch (OperatingSystem.current()) {
	case OperatingSystem.LINUX:
		project.ext.lwjglNatives = "natives-linux"
		break
	case OperatingSystem.MAC_OS:
		project.ext.lwjglNatives = "natives-macos"
		break
	case OperatingSystem.WINDOWS:
		project.ext.lwjglNatives = "natives-windows"
		break
}

dependencies {
	implementation "org.lwjgl:lwjgl:$lwjglVersion"
	implementation "org.lwjgl:lwjgl-shaderc:$lwjglVersion"
	runtimeOnly "org.lwjgl:lwjgl:$lwjglVersion:$lwjglNatives"
	runtimeOnly "org.lwjgl:lwjgl-shaderc:$lwjglVersion:$lwjglNatives"
}

```

By this one:

```gradle
project.ext.lwjglVersion = "3.2.3"
def osArch = System.getProperty("os.arch")
project.ext.arch = osArch.startsWith("armv8") || osArch.contains("64") ? "x86-64" : "x86"

switch ( OperatingSystem.current() ) {
	case OperatingSystem.WINDOWS:
		project.ext.OS = "windows"
		break
	case OperatingSystem.LINUX:
		project.ext.OS = "linux"
		break
	case OperatingSystem.MAC_OS:
		project.ext.OS = "macos"
		break
}

class LwjglRule implements ComponentMetadataRule { //val os: String, val arch: String, val classifier: String)
	private def nativeVariants = [
		[os: OperatingSystemFamily.LINUX, arch: "arm32", classifier: "natives-linux-arm32"],
		[os: OperatingSystemFamily.LINUX, arch: "arm64", classifier: "natives-linux-arm64"],
		[os: OperatingSystemFamily.LINUX, arch: "x86-64", classifier: "natives-linux"],
		[os: OperatingSystemFamily.WINDOWS, arch: "x86", classifier: "natives-windows-x86"],
		[os: OperatingSystemFamily.WINDOWS, arch: "x86-64", classifier: "natives-windows"],
		[os: OperatingSystemFamily.MACOS, arch: "x86-64", classifier: "natives-macos"]
	]

	@javax.inject.Inject
	ObjectFactory getObjects() { }

	void execute(ComponentMetadataContext context) {
		context.details.withVariant("runtime") {
			attributes {
				attributes.attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(OperatingSystemFamily, "none"))
				attributes.attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(MachineArchitecture, "none"))
			}
		}
		nativeVariants.each { variantDefinition ->
			context.details.addVariant("${variantDefinition.classifier}-runtime", "runtime") {
				attributes {
					attributes.attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(OperatingSystemFamily, variantDefinition.os))
					attributes.attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(MachineArchitecture, variantDefinition.arch))
				}
				withFiles {
					addFile("${context.details.id.name}-${context.details.id.version}-${variantDefinition.classifier}.jar")
				}
			}
		}
	}
}

configurations["runtimeClasspath"].attributes {
	attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(OperatingSystemFamily, "$project.ext.OS"))
	attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(MachineArchitecture, "$project.ext.arch"))
}

dependencies {
	components {
		withModule("org.lwjgl:lwjgl", LwjglRule)
		withModule("org.lwjgl:lwjgl-shaderc", LwjglRule)
	}
	implementation "org.lwjgl:lwjgl:$lwjglVersion"
	implementation "org.lwjgl:lwjgl-shaderc:$lwjglVersion"
}

```

---

<div class="post-metadata">

**Author:** ![jendrik](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/jendrik/32/7964_2.png) [@jendrik](https://discuss.gradle.org/u/jendrik)\
**Post date:** [January 24, 2020, 11:26am UTC](https://discuss.gradle.org/t/loading-native-things-not-twice/15180/5 "2020-01-24T11:26:05Z")

</div>

@Ealrann good to hear that it works! Although I indeed misunderstood the issue. Curious why this fixed it. How are the inputs to your custom task defined? Are you using `configurations.runtimeClasspath` as input of some sorts?

---

<div class="post-metadata">

**Author:** ![Ealrann](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/ealrann/32/8268_2.png) [@Ealrann](https://discuss.gradle.org/u/Ealrann)\
**Post date:** [January 24, 2020, 12:38pm UTC](https://discuss.gradle.org/t/loading-native-things-not-twice/15180/6 "2020-01-24T12:38:03Z")

</div>

Yeah, I don’t understand neither. So I double checked, and both times, I had a better behavior with the `dependencies { components { withModule("org.lwjgl:lwjgl", LwjglRule)`. But well, maybe I did something wrong somewhere…

> [@jendrik](#):
>
> How are the inputs to your custom task defined

I define first an incremental task:

```gradle
public abstract class GradleShaderc extends DefaultTask
{
	@Incremental
	@PathSensitive(PathSensitivity.NAME_ONLY)
	@InputDirectory
	abstract DirectoryProperty getInputDir();

	@OutputDirectory
	abstract DirectoryProperty getOutputDir();
	
	@TaskAction
	void compileShader(InputChanges inputChanges)
	{
		final var inputDir = getInputDir();
		final var outputDir = getOutputDir();

```

And then I configure the task in a build.gradle:

```gradle
shadercCompile {
	inputDir = file("src/main/shader/")
	outputDir = file("src/main/resources/")
}

```

> [@jendrik](#):
>
> Are you using `configurations.runtimeClasspath` as input of some sorts?

No.
