From 8d495c4b451a7b530dc4615f1860e00d54dfdce5 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Tue, 20 Aug 2019 15:17:24 +0700 Subject: [PATCH] Gradle, native: Produce binaries from klibs and bump K/N version Earlier all native binaries were produced directly from sources of corresponding compilations. This patch changes this behavior. Now a klibrary produced by a compilation is used to build a final binary instead of sources. This allows us to avoid parsing the same sources several times and reduces build time. This patch also updates K/N version to 1.3.60-dev-11975, to get the corresponding support from the compiler side. Issue #KT-33076 Fixed --- build.gradle.kts | 2 +- .../kotlin/gradle/NewMultiplatformIT.kt | 52 ++- .../groovy-dsl/build.gradle | 4 + .../kotlin-dsl/build.gradle.kts | 5 +- .../sources/DefaultLanguageSettingsBuilder.kt | 4 +- .../native/KotlinNativeTargetConfigurator.kt | 2 +- .../gradle/targets/native/NativeBinaries.kt | 6 +- .../targets/native/tasks/KotlinNativeTasks.kt | 297 +++++++++++------- 8 files changed, 230 insertions(+), 142 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b5a0b909c60..c7598cd9cc1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -169,7 +169,7 @@ extra["versions.trove4j"] = "1.0.20181211" extra["versions.ktor-network"] = "1.0.1" if (!project.hasProperty("versions.kotlin-native")) { - extra["versions.kotlin-native"] = "1.3.50-dev-11052" + extra["versions.kotlin-native"] = "1.3.60-dev-11975" } val isTeamcityBuild = project.kotlinBuildProperties.isTeamcityBuild diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index fe1b4f196cd..167aa9cd53c 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -911,7 +911,6 @@ class NewMultiplatformIT : BaseGradleIT() { // Remove outputs and check that they are rebuilt. assertTrue(projectDir.resolve(headerPaths[0]).delete()) - assertTrue(projectDir.resolve(klibPath).delete()) if (HostManager.hostIsMac) { assertTrue(projectDir.resolve(frameworkPaths[0]).deleteRecursively()) } @@ -919,8 +918,8 @@ class NewMultiplatformIT : BaseGradleIT() { build("assemble") { assertSuccessful() assertTasksUpToDate(linkTasks.drop(1)) + assertTasksUpToDate(klibTask) assertTasksExecuted(linkTasks[0]) - assertTasksExecuted(klibTask) if (HostManager.hostIsMac) { assertTasksUpToDate(frameworkTasks.drop(1)) @@ -939,6 +938,16 @@ class NewMultiplatformIT : BaseGradleIT() { projectName: String, gradleVersionRequired: GradleVersionRequired = gradleVersion ) = with(transformProjectWithPluginsDsl(projectName, gradleVersionRequired, "new-mpp-native-binaries")) { + + fun CompiledProject.checkCommandLineFor(vararg taskPaths: String, check: (String) -> Unit) = taskPaths.forEach { taskPath -> + val commandLine = output.lineSequence().dropWhile { + !it.contains("Executing actions for task '$taskPath'") + }.first { + it.contains("Run tool: konanc") + } + check(commandLine) + } + val hostSuffix = nativeHostTargetName.capitalize() val binaries = mutableListOf( "debugExecutable" to "native-binary", @@ -973,10 +982,14 @@ class NewMultiplatformIT : BaseGradleIT() { val binariesTasks = arrayOf("${nativeHostTargetName}MainBinaries", "${nativeHostTargetName}TestBinaries") + val compileTask = "compileKotlin$hostSuffix" + val compileTestTask = "compileTestKotlin$hostSuffix" + // Check that all link and run tasks are generated. build(*binariesTasks) { assertSuccessful() assertTasksExecuted(linkTasks.map { ":$it" }) + assertTasksExecuted(":$compileTask", ":$compileTestTask") outputFiles.forEach { assertFileExists(it) } @@ -997,6 +1010,14 @@ class NewMultiplatformIT : BaseGradleIT() { assertSuccessful() } + // Check that kotlinOptions work fine for a compilation. + build(compileTask) { + assertSuccessful() + checkCommandLineFor(":$compileTask") { + assertTrue(it.contains("-verbose")) + } + } + // Check that run tasks work fine and an entry point can be specified. build("runDebugExecutable$hostSuffix") { assertSuccessful() @@ -1010,6 +1031,13 @@ class NewMultiplatformIT : BaseGradleIT() { build("runTest2ReleaseExecutable$hostSuffix") { assertSuccessful() + assertTasksExecuted(":$compileTestTask") + checkCommandLineFor(":linkTest2ReleaseExecutable$hostSuffix") { + assertTrue(it.contains("-tr")) + assertTrue(it.contains("-Xtime")) + // Check that kotlinOptions of the compilation don't affect the binary. + assertFalse(it.contains("-verbose")) + } assertTrue(output.contains("tests.foo")) } @@ -1019,13 +1047,6 @@ class NewMultiplatformIT : BaseGradleIT() { assertTrue(output.contains("tests.foo")) } - fun CompiledProject.checkFrameworkCompilationCommandLine(check: (String) -> Unit) { - output.lineSequence().filter { - it.contains("Run tool: konanc") && it.contains("-p framework") - }.toList().also { - assertTrue(it.isNotEmpty()) - }.forEach(check) - } if (HostManager.hostIsMac) { // Check dependency exporting and bitcode embedding in frameworks. @@ -1036,7 +1057,7 @@ class NewMultiplatformIT : BaseGradleIT() { fileInWorkingDir("build/bin/ios/releaseFramework/native_binary.framework/Headers/native_binary.h") .readText().contains("+ (int32_t)exported") // Check that by default release frameworks have bitcode embedded. - checkFrameworkCompilationCommandLine { + checkCommandLineFor(":linkReleaseFrameworkIos") { assertTrue(it.contains("-Xembed-bitcode")) assertTrue(it.contains("-opt")) } @@ -1049,7 +1070,7 @@ class NewMultiplatformIT : BaseGradleIT() { fileInWorkingDir("build/bin/ios/debugFramework/native_binary.framework/Headers/native_binary.h") .readText().contains("+ (int32_t)exported") // Check that by default debug frameworks have bitcode marker embedded. - checkFrameworkCompilationCommandLine { + checkCommandLineFor(":linkDebugFrameworkIos") { assertTrue(it.contains("-Xembed-bitcode-marker")) assertTrue(it.contains("-g")) } @@ -1058,7 +1079,7 @@ class NewMultiplatformIT : BaseGradleIT() { // Check manual disabling bitcode embedding, custom command line args and building a static framework. build("linkCustomReleaseFrameworkIos") { assertSuccessful() - checkFrameworkCompilationCommandLine { + checkCommandLineFor(":linkCustomReleaseFrameworkIos") { assertTrue(it.contains("-linker-option -L.")) assertTrue(it.contains("-Xtime")) assertTrue(it.contains("-Xstatic-framework")) @@ -1072,18 +1093,21 @@ class NewMultiplatformIT : BaseGradleIT() { assertSuccessful() assertFileExists("build/bin/iosSim/releaseFramework/native_binary.framework") assertFileExists("build/bin/iosSim/debugFramework/native_binary.framework") - checkFrameworkCompilationCommandLine { + checkCommandLineFor(":linkReleaseFrameworkIosSim", ":linkDebugFrameworkIosSim") { assertFalse(it.contains("-Xembed-bitcode")) assertFalse(it.contains("-Xembed-bitcode-marker")) } } - // Check that plugin doesn't allow exporting dependencies not added in the API configuration. val buildFile = listOf("build.gradle", "build.gradle.kts").map { projectDir.resolve(it) }.single { it.exists() } buildFile.modify { it.replace("api(project(\":exported\"))", "") } + projectDir.resolve("src/commonMain/kotlin/PackageMain.kt").modify { + // Remove usages of the ":exported" dependency to be able to compile the sources. + it.replace("import com.example.exported", "").replace("val exp = exported()", "val exp = 42") + } build("linkReleaseFrameworkIos") { assertFailed() val failureMsg = "Following dependencies exported in the releaseFramework binary " + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/groovy-dsl/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/groovy-dsl/build.gradle index b5fccf348c1..7129216fcbc 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/groovy-dsl/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/groovy-dsl/build.gradle @@ -37,6 +37,7 @@ kotlin { mingwX64("mingw64") configure([macos64, linux64, mingw64]) { + compilations.main.kotlinOptions.verbose = true binaries { executable() // Executable with default name. @@ -54,6 +55,9 @@ kotlin { executable("test2", [RELEASE]) { compilation = compilations["test"] freeCompilerArgs.add("-tr") + linkTask.kotlinOptions { + freeCompilerArgs += "-Xtime" + } } sharedLib([RELEASE]) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/kotlin-dsl/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/kotlin-dsl/build.gradle.kts index a1f1b7993ce..268b7aed056 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/kotlin-dsl/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-binaries/kotlin-dsl/build.gradle.kts @@ -27,7 +27,7 @@ kotlin { val windows = mingwX64("mingw64") configure(listOf(macos, linux, windows)) { - + compilations["main"].kotlinOptions.verbose = true binaries { executable() // Executable with default name. @@ -45,6 +45,9 @@ kotlin { executable("test2") { compilation = compilations["test"] freeCompilerArgs.add("-tr") + linkTask.kotlinOptions { + freeCompilerArgs += "-Xtime" + } } sharedLib(listOf(RELEASE)) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt index 36a2eedbec2..5c6512c92bc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt @@ -70,7 +70,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { val pluginOptionsTask = compilerPluginOptionsTask.value ?: return null return when (pluginOptionsTask) { is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions - is AbstractKotlinNativeCompile -> pluginOptionsTask.compilerPluginOptions + is AbstractKotlinNativeCompile<*> -> pluginOptionsTask.compilerPluginOptions else -> error("Unexpected task: $pluginOptionsTask") }.arguments } @@ -80,7 +80,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { val pluginClasspathTask = compilerPluginOptionsTask.value ?: return null return when (pluginClasspathTask) { is AbstractKotlinCompile<*> -> pluginClasspathTask.pluginClasspath - is AbstractKotlinNativeCompile -> pluginClasspathTask.compilerPluginClasspath ?: pluginClasspathTask.project.files() + is AbstractKotlinNativeCompile<*> -> pluginClasspathTask.compilerPluginClasspath ?: pluginClasspathTask.project.files() else -> error("Unexpected task: $pluginClasspathTask") } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index fc731b8f45e..e3628201cf9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -43,7 +43,7 @@ open class KotlinNativeTargetConfigurator( return buildDir.resolve("classes/kotlin/$targetSubDirectory${compilation.name}") } - private fun AbstractKotlinNativeCompile.addCompilerPlugins() { + private fun AbstractKotlinNativeCompile<*>.addCompilerPlugins() { SubpluginEnvironment .loadSubplugins(project, kotlinPluginVersion) .addSubpluginOptions(project, this, compilerPluginOptions) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeBinaries.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeBinaries.kt index 71e7e5be95d..f56acf2bbfe 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeBinaries.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeBinaries.kt @@ -58,7 +58,11 @@ sealed class NativeBinary( } /** Additional arguments passed to the Kotlin/Native compiler. */ - var freeCompilerArgs: MutableList = mutableListOf() + var freeCompilerArgs: List + get() = linkTask.kotlinOptions.freeCompilerArgs + set(value) { + linkTask.kotlinOptions.freeCompilerArgs = value + } // Link task access. val linkTaskName: String diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 9ef177c1b91..1a0d02ee0ee 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.compilerRunner.KonanInteropRunner import org.jetbrains.kotlin.compilerRunner.konanHome import org.jetbrains.kotlin.compilerRunner.konanVersion import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder @@ -85,7 +86,7 @@ private fun Collection.filterExternalKlibs(project: Project) = filter { } // endregion -abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile { +abstract class AbstractKotlinNativeCompile : AbstractCompile() { init { sourceCompatibility = "1.6" @@ -109,20 +110,9 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile @Input get() = kotlinOptions.freeCompilerArgs - // region Language settings imported from a SourceSet. - val languageSettings: LanguageSettingsBuilder? - @Internal get() = project.kotlinExtension.sourceSets.findByName(compilation.defaultSourceSetName)?.languageSettings - - val languageVersion: String? - @Optional @Input get() = languageSettings?.languageVersion - - val apiVersion: String? - @Optional @Input get() = languageSettings?.apiVersion - - val progressiveMode: Boolean - @Input get() = languageSettings?.progressiveMode ?: false - - val enabledLanguageFeatures: Set - @Input get() = languageSettings?.enabledLanguageFeatures ?: emptySet() - - val experimentalAnnotationsInUse: Set - @Input get() = languageSettings?.experimentalAnnotationsInUse.orEmpty() - // endregion. - // region DSL for compiler options - private inner class NativeCompilerOpts : KotlinCommonOptions { - override var apiVersion: String? - get() = languageSettings?.apiVersion - set(value) { languageSettings!!.apiVersion = value } - - override var languageVersion: String? - get() = this@AbstractKotlinNativeCompile.languageVersion - set(value) { languageSettings!!.languageVersion = value } - - override var allWarningsAsErrors: Boolean = false - override var suppressWarnings: Boolean = false - override var verbose: Boolean = false - - // TODO: Drop extraOpts in 1.3.70 and create a list here directly - // Delegate for compilations's extra options. - override var freeCompilerArgs: List - get() = compilation.extraOptsNoWarn - set(value) { - compilation.extraOptsNoWarn = value.toMutableList() - } - } - - @Internal - override val kotlinOptions: KotlinCommonOptions = NativeCompilerOpts() - - override fun kotlinOptions(fn: KotlinCommonOptions.() -> Unit) { - kotlinOptions.fn() - } - - override fun kotlinOptions(fn: Closure<*>) { - fn.delegate = kotlinOptions - fn.call() - } + @get:Internal + abstract val kotlinOptions: T + abstract fun kotlinOptions(fn: T.() -> Unit) + abstract fun kotlinOptions(fn: Closure<*>) // endregion. @@ -225,27 +166,18 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile @Internal get() = buildCommonArgs() + // Used by IDE via reflection. val defaultSerializedCompilerArguments: List @Internal get() = buildCommonArgs(true) - private fun buildCommonArgs(defaultsOnly: Boolean = false): List = mutableListOf().apply { - + // Args used by both the compiler and IDEA. + protected open fun buildCommonArgs(defaultsOnly: Boolean = false): List = mutableListOf().apply { add("-Xmulti-platform") - // Language features. - addArgIfNotNull("-language-version", languageVersion) - addArgIfNotNull("-api-version", apiVersion) - addKey("-progressive", progressiveMode) - enabledLanguageFeatures.forEach { featureName -> - add("-XXLanguage:+$featureName") - } - experimentalAnnotationsInUse.forEach { annotationName -> - add("-Xuse-experimental=$annotationName") - } - // Compiler plugins. compilerPluginClasspath?.let { pluginClasspath -> pluginClasspath.map { it.canonicalPath }.sorted().forEach { path -> @@ -267,7 +199,8 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile = mutableListOf().apply { + // Args passed to the compiler only (except sources). + protected open fun buildCompilerArgs(): List = mutableListOf().apply { addKey("-opt", optimized) addKey("-g", debuggable) addKey("-ea", debuggable) @@ -275,29 +208,21 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile - addArg("-l", library.absolutePath) - } - } - - val friends = friendModule?.files - if (friends != null && friends.isNotEmpty()) { - addArg("-friend-modules", friends.map { it.absolutePath }.joinToString(File.pathSeparator)) - } - - addAll(buildCommonArgs(defaultsOnly)) - - // Sources. - addAll(getSource().map { it.absolutePath }) - if (!commonSources.isEmpty) { - add("-Xcommon-sources=${commonSources.map { it.absolutePath }.joinToString(separator = ",")}") + // Libraries. + libraries.files.filterExternalKlibs(project).forEach { library -> + addArg("-l", library.absolutePath) } } + // Sources passed to the compiler. + // We add sources after all other arguments to make the command line more readable and simplify debugging. + protected abstract fun buildSourceArgs(): List + + private fun buildArgs(): List = + buildCompilerArgs() + buildCommonArgs() + buildSourceArgs() + @TaskAction override fun compile() { val output = outputFile.get() @@ -309,7 +234,7 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile(), KotlinCompile { @Internal override lateinit var compilation: KotlinNativeCompilation @@ -325,12 +250,119 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile() { @get:Internal override val baseName: String get() = if (compilation.isMainCompilation) project.name else compilation.name + + // Inputs and outputs. + // region Sources. + @InputFiles + @SkipWhenEmpty + override fun getSource(): FileTree = project.files(compilation.allSources).asFileTree + + private val commonSources: FileCollection + // Already taken into account in getSources method. + get() = project.files(compilation.commonSources).asFileTree + + private val friendModule: FileCollection? + get() = compilation.friendCompilation?.output?.allOutputs + // endregion. + + // region Language settings imported from a SourceSet. + val languageSettings: LanguageSettingsBuilder? + @Internal get() = project.kotlinExtension.sourceSets.findByName(compilation.defaultSourceSetName)?.languageSettings + + val languageVersion: String? + @Optional @Input get() = languageSettings?.languageVersion + + val apiVersion: String? + @Optional @Input get() = languageSettings?.apiVersion + + val progressiveMode: Boolean + @Input get() = languageSettings?.progressiveMode ?: false + + val enabledLanguageFeatures: Set + @Input get() = languageSettings?.enabledLanguageFeatures ?: emptySet() + + val experimentalAnnotationsInUse: Set + @Input get() = languageSettings?.experimentalAnnotationsInUse.orEmpty() + // endregion. + + // region Kotlin options. + private inner class NativeCompileOptions : KotlinCommonOptions { + override var apiVersion: String? + get() = languageSettings?.apiVersion + set(value) { languageSettings!!.apiVersion = value } + + override var languageVersion: String? + get() = this@KotlinNativeCompile.languageVersion + set(value) { languageSettings!!.languageVersion = value } + + override var allWarningsAsErrors: Boolean = false + override var suppressWarnings: Boolean = false + override var verbose: Boolean = false + + // TODO: Drop extraOpts in 1.3.70 and create a list here directly + // Delegate for compilations's extra options. + override var freeCompilerArgs: List + get() = compilation.extraOptsNoWarn + set(value) { + compilation.extraOptsNoWarn = value.toMutableList() + } + } + + override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions() + + override fun kotlinOptions(fn: KotlinCommonOptions.() -> Unit) { + kotlinOptions.fn() + } + + override fun kotlinOptions(fn: Closure<*>) { + fn.delegate = kotlinOptions + fn.call() + } + // endregion. + + // region Building args. + override fun buildCommonArgs(defaultsOnly: Boolean): List = mutableListOf().apply { + addAll(super.buildCommonArgs(defaultsOnly)) + + // Language features. + addArgIfNotNull("-language-version", languageVersion) + addArgIfNotNull("-api-version", apiVersion) + addKey("-progressive", progressiveMode) + enabledLanguageFeatures.forEach { featureName -> + add("-XXLanguage:+$featureName") + } + experimentalAnnotationsInUse.forEach { annotationName -> + add("-Xuse-experimental=$annotationName") + } + } + + override fun buildCompilerArgs(): List = mutableListOf().apply { + addAll(super.buildCompilerArgs()) + + val friends = friendModule?.files + if (friends != null && friends.isNotEmpty()) { + addArg("-friend-modules", friends.map { it.absolutePath }.joinToString(File.pathSeparator)) + } + } + + override fun buildSourceArgs(): List = mutableListOf().apply { + addAll(getSource().map { it.absolutePath }) + if (!commonSources.isEmpty) { + add("-Xcommon-sources=${commonSources.map { it.absolutePath }.joinToString(separator = ",")}") + } + } + // endregion. } /** * A task producing a final binary from a compilation. */ -open class KotlinNativeLink : AbstractKotlinNativeCompile() { +open class KotlinNativeLink : AbstractKotlinNativeCompile() { + + init { + dependsOn(project.provider { compilation.compileKotlinTask }) + } + @Internal lateinit var binary: NativeBinary @@ -338,6 +370,13 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile() { override val compilation: KotlinNativeCompilation get() = binary.compilation + @InputFile + val intermediateLibrary: Provider = project.provider { + compilation.compileKotlinTask.outputFile.get() + } + + override fun getSource(): FileTree = project.files(intermediateLibrary.get()).asFileTree + @get:Input override val outputKind: CompilerOutputKind get() = binary.outputKind.compilerOutputKind @@ -354,6 +393,25 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile() { override val baseName: String get() = binary.baseName + inner class NativeLinkOptions: KotlinCommonToolOptions { + override var allWarningsAsErrors: Boolean = false + override var suppressWarnings: Boolean = false + override var verbose: Boolean = false + override var freeCompilerArgs: List = listOf() + } + + override val kotlinOptions: KotlinCommonToolOptions = NativeLinkOptions() + + override fun kotlinOptions(fn: KotlinCommonToolOptions.() -> Unit) { + kotlinOptions.fn() + } + + override fun kotlinOptions(fn: Closure<*>) { + fn.delegate = kotlinOptions + fn.call() + } + + // Binary-specific options. @get:Optional @get:Input val entryPoint: String? @@ -385,32 +443,27 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile() { val embedBitcode: Framework.BitcodeEmbeddingMode get() = (binary as? Framework)?.embedBitcode ?: Framework.BitcodeEmbeddingMode.DISABLE - @get:Input - val freeCompilerArgs: List - get() = binary.freeCompilerArgs + override fun buildCompilerArgs(): List = mutableListOf().apply { + addAll(super.buildCompilerArgs()) - override fun buildArgs(defaultsOnly: Boolean): List { - val superArgs = super.buildArgs(defaultsOnly) - return mutableListOf().apply { - addAll(superArgs) - addKey("-tr", processTests) - addArgIfNotNull("-entry", entryPoint) - when (embedBitcode) { - Framework.BitcodeEmbeddingMode.MARKER -> add("-Xembed-bitcode-marker") - Framework.BitcodeEmbeddingMode.BITCODE -> add("-Xembed-bitcode") - else -> { /* Do nothing. */ } - } - linkerOpts.forEach { - addArg("-linker-option", it) - } - exportLibraries.files.filterExternalKlibs(project).forEach { - add("-Xexport-library=${it.absolutePath}") - } - addKey("-Xstatic-framework", isStaticFramework) - addAll(freeCompilerArgs) + addKey("-tr", processTests) + addArgIfNotNull("-entry", entryPoint) + when (embedBitcode) { + Framework.BitcodeEmbeddingMode.MARKER -> add("-Xembed-bitcode-marker") + Framework.BitcodeEmbeddingMode.BITCODE -> add("-Xembed-bitcode") + else -> { /* Do nothing. */ } } + linkerOpts.forEach { + addArg("-linker-option", it) + } + exportLibraries.files.filterExternalKlibs(project).forEach { + add("-Xexport-library=${it.absolutePath}") + } + addKey("-Xstatic-framework", isStaticFramework) } + override fun buildSourceArgs(): List = listOf("-Xinclude=${intermediateLibrary.get().absolutePath}") + private fun validatedExportedLibraries() { val exportConfiguration = exportLibraries as? Configuration ?: return val apiFiles = project.configurations.getByName(compilation.apiConfigurationName).files.filterExternalKlibs(project)