Usking kmmbridge to publish to cocoapods, with SQL...
# touchlab-tools
r
Usking kmmbridge to publish to cocoapods, with SQLDelight as a dependency, I'm getting this at pod lint time:
Copy code
Undefined symbols for architecture arm64:
      "_sqlite3_bind_blob", referenced from:
          _kfun:co.touchlab.sqliter.interop.ActualSqliteStatement#bindBlob(<http://kotlin.Int;kotlin.ByteArray|kotlin.Int;kotlin.ByteArray>){} in MobileSdk[arm64][2](MobileSdk.framework.o)
      "_sqlite3_bind_double", referenced from:
          _kfun:co.touchlab.sqliter.interop.ActualSqliteStatement#bindDouble(<http://kotlin.Int;kotlin.Double|kotlin.Int;kotlin.Double>){} in MobileSdk[arm64][2](MobileSdk.framework.o)
However, my cocoapods plugin framework
isStatic = true
so why would these symbols not be found?
Seems using dynamic linking fixes the problem. Weird.
You need to add
-lsqlite3
to linker flags. Even the JB docs are "wrong". Yes, making the framework dynamic works around the problem, but linker flags are normal native dev things. There are plenty of valid reasons you won't want a dynamic framework. But, yeah, if you don't want to bother with linker flags, for that specific issue, you can use a dynamic framework.
I submitting a PR to update the docs, which it seems was closed, although I don't see it in "closed" either. if they just closed it without comment, I'll be pretty frustrated. People follow these docs like they're "correct". https://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-ktor-sqldelight.html#turn-off-static-linking
r
So two things: 1) For cocoapods lint, where would I add this linker flag? 2) Isn't this what the SQLDelight configuration
linkSqlite
is supposed to do (it defaults to
true
)
k
1) For cocoapods lint, where would I add this linker flag?
No idea. Quick google has something that sounds promising, but we've been off CocoaPods for a while and I've only done linker flags for builds: https://stackoverflow.com/questions/59299875/how-do-i-solve-linker-errors-from-the-cocoapods-lint-command
2) Isn't this what the SQLDelight configuration
linkSqlite
is supposed to do (it defaults to
true
)
SqlDelight config does that to try to make life easier for Android devs, but I'm on the fence about it. It's sort of "magic", but leads to all kinds of confusion. For example, think of "static Framework" like "jar" and "dynamic Framework" like "aar". Not a direct comparison, but the dynamic framework carries some more metadata. That linker flag is one example. That's why you don't need it elsewhere. However, dynamic frameworks in other linking contexts can be a (relative) nightmare: https://crashkios.touchlab.co/docs/bugsnag#step-3---setup-dynamic-linking-optional
Looks like I wrote up the PR to the JB docs but never submitted it. Sorry JB xoxo. https://github.com/JetBrains/kotlin-multiplatform-dev-docs/pull/250
👍 1
r
Re
linkSqlite
I think I understand: it sets the metadata for dynamic linking, but the confusion arises because it does not add the link flag to xcode for static linking. Is that right? The SQLDelight docs on that flag could really use some love in that case.
we've been off CocoaPods for a while
Unfortunately I'm stuck on CocoaPods because this library is used in a React Native project, and they haven't migrated to SPM yet.
https://touchlab.co/kmmbridge-quick-start-cocoapods has an example of adding
sqlite3
to cocoapods via
extraSpecAttributes["libraries"]
which seems to match the cocoapod docs:
Copy code
extraSpecAttributes["libraries"] = "'c++', 'sqlite3'"
That would probably do it for the cocoapods lint with a static framework (but I'm fine with dynamic linking for now).
k
Re
linkSqlite
I think I understand: it sets the metadata for dynamic linking, but the confusion arises because it does not add the link flag to xcode for static linking. Is that right?
TL;DR - Yes. The longer version is that a dynamic framework is sort of a standalone executable living inside your executable (iOS experts, I said "sort of"). It needs everything defined to conceivably be run, or at least used. Static is more of a box of executable code. the final build takes chunks of that code and directly inserts it into your final executable. So, when building a static framework, the compiler doesn't care if code you reference is actually available, just that you've defined it. For ObjC, you just need headers to other code, and supplying that binary at link time is your problem. For dynamic, while assembling, it expects that binary to be available. To ensure that, dynamic frameworks also include your defined linker flags. In this case,
-lsqlite3
. KMP is difficult for most devs, because most are Android devs, and all this "linking" stuff is pretty foreign, unless you've done a lot of JNI. The particulars of Xcode tooling are sort of weird too. So, a lot of the docs are "turn on linking in SqlDelight config, and use a dynamic framework". However, for anything beyond fairly basic KMP, you'll need to have a working understanding of this stuff, or struggle quite a bit. That's why I push back on saying "use dynamic" without at least a mention that that is an oversimplified "solution".
👍 1
k
That would probably do it for the cocoapods lint with a static framework (but I'm fine with dynamic linking for now).
KMMBridge used to be more "balanced" between CocoaPods and SPM, but at this point, almost everybody wants SPM, and the actual publishing of CocoaPods is much more complex, because of the external spec repo, so the new version of KMMBridge supports CocoaPods, but the recent tutorials don't go into it. I kind of prefer CocoaPods personally as I've done it for a long time, and SPM is very locked down, which makes KMP build integration brutal, but CocoaPods is "a lot", config wise, and brain is full. That snippet you sent sounds right.
I would guess RN hasn't moved to SPM for the same reasons I just mentioned. SPM is very good with Swift, and pretty good with ObjC. Anything else, painful. I don't think Apple is trying to block out other languages as a goal. I think SPM tries really hard to remove external factors in builds for simplicity and portability, and Apple very much doesn't care about non-Apple build tech.
Pulling and building an SPM dependency generally "just works", while a serious CocoaPods project might involve extra stuff, outside of a recent ruby version, etc. So, I see the value in locking down SPM, but it has costs.
An interesting example with Apple. One Xcode release totally broke the Xcode Kotlin plugin. It was actually an Xcode bug, just with something almost nobody uses. Our team reached out to the Xcode team, and the response was kind of "meh, it's not a priority", but not, "yes, we closed down that loophole". Then magically it was fixed soon after.
🥲 1
But, building for iOS with things other than Swift and ObjC is very much trying to integrate with a platform that does not care if you're successful.
1
r
Thank you so much for this discussion. My understanding has increased significantly. Would appreciate your review on that SQLDelight PR I submitted above.
k
I'll add it to the list. Getting way behind on "today" already 🙂
😁 1