Does anyone have tips for improving iterative/debu...
# kotlin-native
Does anyone have tips for improving iterative/debug KMP/iOS workflows without having a monorepo setup? Current setup: We currently have separate repos for our shared libraries and iOS app (
). Our current approach is that `quizlet-kmp`'s CI builds the framework and publishes it to our private spec repo. iOS folks can then just pull the latest version. Problem: This approach has worked fine for us for the past while, but some issues with this approach that are starting to get annoying are: 1. It takes a lot of time to iterate within KMP and test the change on iOS. Having to push, wait for a release to be published, update your podfile, etc is time consuming. We want an opt-in way to allow iOS folks to develop using locally checked out KMP sources. 2. We can't drop breakpoints into the KMP code to debug issues on iOS. My understanding is that this is impossible to do unless you've built the code locally. What we're thinking: 1. The official Kotlin/Native Cocoapods Plugin seems to address issue 1 if we use it in an opt-in way (defaulting to CI builds instead). 2. Touchlab's xcode-kotlin plugin for Xcode seems to address issue 2 if the framework is built locally (and I think it's designed to be used alongside the cocoapods plugin?) Both of the examples for these tools are using a monorepo setup though. Has anyone gotten them working with separate, independent repos? I think I should be able to get the cocoapods plugin working by pointing the ios app's
to the absolute path of `quizlet-kmp`'s generated Podspec (regardless of directory). This could be conditionally done for every iOS engineer, since the Podfile is just a ruby script. I also think the xcode-kotlin plugin should also allow me to drag in files from any arbitrary directory. I'd love to hear if anyone else has done so and can confirm!
I was planning on building an xcframework to an S3 bucket, and then importing the built binary through Swift Package Manager.
But I also haven’t gotten there yet, so I’ll let you know how it goes in a couple weeks 😂
Nice, we’re already consuming “release versions” of our xcframeworks via cocoapods but we’re trying to smooth out the process for iterating and debugging between releases
gotcha. if you’re really needing the xcode-kotlin plugin, I suppose there’s always environment variables and shell scripts to copy things or link things around.
beyond that, the only other option i can think of is git submodules.
We don't have an all-in-one tool to set this up currently, but one thing that helps the round-trip during development is having an environment toggle to switch between consuming a remote pod, and building it locally. When you're making changes to the shared code, you can toggle to the local version, point it to wherever the shared code lives locally, and have it build from gradle the way the default cocoapods integration works. This should allow you to iterate more quickly as well as debug when necessary.
👍 2
FWIW, local xcframeworks can also be consumed via a path from SPM as well.
👆 1
When you're making changes to the shared code, you can toggle to the local version, point it to wherever the shared code lives locally, and have it build from gradle the way the default cocoapods integration works.
Yup, this is exactly what I'm hoping to set up! Just wanted to make sure that both xcode-kotlin and the default cocoapods integration work with arbitrary absoluate paths, rather than somewhere in the same hierarchy as the actual iOS xcode project
cc @Konstantin Tskhovrebov
I don’t know about xcode-kotlin (@kpgalligan) but our cocoapods gradle plugin generates podspec which can be used directly from xcode project by absolute path. As I know there are no differences between absolute local path and remote location
As @russhwolf mentioned, we've been setting up binary/CI build with a toggle to compile/build local. There are a few reasons to do so. The round trip cycle is long if you only consume CI binary. I'm also not a fan of hard boundaries between the teams. Maybe you need another piece of data but the "shared code" team didn't add it in the last release. Now you need to file a ticket, etc. If you can edit the code, edit the code. Same for bugs. We're also generally trying to "sell" the iOS team on contributing to Kotlin, but doing so in a way that doesn't require learning everything at once, changing, IDE's, etc. The binary build is a good way to start, but having no easy path to editing code is a blocker. So, that's the "why" of the toggle build.
👍 1
I'd recommend having your local set up such that you check out both repos to the same folder. So something like this:
Copy code
  |  |-quizlet-ios
  |  |-quizlet-kmp
same 1
Then the local Podfile path can be relative and the same for everybody.
On debugging, the Kotlin compiler puts absolute file paths for debugging info. I believe that is true for other llvm compilers, not just Kotlin (I've said that a lot and nobody has corrected me, but I haven't researched it a ton. Anyway). If you build on CI, the debug info will be for the CI's path, so breakpoints won't do anything. You can map paths to the local machine. There's a blog post here about it:
Now, adding code to Xcode. You can point at arbitrary files/folders, but it can be a little tricky. If you are using the CI build, but somebody dragged in references to
which doesn't exist on your drive, the project should still build, but that's frustrating. Cocoapods as of a couple years ago did not have a way to just reference a file/folder. I was either source that needed to be built, or a resource that would be packaged into your build, so you can't just have "extra files" in a podspec, unless something has changed.
However, I think even if you don't have files in your navigator, you can still step into a file while debugging, if it exists on disk. I'd need to try that again, though.
I don’t know about xcode-kotlin
It's barely a plugin. Even if we wanted to do crazy things, Xcode is pretty locked down. The "plugin" tell Xcode that
files are source, which means you can put breakpoints on them in the IDE, and adds a color definition, so you get some source coloring. After that, it's basically a lightly modified version of the lldb script that ships with Kotlin native.
The lldb script in kotlin native was optimized for command line. You'd ask it to print an object, and it would walk the whole graph. Xcode (and Appcode, Android Studio, etc) do that at scale, for each object. That introduces serious performance issues. A couple years ago we pushed ( a bunch of the optimizations we made to that script. Some wound up in the main script (caching field data, reducing IPC calls, etc). Some of them were pretty hacky, though (ex: We've since merged the xcode-kotlin plugin with the main lldb script, but visual debugging can be slow, and a revisit has been on the todo list for a while (but I'm secretly waiting for somebody else to do it 🙂 )
I also haven't figured out a good way to do reasonable
calls on the command line and have reasonable visual debugging performance, but some day soon we'll have to figure that out (
That's the full brain dump on debugging and Kotlin/Native.
cc @svyatoslav.scherbina
Haven't tried debugging in AS for a while, but needed to debug a native test today. Stepping over statements is much improved. It used to take a long time to get data back for each value, but it's pretty fast now.
Wow, super pleasant surprise to wake up to all this detail: thanks a bunch friends! Looks like we shouldn't have problems for opt-in local builds with the cocoapods plugin. It seems like this might be the one rough edge with the xcode-kotlin plugin for folks who haven't opted-in: At the same time, we can definitely just make sure everyone's checked out the kmp repo, even if they aren't using it for local sources. Eventually, we might look into @basher’s approach of embedding plists in dsyms for CI builds: I imagine some things might have changed now that xcframeworks are a thing though 😅
We had non-monorepo for awhile, but then eventually switched, mainly to make it impossible to ship pods that broke builds of clients that hadn't updated yet. In non-monorepo, we had our own podspec for the KMP build (can't remember if plugin-way generates one for you or hides this detail). One of the things we did was take advantage of the fact that a podspec is just ruby, so we had an env var that CI would set when building a release. Locally, that wouldn't be set, so we could do things to improve local development (i.e. set different podspec settings based on presence of that env var), such as build with sources instead of a binary. Then, doing local KMP pod dev is the same as doing local dev for any other pod: update your local Podfile to do
path: '../path_to_pod_repo_root'
Nice. We're probably not going to do a monorepo any time soon, but are noodling on the idea of including the KMP repo as a git submodule within the ios repo to get some of those same benefits
git submodule
Lol yeah not the biggest fan of them, but also it's an easier sell than migrating to a monorepo
the Kotlin compiler puts absolute file paths for debugging info.
We have a compiler flag to change this. See
The lldb script in kotlin native was optimized for command line. You’d ask it to print an object, and it would walk the whole graph.
I believe we’ve changed this a while ago.
I believe we’ve changed this a while ago.
I think I mentioned a bit above, it's been a while since we synced the lldb script we use for Xcode with the one in main source. It's on our near term list of todos. I had't actually used debugging in a while, but I tried it recently and the experience in Android Studio has improved considerably.
🙏 1
👍 1