cashapp / sqldelight

SQLDelight - Generates typesafe Kotlin APIs from SQL
https://cashapp.github.io/sqldelight/
Apache License 2.0
6.15k stars 516 forks source link

IOS build application fails when using sqldelight native driver NativeSqliteDriver #5007

Open PaytonGunnell opened 8 months ago

PaytonGunnell commented 8 months ago

SQLDelight Version

2.0.1

Operating System

macOS Sonoma 14.3

Gradle Version

8.4

Kotlin Version

1.9.22

Dialect

dont know

AGP Version

8.2.1

Describe the Bug

Im using kmm for android and ios multiplatform, I followed this tutorial for sqldelight and when I run the iosApp it crashes with this message:

The following build commands failed: Ld /build/ios/Debug-iphonesimulator/GreetingKMP.app/GreetingKMP normal (in target 'iosApp' from project 'iosApp') (1 failure)

I eventually figured out that if I change the iosMain actual class for DriverFactory:

actual class DriverFactory { actual fun createDriver(): SqlDriver { return NativeSqliteDriver(Database.Schema, "test.db") } }

to this:

actual class DriverFactory { actual fun createDriver(): SqlDriver { TODO() } }

the iosApp build will succeed. Here is a link to the project: https://github.com/PaytonGunnell/GreetingKMP Ive looked around and cant find any solutions, but here are some things I have already tried:

sqldelight: 2.0.1 -> 2.0.0 grade: 8.4 -> 8.2 gradle plugin: 8.2.0 -> 8.2.1 kotlin: 1.9.22 -> 1.9.20 simulator ios version: 17.2 -> 15.0

my kdoctor output: [✓] Operation System [✓] Java [✓] Android Studio [✓] Xcode [✓] CocoaPods

Conclusion: ✓ Your operation system is ready for Kotlin Multiplatform Mobile Development!

Stacktrace

No response

Gradle Build Script

plugins {
    id("org.jetbrains.kotlin.multiplatform").version("1.9.22")
    id("com.android.library").version("8.2.1")
    kotlin("plugin.serialization").version("1.9.22")
    id("com.google.devtools.ksp")
    id("com.rickclephas.kmp.nativecoroutines")
    id("app.cash.sqldelight").version("2.0.1")
}

sqldelight {
    databases {
        create("Database") {
            packageName.set("com.example")
        }
    }
}

kotlin {
    targets.all {
        compilations.all {
            compilerOptions.configure {
                freeCompilerArgs.add("-Xexpect-actual-classes")
            }
        }
    }
    androidTarget {
        compilations.all {
            kotlinOptions {
                jvmTarget = "1.8"
            }
        }
    }

    jvm()

    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "Shared"
            isStatic = true
        }
    }

    sourceSets {
        val ktorVersion = "2.3.8"
        val sqldelightVersion = "2.0.1"

        all {
            languageSettings.optIn("kotlin.experimental.ExperimentalObjCName")
        }
        commonMain.dependencies {
            // Datetime
            implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")

            // Coroutines
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")

            // Ktor
            implementation("io.ktor:ktor-client-core:$ktorVersion")
            implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
            implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")

            // SQLDelight
            implementation("app.cash.sqldelight:runtime:$sqldelightVersion")

            // Koin
            implementation("io.insert-koin:koin-core:3.5.3")
            implementation("io.insert-koin:koin-test:3.5.3")
        }
        commonTest.dependencies {
            implementation("org.jetbrains.kotlin:kotlin-test:1.9.22")
        }
        androidMain.dependencies {
            // Ktor
            implementation("io.ktor:ktor-client-android:$ktorVersion")

            // SQLDelight
            implementation("app.cash.sqldelight:android-driver:$sqldelightVersion")
        }
        iosMain.dependencies {
            // Ktor
            implementation("io.ktor:ktor-client-darwin:$ktorVersion")

            // SQLDelight
            implementation("app.cash.sqldelight:native-driver:$sqldelightVersion")
        }
        jvmMain.dependencies {
            // SQLDelight
            implementation(libs.sqldelight.driver)
        }
    }
}

android {
    namespace = "com.example.greetingkmp.shared"
    compileSdk = libs.versions.android.compileSdk.get().toInt()
    defaultConfig {
        minSdk = libs.versions.android.minSdk.get().toInt()
    }
}
PaytonGunnell commented 8 months ago

I figured out that if you change in gradle isStatic = true to isSataic = false, the ios build will run.

build.gradle.kts (:shared):

android { ... listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.binaries.framework { baseName = "Shared"
isStatic = false // Changed from true -> false } } ... }

Is this a good solution or does this cause other problems? I dont know what changing isStatic does.

john17727 commented 7 months ago

I'm facing this issue too and the isStatic workaround worked for me as well.

projectdelta6 commented 6 months ago

I've also run into this issue, and changing isStatic to false solves it, bit I have no idea what that actually does or if it will cause other problems later on?

aMujeeb commented 6 months ago

This work around solved the problem. No idea though..

oblakr24 commented 3 months ago

Still an issue on 2.0.2 on iOS, isStatic = false is a workaround, but I would not consider this a fix.

ikvarxt commented 3 months ago

Check out this Turn off static linking

JulianBissekkou commented 3 months ago

Whenever I do this it fails with an exception while starting the app. Its not able to find the shared compiled kotlin library.

garretyoder commented 2 weeks ago

Confirming the above, turning static to false seems to break recent versions of compose. Months ago this worked, but the new versions of compose seem to break when you dynamically link. Not sure how to get SQLDelight to work with them.