Hey there! I’m trying to integrate our multiplatfo...
# ios
m
Hey there! I’m trying to integrate our multiplatform framework into a big iOS project, where we use
project.yml
to generate the xcodeproj file. Did anyone manage to do this? I’m following the blog post https://blog.jetbrains.com/kotlin/2021/07/multiplatform-gradle-plugin-improved-for-connecting-kmm-modules/ to use the
embedAndSignAppleFrameworkForXcode
task, but I can’t even get it working by manually adjusting the Xcode settings - it won’t find the module. Did anyone achieve this using
project.yml
? Thank you!
PS: I can’t find any documentation at all on kotlinlang.org about the
embedAndSignAppleFrameworkForXcode
task. Is somebody working on that? This seems like an important gap in the docs right now.
h
Do you use this tool? https://github.com/yonaskolb/XcodeGen Sounds nice, will try it out. Maybe a candidate for KGP/Amper too
m
Yes, exactly - that’s the one 🙂
So I managed to modify the
project.yml
so the
embedAndSignAppleFrameworkForXcode
task is run and the framework gets generated! That’s at least half the thing. For anyone trying this, I’ve had some luck using this:
Copy code
preBuildScripts:
      - script: |
          env # prints env variables for debugging
          cd "$SRCROOT/../shared"
          ./gradlew :embedAndSignAppleFrameworkForXcode
        name: "Compile shared.framework"
        showEnvVars: true
        basedOnDependencyAnalysis: false
However, when I try to include that framework somewhere else, I get the following linker error:
Copy code
ld: Undefined symbols:
  _OBJC_CLASS_$_ClassA, referenced from:
       in SomeModule.o
  _OBJC_CLASS_$_ClassB, referenced from:
       in SomeModule.o
  _OBJC_CLASS_$_ClassC, referenced from:
       in SomeModule.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
(real class names have been removed). Any idea how to pull in that fresh framework into other targets?
(ah, well - the linker error actually came from me creating a new target called
shared
, which will then create a second
shared.framework
, which of course does not contain the symbols I need - leading to the linker to fail. But I still don’t know how to use the compiled KMM shared.framework across all our projects modules.
So I did more digging into this, and I managed to compile one module manually on the terminal - though I have absolutely no clue how to tell Xcode what I did. The problem was a 12k big
clang
command. I put that into a
test.sh
so I could execute it again and again in a quick way. There are a lot of
-F
options in there, which specify the framework search paths. The one for the
shared.framework
was at the end - once I pulled that before all other
-F
options, the clang command succeeded and created a binary
The culprit seems to be a
-F
option that defines something with
EagerLinkingTBDs
- does anybody know more about that? This seems to contain a
.tbd
file with some JSON data about the shared framework, so that gets picked up by clang instead of picking up the real
shared.framework
. Any ideas would be welcome!
This is how the parameter looks like by the way (redacted):
-F/Users/mreichelt/Library/Developer/Xcode/DerivedData/MyProject-fprqwlsbahdjfhwbvkfnwnxjixzpn/Build/Intermediates.noindex/EagerLinkingTBDs/Debug-iphonesimulator
This looks like https://developer.apple.com/documentation/xcode/build-settings-reference#Eager-Linking - but the target we use in our project does not have eager linking enabled. Weird.
So I found the actual issue. TL;DR: always clear your DerivedData when you make multiple xcodegen/project.yml / Xcode changes. Longer explanation what happened on my machine: 1. I tried to create a
shared
target in project.yml, which xcodegen would then put into the Xcode .pbxproj file. 2. The issue with that is: this would create a (Swift)
shared.framework
, with the actual KMM
shared.framework
living inside it (under the
Frameworks
folder) ⚠️ 3. Xcode seems to generate an empty
EagerLinkingTBDs
directory, with a .tbd file - for the Swift
shared.framework
! 4. Now every module trying to use
shared.framework
will fail to link, because it will try to link against the TBD version, and definitely not the KMM module. So in the end, after I cleaned the DerivedData folder, I could successfully import the KMM
shared.framework
by directly linking it in my desired module
SomeModule
. CC @hfhbd What I didn’t manage to get done yet is: how can I include the
shared.framework
in multiple Xcode targets, without calling Gradle for each target? Still investigating.