[Gradle] Pass through errors from Gradle to Xcode
^KT-55650 Verification Pending
This commit is contained in:
committed by
Space Team
parent
7914d3dd42
commit
af649cbb44
+139
@@ -227,4 +227,143 @@ class AppleFrameworkIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `configuration errors reported to Xcode when embedAndSign task requested`() {
|
||||
with(Project("sharedAppleFramework")) {
|
||||
setupWorkingDir()
|
||||
projectDir.resolve("shared/build.gradle.kts").appendText(
|
||||
"""
|
||||
kotlin {
|
||||
sourceSets["commonMain"].dependencies {
|
||||
implementation("com.example.unknown:dependency:0.0.1")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
build(
|
||||
":shared:embedAndSignAppleFrameworkForXcode",
|
||||
options = defaultBuildOptions().copy(
|
||||
customEnvironmentVariables = mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "iphoneos123",
|
||||
"ARCHS" to "arm64",
|
||||
"TARGET_BUILD_DIR" to "no use",
|
||||
"FRAMEWORKS_FOLDER_PATH" to "no use"
|
||||
)
|
||||
)
|
||||
) {
|
||||
assertFailed()
|
||||
assertContains("error: Could not find com.example.unknown:dependency:0.0.1.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `compilation errors reported to Xcode when embedAndSign task requested`() {
|
||||
with(Project("sharedAppleFramework")) {
|
||||
setupWorkingDir()
|
||||
projectDir.resolve("shared/src/commonMain/kotlin/com/github/jetbrains/myapplication/Greeting.kt")
|
||||
.appendText("this can't be compiled")
|
||||
|
||||
build(
|
||||
":shared:embedAndSignAppleFrameworkForXcode",
|
||||
options = defaultBuildOptions().copy(
|
||||
customEnvironmentVariables = mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "iphoneos123",
|
||||
"ARCHS" to "arm64",
|
||||
"TARGET_BUILD_DIR" to "no use",
|
||||
"FRAMEWORKS_FOLDER_PATH" to "no use"
|
||||
)
|
||||
)
|
||||
) {
|
||||
assertFailed()
|
||||
assertContains("/sharedAppleFramework/shared/src/commonMain/kotlin/com/github/jetbrains/myapplication/Greeting.kt:7:2: error: Expecting a top level declaration")
|
||||
assertContains("error: Compilation finished with errors")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `compilation errors printed with Gradle-style when any other task requested`() {
|
||||
with(Project("sharedAppleFramework")) {
|
||||
setupWorkingDir()
|
||||
projectDir.resolve("shared/src/commonMain/kotlin/com/github/jetbrains/myapplication/Greeting.kt")
|
||||
.appendText("this can't be compiled")
|
||||
|
||||
build(
|
||||
":shared:assembleDebugAppleFrameworkForXcodeIosArm64",
|
||||
options = defaultBuildOptions().copy(
|
||||
customEnvironmentVariables = mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "iphoneos123",
|
||||
"ARCHS" to "arm64",
|
||||
"TARGET_BUILD_DIR" to "no use",
|
||||
"FRAMEWORKS_FOLDER_PATH" to "no use"
|
||||
)
|
||||
)
|
||||
) {
|
||||
assertFailed()
|
||||
assertContains("e: file:///")
|
||||
assertNotContains("error: Compilation finished with errors")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `compilation errors printed with Xcode-style with explicit option`() {
|
||||
with(Project("sharedAppleFramework")) {
|
||||
setupWorkingDir()
|
||||
projectDir.resolve("shared/src/commonMain/kotlin/com/github/jetbrains/myapplication/Greeting.kt")
|
||||
.appendText("this can't be compiled")
|
||||
|
||||
build(
|
||||
":shared:assembleDebugAppleFrameworkForXcodeIosArm64", "-Pkotlin.native.useXcodeMessageStyle=true",
|
||||
options = defaultBuildOptions().copy(
|
||||
customEnvironmentVariables = mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "iphoneos123",
|
||||
"ARCHS" to "arm64",
|
||||
"TARGET_BUILD_DIR" to "no use",
|
||||
"FRAMEWORKS_FOLDER_PATH" to "no use"
|
||||
)
|
||||
)
|
||||
) {
|
||||
assertFailed()
|
||||
assertContains("/sharedAppleFramework/shared/src/commonMain/kotlin/com/github/jetbrains/myapplication/Greeting.kt:7:2: error: Expecting a top level declaration")
|
||||
assertContains("error: Compilation finished with errors")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `compilation errors reported to Xcode when embedAndSign task requested and compiler runs in a separate process`() {
|
||||
with(Project("sharedAppleFramework")) {
|
||||
setupWorkingDir()
|
||||
projectDir.resolve("shared/src/commonMain/kotlin/com/github/jetbrains/myapplication/Greeting.kt")
|
||||
.appendText("this can't be compiled")
|
||||
|
||||
build(
|
||||
":shared:embedAndSignAppleFrameworkForXcode", "-Pkotlin.native.disableCompilerDaemon=true",
|
||||
options = defaultBuildOptions().copy(
|
||||
customEnvironmentVariables = mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "iphoneos123",
|
||||
"ARCHS" to "arm64",
|
||||
"TARGET_BUILD_DIR" to "no use",
|
||||
"FRAMEWORKS_FOLDER_PATH" to "no use"
|
||||
)
|
||||
)
|
||||
) {
|
||||
assertFailed()
|
||||
assertContains("/sharedAppleFramework/shared/src/commonMain/kotlin/com/github/jetbrains/myapplication/Greeting.kt:7:2: error: Expecting a top level declaration")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+71
@@ -875,6 +875,77 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testSyncFrameworkUseXcodeStyleErrorsWhenConfigurationFailed() {
|
||||
with(project) {
|
||||
gradleBuildScript().appendText(
|
||||
"""
|
||||
kotlin {
|
||||
sourceSets["commonMain"].dependencies {
|
||||
implementation("com.example.unknown:dependency:0.0.1")
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
build(
|
||||
"syncFramework",
|
||||
"-Pkotlin.native.cocoapods.platform=iphonesimulator",
|
||||
"-Pkotlin.native.cocoapods.archs=x86_64",
|
||||
"-Pkotlin.native.cocoapods.configuration=Debug"
|
||||
) {
|
||||
assertFailed()
|
||||
assertContains("error: Could not find com.example.unknown:dependency:0.0.1.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSyncFrameworkUseXcodeStyleErrorsWhenCompilationFailed() {
|
||||
with(project) {
|
||||
projectDir.resolve("src/commonMain/kotlin/A.kt").appendText("this can't be compiled")
|
||||
|
||||
build(
|
||||
"syncFramework",
|
||||
"-Pkotlin.native.cocoapods.platform=iphonesimulator",
|
||||
"-Pkotlin.native.cocoapods.archs=x86_64",
|
||||
"-Pkotlin.native.cocoapods.configuration=Debug",
|
||||
) {
|
||||
assertFailed()
|
||||
assertContains("/native-cocoapods-template/src/commonMain/kotlin/A.kt:5:2: error: Expecting a top level declaration")
|
||||
assertContains("error: Compilation finished with errors")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOtherTasksUseGradleStyleErrorsWhenCompilationFailed() {
|
||||
with(project) {
|
||||
projectDir.resolve("src/commonMain/kotlin/A.kt").appendText("this can't be compiled")
|
||||
|
||||
build("linkPodDebugFrameworkIOS") {
|
||||
assertFailed()
|
||||
assertContains("e: file:///")
|
||||
assertContains("/native-cocoapods-template/src/commonMain/kotlin/A.kt:5:2 Expecting a top level declaration")
|
||||
assertNotContains("error: Compilation finished with errors")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOtherTasksUseXcodeStyleErrorsWhenCompilationFailedAndOptionEnabled() {
|
||||
with(project) {
|
||||
projectDir.resolve("src/commonMain/kotlin/A.kt").appendText("this can't be compiled")
|
||||
|
||||
build("linkPodDebugFrameworkIOS", "-Pkotlin.native.useXcodeMessageStyle=true") {
|
||||
assertFailed()
|
||||
assertContains("/native-cocoapods-template/src/commonMain/kotlin/A.kt:5:2: error: Expecting a top level declaration")
|
||||
assertContains("error: Compilation finished with errors")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPodDependencyInUnitTests() =
|
||||
getProjectByName(cocoapodsTestsProjectName).testWithWrapper(":iosX64Test")
|
||||
|
||||
+2
-1
@@ -186,7 +186,8 @@ abstract class KotlinToolRunner(
|
||||
|
||||
try {
|
||||
val mainClass = isolatedClassLoader.loadClass(mainClass)
|
||||
val entryPoint = mainClass.methods.single { it.name == daemonEntryPoint }
|
||||
val entryPoint = mainClass.methods
|
||||
.singleOrNull { it.name == daemonEntryPoint } ?: error("Couldn't find daemon entry point '$daemonEntryPoint'")
|
||||
|
||||
entryPoint.invoke(null, transformedArgs.toTypedArray())
|
||||
} catch (t: InvocationTargetException) {
|
||||
|
||||
+9
-3
@@ -7,11 +7,11 @@ package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
|
||||
import org.jetbrains.kotlin.gradle.dsl.NativeCacheOrchestration
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.useXcodeMessageStyle
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.isAtLeast
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.nativeUseEmbeddableCompilerJar
|
||||
import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService
|
||||
@@ -59,6 +59,7 @@ private val Project.kotlinNativeCompilerJar: String
|
||||
else
|
||||
"$konanHome/konan/lib/kotlin-native.jar"
|
||||
|
||||
|
||||
internal abstract class KotlinNativeToolRunner(
|
||||
protected val toolName: String,
|
||||
private val settings: Settings,
|
||||
@@ -69,6 +70,7 @@ internal abstract class KotlinNativeToolRunner(
|
||||
val konanVersion: CompilerVersion,
|
||||
val konanHome: String,
|
||||
val konanPropertiesFile: File,
|
||||
val useXcodeMessageStyle: Boolean,
|
||||
val jvmArgs: List<String>,
|
||||
val classpath: FileCollection
|
||||
) {
|
||||
@@ -77,6 +79,7 @@ internal abstract class KotlinNativeToolRunner(
|
||||
konanVersion = project.konanVersion,
|
||||
konanHome = project.konanHome,
|
||||
konanPropertiesFile = project.file("${project.konanHome}/konan/konan.properties"),
|
||||
useXcodeMessageStyle = project.useXcodeMessageStyle,
|
||||
jvmArgs = project.jvmArgs,
|
||||
classpath = project.files(project.kotlinNativeCompilerJar, "${project.konanHome}/konan/lib/trove4j.jar")
|
||||
)
|
||||
@@ -86,7 +89,8 @@ internal abstract class KotlinNativeToolRunner(
|
||||
final override val displayName get() = toolName
|
||||
|
||||
final override val mainClass get() = "org.jetbrains.kotlin.cli.utilities.MainKt"
|
||||
final override val daemonEntryPoint get() = "daemonMain"
|
||||
final override val daemonEntryPoint
|
||||
get() = if (!settings.useXcodeMessageStyle) "daemonMain" else "daemonMainWithXcodeRenderer"
|
||||
|
||||
// We need to unset some environment variables which are set by XCode and may potentially affect the tool executed.
|
||||
final override val execEnvironmentBlacklist: Set<String> by lazy {
|
||||
@@ -102,9 +106,11 @@ internal abstract class KotlinNativeToolRunner(
|
||||
val konanHomeRequired = !settings.konanVersion.isAtLeast(1, 4, 0) ||
|
||||
settings.konanVersion.toString(showMeta = false, showBuild = false) in listOf("1.4-M1", "1.4-M2")
|
||||
|
||||
val messageRenderer = if (settings.useXcodeMessageStyle) MessageRenderer.XCODE_STYLE else MessageRenderer.GRADLE_STYLE
|
||||
|
||||
listOfNotNull(
|
||||
if (konanHomeRequired) "konan.home" to settings.konanHome else null,
|
||||
MessageRenderer.PROPERTY_KEY to MessageRenderer.GRADLE_STYLE.name
|
||||
MessageRenderer.PROPERTY_KEY to messageRenderer.name
|
||||
).toMap()
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_SLOW_SOURCES_JAR_RESOLVER
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_DEPENDENCY_PROPAGATION
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_USE_XCODE_MESSAGE_STYLE
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_DEFAULT_DEPENDENCY
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_JDK_VARIANTS_VERSION_ALIGNMENT
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||
@@ -361,6 +362,12 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
||||
key.removePrefix(KOTLIN_NATIVE_BINARY_OPTION_PREFIX)
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces K/N compiler to print messages which could be parsed by Xcode
|
||||
*/
|
||||
val nativeUseXcodeMessageStyle: Boolean?
|
||||
get() = booleanProperty(KOTLIN_NATIVE_USE_XCODE_MESSAGE_STYLE)
|
||||
|
||||
/**
|
||||
* Allows a user to specify additional arguments of a JVM executing KLIB commonizer.
|
||||
*/
|
||||
@@ -548,6 +555,7 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
||||
const val KOTLIN_BUILD_REPORT_SINGLE_FILE = "kotlin.build.report.single_file"
|
||||
const val KOTLIN_BUILD_REPORT_HTTP_URL = "kotlin.build.report.http.url"
|
||||
const val KOTLIN_OPTIONS_SUPPRESS_FREEARGS_MODIFICATION_WARNING = "kotlin.options.suppressFreeCompilerArgsModificationWarning"
|
||||
const val KOTLIN_NATIVE_USE_XCODE_MESSAGE_STYLE = "kotlin.native.useXcodeMessageStyle"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+3
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.kotlinIdeMultiplatformImport
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.locateOrRegisterIdeResolveDependenciesTask
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companion.sourceSetFreeCompilerArgsPropertyName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.addBuildListenerForXcode
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.checkAndReportDeprecatedNativeTargets
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.handleHierarchicalStructureFlagsMigration
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
|
||||
@@ -81,6 +82,8 @@ class KotlinMultiplatformPlugin : Plugin<Project> {
|
||||
// Ensure that the instance is created and configured during apply
|
||||
project.kotlinIdeMultiplatformImport
|
||||
project.locateOrRegisterIdeResolveDependenciesTask()
|
||||
|
||||
project.addBuildListenerForXcode()
|
||||
}
|
||||
|
||||
private fun exportProjectStructureMetadataForOtherBuilds(
|
||||
|
||||
+6
-1
@@ -31,6 +31,11 @@ import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import java.io.File
|
||||
|
||||
internal object AppleXcodeTasks {
|
||||
const val embedAndSignTaskPrefix = "embedAndSign"
|
||||
const val embedAndSignTaskPostfix = "AppleFrameworkForXcode"
|
||||
}
|
||||
|
||||
private object XcodeEnvironment {
|
||||
val buildType: NativeBuildType?
|
||||
get() {
|
||||
@@ -144,7 +149,7 @@ internal fun Project.registerEmbedAndSignAppleFrameworkTask(framework: Framework
|
||||
val envFrameworkSearchDir = XcodeEnvironment.frameworkSearchDir
|
||||
val envSign = XcodeEnvironment.sign
|
||||
|
||||
val frameworkTaskName = lowerCamelCaseName("embedAndSign", framework.namePrefix, "AppleFrameworkForXcode")
|
||||
val frameworkTaskName = lowerCamelCaseName(AppleXcodeTasks.embedAndSignTaskPrefix, framework.namePrefix, AppleXcodeTasks.embedAndSignTaskPostfix)
|
||||
|
||||
if (envBuildType == null || envTargets.isEmpty() || envEmbeddedFrameworksDir == null || envFrameworkSearchDir == null) {
|
||||
locateOrRegisterTask<DefaultTask>(frameworkTaskName) { task ->
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp.apple
|
||||
|
||||
import org.gradle.BuildAdapter
|
||||
import org.gradle.BuildResult
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_USE_XCODE_MESSAGE_STYLE
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin
|
||||
import org.jetbrains.kotlin.gradle.utils.getOrPutRootProjectProperty
|
||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||
|
||||
internal val Project.useXcodeMessageStyle: Boolean
|
||||
get() = getOrPutRootProjectProperty("$KOTLIN_NATIVE_USE_XCODE_MESSAGE_STYLE.extra") {
|
||||
PropertiesProvider(this).nativeUseXcodeMessageStyle ?: isXcodeTasksRequested
|
||||
}
|
||||
|
||||
private val Project.isXcodeTasksRequested: Boolean
|
||||
get() = gradle.startParameter.taskNames.any { requestedTask ->
|
||||
val name = requestedTask.substringAfterLast(':')
|
||||
val isSyncTask = name == KotlinCocoapodsPlugin.SYNC_TASK_NAME
|
||||
val isEmbedAndSignTask = name.startsWith(AppleXcodeTasks.embedAndSignTaskPrefix) && name.endsWith(AppleXcodeTasks.embedAndSignTaskPostfix)
|
||||
isSyncTask || isEmbedAndSignTask
|
||||
}
|
||||
|
||||
internal fun Project.addBuildListenerForXcode() {
|
||||
if (!useXcodeMessageStyle) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isConfigurationCacheAvailable(gradle)) {
|
||||
// TODO https://youtrack.jetbrains.com/issue/KT-55832
|
||||
// Configuration cache case will be supported later
|
||||
return
|
||||
}
|
||||
|
||||
gradle.addBuildListener(XcodeBuildErrorListener)
|
||||
}
|
||||
|
||||
private object XcodeBuildErrorListener : BuildAdapter() {
|
||||
@Suppress("OVERRIDE_DEPRECATION") // Listener is added only when configuration cache is disabled
|
||||
override fun buildFinished(result: BuildResult) {
|
||||
if (result.failure != null) {
|
||||
val rootCause = generateSequence(result.failure) { it.cause }.last()
|
||||
val message = rootCause.message ?: rootCause.toString()
|
||||
System.err.println("error: ${message.lineSequence().first()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user