melix / jmh-gradle-plugin

Integrates the JMH benchmarking framework with Gradle
Apache License 2.0
659 stars 88 forks source link

How to use java toolchain with plugin? #218

Closed austinarbor closed 1 year ago

austinarbor commented 2 years ago

It looks like some code was added to help use a configured java toolchain (https://github.com/melix/jmh-gradle-plugin/blob/master/src/main/java/me/champeau/jmh/WithJavaToolchain.java), but I can't seem to get it to work.

When I try

tasks.withType(me.champeau.jmh.JmhBytecodeGeneratorTask).configureEach {
    javaLauncher = javaToolchains.launcherFor {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

I get the error > error: invalid source release: 17

When I try

tasks.withType(me.champeau.jmh.JMHTask).configureEach {
    javaLauncher = javaToolchains.launcherFor {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

I get the error has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0

If I already have jdk17 in the shell, everything works fine. Can you let me know what I am doing wrong to use the toolchain?

Thanks

austinarbor commented 2 years ago

I also just tried

jmh {
    javaLauncher.set(
            javaToolchains.launcherFor {
                languageVersion = JavaLanguageVersion.of(17)
            }
    )
}

But that gave me the same error as the 2nd attempt above

bric3 commented 2 years ago

@austinarbor You may need to set this on the compile tasks as well.

Indeed the toolchain configures the default compileJava task but not the one that is created by the JMH Gradle plugin

This is what what I use (ignore the panama flags, options), to run Gradle with JDK 17 but run benchmarks of JDK 18 code.

Notice this code is snippet is kotlin script.

java {
  toolchain {
    languageVersion.set(JavaLanguageVersion.of(18))
  }
}
val launcher = javaToolchains.launcherFor(java.toolchain).get()

jmh {
  jvm.set(launcher.executablePath.asFile.absolutePath)
}

tasks {
  withType<JavaCompile>().configureEach {
    options.compilerArgs = listOf(
            "--add-modules", "jdk.incubator.foreign"
    )
    options.release.set(18)
    javaCompiler.set(project.javaToolchains.compilerFor(java.toolchain))
  }

  withType<JavaExec>().configureEach {
    environment("JAVA_LIBRARY_PATH", ".:${project.projectDir}/jni")
    jvmArgs("--enable-native-access=ALL-UNNAMED",
            "--add-modules", "jdk.incubator.foreign")
    javaLauncher.set(project.javaToolchains.launcherFor(java.toolchain))
  }

  withType<JmhBytecodeGeneratorTask>().configureEach {
    javaLauncher.set(project.javaToolchains.launcherFor(java.toolchain))
  }
}
austinarbor commented 2 years ago

@bric3 thanks for the suggestion - unfortunately that resulted in the same error for me java.lang.UnsupportedClassVersionError: ... has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0

What java version are you using when you run the commands? If I do everything with 17 set in my current shell it works fine - but once I switch to Java 8 to make sure the toolchain is working, it produces an error

bric3 commented 2 years ago

Do you have a reproducer?

austinarbor commented 2 years ago

@bric3 try running ./gradlew jmh on https://github.com/austinarbor/jmh-toolchain-issue with anything lower than 17

bric3 commented 2 years ago

Ah of course, I forgot to mention to set the jvm parameter in the jmh configuration, updating my comment above.

So basically in your reproducer you should add. I've kept the repetition of the javaToolchains.launcherFor but you might want to refactor this in a single variable.

diff --git i/build.gradle w/build.gradle
--- i/build.gradle
+++ w/build.gradle
@@ -16,6 +16,25 @@ java {
     }
 }

+jmh {
+    jvm = javaToolchains.launcherFor({
+        languageVersion = JavaLanguageVersion.of(17)
+    }).get().executablePath.asFile.absolutePath
+}
+
+tasks.withType(JavaCompile).configureEach {
+    javaCompiler = project.javaToolchains.compilerFor {
+        languageVersion = JavaLanguageVersion.of(17)
+    }
+}
+
+
+tasks.withType(JavaExec).configureEach {
+    javaLauncher = javaToolchains.launcherFor {
+        languageVersion = JavaLanguageVersion.of(17)
+    }
+}
+
 tasks.withType(me.champeau.jmh.JmhBytecodeGeneratorTask).configureEach {
     javaLauncher = javaToolchains.launcherFor {
         languageVersion = JavaLanguageVersion.of(17)
austinarbor commented 2 years ago

@bric3 thanks, that seems to get it working. I refactored into the below. Unfortunately it's still quite verbose, I wish there was an easier way. Do you know why the JavaCompile configuration is required? Based on gradle docs I thought that was handled automatically by the toolchain

  1. Setup all compile, test and javadoc tasks to use the defined toolchain which may be different than the one Gradle itself uses
def javaVersion = JavaLanguageVersion.of(17)
def compiler = javaToolchains.compilerFor {
    languageVersion = javaVersion
}

def launcher = javaToolchains.launcherFor {
    languageVersion = javaVersion
}

java {
    toolchain {
        languageVersion = javaVersion
    }
}

jmh {
    jvm = launcher.get().executablePath.asFile.absolutePath
}

tasks.withType(JavaCompile).configureEach {
    javaCompiler = compiler
}

tasks.withType(me.champeau.jmh.JmhBytecodeGeneratorTask).configureEach {
    javaLauncher = launcher
}
bric3 commented 2 years ago

Do you know why the JavaCompile configuration is required

That's because the toolchain support only configures the default one from the java plugin. I think this a prudent default form the gradle team.

austinarbor commented 2 years ago

Ah yea this makes total sense. For some reason my brain wasn't grokking that the JMH task was using its own compilation task. Thanks for all the help

TheMrMilchmann commented 1 year ago

I ran into the same issue just now and quickly prototyped #228 to make the interaction with toolchains (in my opinion) more intuitive.

melix commented 1 year ago

Fixed by https://github.com/melix/jmh-gradle-plugin/pull/228