Apollo-android: KMM - Unable to complete `packForXcode` to build project containing `com.apollographql.apollo3:apollo-normalized-cache-sqlite`

Created on 21 Apr 2021  路  7Comments  路  Source: apollographql/apollo-android

Summary
After adding the com.apollographql.apollo3:apollo-normalized-cache-sqlite dependency, my bare-bones KMM project will no longer successfully complete the the packForXcode task. I've listed console output and attached debug-console output.

As a workaround, if I add the com.squareup.sqldelight to my common:build.gradle.kts, the task completes successful and the shared framework functions as expected in the iOS target. I wouldn't expect this is a sensible workaround, I've randomly stumbled upon it. Is there a missing dependency somewhere being provided by this plugin?

Version
3.0.0-dev6
Macbook Pro with M1 CPU (should that make any difference)

Description

  • A new KMM project created with Android Studio Arctic Fox | 2020.3.1 Canary 14
  • Add the following set of dependencies all at version 3.0.0-dev6...

    • com.apollographql.apollo3 (plugin)

    • com.apollographql.apollo3:apollo-runtime-kotlin

    • com.apollographql.apollo3:apollo-normalized-cache-sqlite

    • com.apollographql.apollo3:apollo-cache-interceptor

  • run ./gradlew packForXcode at external terminal - observe below error
  • Add the following plugin to common:build.gradle.kts

    • com.squareup.sqldelight (v1.4.4)

  • run ./gradlew packForXcode at external terminal - completes successfully
./gradlew packForXcode          

The Kotlin source set androidAndroidTestRelease was configured but not added to any Kotlin compilation. You can add a source set to a target's compilation by connecting it with the compilation's default source set using 'dependsOn'.
See https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#connecting-source-sets

> Task :shared:linkDebugFrameworkIos FAILED
e: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld invocation reported errors
Please try to disable compiler caches and rerun the build. To disable compiler caches, add the following line to the gradle.properties file in the project's root directory:

    kotlin.native.cacheKind=none

Also, consider filing an issue with full Gradle log here: https://kotl.in/issue
The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld command returned non-zero exit code: 1.
output:
Undefined symbols for architecture x86_64:
  "_sqlite3_bind_text16", referenced from:
      _SQLiter_SQLiteStatement_nativeBindString in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_bind_int64", referenced from:
      _SQLiter_SQLiteStatement_nativeBindLong in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_last_insert_rowid", referenced from:
      _SQLiter_SQLiteStatement_nativeExecuteForLastInsertedRowId in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_sql", referenced from:
      android::sqliteTraceV2Callback(unsigned int, void*, void*, void*) in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_reset", referenced from:
      _SQLiter_SQLiteConnection_nativeResetStatement in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_changes", referenced from:
      _SQLiter_SQLiteStatement_nativeExecuteForChangedRowCount in libco.touchlab:sqliter-cache.a(result.o)
      _SQLiter_SQLiteStatement_nativeExecuteForLastInsertedRowId in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_open_v2", referenced from:
      _SQLiter_SQLiteConnection_nativeOpen in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_db_config", referenced from:
      _SQLiter_SQLiteConnection_nativeOpen in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_bind_double", referenced from:
      _SQLiter_SQLiteStatement_nativeBindDouble in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_trace_v2", referenced from:
      _SQLiter_SQLiteConnection_nativeOpen in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_bind_parameter_index", referenced from:
      _SQLiter_SQLiteConnection_nativeBindParameterIndex in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_bytes", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnGetString in libco.touchlab:sqliter-cache.a(result.o)
      _SQLiter_SQLiteConnection_nativeColumnGetBlob in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_finalize", referenced from:
      _SQLiter_SQLiteStatement_nativeFinalizeStatement in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_text", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnGetString in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_name", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnName in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_close", referenced from:
      _SQLiter_SQLiteConnection_nativeClose in libco.touchlab:sqliter-cache.a(result.o)
      _SQLiter_SQLiteConnection_nativeOpen in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_prepare16_v2", referenced from:
      _SQLiter_SQLiteConnection_nativePrepareStatement in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_type", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnIsNull in libco.touchlab:sqliter-cache.a(result.o)
      _SQLiter_SQLiteConnection_nativeColumnType in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_count", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnCount in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_bind_blob", referenced from:
      _SQLiter_SQLiteStatement_nativeBindBlob in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_db_readonly", referenced from:
      _SQLiter_SQLiteConnection_nativeOpen in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_int64", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnGetLong in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_busy_timeout", referenced from:
      _SQLiter_SQLiteConnection_nativeOpen in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_bind_null", referenced from:
      _SQLiter_SQLiteStatement_nativeBindNull in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_extended_errcode", referenced from:
      android::throw_sqlite3_exception(sqlite3*) in libco.touchlab:sqliter-cache.a(result.o)
      android::throw_sqlite3_exception(sqlite3*, char const*) in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_double", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnGetDouble in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_column_blob", referenced from:
      _SQLiter_SQLiteConnection_nativeColumnGetBlob in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_step", referenced from:
      _SQLiter_SQLiteConnection_nativeStep in libco.touchlab:sqliter-cache.a(result.o)
      _SQLiter_SQLiteStatement_nativeExecute in libco.touchlab:sqliter-cache.a(result.o)
      _SQLiter_SQLiteStatement_nativeExecuteForChangedRowCount in libco.touchlab:sqliter-cache.a(result.o)
      _SQLiter_SQLiteStatement_nativeExecuteForLastInsertedRowId in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_clear_bindings", referenced from:
      _SQLiter_SQLiteConnection_nativeClearBindings in libco.touchlab:sqliter-cache.a(result.o)
  "_sqlite3_errmsg", referenced from:
      android::throw_sqlite3_exception(sqlite3*) in libco.touchlab:sqliter-cache.a(result.o)
      android::throw_sqlite3_exception(sqlite3*, char const*) in libco.touchlab:sqliter-cache.a(result.o)
ld: symbol(s) not found for architecture x86_64

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':shared:linkDebugFrameworkIos'.
> Compilation finished with errors

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2m 1s
5 actionable tasks: 2 executed, 3 up-to-date

debug-output-no-sqldelight.txt

Bug

All 7 comments

Thanks for filing this in details!

For some reason, the "New Project" wizard in Android Studio canary 14 doesn't give me a packForXcode target. Maybe it's a matter of KMM plugin version? I have 0.2.3.

In all cases, I made a small reproducer there: https://github.com/martinbonnin/kmm-link-error/tree/main

./gradlew :shared:linkDebugFrameworkIos seems to compile fine. Can you see anything different in your setup?

It looks like I hadn't used the cocoapods integration in the initial project setup. I _think_ when you don't enable cocoapods, the wizzard generates the following custom build task for you to use (and the iOS project executes it during it's build)...

val packForXcode by tasks.creating(Sync::class) {
    val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
    val framework = kotlin.targets.getByName<KotlinNativeTarget>("ios").binaries.getFramework(mode)
    val targetDir = File(buildDir, "xcode-frameworks")

    group = "build"
    dependsOn(framework.linkTask)
    inputs.property("mode", mode)

    from({ framework.outputDirectory })
    into(targetDir)
}

tasks.getByName("build").dependsOn(packForXcode)

I've copied your cocoapods setup, and everything seems to be fine from a compilation/linking point of view. Thanks so much for pointing this out 鉂わ笍

I just need to figure out how to have the cocoapods setup regenerate and reimport the framework during the iOS project build now - it seems to always use a stale version and I'm not sure yet how to force an update.

Ah thanks, I didn't even know there was an option for that :).

I updated the project to use packForXcode: https://github.com/martinbonnin/kmm-link-error/commit/0012507e3456c4711e1e6aa39310c8efbc9c89d4

And it still links. So I'm thinking there might be something else involved there. Did you try that suggestion from the logs you pasted?

e: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld invocation reported errors
Please try to disable compiler caches and rerun the build. To disable compiler caches, add the following line to the gradle.properties file in the project's root directory:

    kotlin.native.cacheKind=none

Looks like there might be some wrong caches somewhere?

I did try disabling the compiler cache, but it didn't help.

I've also rm -rf the ~/.gradle/caches, but don't see how that could be a thing here.

I'll pull your repro project again and try it

Your repro project seems to work fine in with packForXcode

Mine still does not, and I can't get to the bottom of why. 馃

I've copied all your gradle settings and even used the same gradlew version, but I get the same ld: symbol(s) not found for architecture x86_64 as above.

Adding linkerOpts.add("-lsqlite3") to the iosTarget -> binaries -> framework section of build.gradle.kts causes the linking to happen and packForXcode to complete successfully.

    iosTarget("ios") {
        binaries {
            framework {
                baseName = "shared"
                linkerOpts.add("-lsqlite3")
            }
        }
    }
Was this page helpful?
0 / 5 - 0 ratings