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 062213d886a..ea2093fd1d9 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 @@ -934,20 +934,20 @@ class NewMultiplatformIT : BaseGradleIT() { @Test fun testNativeBinaryGroovyDSL() = doTestNativeBinaryDSL("groovy-dsl") + private fun CompiledProject.checkNativeCommandLineFor(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) + } + private fun doTestNativeBinaryDSL( 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", @@ -1013,7 +1013,7 @@ class NewMultiplatformIT : BaseGradleIT() { // Check that kotlinOptions work fine for a compilation. build(compileTask) { assertSuccessful() - checkCommandLineFor(":$compileTask") { + checkNativeCommandLineFor(":$compileTask") { assertTrue(it.contains("-verbose")) } } @@ -1032,7 +1032,7 @@ class NewMultiplatformIT : BaseGradleIT() { build("runTest2ReleaseExecutable$hostSuffix") { assertSuccessful() assertTasksExecuted(":$compileTestTask") - checkCommandLineFor(":linkTest2ReleaseExecutable$hostSuffix") { + checkNativeCommandLineFor(":linkTest2ReleaseExecutable$hostSuffix") { assertTrue(it.contains("-tr")) assertTrue(it.contains("-Xtime")) // Check that kotlinOptions of the compilation don't affect the binary. @@ -1057,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. - checkCommandLineFor(":linkReleaseFrameworkIos") { + checkNativeCommandLineFor(":linkReleaseFrameworkIos") { assertTrue(it.contains("-Xembed-bitcode")) assertTrue(it.contains("-opt")) } @@ -1070,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. - checkCommandLineFor(":linkDebugFrameworkIos") { + checkNativeCommandLineFor(":linkDebugFrameworkIos") { assertTrue(it.contains("-Xembed-bitcode-marker")) assertTrue(it.contains("-g")) } @@ -1079,7 +1079,7 @@ class NewMultiplatformIT : BaseGradleIT() { // Check manual disabling bitcode embedding, custom command line args and building a static framework. build("linkCustomReleaseFrameworkIos") { assertSuccessful() - checkCommandLineFor(":linkCustomReleaseFrameworkIos") { + checkNativeCommandLineFor(":linkCustomReleaseFrameworkIos") { assertTrue(it.contains("-linker-option -L.")) assertTrue(it.contains("-Xtime")) assertTrue(it.contains("-Xstatic-framework")) @@ -1093,7 +1093,7 @@ class NewMultiplatformIT : BaseGradleIT() { assertSuccessful() assertFileExists("build/bin/iosSim/releaseFramework/native_binary.framework") assertFileExists("build/bin/iosSim/debugFramework/native_binary.framework") - checkCommandLineFor(":linkReleaseFrameworkIosSim", ":linkDebugFrameworkIosSim") { + checkNativeCommandLineFor(":linkReleaseFrameworkIosSim", ":linkDebugFrameworkIosSim") { assertFalse(it.contains("-Xembed-bitcode")) assertFalse(it.contains("-Xembed-bitcode-marker")) } @@ -1117,6 +1117,30 @@ class NewMultiplatformIT : BaseGradleIT() { } } + // Check that we still can build binaries from sources if the corresponding property is specified. + // TODO: Drop in 1.3.70. + @Test + fun testLinkNativeBinaryFromSources() = with( + transformProjectWithPluginsDsl("groovy-dsl", gradleVersion, "new-mpp-native-binaries") + ) { + val linkTask = ":linkDebugExecutable${nativeHostTargetName.capitalize()}" + + val prefix = CompilerOutputKind.PROGRAM.prefix(HostManager.host) + val suffix = CompilerOutputKind.PROGRAM.suffix(HostManager.host) + val fileName = "${prefix}native-binary$suffix" + val outputFile = "build/bin/$nativeHostTargetName/debugExecutable/$fileName" + + build(linkTask, "-Pkotlin.native.linkFromSources") { + assertSuccessful() + assertTasksExecuted(linkTask) + assertFileExists(outputFile) + checkNativeCommandLineFor(linkTask) { + assertTrue(it.contains("-Xcommon-sources=")) + assertTrue(it.contains(projectDir.resolve("src/commonMain/kotlin/RootMain.kt").absolutePath)) + } + } + } + @Test fun testNativeFreeArgsWarning() = with(transformProjectWithPluginsDsl("kotlin-dsl", gradleVersion, "new-mpp-native-binaries")) { gradleBuildScript().appendText( 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 1a0d02ee0ee..9c193a6a2ec 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 @@ -360,7 +360,9 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile() { init { - dependsOn(project.provider { compilation.compileKotlinTask }) + if (!linkFromSources) { + dependsOn(project.provider { compilation.compileKotlinTask }) + } } @Internal @@ -370,12 +372,21 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile = project.provider { compilation.compileKotlinTask.outputFile.get() } - override fun getSource(): FileTree = project.files(intermediateLibrary.get()).asFileTree + @InputFiles + @SkipWhenEmpty + override fun getSource(): FileTree = + if (linkFromSources) { + // Allow a user to force the old behaviour of a link task. + // TODO: Remove in 1.3.70. + project.files(compilation.allSources).asFileTree + } else { + project.files(intermediateLibrary.get()).asFileTree + } @get:Input override val outputKind: CompilerOutputKind @@ -443,6 +454,13 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile = mutableListOf().apply { addAll(super.buildCompilerArgs()) @@ -462,7 +480,25 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile = listOf("-Xinclude=${intermediateLibrary.get().absolutePath}") + override fun buildSourceArgs(): List { + return if (!linkFromSources) { + listOf("-Xinclude=${intermediateLibrary.get().absolutePath}") + } else { + // Allow a user to force the old behaviour of a link task. + // TODO: Remove in 1.3.70. + mutableListOf().apply { + val friends = compilation.friendCompilation?.output?.allOutputs?.files + if (friends != null && friends.isNotEmpty()) { + addArg("-friend-modules", friends.joinToString(File.pathSeparator) { it.absolutePath }) + } + + addAll(project.files(compilation.allSources).map { it.absolutePath }) + if (!compilation.commonSources.isEmpty) { + add("-Xcommon-sources=${compilation.commonSources.joinToString(separator = ",") { it.absolutePath }}") + } + } + } + } private fun validatedExportedLibraries() { val exportConfiguration = exportLibraries as? Configuration ?: return @@ -500,6 +536,10 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile