getsentry / sentry-kotlin-multiplatform

Sentry SDK for Kotlin Multiplatform
MIT License
136 stars 19 forks source link

Compilation failed: Linking globals named 'kniprot_cocoapods_Sentry3_SentryMetricsAPIDelegate': symbol multiply defined! #224

Closed plusmobileapps closed 5 months ago

plusmobileapps commented 5 months ago

Platform

Apple, Android

Installed

CocoaPods

Version

0.6.0

Steps to Reproduce

Following the setup instructions in shared build.gradle.kts:

# libs.versions.toml
"sentry-core = { group = "io.sentry", name = "sentry-kotlin-multiplatform", version = "0.6.0" }
kotlin {
    androidTarget()
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    cocoapods {
        ios.deploymentTarget = "16.0"
        podfile = project.file("../iosApp/Podfile")

        pod("Sentry") {
            version = "~> 8.25.0"
            extraOpts += listOf("-compiler-option", "-fmodules")
        }

        framework {
            baseName = "shared"

            export(libs.sentry.core)
        }
    }

Podfile is:

target 'iosApp' do
  use_frameworks!
  platform :ios, '16.0'
  pod 'shared', :path => '../shared'
end

Build the iOS app.

Expected Result

App should compile.

Actual Result

Compilation failed: Linking globals named 'kniprot_cocoapods_Sentry3_SentryMetricsAPIDelegate': symbol multiply defined!
java.lang.Error: Linking globals named 'kniprot_cocoapods_Sentry3_SentryMetricsAPIDelegate': symbol multiply defined!

I've tried a couple of different options laid out in this forum post such as using static frameworks in the Podfile or clearing caches and reinitializing pod file project. But still not sure what is causing the build error.

buenaflor commented 5 months ago

Hey thanks for raising this, I've actually come up with the same issue yesterday by accident. I'm currently investigating this.

buenaflor commented 5 months ago

Which Xcode version do you have installed?

buenaflor commented 5 months ago

Please check if this fixes your issue, add this to shared/build.gradle.kts:

kotlin {
  // other kmp config

  targets.withType<KotlinNativeTarget>().all {
      compilations["main"].cinterops["Sentry"].extraOpts(
          "-compiler-option", "-DSentryIntegrationProtocol=SentryIntegrationProtocolUnavailable",
          "-compiler-option", "-DSentryMetricsAPIDelegate=SentryMetricsAPIDelegateUnavailable"
      )
  }
}
robert-nash commented 5 months ago

I am also experiencing the same problem. I tried your fix @buenaflor but then I get the following error when performing gradle sync: DefaultCInteropSettings with name 'Sentry' not found.

I don't understand the detail of your fix so sorry if I'm missing the point!

buenaflor commented 5 months ago

@robert-nash can you post your build.gradle setup?

robert-nash commented 5 months ago

Here you go @buenaflor, thanks for taking a look:

import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework

plugins {
    id("maven-publish")
    kotlin("multiplatform")
    kotlin("native.cocoapods")
    kotlin("plugin.serialization")
    id("com.android.library")
}

repositories {
    mavenCentral()
    google()
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.1")
    implementation("junit:junit:4.13.2")
    implementation("org.junit.jupiter:junit-jupiter:5.8.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.ext:junit-ktx:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}

publishing {
    repositories {
        maven {
            name = "XXXXX"
            url = uri("https://maven.pkg.github.com/XXXXXX/XXXXXXXXXXXXX")
            credentials(PasswordCredentials::class)
        }
    }
}

version = "1.0.0"
group = "com.XXXX.XXXXX"

@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
kotlin {
    targetHierarchy.default()

    task("testClasses")

    androidTarget {
        publishLibraryVariants("release", "debug")
        compilations.all {
            kotlinOptions {
                jvmTarget = "1.8"
            }
        }
    }

    val xcf = XCFramework()

    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
            xcf.add(this)
        }
    }

    sourceSets {
        val ktorVersion = "2.3.3"
        val koinVersion = "3.4.0"

        val commonMain by getting {
            dependencies {
                implementation("io.github.aakira:napier:2.6.1")
                implementation("io.ktor:ktor-client-core:$ktorVersion")
                implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
                implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
                implementation("com.russhwolf:multiplatform-settings:1.1.1")
                implementation("com.russhwolf:multiplatform-settings-test:1.1.1")
                implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0-RC.2")
                api("io.insert-koin:koin-core:$koinVersion")
                implementation("io.insert-koin:koin-test:$koinVersion")
                implementation("io.sentry:sentry-kotlin-multiplatform:0.6.0")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("androidx.startup:startup-runtime:1.1.1")
                implementation("com.google.android.gms:play-services-location:21.0.1")
                implementation("io.ktor:ktor-client-cio:$ktorVersion")
            }
        }
        val androidUnitTest by getting {
            dependencies {
                implementation("org.robolectric:robolectric:4.11.1")
            }
        }
        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-darwin:$ktorVersion")
            }
        }

        targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>().all {
            compilations["main"].cinterops["Sentry"].extraOpts(
                "-compiler-option", "-DSentryIntegrationProtocol=SentryIntegrationProtocolUnavailable",
                "-compiler-option", "-DSentryMetricsAPIDelegate=SentryMetricsAPIDelegateUnavailable"
            )
        }
    }

    cocoapods {
        version = version
        summary = "Some description for a Kotlin/Native module"
        homepage = "Link to a Kotlin/Native module homepage"

        name = "XXXXXXXXXXXX"

        framework {
            baseName = "XXXXXXXXXX"
        }

        source =
            "{ :git => \"git@github.com:xxxxxx/XXXXXXXXXXXX.git\", :branch => \"debug\"}"

        extraSpecAttributes = mutableMapOf("platform" to ":ios, '13.4'")
        ios.deploymentTarget = "13.4"

        pod("Sentry") {
            version = "~> 8.25"
            extraOpts += listOf("-compiler-option", "-fmodules")
        }
    }
}

android {
    compileSdk = 33
    defaultConfig {
        minSdk = 21
        namespace = "live.XXXXXXXX.XXXXXXXX"
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    testOptions {
        unitTests {
            isIncludeAndroidResources = true
        }
    }
    packaging {
        resources.excludes.addAll(
            listOf(
                "META-INF/LICENSE.md",
                "META-INF/LICENSE-notice.md"
            )
        )
    }
}
buenaflor commented 5 months ago

hm I've tried it out with a minimal example and it works on my end.

buenaflor commented 5 months ago

This should be fixed in 0.7.1 please check to confirm

plusmobileapps commented 5 months ago

Thanks for the quick fix @buenaflor, I verified that this is working again on kotlin native with 0.7.1 🚀