Handling LWJGL natives with custom dependency configurations

A few thoughts from my side:

Yes, the final consumer has to say what it wants to select on its classpath. That’s the beauty of the system. A drawback for “native” Jars right now is that there is no default built into Gradle for this. Which means a consumer always needs to make some selection. I would like to write an issue at Gradle to discuss what could be done about that. As it not only concerns LWJGL but all libraries with native Jars.
We have a plugin that you can apply that configures some defaults. (But also adds tasks for jpackage.) I am thinking about extracting the variant selection part into a separate plugin. But first I want to start the general discussion if something like that could eventually become part of Gradle core.

For the variant design, there are certainly different options to design it. The following is what I would do after also looking at LWJGL as an example for some time (Here is an example using it and patching variants: GitHub - jjohannes/javarcade: Example used in presentations about Modularization and Dependency Management in Java projects)

  • I would not make a difference between Module System and not Module System. I am not sure I understand why there should be a distinction. It is a way of how Java is loading the Jars, but in the end the same Jars should be selected no matter if the Module System is used or not. Otherwise, things get unnecessarily complicated.
  • I think there is no need for compile time “native” variants. The Jars are only needed at runtime. At compile time, you only need the “main” Jar. So the standard “apiElements” variant should suffice.
  • Reiterating over this, I would no longer do what the docs do in the Component Metadata example (having variants with two Jars). Instead, I would add variants only to the native component and, in addition to the attributes, add a capability to them (aka feature variant). As I did here. The capability allows Gradle to select two different variants of the same component. Thus, I would add a rule that adds a dependency that points at the “native” variant via capability of the same component to the “main” component so that it automatically get pulled in. Unfortunately, component metadata rules do not support this yet. But in the published Gradle metdata you can do that. In my example, I add the dependencies to the “native” feature directly as I can’t do it in a rule. If I would be able to do it in the rule, the complete rule would look somehow like this:
      module("org.lwjgl:lwjgl$module") {
        // Add dependency to "natives" feature (mockup, as this is not yet available in the 
        // jvm-conflict-resolution plugin due to github.com/gradle/gradle/issues/30088)
        addRuntimeOnlyDependencyWithFeature("org.lwjgl:lwjgl$module", "natives")

        // Add serveral "natives" feature variants with different attributes
        addTargetPlatformVariant("natives",
          "natives-linux", LINUX, X86_64)
        addTargetPlatformVariant("natives",
          "natives-linux-arm64", LINUX, ARM64)
        addTargetPlatformVariant("natives",
          "natives-macos", MACOS, X86_64)
        addTargetPlatformVariant("natives",
          "natives-macos-arm64", MACOS, ARM64)
        addTargetPlatformVariant("natives",
          "natives-windows", WINDOWS, X86_64)
        addTargetPlatformVariant("natives",
          "natives-windows-arm64", WINDOWS, ARM64)
      }

I am almost gone for holidays, but I am very interested in getting this right for LWJGL as I created the issue you linked. If you continue on this, I would be happy to review a (Draft) PR. I think it is easier to discuss this on a PR we can all try out instead of here.
I will only be able to give more feedback in September though, when I am back.

1 Like