GitLiveApp / firebase-kotlin-sdk

A Kotlin-first SDK for Firebase
https://gitliveapp.github.io/firebase-kotlin-sdk/
Apache License 2.0
1.08k stars 154 forks source link

Linker errors when building for iOS #111

Closed gushromp closed 3 years ago

gushromp commented 3 years ago

Hi, in my KMM project, I've added the following to shared/build.gradle.kts:

sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("dev.gitlive:firebase-auth:1.0.0")
                ...

But when I try building the iOS application, I get the following linker errors:

.app/iosApp
ld: warning: Could not find or use auto-linked framework 'GoogleDataTransport'
ld: warning: Could not find or use auto-linked framework 'FirebaseCoreDiagnostics'
ld: warning: Could not find or use auto-linked framework 'FirebaseAnalytics'
ld: warning: Could not find or use auto-linked framework 'nanopb'
ld: warning: Could not find or use auto-linked framework 'FirebaseAuth'
ld: warning: Could not find or use auto-linked framework 'FIRAnalyticsConnector'
ld: warning: Could not find or use auto-linked framework 'GoogleUtilities'
ld: warning: Could not find or use auto-linked framework 'FirebaseCore'
ld: warning: Could not find or use auto-linked framework 'GoogleAppMeasurement'
ld: warning: Could not find or use auto-linked framework 'GTMSessionFetcher'
ld: warning: Could not find or use auto-linked framework 'FirebaseInstallations'
ld: warning: Could not find or use auto-linked framework 'PromisesObjC'
Undefined symbols for architecture x86_64:
  "_FIRAuthErrorDomain", referenced from:
      _cocoapods_FirebaseAuth_FIRAuthErrorDomain_getter_wrapper0 in shared(result.o)
     (maybe you meant: _cocoapods_FirebaseAuth_FIRAuthErrorDomain_getter_wrapper0, knifunptr_cocoapods_FirebaseAuth3_FIRAuthErrorDomain_getter )
  "_OBJC_CLASS_$_FIRUser", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRMultiFactorSession", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRPhoneAuthProvider", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRAuthDataResult", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRGoogleAuthProvider", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRMultiFactorInfo", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIREmailAuthProvider", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRGitHubAuthProvider", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRFacebookAuthProvider", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRActionCodeSettings", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRTwitterAuthProvider", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRAuth", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIROAuthProvider", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIROptions", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRActionCodeInfo", referenced from:
      objc-class-ref in shared(result.o)
  "_OBJC_CLASS_$_FIRApp", referenced from:
      objc-class-ref in shared(result.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I noticed that, when cloning the firebase-kotlin-sdk repository and trying to build firebase-auth from there, there's an additional Carthage step which seems to download the required frameworks and link them: *** Downloading binary-only framework FirebaseAuthBinary at "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAuthBinary.json"

... but this step doesn't seem to happen when using dev.gitlive:firebase-auth:1.0.0 as a dependency. Is there a way to solve this issue? Thanks.

nbransby commented 3 years ago

@Daeda88 can you help with this?

Daeda88 commented 3 years ago

I think currently the library doesnt export Firebase to projects implementing it. It just tells Xcode to import the library. To add it, in your build.gradle:

kotlin {
    ios {
        binaries {
            framework {
                isStatic = false
                transitiveExport = true

                linkerOpts("-F${rootProject.projectDir}/ios/Carthage/Build/iOS/")
                linkerOpts("-ObjC")
            }
            getTest("DEBUG").apply {
                linkerOpts("-F${rootProject.projectDir}/ios/Carthage/Build/iOS/")
                linkerOpts("-ObjC")
            }
        }
    }
   ...
   tasks {
        listOf("bootstrap", "update").forEach {
            task<Exec>("carthage${it.capitalize()}") {
                group = "carthage"
                executable = "carthage"
                args(
                    it,
                    "--project-directory", "${rootProject.projectDir}/ios/",
                    "--platform", "iOS",
                    "--cache-builds"
                )
            }
        }
    }
}

afterEvaluate {
    tasks.named("linkDebugTestIosArm64").configure {
        dependsOn(tasks.named("carthageBootstrap"))
    }
    tasks.named("linkDebugTestIosX64").configure {
        dependsOn(tasks.named("carthageBootstrap"))
    }
    tasks.named("linkDebugFrameworkIosArm64").configure {
        dependsOn(tasks.named("carthageBootstrap"))
    }
    tasks.named("linkDebugFrameworkIosX64").configure {
        dependsOn(tasks.named("carthageBootstrap"))
    }
    tasks.named("linkReleaseFrameworkIosArm64").configure {
        dependsOn(tasks.named("carthageBootstrap"))
    }
    tasks.named("linkReleaseFrameworkIosX64").configure {
        dependsOn(tasks.named("carthageBootstrap"))
    }
}
Daeda88 commented 3 years ago

With Kotlin 1.4, exporting additional libraries has become a bit easier iirc, so this should probably be upgraded.

Daeda88 commented 3 years ago

Alternatively, you can jut import Firebase through cocoapods in your ios project

heckslam commented 3 years ago

@Daeda88 I tried your solution but get the following error:

> Task :shared:carthageBootstrap FAILED
*** No Cartfile.resolved found, updating dependencies
Failed to read file or folder at /Users/user/StudioProjects/TestFirebaseKmm/iosApp/Cartfile: Error Domain=NSCocoaErrorDomain Code=260 "The file “Cartfile” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/user/StudioProjects/TestFirebaseKmm/iosApp/Cartfile, NSUnderlyingError=0x7ffd88e0bcc0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

How the Cartfile should look to work with Firebase-Auth?

Daeda88 commented 3 years ago

sorry, forgot about that part. Add a Cartfile ${rootProject.projectDir}/ios/ containing the required Firebase dependencies: binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAnalyticsBinary.json" == 6.30.0 binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseAuthBinary.json" == 6.30.0 binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseFirestoreBinary.json" == 6.30.0 binary "https://dl.google.com/dl/firebase/ios/carthage/FirebaseFunctionsBinary.json" == 6.30.0

rocketraman commented 3 years ago

I don't pretend to understand all the complexities around this, however I will note my use case and the issue I ran into in case its helpful to anyone. I recently upgraded to Firebase SDK 1.2.0. Because I have some platform code in iosMain that uses FirebaseAuth directly, I also import FirebaseAuth into my cocoapods block, using with the same version as is exported from the SDK (https://github.com/GitLiveApp/firebase-kotlin-sdk/blob/v1.2.0/firebase-auth/src/iosMain/c_interop/Cartfile):

pod("FirebaseAuth", "~> 7.3.0")

When doing this, my iOS build fails when running syncFramework with this error at linkDebugFrameworkIosX64:

error: Linking globals named 'cocoapods_FirebaseAuth_FIRAuthErrorDomain_getter_wrapper0': symbol multiply defined!

After much futzing about, the workaround in my case appeared to be to remove pod("FirebaseAuth", "~> 7.3.0") from my cocoapods block, which is a bit odd to me that this works because my code in iosMain depends on importing cocoapods.FirebaseAuth.*.

I don't understand exactly what is happening here, but I will also note that Firebase 7 has changed to use dynamic linking by default instead of static linking as in previous versions, see:

I do also import Firebase/Auth in my iOS project's Podfile, to workaround this issue, as per https://github.com/GitLiveApp/firebase-kotlin-sdk/issues/111#issuecomment-738773116.

leoull commented 1 year ago

This post worked for me

leoull commented 1 year ago

I resolved the issue and made a sample project: https://github.com/leoull/KMM-FirebaseAuth

JasonTranz commented 1 year ago

"ld: framework not found FirebaseFirestore"

Hi @Daeda88,

I'm not an iOS developer. I am using the Cocoapod in my project. I don't know as well as don't use Carthage library and I'm facing this problem. Do you have any other solutions?

Daeda88 commented 1 year ago

With the latest master I'd recommend using Cocoapods as well. I'm still doing an upgrade myself but it seems Carthage is giving issues with the deployment target when compiling ios. Just update the pod in your shared gradle using the 'native.cocoapods' plugin. Unfortunately those dependencies are not transitive so you have to import them yourself

Reedyuk commented 1 year ago

Carthage was really a temporary measure until cocoa pods was working. It's recommended to use cocoa pods going forward

JasonTranz commented 1 year ago

With the latest master I'd recommend using Cocoapods as well. I'm still doing an upgrade myself but it seems Carthage is giving issues with the deployment target when compiling ios. Just update the pod in your shared gradle using the 'native.cocoapods' plugin. Unfortunately those dependencies are not transitive so you have to import them yourself

Thanks for noticing this. Can you describe what steps I could do to resolve this problem?

JasonTranz commented 1 year ago

Carthage was really a temporary measure until cocoa pods was working. It's recommended to use cocoa pods going forward

Sorry, KMM is using Cocoadpods to manage the dependency iOS app. Any suggestion for this?

JasonTranz commented 1 year ago

I have a KMM project and I try to import firebase and its services of them to my project. I got stuck when build gradle to run iOS app and I found out this problem.

e: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld invocation reported errors

The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld command returned non-zero exit code: 1. output: ld: framework not found FirebaseFirestore

Note: you can see my repository here to clear the context https://github.com/jasontran98/crypto-app-with-kmm