【问题标题】:Can we force the use of a JDK as Gradle Java toolchain?我们可以强制使用 JDK 作为 Gradle Java 工具链吗?
【发布时间】:2023-02-20 15:49:55
【问题描述】:

Gradle 6.7 引入了Java toolchains。

在文档中,他们声明Gradle 选择符合构建要求的 JRE/JDK ... 默认情况下,Gradle 更喜欢安装的 JDK 而不是 JRE ...(来自docs.gradle.org: Toolchains for JVM projects)。

因此,如果我们同时安装了 JRE 和 JDK,则选择 JDK。

问题:

假设用户只安装了一个 JRE。

然而,我们希望使用 Java 工具链通过 Gradle(JavaExec 任务)运行我们的应用程序,但必须确保使用 JDK 运行,因为该应用程序依赖于 tools.jar,它不是 JRE 的一部分。

问题:

在使用 Java 工具链时,是否可以强制 Gradle 将 JDK 用于所有任务(包括运行/启动),而不仅仅是编译? (请参阅以下带注释的最小示例)

// This build.gradle should ensure that the application is run using a JDK of version 9 
plugins {
    id 'application'
}
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(9)
        // QUESTION: How to force JDK here? <------
    }
}
// for JavaExec task runJar
tasks.withType(JavaExec).configureEach {
    javaLauncher = javaToolchains.launcherFor(java.toolchain)
}
task runJar(type: JavaExec) {
    classpath = files(jar.archiveFile)
}
...

【问题讨论】:

  • 这回答了你的问题了吗? How do I tell Gradle to use specific JDK version?
  • @MartinZeitler:不,这没有回答我的问题。我不关心使用哪个 Java 版本来运行Gradle守护进程,我也不想手动将 JDK 路径设置到某个位置。我想使用 Java 工具链来构建和运行,并且在这两种情况下都想使用 JDK,而不是 JRE。但是感谢您参考另一个问题!
  • JDK 包含 JRE ...并且 Gradle 将链接到 rt.jar,无论您是否喜欢。我对此非常确定,因为如果没有它在类路径上,我的 Gradle 插件 javadocs 将无法构建。

标签: java gradle build.gradle build-system gradle-java-toolchain


【解决方案1】:

您使用的是什么工具?如果是IntelliJ,那么

IntelliJ 中的一项功能,如果配置了 java 工具链,它会在哪里查找,如果配置了,那么我就不可能在其中进行不匹配的配置:

运行配置 项目结构 > 项目SDK 项目结构 > 项目语言水平

enter image description here

【讨论】:

  • 我从命令行运行我的 Gradle 脚本,不使用任何特定工具。
【解决方案2】:

这解决方案我终于想出了:

我现在在我的项目中使用存储在settings.gradle 文件中的org.gradle.java.installations.auto-detect=false。在 Gradle 中使用 Java 工具链时,这将忽略任何本地安装的 Java 版本。

因此,它将下载一个合适的JDK在第一次运行时,将在以后的运行中重用这个 JDK。

上行空间:我们确保即使本地 JRE 存在,我们也会下载 JDK(例如,我们可以确定 tools.jar 存在)。

缺点:如果机器上存在匹配的 JDK,我们还会下载一个 JDK。

【讨论】:

    【解决方案3】:

    对于我们这些根据业务需求在构建机器上没有互联网的人来说,叹, https://docs.gradle.org/current/userguide/toolchains.html 描述按供应商选择工具链:

    java {
        toolchain {
    ...
            vendor = JvmVendorSpec.ADOPTIUM // or vendor = JvmVendorSpec.matching("Private Build") in my case. find the Vendor = value you need with ./gradlew -q javaToolchains
        }
    }
    

    甚至完整的自定义工具链位置:

    org.gradle.java.installations.fromEnv=JDK8,JRE17 //来自环境变量 org.gradle.java.installations.paths=/custom/path/jdk1.8,/shared/jre11

    【讨论】:

      【解决方案4】:

      总是必须先添加rt.jar:

      task runJar(type: JavaExec) {
          classpath = files(new File(System.getProperty('java.home') + File.separator + 'lib' + File.separator + 'rt.jar'))
          classpath += files(jar.archiveFile)
          ...
      }
      runJar.onlyIf {
          new File(System.getProperty('java.home') + File.separator + 'lib' + File.separator + 'rt.jar')).exists()
      }
      

      这可能仍然需要 jar.archiveFile 内的 mainClassName。使用JavaExec可以设置任何environment变量...包括。 JAVA_HOME,因此可以根据任务交替使用。但是也可以使用 Exec 任务然后直接运行 java -jar some.jar。
      我什至不太确定这些“仅限运行时”的 JRE 发行版是否仍然存在?
      我只知道没有tools.jar

      【讨论】:

      • “一个人总是必须先添加 rt.jar”......那不是真的,为什么我必须显式添加 rt.jar(无论如何它应该在引导路径上?我的问题中所述的 runJar 任务运行良好没问题。是的,有“仅运行时”的 JRE,我需要确保 Java 工具链选择(并在必要时下载)JDK,因为我们依赖位于 tools.jar 中的 JDI。遗憾的是,您的回答确实如此不包含与 Java 工具链相关的任何内容。(旁注:你是对的,我们将 jar 配置为在其清单中有一个主类)
      • java.toolchain 将在没有 JDK 时下载;见~/.gradle/jdks。而且我仍然没有在我的包管理器中找到任何单独的 JRE 包……Oracle/Sun Java 的分发方式与此类似。所以通常应该可以全局强制使用~/.gradle/jdks/xyz(最初不存在),但是可以写gradle.properties,以便在第二次运行时使用;还有org.gradle.java.installations.auto-detect=false。甚至可以为每个任务指定它:docs.gradle.org/current/userguide/…
      • 插件代码提供了更多的灵活性(Java 可能比 Groovy 更容易编写):docs.gradle.org/current/userguide/toolchains.html#sec:plugins
      • 在我的例子中,classpath 只是被配置 - 而不是给出......这意味着我可以将它链接到我想要的任何版本 rt.jar。如果没有运行时 rt.jar,则不会链接任何内容(尽管这与 Javadoc 任务相当相关)。
      • 刚找到任务:javaToolchains,它列出了所有任务,并告诉它是否是 JDK。
      猜你喜欢
      • 1970-01-01
      • 2021-03-27
      • 1970-01-01
      • 2023-01-22
      • 1970-01-01
      • 2021-01-17
      • 2017-10-15
      • 2017-06-19
      • 1970-01-01
      相关资源
      最近更新 更多