Gradle, native: Report passing binary-specific args to compilation
Earlier we propagated all free args specified for a compilation into a link task. It was required because the link task actually compiled the same source as the compile task but with another output kind. But currently a link task produces a final binary from a klib instead of sources. It means that such a propagation becomes incorrect. Now options related to the compiler frontend like -Xexperimental must be specified per compilation while options related to the compiler backend (e.g. -opt, -g, -Xstatic-framework etc) - per binary. This path shows a special warning if some of "binary-specific" arguments are passed to a compilation.
This commit is contained in:
+35
@@ -1117,6 +1117,41 @@ class NewMultiplatformIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNativeFreeArgsWarning() = with(transformProjectWithPluginsDsl("kotlin-dsl", gradleVersion, "new-mpp-native-binaries")) {
|
||||||
|
gradleBuildScript().appendText(
|
||||||
|
"""kotlin.targets["macos64"].compilations["main"].kotlinOptions.freeCompilerArgs += "-opt""""
|
||||||
|
)
|
||||||
|
gradleBuildScript("exported").appendText(
|
||||||
|
"""
|
||||||
|
kotlin.targets["macos64"].compilations["main"].kotlinOptions.freeCompilerArgs += "-opt"
|
||||||
|
kotlin.targets["macos64"].compilations["test"].kotlinOptions.freeCompilerArgs += "-g"
|
||||||
|
kotlin.targets["linux64"].compilations["main"].kotlinOptions.freeCompilerArgs +=
|
||||||
|
listOf("-g", "-Xdisable-phases=Devirtualization,BuildDFG")
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
build("tasks") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains(
|
||||||
|
"""
|
||||||
|
The following free compiler arguments must be specified for a binary instead of a compilation:
|
||||||
|
* In project ':':
|
||||||
|
* In target 'macos64':
|
||||||
|
* Compilation: 'main', arguments: [-opt]
|
||||||
|
* In project ':exported':
|
||||||
|
* In target 'linux64':
|
||||||
|
* Compilation: 'main', arguments: [-g, -Xdisable-phases=Devirtualization,BuildDFG]
|
||||||
|
* In target 'macos64':
|
||||||
|
* Compilation: 'main', arguments: [-opt]
|
||||||
|
* Compilation: 'test', arguments: [-g]
|
||||||
|
|
||||||
|
Please move them into final binary declarations. E.g. binaries.executable { freeCompilerArgs += "..." }
|
||||||
|
See more about final binaries: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#building-final-native-binaries.
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSourceJars() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
fun testSourceJars() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
||||||
setupWorkingDir()
|
setupWorkingDir()
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ kotlin {
|
|||||||
|
|
||||||
executable("test2", [RELEASE]) {
|
executable("test2", [RELEASE]) {
|
||||||
compilation = compilations["test"]
|
compilation = compilations["test"]
|
||||||
freeCompilerArgs.add("-tr")
|
freeCompilerArgs += "-tr"
|
||||||
linkTask.kotlinOptions {
|
linkTask.kotlinOptions {
|
||||||
freeCompilerArgs += "-Xtime"
|
freeCompilerArgs += "-Xtime"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ kotlin {
|
|||||||
|
|
||||||
executable("test2") {
|
executable("test2") {
|
||||||
compilation = compilations["test"]
|
compilation = compilations["test"]
|
||||||
freeCompilerArgs.add("-tr")
|
freeCompilerArgs += "-tr"
|
||||||
linkTask.kotlinOptions {
|
linkTask.kotlinOptions {
|
||||||
freeCompilerArgs += "-Xtime"
|
freeCompilerArgs += "-Xtime"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.gradle.plugin
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.DisabledNativeTargetsReporter
|
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
|
||||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 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.targets.native
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||||
|
|
||||||
|
internal object CompilationFreeArgsValidator : AggregateReporter() {
|
||||||
|
|
||||||
|
private const val EXTRA_PROPERTY_NAME = "org.jetbrains.kotlin.native.incorrectFreeArgs"
|
||||||
|
|
||||||
|
private data class IncorrectArgumentsReport(val compilation: KotlinNativeCompilation, val incorrectArgs: List<String>) {
|
||||||
|
val target: KotlinNativeTarget
|
||||||
|
get() = compilation.target
|
||||||
|
|
||||||
|
val project: Project
|
||||||
|
get() = target.project
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.startsWithIncorrectPrefix() = incorrectArgPrefixes.any { startsWith(it) }
|
||||||
|
private fun String.disablesDevirtualization() = startsWith("-Xdisable-phases=") && contains("Devirtualization")
|
||||||
|
|
||||||
|
private fun Project.getOrRegisterIncorrectArguments(): MutableList<IncorrectArgumentsReport> =
|
||||||
|
getOrRegisterData(this, EXTRA_PROPERTY_NAME)
|
||||||
|
|
||||||
|
private fun String.withIndent(indent: Int) = prependIndent(" ".repeat(indent))
|
||||||
|
|
||||||
|
fun validate(compilation: KotlinNativeCompilation) {
|
||||||
|
val incorrectArgs = compilation.kotlinOptions.freeCompilerArgs.filter { arg ->
|
||||||
|
arg.startsWithIncorrectPrefix() || arg.disablesDevirtualization()
|
||||||
|
}
|
||||||
|
if (incorrectArgs.isNotEmpty()) {
|
||||||
|
compilation.target.project
|
||||||
|
.getOrRegisterIncorrectArguments()
|
||||||
|
.add(IncorrectArgumentsReport(compilation, incorrectArgs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message format is the following:
|
||||||
|
*
|
||||||
|
* The following free compiler arguments must be specified for a binary instead of a compilation:
|
||||||
|
* * In project ':':
|
||||||
|
* * In target 'macos':
|
||||||
|
* Compilation: 'main', arguments: [-opt]
|
||||||
|
* * In project ':test':
|
||||||
|
* * In target 'macos':
|
||||||
|
* Compilation: 'main', arguments: [-opt, -g]
|
||||||
|
* Compilation: 'test', arguments: [-opt, -g, -Xdisable-phases=Devirtualization,BuildDFG]
|
||||||
|
*/
|
||||||
|
override fun printWarning(project: Project) {
|
||||||
|
// filterIsInstance helps against potential class loaders conflict or misconfiguration.
|
||||||
|
@Suppress("UselessCallOnCollection")
|
||||||
|
val incorrectArgs = project
|
||||||
|
.getOrRegisterIncorrectArguments()
|
||||||
|
.filterIsInstance<IncorrectArgumentsReport>()
|
||||||
|
.groupBy { it.project }
|
||||||
|
.toSortedMap(compareBy { it.path })
|
||||||
|
|
||||||
|
if (incorrectArgs.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val message = buildString {
|
||||||
|
appendln()
|
||||||
|
appendln("The following free compiler arguments must be specified for a binary instead of a compilation:")
|
||||||
|
incorrectArgs.forEach { (project, reports) ->
|
||||||
|
appendln("* In project '${project.path}':".withIndent(1))
|
||||||
|
val groupedReports = reports
|
||||||
|
.groupBy { it.target }
|
||||||
|
.toSortedMap(compareBy { it.name })
|
||||||
|
groupedReports.forEach { (target, reports) ->
|
||||||
|
appendln("* In target '${target.name}':".withIndent(2))
|
||||||
|
reports.forEach {
|
||||||
|
appendln(
|
||||||
|
"* Compilation: '${it.compilation.name}', arguments: [${it.incorrectArgs.joinToString()}]".withIndent(3)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendln()
|
||||||
|
appendln(
|
||||||
|
"""
|
||||||
|
Please move them into final binary declarations. E.g. binaries.executable { freeCompilerArgs += "..." }
|
||||||
|
See more about final binaries: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#building-final-native-binaries.
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
project.logger.warn(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val incorrectArgPrefixes = listOf(
|
||||||
|
// Optimizations/debug info.
|
||||||
|
"-opt",
|
||||||
|
"-g",
|
||||||
|
"-ea",
|
||||||
|
"-enable-assertions",
|
||||||
|
// Test runners.
|
||||||
|
"-trn",
|
||||||
|
"-generate-no-exit-test-runner",
|
||||||
|
"-tr",
|
||||||
|
"-generate-test-runner",
|
||||||
|
"-trw",
|
||||||
|
"-generate-worker-test-runner",
|
||||||
|
// Linker parameters and entry point.
|
||||||
|
"-linker-option",
|
||||||
|
"-linker-options",
|
||||||
|
"-e",
|
||||||
|
"-entry",
|
||||||
|
"-nomain",
|
||||||
|
// Runtime settings.
|
||||||
|
"-memory-model",
|
||||||
|
|
||||||
|
// Coverage.
|
||||||
|
"-Xcoverage",
|
||||||
|
"-Xcoverage-file",
|
||||||
|
"-Xlibrary-to-cover",
|
||||||
|
// Reverse ObjC interop and framework producing.
|
||||||
|
"-Xembed-bitcode",
|
||||||
|
"-Xembed-bitcode-marker",
|
||||||
|
"-Xexport-library",
|
||||||
|
"-Xframework-import-header",
|
||||||
|
"-Xobjc-generics",
|
||||||
|
"-Xstatic-framework",
|
||||||
|
// Advanced debug info.
|
||||||
|
"-Xdebug-info-version",
|
||||||
|
"-Xg0",
|
||||||
|
// Other.
|
||||||
|
"-Xinclude",
|
||||||
|
"-Xruntime"
|
||||||
|
)
|
||||||
|
}
|
||||||
+51
-45
@@ -3,15 +3,30 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* 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
|
package org.jetbrains.kotlin.gradle.targets.native
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.plugins.ExtraPropertiesExtension
|
import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
|
||||||
internal object DisabledNativeTargetsReporter {
|
internal abstract class AggregateReporter {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
protected fun <T> getOrRegisterData(project: Project, propertyName: String): MutableList<T> =
|
||||||
|
project.rootProject.extensions.getByType(ExtraPropertiesExtension::class.java).run {
|
||||||
|
if (!has(propertyName)) {
|
||||||
|
set(propertyName, mutableListOf<T>())
|
||||||
|
project.gradle.taskGraph.whenReady { printWarning(project) }
|
||||||
|
}
|
||||||
|
get(propertyName)
|
||||||
|
} as MutableList<T>
|
||||||
|
|
||||||
|
protected abstract fun printWarning(project: Project)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object DisabledNativeTargetsReporter : AggregateReporter() {
|
||||||
private const val EXTRA_PROPERTY_NAME = "org.jetbrains.kotlin.native.disabledTargets"
|
private const val EXTRA_PROPERTY_NAME = "org.jetbrains.kotlin.native.disabledTargets"
|
||||||
|
|
||||||
internal const val WARNING_PREFIX = "Some Kotlin/Native targets cannot be built on this "
|
internal const val WARNING_PREFIX = "Some Kotlin/Native targets cannot be built on this "
|
||||||
@@ -25,51 +40,42 @@ internal object DisabledNativeTargetsReporter {
|
|||||||
|
|
||||||
private data class DisabledTarget(val project: Project, val target: KotlinNativeTarget, val supportedHosts: Collection<KonanTarget>)
|
private data class DisabledTarget(val project: Project, val target: KotlinNativeTarget, val supportedHosts: Collection<KonanTarget>)
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private fun getOrRegisterDisabledTargets(project: Project) =
|
private fun getOrRegisterDisabledTargets(project: Project) =
|
||||||
project.rootProject.extensions.getByType(ExtraPropertiesExtension::class.java).run {
|
getOrRegisterData<DisabledTarget>(project, EXTRA_PROPERTY_NAME)
|
||||||
if (!has(EXTRA_PROPERTY_NAME)) {
|
|
||||||
set(EXTRA_PROPERTY_NAME, mutableListOf<DisabledTarget>())
|
|
||||||
printWarningWhenTaskGraphIsReady(project)
|
|
||||||
}
|
|
||||||
get(EXTRA_PROPERTY_NAME)
|
|
||||||
} as MutableList<DisabledTarget>
|
|
||||||
|
|
||||||
private fun printWarningWhenTaskGraphIsReady(project: Project) {
|
override fun printWarning(project: Project) {
|
||||||
project.gradle.taskGraph.whenReady {
|
if (PropertiesProvider(project).ignoreDisabledNativeTargets == true) {
|
||||||
if (PropertiesProvider(project).ignoreDisabledNativeTargets == true) {
|
return
|
||||||
return@whenReady
|
|
||||||
}
|
|
||||||
|
|
||||||
val disabledTargetsList = getOrRegisterDisabledTargets(project)
|
|
||||||
|
|
||||||
@Suppress("UselessCallOnCollection") // filterIsInstance helps against potential class loaders conflict or misconfiguration
|
|
||||||
val disabledTargetGroups = disabledTargetsList
|
|
||||||
.filterIsInstance<DisabledTarget>()
|
|
||||||
.groupBy { it.project }
|
|
||||||
.mapValues { (_, disabledTargetsInProject) -> disabledTargetsInProject.groupBy { it.supportedHosts } }
|
|
||||||
.toSortedMap(compareBy { it.path })
|
|
||||||
|
|
||||||
project.logger.warn(buildString {
|
|
||||||
appendln("\n$WARNING_PREFIX${HostManager.host} machine and are disabled:")
|
|
||||||
|
|
||||||
disabledTargetGroups.forEach { (targetProject, targetsBySupportedHosts) ->
|
|
||||||
appendln(
|
|
||||||
" * In project '${targetProject.path}':"
|
|
||||||
)
|
|
||||||
targetsBySupportedHosts.forEach { (supportedHosts, disabledTargets) ->
|
|
||||||
append(" * target" + "s".takeIf { disabledTargets.size > 1 }.orEmpty() + " ")
|
|
||||||
append(disabledTargets.joinToString { "'${it.target.name}'" })
|
|
||||||
|
|
||||||
val supportedHostsString = when (supportedHosts.size) {
|
|
||||||
1 -> "a ${supportedHosts.single()} host"
|
|
||||||
else -> "one of the hosts: ${supportedHosts.joinToString(", ")}"
|
|
||||||
}
|
|
||||||
appendln(" (can be built with $supportedHostsString)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appendln("To hide this message, add '$DISABLE_WARNING_PROPERTY_NAME=true' to the Gradle properties.")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val disabledTargetsList = getOrRegisterDisabledTargets(project)
|
||||||
|
|
||||||
|
@Suppress("UselessCallOnCollection") // filterIsInstance helps against potential class loaders conflict or misconfiguration.
|
||||||
|
val disabledTargetGroups = disabledTargetsList
|
||||||
|
.filterIsInstance<DisabledTarget>()
|
||||||
|
.groupBy { it.project }
|
||||||
|
.mapValues { (_, disabledTargetsInProject) -> disabledTargetsInProject.groupBy { it.supportedHosts } }
|
||||||
|
.toSortedMap(compareBy { it.path })
|
||||||
|
|
||||||
|
project.logger.warn(buildString {
|
||||||
|
appendln("\n$WARNING_PREFIX${HostManager.host} machine and are disabled:")
|
||||||
|
|
||||||
|
disabledTargetGroups.forEach { (targetProject, targetsBySupportedHosts) ->
|
||||||
|
appendln(
|
||||||
|
" * In project '${targetProject.path}':"
|
||||||
|
)
|
||||||
|
targetsBySupportedHosts.forEach { (supportedHosts, disabledTargets) ->
|
||||||
|
append(" * target" + "s".takeIf { disabledTargets.size > 1 }.orEmpty() + " ")
|
||||||
|
append(disabledTargets.joinToString { "'${it.target.name}'" })
|
||||||
|
|
||||||
|
val supportedHostsString = when (supportedHosts.size) {
|
||||||
|
1 -> "a ${supportedHosts.single()} host"
|
||||||
|
else -> "one of the hosts: ${supportedHosts.joinToString(", ")}"
|
||||||
|
}
|
||||||
|
appendln(" (can be built with $supportedHostsString)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendln("To hide this message, add '$DISABLE_WARNING_PROPERTY_NAME=true' to the Gradle properties.")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.CompilationFreeArgsValidator
|
||||||
|
|
||||||
class KotlinNativeCompilationFactory(
|
class KotlinNativeCompilationFactory(
|
||||||
val project: Project,
|
val project: Project,
|
||||||
@@ -22,5 +24,8 @@ class KotlinNativeCompilationFactory(
|
|||||||
if (name == KotlinCompilation.TEST_COMPILATION_NAME) {
|
if (name == KotlinCompilation.TEST_COMPILATION_NAME) {
|
||||||
friendCompilationName = KotlinCompilation.MAIN_COMPILATION_NAME
|
friendCompilationName = KotlinCompilation.MAIN_COMPILATION_NAME
|
||||||
}
|
}
|
||||||
|
project.whenEvaluated {
|
||||||
|
CompilationFreeArgsValidator.validate(this@apply)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator
|
import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
|
||||||
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
|
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.internals
|
package org.jetbrains.kotlin.gradle.internals
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.DisabledNativeTargetsReporter
|
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
|
||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user