6.7.0 - Alpha11 - 修复 Gradle 构建脚本 Java 与 Kotlin 的 JVM 目标版本一致性问题

This commit is contained in:
SuperMonster003
2025-11-13 00:22:34 +08:00
parent 8703d22935
commit 6dfdb81106
9 changed files with 248 additions and 156 deletions

View File

@@ -1,6 +1,7 @@
package org.autojs.build
import org.gradle.api.Action
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.CopySpec
@@ -251,16 +252,16 @@ object Utils {
val installer = {
project.logInfo("[JvmConv] Detected Android plugin in module='${project.path}', installing configuration")
// Java: Use Toolchain (module-level + task-level), do not set --release.
// zh-CN: Java: 使用 Toolchain (模块级 + 任务级), 不要设置 --release.
System.getProperty("gradle.java.version.select").let { ver ->
configureJavaToolchainLanguageLevel(project, ver)
configureJavaToolchainForAllJavaCompile(project, ver)
configureKotlinJvmToolchain(project, ver)
}
configureJavaToolchainLanguageLevel(project, versions.javaVersionInt)
configureJavaToolchainForAllJavaCompile(project, versions.javaVersionInt)
// Kotlin: Continue lazy configuration to set jvmTarget.
// zh-CN: Kotlin: 继续懒配置设置 jvmTarget.
configureKotlinJvmTargetLazily(project, versions)
System.getProperty("gradle.jvm.target.effective").let { ver ->
configureAndroidCompileOptions(project, ver)
configureKotlinJvmTargetLazily(project, ver)
}
project.logInfo("[JvmConv] Installed Java toolchain (module+tasks) and Kotlin jvmTarget for '${project.path}'")
}
@@ -271,7 +272,7 @@ object Utils {
// Module-level toolchain: Let AGP/Gradle know which JDK language level should be used for this module.
// zh-CN: 模块级 Toolchain: 让 AGP/Gradle 知道本模块应使用的 JDK 语言级别.
private fun configureJavaToolchainLanguageLevel(project: Project, target: Int) {
private fun configureJavaToolchainLanguageLevel(project: Project, target: String) {
val javaExt = project.extensions.findByType(JavaPluginExtension::class.java)
if (javaExt == null) {
project.logWarn("[JvmConv] JavaPluginExtension not found in '${project.path}', skip module-level toolchain")
@@ -286,9 +287,24 @@ object Utils {
}
}
private fun configureKotlinJvmToolchain(project: Project, target: String) {
project.plugins.withId("org.jetbrains.kotlin.android") {
project.extensions.findByName("kotlin")?.let { kotlinExt ->
runCatching {
kotlinExt.javaClass.getMethod("jvmToolchain", Int::class.java)
.invoke(kotlinExt, target.toInt())
}.onSuccess {
project.logInfo("[JvmConv] Kotlin jvmToolchain set to $target for '${project.path}'")
}.onFailure {
project.logError("[JvmConv] Set Kotlin jvmToolchain failed on '${project.path}': ${it.message}", it)
}
}
}
}
// Task-level Toolchain: Specify javaCompiler for all JavaCompile tasks, without setting --release (prohibited by AGP).
// zh-CN: 任务级 Toolchain: 对所有 JavaCompile 指定 javaCompiler, 且不要设置 --release (AGP 禁止).
private fun configureJavaToolchainForAllJavaCompile(project: Project, target: Int) {
private fun configureJavaToolchainForAllJavaCompile(project: Project, target: String) {
val toolchains = runCatching {
project.extensions.getByType(JavaToolchainService::class.java)
}.onFailure {
@@ -309,6 +325,37 @@ object Utils {
})
}
// 将 Android 的 compileOptions.sourceCompatibility/targetCompatibility 设置为给定目标 (如 "24"), 确保与 Kotlin 一致
// zh-CN: 使用反射避免对 AGP 具体类型的直接依赖; 兼容 application/library.
private fun configureAndroidCompileOptions(project: Project, target: String) {
val androidExt = project.extensions.findByName("android") ?: run {
project.logWarn("[JvmConv] Android extension not found in '${project.path}', skip compileOptions alignment")
return
}
runCatching {
val compileOptions = androidExt.javaClass.methods
.firstOrNull { it.name == "getCompileOptions" && it.parameterTypes.isEmpty() }
?.invoke(androidExt) ?: return@runCatching project.logWarn("[JvmConv] compileOptions not found on android extension for '${project.path}'")
val javaVersionClass = Class.forName("org.gradle.api.JavaVersion")
val javaVersion = JavaVersion.toVersion(target)
val setSource = compileOptions.javaClass.methods.firstOrNull {
it.name == "setSourceCompatibility" && it.parameterTypes.size == 1 && it.parameterTypes[0] == javaVersionClass
} ?: throw IllegalStateException("setSourceCompatibility(JavaVersion) not found")
val setTarget = compileOptions.javaClass.methods.firstOrNull {
it.name == "setTargetCompatibility" && it.parameterTypes.size == 1 && it.parameterTypes[0] == javaVersionClass
} ?: throw IllegalStateException("setTargetCompatibility(JavaVersion) not found")
setSource.invoke(compileOptions, javaVersion)
setTarget.invoke(compileOptions, javaVersion)
project.logInfo("[JvmConv] Android compileOptions source/target set to Java $target for '${project.path}'")
}.onFailure {
project.logError("[JvmConv] Configure Android compileOptions failed on '${project.path}': ${it.message}", it)
}
}
// Configure jvmTarget for KotlinCompile tasks:
// Use configureEach for lazy configuration on task creation;
// Compatible with old and new APIs.
@@ -316,8 +363,8 @@ object Utils {
// 为 KotlinCompile 任务设置 jvmTarget:
// 使用 configureEach, 任务实现时自动应用;
// 兼容新旧 API.
private fun configureKotlinJvmTargetLazily(project: Project, versions: Versions) {
val desiredStr = versions.javaVersionString // e.g. "22"
private fun configureKotlinJvmTargetLazily(project: Project, target: String) {
val desiredStr = target // e.g. "22"
val desiredEnumName = "JVM_${desiredStr}" // e.g. "JVM_22"
project.logInfo("[JvmConv] Will configure Kotlin jvmTarget lazily to '$desiredEnumName' in '${project.path}'")

View File

@@ -2,7 +2,6 @@ package org.autojs.build
import org.autojs.build.Utils.getOrNull
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.execution.TaskExecutionGraph
@@ -10,7 +9,6 @@ import org.gradle.kotlin.dsl.extra
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.*
import kotlin.properties.Delegates
import kotlin.text.RegexOption.IGNORE_CASE
class Versions @JvmOverloads constructor(
@@ -18,15 +16,16 @@ class Versions @JvmOverloads constructor(
filePath: String = "${project.rootDir}/version.properties",
) {
private val gradle = project.gradle
private val logger = project.logger
private val currentVersionInt = JavaVersion.current().majorVersion.toInt()
private val bp = BuildProperties.loadFrom(filePath)
private val javaVersionMinSuggested: Int = bp.requireInt("JAVA_VERSION_MIN_SUGGESTED")
private val javaVersionCurrentInt = JavaVersion.current().majorVersion.toInt()
private val javaVersionMinSupported: Int = bp.requireInt("JAVA_VERSION_MIN_SUPPORTED")
private val javaVersionMaxSupported: Int = bp.requireInt("JAVA_VERSION_MAX_SUPPORTED")
private val javaVersionInt: Int = System.getProperty("gradle.java.version.select").toInt()
private val javaVersionInfoSuffix: String = System.getProperty("gradle.java.version.suffix", "")
private var isBuildNumberAutoIncremented = false
private val minBuildTimeGap = Utils.hours2Millis(0.75)
@@ -41,93 +40,12 @@ class Versions @JvmOverloads constructor(
val appVersionCode = bp.requireInt("VERSION_BUILD")
val vscodeExtRequiredVersion = bp.requireString("VSCODE_EXT_REQUIRED_VERSION")
private val javaVersionMinSupported: Int = bp.requireInt("JAVA_VERSION_MIN_SUPPORTED")
var javaVersionInt by Delegates.notNull<Int>()
var javaVersionInfoSuffix by Delegates.notNull<String>()
val javaVersion: JavaVersion
get() = JavaVersion.toVersion(javaVersionInt)
val javaVersionString: String
get() = javaVersion.toString()
init {
validateCurrentVersion()
determineJavaVersion().also { (javaVersionInt, javaVersionInfoSuffix) ->
this.javaVersionInt = javaVersionInt
this.javaVersionInfoSuffix = javaVersionInfoSuffix
}
}
private fun validateCurrentVersion() {
if (gradle.extra.getOrNull<Boolean>(VALIDATED_EXTRA_KEY) == true) {
return
}
if (currentVersionInt < javaVersionMinSupported) {
throw GradleException("Current Gradle JDK version [$currentVersionInt] does not meet the minimum requirement which [$javaVersionMinSupported] is needed.")
}
if (currentVersionInt < javaVersionMinSuggested) {
val suffix = if (javaVersionMaxSupported > 0) " (but not higher than [$javaVersionMaxSupported])" else ""
logger.error("It is recommended to upgrade current Gradle JDK version [$currentVersionInt] to [$javaVersionMinSuggested] or higher$suffix.")
}
if (currentVersionInt > javaVersionMaxSupported) {
val suffix = if (javaVersionMaxSupported > javaVersionMinSuggested) " or lower (but not lower than [$javaVersionMinSuggested])" else ""
logger.error("It is recommended to downgrade current Gradle JDK version [$currentVersionInt] to [$javaVersionMaxSupported]$suffix, as Gradle may be not compatible with JDK [$currentVersionInt] for now.")
}
gradle.extra.set(VALIDATED_EXTRA_KEY, true)
}
private fun determineJavaVersion(): Pair<Int, String> {
var javaVersionInfoSuffix = ""
gradle.extra.getOrNull<Int>("javaVersionOverriddenByUser")?.let {
javaVersionInfoSuffix += " [user-specified]"
return it to javaVersionInfoSuffix
}
var versionInt = JavaVersion.current().majorVersion.toInt()
run tryAdjustJavaVersionByKotlinJvmTarget@{
var isJvmCoercive = false
while (versionInt > javaVersionMinSupported) {
if (isJvmTargetAvailable(versionInt)) {
break
}
versionInt -= 1
isJvmCoercive = true
}
if (isJvmCoercive) {
javaVersionInfoSuffix += " [coercive-jvm-downgraded]"
}
}
gradle.extra.getOrNull<Int>("javaVersionCoercedByGradle")?.let {
if (versionInt > it) {
versionInt = it
javaVersionInfoSuffix += " [coercive-gradle-downgraded]"
}
}
return versionInt to javaVersionInfoSuffix
}
private fun isJvmTargetAvailable(target: Int): Boolean {
try {
// Weak dependency with Kotlin plugin: Use reflection to check if JvmTarget is available;
// if reflection fails, treat it as available (to avoid incorrect downgrading).
// zh-CN: 与 Kotlin 插件弱依赖: 反射判断 JvmTarget 是否可用; 反射失败则视为可用 (避免误降级).
val cls = Class.forName("org.jetbrains.kotlin.gradle.dsl.JvmTarget")
cls.enumConstants?.let { values ->
return values.any { it?.toString().equals("JVM_$target", true) }
}
} catch (e: Throwable) {
logger.error("Failed to check JVM target availability: $e")
}
return true
}
operator fun get(propertyName: String) = bp[propertyName]
operator fun get(propertyInfo: List<String>) = bp[propertyInfo]
@@ -138,6 +56,7 @@ class Versions @JvmOverloads constructor(
val infoVerName = "Version name: $appVersionName"
val infoVerCode = "Version code: ${if (isBuildNumberAutoIncremented) "${appVersionCode + 1} [auto-incremented]" else appVersionCode}"
val infoVerSdk = "SDK versions: min [$sdkVersionMin] / target [$sdkVersionTarget] / compile [$sdkVersionCompile]"
val infoVerJdk = "JDK versions: min [$javaVersionMinSupported] / select [$javaVersionInt] / current [$javaVersionCurrentInt] / max [$javaVersionMaxSupported]"
val infoVerJava = "Java version: $javaVersion${
when {
gradle.extra.getOrNull<Boolean>("isHideConsoleInfoHintSuffix") == true -> ""
@@ -145,7 +64,7 @@ class Versions @JvmOverloads constructor(
}
}"
val maxLength = arrayOf(title, infoVerName, infoVerCode, infoVerSdk, infoVerJava).maxOf { it.length }
val maxLength = arrayOf(title, infoVerName, infoVerCode, infoVerSdk, infoVerJdk, infoVerJava).maxOf { it.length }
arrayOf(
"=".repeat(maxLength),
@@ -154,6 +73,7 @@ class Versions @JvmOverloads constructor(
infoVerName,
infoVerCode,
infoVerSdk,
infoVerJdk,
infoVerJava,
"=".repeat(maxLength),
"",
@@ -203,8 +123,4 @@ class Versions @JvmOverloads constructor(
}
}
companion object {
private const val VALIDATED_EXTRA_KEY = "org.autojs.build.Versions.currentValidated"
}
}