- Contents
- Consuming Toolchains
- Specify custom toolchains for individual tasks
- Auto detection of installed toolchains
- Auto Provisioning
- Custom Toolchain locations
- Precedence
- Toolchains for plugin authors
默认来说,Gradle 使用运行Gradle 自己的Java 版本来构建JVM项目 ..
这并总是想要 …
在不同开发者的机器上使用不同的Java版本构建项目以及CI服务器上可能都会出现问题 ..
除此之外,你也许想要使用一个不支持运行Gradle 的Java 版本构建项目 …
Java Toolchain 由此而生(简单指的是工具链) 是一个工具的集合,通常来自本地JRE / JDK 安装被用来配置构建的不同方面 …
构建任务也许使用javac 作为它们的编译器,测试以及执行任务也许使用java 命令,并且javadoc 被用来生成文档 …
Consuming Toolchains(*)
一个构建能够全局定义工具链的目标是什么 - 通过指定Java 语言版本和厂商
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
执行这个构建(例如 gradle check) 现在将处理你以及其他人运行你的构建的各种事情 …
- 配置所有的编译,测试以及javadoc 任务去使用定义的工具链(可以不同于运行Gradle自己使用的Java 版本)
- Gradle 检测本地安装的JVMs
- Gradle 选择一个JRE/JDK 匹配构建的需求(例如JVM 支持JAVA 11)
- 如果匹配的JVM 不存在,它将会自动的下载匹配匹配的JDK(从AdoptOpenJdk)
工具链在Java 插件中得到支持(并且可以在任务中定义) 对于Groovy 插件,编译支持但是可能不支持Groovydoc 生成 .. 对于Scala 插件, 编译以及Scaladoc 生成都是支持的 …
Using toolchains by specific vendors
对于你的构建需要特定的JRE/JDK,你需要想为工具链定义特定厂商
JvmVendorSpec 拥有已知知名的JVM 厂商(它们由Gradle 组织并维护) .
这是一个优势Gradle 能够处理任何不一致的JDK 版本(通过完整的编码厂商信息)
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.ADOPTIUM
}
}
如果这个厂商你想要换成一个其他不知名的厂商,你也能够限制工具链去匹配必要的java.vendor系统属性的工具链 …
例如,匹配一个自定义厂商的工具链(它关心java.vendor属性是否包含匹配的字符串)
匹配时大小写不敏感的 ..
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.matching("customString")
}
}
Selecting toolchains by their 虚拟机实现
如果你的项目需要一个特定的实现,你能够基于实现过滤,当前可用的实现可以是:
- VENDOR_SPECIFIC
表现为一个占位符并且可匹配任何任何厂商的实现(例如: hotspot,zulu …)
- J9
仅匹配使用OpenJ9 / IBM J9运行时引擎的虚拟机实现
例如,为了使用IBM Semeru JVM,通过AdoptOpenJDK发行的 .. 你能够指定过滤器如下所述:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
vendor = JvmVendorSpec.IBM_SEMERU
implementation = JvmImplementation.J9
}
}
Java 主版本,厂商(如果需要) 以及实现(如果指定) 将会作为编译的输入以及测试执行的输入 ..
Specify custom toolchains for individual tasks
当你想要为某个特定的任务实现特定的工具链,你能够进行指定 ..
例如,Test任务暴露了一个JavaLauncher 属性 - 它能够定义启动测试的java 执行器是什么 …
如下所示,我们配置所有的java 编译任务使用JDK 8. 除此之外,我们引入了一个新的Test任务(它将通过使用JDK 14运行单元测试)
tasks.withType(JavaCompile).configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(8)
}
}
task('testsOn14', type: Test) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(14)
}
}
除此之外,在application子项目中,我们增加了额外的Java 执行任务去使用JDK 14运行我们的应用 ..
task('runOn14', type: JavaExec) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(14)
}
classpath = sourceSets.main.runtimeClasspath
mainClass = application.mainClass
}
依赖于这个任务,一个JRE 可能对于其他任务来说已经足够,然而对于(例如编译)需要一个JDK,默认来说Gradle 更加偏好安装JDK 而不是JRE(如果它们满足这些需求)
工具链工具提供器能够通过javaToolchains 扩展抓取 …
三个工具是可用的:
- JavaCompiler (由JavaCompile任务使用)
- JavaLauncher (由JavaExec 或者 Test 任务使用)
- JavadocTool 由Javadoc 任务使用
依靠Java executable 或者 Java home 与任务集成
任何任务能够配置Java Executable 的路径或者Java home 位置,能够从工具链中受益 ..
然而你或许不能应该直接关联一个工具链,它们有一些元数据 - 能够访问它们的全路径或者它们所属的Java 安装的路径 … ```groovy def compiler = javaToolchains.compilerFor { languageVersion = JavaLanguageVersion.of(11) }
tasks.withType(KotlinJvmCompile).configureEach { kotlinOptions.jdkHome = compiler.get().metadata.installationPath.asFile.absolutePath }
类似的,通过compiler.get().executablePath 能够获取给定工具链的javac 的完整路径 ..<br />但是请注意,这可能会急切地实现(并提供)工具链。
<a name="ObQUl"></a>
# Auto detection of installed toolchains
默认来说,Gradle 自动检测本地的JRE/JDK 安装,因此对于用户来说不需要额外的配置 ...<br />以下列出了通常的包管理,工具以及由JVM自动检测的位置 ...<br />JVM 自动检测已知工作方式:
- 操作系统特定的位置: Linux / MacOS / Windows
- 包管理器: [Asdf-vm](https://asdf-vm.com/#/),[Jabba](https://github.com/shyiko/jabba),[SDKMAN](https://sdkman.io/)
- [Maven Toolchain](https://maven.apache.org/guides/mini/guide-using-toolchains.html) 规范
在所有已检测的JRE /JDK 安装的集合中,根据[Toolchain Precedence Rules](https://docs.gradle.org/current/userguide/toolchains.html#sec:precedence) 抓取一个 ...
<a name="Wo116"></a>
## How to disable auto-detection
为了禁用自动检测,你能够使用 org.gradle.java.installations.auto-detect Gradle 属性 ...
- 要么 启动gradle 时提供参数 -Porg.gradle.java.installations.auto-detect=false
- 要么 放置org.gradle.java.installations.auto-detect=false 到gradle.properties文件中
<a name="G2zUQ"></a>
# 自动提供
如果Gradle 没有发现本地可用的工具链匹配构建的需求,它将自动的尝试从AdoptOpenJDK中下载. 默认他将请求一个HotSpot JDK(匹配当前操作系统以及架构的 JDK),提供的JDK 自动安装到 [Gradle User Home directory](https://docs.gradle.org/current/userguide/directory_layout.html#dir:gradle_user_home) .
> Gradle 仅仅会下载GA 发行版的JDK,这不支持任何早期访问版本(实验版本)
一旦提供的JDK 安装到Gradle 用户家目录中,那么这些JDK 对于自动建额就可见了(自动选择)并且能够被后续的构建使用,就像安装到系统上的其他JDK一样,因此自动提供仅仅在自动检测发现一个合适的JDK失败之后触发,自动提供仅仅会下载新的JDK 并且 不会涉及已经安装的JDK的更新 ...<br />任何自动配置的 JDK 都不会被自动配置重新访问和自动更新,即使有一个新的微小变化的版本可用 ...<br />默认来说,公共的[AdoptOpenJDK APIs](https://api.adoptopenjdk.net/) 能够用来检测并下载匹配的JDK ..
> 由于AdoptOpenJDK的改变并且它迁移了项目到 [Eclipse Adoptium](https://adoptium.net/),现在从Eclipse Adoptium 提供JDK的下载端点(或者IBM Semeru)下载,不再从 AdoptOpenJDK 构建
> 使用JvmVendorSpec.ADOPTOPENJDK 并且自动解析将会导致启用的警告 ...
如果你想要使用其他服务器(它们是兼容AdoptOpenJDK v3版本的API)进行自动提供,你能够指定Gradle 去使用不同的host ...<br />Gradle 属性使用示例如下:
```groovy
org.gradle.jvm.toolchain.install.adoptopenjdk.baseUri=https://api.company.net/
仅仅安全协议https是支持的,这需要确保在下载期间没有任何一个能够被干预(篡改) ..
Viewing and debugging toolchains
gradle 能够显示所有已经检测的工具链以及它们包含的元数据 …
举个例子,为了展示一个项目的所有工具链,可以运行:
gradle -q javaToolchains
此命令的输出如下:
gradle -q javaToolchains
- Options
| Auto-detection: Enabled
| Auto-download: Enabled- AdoptOpenJDK 1.8.0_242
| Location: /Users/username/myJavaInstalls/8.0.242.hs-adpt/jre
| Language Version: 8
| Vendor: AdoptOpenJDK
| Architecture: x86_64
| Is JDK: false
| Detected by: system property ‘org.gradle.java.installations.paths’- Microsoft JDK 16.0.2+7
| Location: /Users/username/.sdkman/candidates/java/16.0.2.7.1-ms
| Language Version: 16
| Vendor: Microsoft
| Architecture: aarch64
| Is JDK: true
| Detected by: SDKMAN!- OpenJDK 15-ea
| Location: /Users/user/customJdks/15.ea.21-open
| Language Version: 15
| Vendor: AdoptOpenJDK
| Architecture: x86_64
| Is JDK: true
| Detected by: environment variable ‘JDK16’- Oracle JDK 1.7.0_80
| Location: /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home/jre
| Language Version: 7
| Vendor: Oracle
| Architecture: x86_64
| Is JDK: false
| Detected by: macOS java_home
这有助于调试哪些工具链可用于构建、如何检测它们以及 Gradle 了解这些工具链的元数据类型。
How to disable auto provisioning
为了禁用自动提供,你能够使用org.gradle.java.installations.auto-download Gradle 属性..
- 要么 通过 -Porg.gradle.java.installations.auto-download=false
- 要么放置org.gradle.java.installations.auto-download= false 到gradle.properties中
Custom Toolchains locations
如果自动检测本地工具链是不足够的或者被禁用,它们也有额外的方式能够让Gradle 直到安装的toolchains ..
如果你的配置已经提供了指向安装的JVM的环境变量,你能够让Gradle 知道那些环境变量能够被它关心 … 加上环境变量 JDK8 / JRE14指向一个有效的java 安装,以下的指令能够让Gradle 知道解析这些环境变量并考虑这些安装(当查询一个匹配的工具链时)
org.gradle.java.installations.fromEnv = JDK8,JRE14
除此之外,你能够提供一个逗号分隔的列表(路径的列表 它们指定的使用org.gradle.java.installations.paths的属性)
例如在你的gradle.properties中可以指定Gradle 在检测 JVM时所查看的那些目录 …
Gradle 将会处理这些目录(尽可能的)作为安装,但是不会检测任何内嵌的目录 …
org.gradle.java.installations.paths=/custom/path./jdk1.8,/shared/jre11
自定义工具链不是优于自动检测的.如果自动检测打开,那么自定义工具链仍然能够被指定,但是它们将会扩展所有检测的JRE/JDK 位置 .. 在这些位置之间,还是通过工具链优先级规则 选择一个 …
Precedence
Gradle 将会排序所有的JDK/JRE安装 (根据构建的匹配工具链的规范) 并且将拿取第一个
排序规则基于以下规则:
- 运行Gradle 本身的安装作为首选(如果可以)
- JDK 优于 JRE
- 某些厂商优于未知名厂商
- ADOPTIUM
- ADOPTOPENJDK
- AMAZON
- APPLE
- AZUL
- BELLSOFT
- GRAAL_VM
- HEWLETT_PACKARD
- IBM
- IBM_SEMERU
- MICROSOFT
- ORACLE
- SAP
- everything else
- 更高的主版本优先
- 更高的微版本优先
- 根据词典顺序排序安装路径(用于确定性地决定相同类型、来自相同供应商和具有相同版本的安装的最后手段标准)
所有的规则形成了多个级别的分类标准,在它们所展示的顺序中,让我们通过例子来说明,
例如我们只有一个条件(仅仅只想要使用JAVA 17)并且我们的机制上安装了已检测到的
Oracle JRE v17.0.0,Oracle v17.0.1,Microsoft JDK 17.0.0,Microsoft JRE17.0.1,Microsoft JDK17.0.1,让我们假设Gradle 通过使用不同的主版本进行运行,
因此它不匹配工具链的规范(所以它不符合工具链规范(这是重点,否则该安装将优先于其他所有安装,并且我们的示例将提供较少的信息,那就是我们可能直接安装JAVA17并使用)
当我们应用上述的规则,它们进行排序我们将得到以下列表:
- Microsoft JDK 17.0.1
- Microsoft JDK 17.0.0
- Oracle JDK v17.0.0
- Microsoft JRE v17.0.1
- Oracle JRE v17.0.1
JRE结尾(优于应用了JDK 优于JRE的规则),然后在这两个类别中,在应用优先选择该供应商而不是 Oracle 的规则之后,Microsoft 安装首先结束 ..
然后相同的Microsoft JDK版本排序根据主版本优先的结果,应用再多的规则也不会改变这个最终顺序 …(只能获取一个此列表的子集)
Toolchains for plugin authors
为插件构建工具链 …
自定义任务需要来自JDK的工具(应该暴露一个Property
这个属性应该被声明一个@Nested input.
通过注册JavaToolchainService到插件或者任务中,它能够关联一个约定到这些属性中(通过包含此项目的来自java扩展的JavaToolchainSpec)
以下例子展示了如何使用默认的工具链作为约定(当允许用户独立的配置每一个任务的工具链时) ..
import javax.inject.Inject;
abstract class CustomTaskUsingToolchains extends DefaultTask {
@Nested
abstract Property<JavaLauncher> getLauncher()
@Inject
CustomTaskUsingToolchains() {
// Access the default toolchain
def toolchain = project.getExtensions().getByType(JavaPluginExtension.class).toolchain
// acquire a provider that returns the launcher for the toolchain
JavaToolchainService service = project.getExtensions().getByType(JavaToolchainService.class)
Provider<JavaLauncher> defaultLauncher = service.launcherFor(toolchain);
// use it as our default for the property
launcher.convention(defaultLauncher);
}
@TaskAction
def showConfiguredToolchain() {
println launcher.get().executablePath
println launcher.get().metadata.installationPath
}
}
plugins {
id 'java'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(8)
}
}
tasks.register('showDefaultToolchain', CustomTaskUsingToolchains)
tasks.register('showCustomToolchain', CustomTaskUsingToolchains) {
launcher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(16)
}
}
当属性正确的配置为@Nested, 他将自动的跟踪Java 主版本以及厂商以及实现(作为输入) 如果厂商和实现指定 …