Skip to content

Commit a27f199

Browse files
AYastrebovSpace Team
authored andcommitted
[Gradle] Add binary configuration check to KotlinNativeLink task
^KT-81359
1 parent 3b93a31 commit a27f199

File tree

4 files changed

+113
-53
lines changed

4 files changed

+113
-53
lines changed

libraries/tools/kotlin-gradle-plugin/api/all/kotlin-gradle-plugin.api

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6162,7 +6162,7 @@ public abstract class org/jetbrains/kotlin/gradle/tasks/KotlinNativeCompile : or
61626162
public fun setupCompilerArgs (Lorg/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments;ZZ)V
61636163
}
61646164

6165-
public abstract class org/jetbrains/kotlin/gradle/tasks/KotlinNativeLink : org/jetbrains/kotlin/gradle/tasks/AbstractKotlinCompileTool, org/jetbrains/kotlin/gradle/internal/UsesClassLoadersCachingBuildService, org/jetbrains/kotlin/gradle/plugin/statistics/UsesBuildFusService, org/jetbrains/kotlin/gradle/report/UsesBuildMetricsService, org/jetbrains/kotlin/gradle/targets/native/UsesKonanPropertiesBuildService, org/jetbrains/kotlin/gradle/targets/native/toolchain/UsesKotlinNativeBundleBuildService, org/jetbrains/kotlin/gradle/tasks/KotlinToolTask {
6165+
public abstract class org/jetbrains/kotlin/gradle/tasks/KotlinNativeLink : org/jetbrains/kotlin/gradle/tasks/AbstractKotlinCompileTool, org/jetbrains/kotlin/gradle/internal/UsesClassLoadersCachingBuildService, org/jetbrains/kotlin/gradle/plugin/diagnostics/UsesKotlinToolingDiagnostics, org/jetbrains/kotlin/gradle/plugin/statistics/UsesBuildFusService, org/jetbrains/kotlin/gradle/report/UsesBuildMetricsService, org/jetbrains/kotlin/gradle/targets/native/UsesKonanPropertiesBuildService, org/jetbrains/kotlin/gradle/targets/native/toolchain/UsesKotlinNativeBundleBuildService, org/jetbrains/kotlin/gradle/tasks/KotlinToolTask {
61666166
public fun <init> (Lorg/jetbrains/kotlin/gradle/plugin/mpp/NativeBinary;Lorg/gradle/api/model/ObjectFactory;)V
61676167
public final fun compile ()V
61686168
public synthetic fun createCompilerArguments (Lorg/jetbrains/kotlin/gradle/plugin/KotlinCompilerArgumentsProducer$CreateCompilerArgumentsContext;)Lorg/jetbrains/kotlin/cli/common/arguments/CommonToolArguments;
@@ -6197,6 +6197,7 @@ public abstract class org/jetbrains/kotlin/gradle/tasks/KotlinNativeLink : org/j
61976197
public final fun isStaticFramework ()Z
61986198
public final fun kotlinOptions (Lkotlin/jvm/functions/Function1;)V
61996199
public final fun kotlinOptions (Lorg/gradle/api/Action;)V
6200+
public fun reportDiagnostic (Lorg/jetbrains/kotlin/gradle/plugin/diagnostics/ToolingDiagnostic;)V
62006201
public fun setCompilerPluginClasspath (Lorg/gradle/api/file/FileCollection;)V
62016202
public final fun setKotlinPluginData (Lorg/gradle/api/provider/Provider;)V
62026203
public fun toolOptions (Lkotlin/jvm/functions/Function1;)V

libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -258,47 +258,83 @@ internal object KotlinToolingDiagnostics {
258258
}
259259
}
260260

261-
object IncompatibleBinaryConfiguration : ToolingDiagnosticFactory(WARNING, DiagnosticGroup.Kgp.Misconfiguration) {
262-
operator fun invoke(binaryName: String, debuggable: Boolean, optimized: Boolean) =
263-
build {
264-
title("Incompatible Binary Configuration")
265-
.description {
266-
when {
267-
debuggable && optimized -> {
268-
"""
269-
Binary '$binaryName' has incompatible configuration: debuggable=true and optimized=true.
270-
Debug binaries should not be optimized as this defeats the purpose of fast compilation and debugging.
271-
Optimization significantly increases compile time while making debugging more difficult.
272-
""".trimIndent()
273-
}
274-
else -> { // !debuggable && !optimized
275-
"""
276-
Binary '$binaryName' has incompatible configuration: debuggable=false and optimized=false.
277-
Release binaries should be optimized to ensure good runtime performance.
278-
Without optimization, you get slow compilation (no debug build optimizations) and poor runtime performance.
279-
""".trimIndent()
280-
}
261+
internal abstract class BaseIncompatibleBinaryConfiguration : ToolingDiagnosticFactory(WARNING, DiagnosticGroup.Kgp.Misconfiguration) {
262+
263+
/**
264+
* Builds the common diagnostic message using context-specific phrases.
265+
*
266+
* @param binaryName The name of the binary.
267+
* @param debuggable The 'debuggable' status.
268+
* @param optimized The 'optimized' status.
269+
* @param contextDescription A phrase describing the context (e.g., "in project '...'").
270+
* @param contextSolution A phrase for the solution (e.g., "in project '...'" or "(... affecting task '...')").
271+
*/
272+
protected fun buildDiagnostic(
273+
binaryName: String,
274+
debuggable: Boolean,
275+
optimized: Boolean,
276+
contextDescription: String,
277+
contextSolution: String
278+
): ToolingDiagnostic = build {
279+
title("Incompatible Binary Configuration")
280+
.description {
281+
when {
282+
debuggable && optimized -> {
283+
"""
284+
Binary '$binaryName' $contextDescription has incompatible configuration: debuggable=true and optimized=true.
285+
This configuration is not recommended. Optimization significantly increases compile time
286+
and makes debugging difficult, which defeats the purpose of a debuggable build.
287+
""".trimIndent()
288+
}
289+
else -> { // !debuggable && !optimized
290+
"""
291+
Binary '$binaryName' $contextDescription has incompatible configuration: debuggable=false and optimized=false.
292+
This build is not optimized, which will result in poor runtime performance (like a debug build),
293+
but it also lacks debug symbols, making it unsuitable for debugging.
294+
This configuration is not recommended for either development or production use.
295+
""".trimIndent()
281296
}
282297
}
283-
.solutions {
284-
when {
285-
debuggable && optimized -> {
286-
listOf(
287-
"Set 'optimized = false' for binary '$binaryName' to enable fast debug compilation",
288-
"Use a release build type if you need optimization",
289-
"Consider creating separate debug and release configurations"
290-
)
291-
}
292-
else -> { // !debuggable && !optimized
293-
listOf(
294-
"Set 'optimized = true' for binary '$binaryName' to improve runtime performance",
295-
"Use a debug build type if you need fast compilation and debugging capabilities",
296-
"Verify that your build type configuration matches your intended use case"
297-
)
298-
}
298+
}
299+
.solutions {
300+
when {
301+
debuggable && optimized -> {
302+
listOf(
303+
"Set 'optimized = false' for binary '$binaryName' $contextSolution to create a standard debug build.",
304+
"If optimization is required, use a release build (debuggable=false, optimized=true)."
305+
)
306+
}
307+
else -> { // !debuggable && !optimized
308+
listOf(
309+
"Set 'optimized = true' for binary '$binaryName' $contextSolution to create a standard release build.",
310+
"Set 'debuggable = true' for binary '$binaryName' $contextSolution to create a standard debug build."
311+
)
299312
}
300313
}
301-
}
314+
}
315+
}
316+
}
317+
318+
internal object IncompatibleBinaryConfiguration : BaseIncompatibleBinaryConfiguration() {
319+
operator fun invoke(projectPath: String, binaryName: String, debuggable: Boolean, optimized: Boolean) =
320+
buildDiagnostic(
321+
binaryName = binaryName,
322+
debuggable = debuggable,
323+
optimized = optimized,
324+
contextDescription = "in project '$projectPath'",
325+
contextSolution = "in project '$projectPath'"
326+
)
327+
}
328+
329+
internal object IncompatibleBinaryTaskConfiguration : BaseIncompatibleBinaryConfiguration() {
330+
operator fun invoke(taskPath: String, binaryName: String, debuggable: Boolean, optimized: Boolean) =
331+
buildDiagnostic(
332+
binaryName = binaryName,
333+
debuggable = debuggable,
334+
optimized = optimized,
335+
contextDescription = "built by task '$taskPath'",
336+
contextSolution = "(in the build script affecting '$taskPath')"
337+
)
302338
}
303339

304340
object NoApplicationTargetFoundDiagnostic : ToolingDiagnosticFactory(WARNING, DiagnosticGroup.Kgp.Misconfiguration) {

libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/NativeBinaryConfigurationChecker.kt

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55

66
package org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers
77

8+
import org.gradle.api.Project
89
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
910
import org.jetbrains.kotlin.gradle.plugin.await
1011
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker
1112
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext
1213
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
1314
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector
15+
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportOncePerGradleProject
1416
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
1517
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBinary
1618

@@ -23,22 +25,24 @@ internal object NativeBinaryConfigurationChecker : KotlinGradleProjectChecker {
2325
multiplatformExtension.targets
2426
.withType(KotlinNativeTarget::class.java)
2527
.configureEach { target ->
26-
target.binaries.configureEach { binary ->
27-
if (hasIncompatibleConfiguration(binary)) {
28-
collector.report(
29-
project,
30-
KotlinToolingDiagnostics.IncompatibleBinaryConfiguration(
31-
binary.name,
32-
binary.debuggable,
33-
binary.optimized
34-
)
35-
)
36-
}
37-
}
28+
project.checkTarget(target, collector)
3829
}
3930
}
4031

41-
private fun hasIncompatibleConfiguration(binary: NativeBinary): Boolean {
42-
return (binary.debuggable && binary.optimized) || (!binary.debuggable && !binary.optimized)
32+
private fun Project.checkTarget(target: KotlinNativeTarget, collector: KotlinToolingDiagnosticsCollector) {
33+
target.binaries.configureEach { binary ->
34+
if (!binary.hasIncompatibleConfiguration) return@configureEach
35+
collector.reportOncePerGradleProject(
36+
project,
37+
KotlinToolingDiagnostics.IncompatibleBinaryConfiguration(
38+
path,
39+
binary.name,
40+
binary.debuggable,
41+
binary.optimized
42+
)
43+
)
44+
}
4345
}
44-
}
46+
}
47+
48+
private val NativeBinary.hasIncompatibleConfiguration: Boolean get() = (debuggable && optimized) || (!debuggable && !optimized)

libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeLink.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.gradle.internal.properties.nativeProperties
2828
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext
2929
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.create
3030
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
31+
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
32+
import org.jetbrains.kotlin.gradle.plugin.diagnostics.UsesKotlinToolingDiagnostics
3133
import org.jetbrains.kotlin.gradle.plugin.mpp.*
3234
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.useXcodeMessageStyle
3335
import org.jetbrains.kotlin.gradle.plugin.statistics.UsesBuildFusService
@@ -66,6 +68,7 @@ constructor(
6668
UsesClassLoadersCachingBuildService,
6769
KotlinToolTask<KotlinCommonCompilerToolOptions>,
6870
UsesKotlinNativeBundleBuildService,
71+
UsesKotlinToolingDiagnostics,
6972
UsesBuildFusService {
7073

7174
init {
@@ -347,6 +350,19 @@ constructor(
347350
}
348351
}
349352

353+
private fun validateBinaryConfiguration() {
354+
if (hasIncompatibleConfiguration) {
355+
reportDiagnostic(
356+
KotlinToolingDiagnostics.IncompatibleBinaryTaskConfiguration(
357+
path,
358+
binaryName,
359+
debuggable,
360+
optimized
361+
)
362+
)
363+
}
364+
}
365+
350366
@Suppress("DEPRECATION_ERROR")
351367
@get:Classpath
352368
protected val friendModule: FileCollection = objectFactory.fileCollection().from({ compilation.friendPaths })
@@ -436,6 +452,7 @@ constructor(
436452
val metricsReporter = metrics.get()
437453

438454
addBuildMetricsForTaskAction(metricsReporter = metricsReporter, languageVersion = null) {
455+
validateBinaryConfiguration()
439456
validatedExportedLibraries()
440457

441458
val output = outputFile.get()
@@ -496,3 +513,5 @@ constructor(
496513
}
497514

498515
internal val String.asValidFrameworkName get() = replace('-', '_')
516+
517+
private val KotlinNativeLink.hasIncompatibleConfiguration get() = (debuggable && optimized) || (!debuggable && !optimized)

0 commit comments

Comments
 (0)