diff --git a/gradle-plugins/compose/build.gradle.kts b/gradle-plugins/compose/build.gradle.kts index a02b508e1a..485c8906ba 100644 --- a/gradle-plugins/compose/build.gradle.kts +++ b/gradle-plugins/compose/build.gradle.kts @@ -70,6 +70,7 @@ dependencies { embedded("org.jetbrains.kotlinx:kotlinx-serialization-core:${BuildProperties.serializationVersion}") embedded("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:${BuildProperties.serializationVersion}") embedded(project(":preview-rpc")) + embedded(project(":jdk-version-probe")) } val shadow = tasks.named("shadowJar") { diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/ComposeProjectProperties.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/ComposeProjectProperties.kt index 977ed4a32e..ab1011bc80 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/ComposeProjectProperties.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/ComposeProjectProperties.kt @@ -20,6 +20,7 @@ internal object ComposeProperties { internal const val MAC_NOTARIZATION_APPLE_ID = "compose.desktop.mac.notarization.appleID" internal const val MAC_NOTARIZATION_PASSWORD = "compose.desktop.mac.notarization.password" internal const val MAC_NOTARIZATION_ASC_PROVIDER = "compose.desktop.mac.notarization.ascProvider" + internal const val CHECK_JDK_VENDOR = "compose.desktop.packaging.checkJdkVendor" fun isVerbose(providers: ProviderFactory): Provider = providers.findProperty(VERBOSE).toBooleanProvider(false) @@ -47,4 +48,7 @@ internal object ComposeProperties { fun macNotarizationAscProvider(providers: ProviderFactory): Provider = providers.findProperty(MAC_NOTARIZATION_ASC_PROVIDER) + + fun checkJdkVendor(providers: ProviderFactory): Provider = + providers.findProperty(CHECK_JDK_VENDOR).toBooleanProvider(true) } \ No newline at end of file diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureJvmApplication.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureJvmApplication.kt index 36d5194667..83707cf8b5 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureJvmApplication.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureJvmApplication.kt @@ -67,6 +67,7 @@ private fun JvmApplicationContext.configureCommonJvmDesktopTasks(): CommonJvmDes taskNameObject = "runtime" ) { jdkHome.set(app.javaHomeProvider) + checkJdkVendor.set(ComposeProperties.checkJdkVendor(project.providers)) jdkVersionProbeJar.from( project.detachedComposeGradleDependency( artifactId = "gradle-plugin-internal-jdk-version-probe" diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/tasks/AbstractCheckNativeDistributionRuntime.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/tasks/AbstractCheckNativeDistributionRuntime.kt index 68dd0518f4..e4e8010c89 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/tasks/AbstractCheckNativeDistributionRuntime.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/tasks/AbstractCheckNativeDistributionRuntime.kt @@ -10,13 +10,19 @@ import org.gradle.api.file.RegularFile import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* +import org.jetbrains.compose.desktop.application.internal.ComposeProperties import org.jetbrains.compose.desktop.application.internal.JvmRuntimeProperties +import org.jetbrains.compose.desktop.application.internal.ExternalToolRunner +import org.jetbrains.compose.desktop.application.internal.JdkVersionProbe +import org.jetbrains.compose.desktop.tasks.AbstractComposeDesktopTask +import org.jetbrains.compose.internal.utils.OS +import org.jetbrains.compose.internal.utils.currentOS import org.jetbrains.compose.internal.utils.executableName import org.jetbrains.compose.internal.utils.ioFile import org.jetbrains.compose.internal.utils.notNullProperty -import org.jetbrains.compose.desktop.application.internal.ExternalToolRunner -import org.jetbrains.compose.desktop.tasks.AbstractComposeDesktopTask +import java.io.ByteArrayInputStream import java.io.File +import java.util.* // __COMPOSE_NATIVE_DISTRIBUTIONS_MIN_JAVA_VERSION__ internal const val MIN_JAVA_RUNTIME_VERSION = 17 @@ -30,6 +36,9 @@ abstract class AbstractCheckNativeDistributionRuntime : AbstractComposeDesktopTa @get:InputDirectory val jdkHome: Property = objects.notNullProperty() + @get:Input + abstract val checkJdkVendor: Property + private val taskDir = project.layout.buildDirectory.dir("compose/tmp/$name") @get:OutputFile @@ -69,18 +78,37 @@ abstract class AbstractCheckNativeDistributionRuntime : AbstractComposeDesktopTa val jpackageExecutabke = jdkHome.getJdkTool("jpackage") ensureToolsExist(javaExecutable, jlinkExecutable, jpackageExecutabke) - val jvmRuntimeVersionString = getJavaRuntimeVersion(javaExecutable) + val jdkRuntimeProperties = getJDKRuntimeProperties(javaExecutable) - val jvmRuntimeVersion = jvmRuntimeVersionString?.toIntOrNull() - ?: jdkDistributionProbingError("JDK version '$jvmRuntimeVersionString' has unexpected format") + val jdkMajorVersionString = jdkRuntimeProperties.getProperty(JdkVersionProbe.JDK_MAJOR_VERSION_KEY) + val jdkMajorVersion = jdkMajorVersionString?.toIntOrNull() + ?: jdkDistributionProbingError("JDK version '$jdkMajorVersionString' has unexpected format") - check(jvmRuntimeVersion >= MIN_JAVA_RUNTIME_VERSION) { + check(jdkMajorVersion >= MIN_JAVA_RUNTIME_VERSION) { jdkDistributionProbingError( "minimum required JDK version is '$MIN_JAVA_RUNTIME_VERSION', " + - "but actual version is '$jvmRuntimeVersion'" + "but actual version is '$jdkMajorVersion'" ) } + if (checkJdkVendor.get()) { + val vendor = jdkRuntimeProperties.getProperty(JdkVersionProbe.JDK_VENDOR_KEY) + if (vendor == null) { + logger.warn("JDK vendor probe failed: $jdkHome") + } else { + if (currentOS == OS.MacOS && vendor.equals("homebrew", ignoreCase = true)) { + error( + """ + |Homebrew's JDK distribution may cause issues with packaging. + |See: https://github.com/JetBrains/compose-multiplatform/issues/3107 + |Possible solutions: + |* Use other vendor's JDK distribution, such as Amazon Corretto; + |* To continue using Homebrew distribution for packaging on your own risk, add "${ComposeProperties.CHECK_JDK_VENDOR}=false" to your gradle.properties + """.trimMargin()) + } + } + } + val modules = arrayListOf() runExternalTool( tool = javaExecutable, @@ -96,17 +124,21 @@ abstract class AbstractCheckNativeDistributionRuntime : AbstractComposeDesktopTa } ) - val properties = JvmRuntimeProperties(jvmRuntimeVersion, modules) + val properties = JvmRuntimeProperties(jdkMajorVersion, modules) JvmRuntimeProperties.writeToFile(properties, javaRuntimePropertiesFile.ioFile) } - private fun getJavaRuntimeVersion(javaExecutable: File): String? { - var javaRuntimeVersion: String? = null + private fun getJDKRuntimeProperties(javaExecutable: File): Properties { + val jdkProperties = Properties() runExternalTool( tool = javaExecutable, args = listOf("-jar", jdkVersionProbeJar.files.single().absolutePath), - processStdout = { stdout -> javaRuntimeVersion = stdout.trim() } + processStdout = { stdout -> + ByteArrayInputStream(stdout.trim().toByteArray()).use { + jdkProperties.loadFromXML(it) + } + } ) - return javaRuntimeVersion + return jdkProperties } } diff --git a/gradle-plugins/jdk-version-probe/src/main/java/org/jetbrains/compose/desktop/application/internal/JdkVersionProbe.java b/gradle-plugins/jdk-version-probe/src/main/java/org/jetbrains/compose/desktop/application/internal/JdkVersionProbe.java index 35edb75f9d..dad19d659b 100644 --- a/gradle-plugins/jdk-version-probe/src/main/java/org/jetbrains/compose/desktop/application/internal/JdkVersionProbe.java +++ b/gradle-plugins/jdk-version-probe/src/main/java/org/jetbrains/compose/desktop/application/internal/JdkVersionProbe.java @@ -4,10 +4,22 @@ */ package org.jetbrains.compose.desktop.application.internal; +import java.io.IOException; import java.lang.reflect.Method; +import java.util.Properties; public class JdkVersionProbe { - public static void main(String[] args) { + public final static String JDK_MAJOR_VERSION_KEY = "jdk.major.version"; + public final static String JDK_VENDOR_KEY = "jdk.vendor"; + + public static void main(String[] args) throws IOException { + Properties properties = new Properties(); + properties.setProperty(JDK_MAJOR_VERSION_KEY, getJDKMajorVersion()); + properties.setProperty(JDK_VENDOR_KEY, System.getProperty("java.vendor")); + properties.storeToXML(System.out, null); + } + + private static String getJDKMajorVersion() { Class runtimeClass = Runtime.class; try { Method version = runtimeClass.getMethod("version"); @@ -15,24 +27,19 @@ public class JdkVersionProbe { Class runtimeVerClass = runtimeVer.getClass(); try { int feature = (int) runtimeVerClass.getMethod("feature").invoke(runtimeVer); - printVersionAndHalt((Integer.valueOf(feature)).toString()); + return (Integer.valueOf(feature)).toString(); } catch (NoSuchMethodException e) { int major = (int) runtimeVerClass.getMethod("major").invoke(runtimeVer); - printVersionAndHalt((Integer.valueOf(major)).toString()); + return (Integer.valueOf(major)).toString(); } } catch (Exception e) { String javaVersion = System.getProperty("java.version"); String[] parts = javaVersion.split("\\."); if (parts.length > 2 && "1".equalsIgnoreCase(parts[0])) { - printVersionAndHalt(parts[1]); + return parts[1]; } else { throw new IllegalStateException("Could not determine JDK version from string: '" + javaVersion + "'"); } } } - - private static void printVersionAndHalt(String version) { - System.out.println(version); - Runtime.getRuntime().exit(0); - } } \ No newline at end of file