diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt index 68e7c8d5624..03fe724bf59 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/CocoaPodsIT.kt @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.gradle.util.runProcess import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.condition.OS +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Path import java.util.zip.ZipFile import kotlin.io.path.* import kotlin.test.assertContains @@ -1049,6 +1051,31 @@ class CocoaPodsIT : KGPBaseTest() { } } + @DisplayName("Build fails when embedAndSign task is used with pod-dependencies") + @GradleTest + fun testEmbedAndSignNotUsedWithPodDepsDiagnostic(gradleVersion: GradleVersion, @TempDir tempDir: Path) { + nativeProjectWithCocoapodsAndIosAppPodFile( + gradleVersion = gradleVersion, + environmentVariables = EnvironmentalVariables( + "CONFIGURATION" to "debug", + "SDK_NAME" to "iphoneos123", + "ARCHS" to "arm64", + "TARGET_BUILD_DIR" to tempDir.absolutePathString(), + "FRAMEWORKS_FOLDER_PATH" to "frameworks", + "BUILT_PRODUCTS_DIR" to tempDir.absolutePathString(), + ) + ) { + + buildGradleKts.addKotlinBlock("iosArm64()") + buildGradleKts.addCocoapodsBlock("""pod("Base64", version="1.1.2")""") + + buildAndFail(":embedAndSignPodAppleFrameworkForXcode") { + assertHasDiagnostic(CocoapodsPluginDiagnostics.EmbedAndSignUsedWithPodDependencies) + } + } + } + + private fun TestProject.buildAndFailWithCocoapodsWrapper( vararg buildArguments: String, assertions: BuildResult.() -> Unit = {}, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt index 902d3eeef82..d403e2817e7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/AppleXcodeTasks.kt @@ -17,6 +17,7 @@ import org.gradle.work.DisableCachingByDefault import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics +import org.jetbrains.kotlin.gradle.plugin.diagnostics.UsesKotlinToolingDiagnostics import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic import org.jetbrains.kotlin.gradle.plugin.mpp.Framework import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType @@ -217,11 +218,7 @@ internal fun Project.registerEmbedAndSignAppleFrameworkTask(framework: Framework val envSign = XcodeEnvironment.sign val userScriptSandboxingEnabled = XcodeEnvironment.userScriptSandboxingEnabled - val frameworkTaskName = lowerCamelCaseName( - AppleXcodeTasks.embedAndSignTaskPrefix, - framework.namePrefix, - AppleXcodeTasks.embedAndSignTaskPostfix - ) + val frameworkTaskName = framework.embedAndSignTaskName() if (envBuildType == null || envTargets.isEmpty() || envEmbeddedFrameworksDir == null) { locateOrRegisterTask(frameworkTaskName) { task -> @@ -250,7 +247,7 @@ internal fun Project.registerEmbedAndSignAppleFrameworkTask(framework: Framework } } - val embedAndSignTask = locateOrRegisterTask(frameworkTaskName) { task -> + val embedAndSignTask = locateOrRegisterTask(frameworkTaskName) { task -> task.group = BasePlugin.BUILD_GROUP task.description = "Embed and sign ${framework.namePrefix} framework as requested by Xcode's environment variables" task.isEnabled = !framework.isStatic @@ -288,6 +285,12 @@ internal fun Project.registerEmbedAndSignAppleFrameworkTask(framework: Framework } } +private fun Framework.embedAndSignTaskName(): String = lowerCamelCaseName( + AppleXcodeTasks.embedAndSignTaskPrefix, + namePrefix, + AppleXcodeTasks.embedAndSignTaskPostfix +) + private val Framework.namePrefix: String get() = KotlinNativeBinaryContainer.extractPrefixFromBinaryName( name, @@ -316,7 +319,7 @@ private fun Project.appleFrameworkDir(frameworkTaskName: String): Provider * To preserve these symlinks we are using the `cp` command instead. * See https://youtrack.jetbrains.com/issue/KT-48594. */ -@DisableCachingByDefault +@DisableCachingByDefault(because = "Caching breaks symlinks inside frameworks") internal abstract class FrameworkCopy : DefaultTask() { @get:Inject @@ -359,3 +362,6 @@ internal abstract class FrameworkCopy : DefaultTask() { fun dsymFile(framework: Provider): Provider = framework.map { File(it.path + ".dSYM") } } } + +@DisableCachingByDefault(because = "Caching breaks symlinks inside frameworks") +internal abstract class EmbedAndSignTask : FrameworkCopy(), UsesKotlinToolingDiagnostics diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsPluginDiagnostics.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsPluginDiagnostics.kt index 8659c8bb7a4..61b8d37214c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsPluginDiagnostics.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsPluginDiagnostics.kt @@ -6,8 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.native.cocoapods import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.ERROR -import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.WARNING +import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.* import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnosticFactory @InternalKotlinGradlePluginApi // used in integration tests @@ -52,4 +51,13 @@ object CocoapodsPluginDiagnostics { operator fun invoke(podName: String, dependencyName: String) = build("Couldn't find declaration of pod '$dependencyName' (interop-binding dependency of pod '${podName}')") } + object EmbedAndSignUsedWithPodDependencies : ToolingDiagnosticFactory(FATAL) { + operator fun invoke() = build( + """ + 'embedAndSign' task can not be used in a project with dependencies to pods. + Please use CocoaPods for integration into Xcode. + """.trimIndent() + ) + } + } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt index 734dcfc872b..8bac645d185 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt @@ -815,6 +815,24 @@ open class KotlinCocoapodsPlugin : Plugin { } } + + private fun checkEmbedAndSignNotUsedTogetherWithPodDependencies(project: Project, kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension) { + cocoapodsExtension.pods.all { + SingleActionPerProject.run(project, "assertEmbedAndSignNotUsedTogetherWithPodDependencies") { + kotlinExtension.targets.withType().all { target -> + target.binaries.withType().all { + project.tasks.withType().all { embedAndSignTask -> + embedAndSignTask.doFirst { + embedAndSignTask.reportDiagnostic(CocoapodsPluginDiagnostics.EmbedAndSignUsedWithPodDependencies()) + } + } + } + } + + } + } + } + private fun Project.gradleWrapperPath(): Provider { return provider { rootProject.tasks.locateTask("wrapper")?.get()?.scriptFile?.absolutePath } } @@ -873,6 +891,7 @@ open class KotlinCocoapodsPlugin : Plugin { createInterops(project, kotlinExtension, cocoapodsExtension) configureLinkingOptions(project, cocoapodsExtension) checkLinkOnlyNotUsedWithStaticFramework(project, cocoapodsExtension) + checkEmbedAndSignNotUsedTogetherWithPodDependencies(project, kotlinExtension, cocoapodsExtension) } }