Closed ArthurBrum closed 4 years ago
Hello!
But the hard part is that I have to consume another library.
Just for more context: is it an ObjC or a Kotlin/Native library?
As for the issue itself, please add -framework
before UIKit
in your def-file:
linkerOpts = -framework External_lib -framework UIKit
I tried this:
3299 (comment)
But got: Key testDebugExecutable is missing in the map.
That's because you tried to change settings of a test executable, not a framework. To change settings of a framework, you need to write something like this:
binaries.getByName("debugFramework").linkerOpts("-framework UIKit")
binaries.getByName("releaseFramework").linkerOpts("-framework UIKit")
But you don't have to do this if you add linker opts to your def-file. See more about Kotlin/Native binaries in this doc.
Yeess!! it worked! Thanks a lot @ilmat192 ! One last thing: I'm trying to remove the duplicated code by doing:
kotlin {
targets {
...
fromPreset(presets.android, 'android')
def buildForDevice = project.findProperty("device")?.toBoolean() ?: false
def iosPreset = (buildForDevice) ? presets.iosArm64 : presets.iosX64
def iosTarget = System.getenv('SDK_NAME')?.startsWith('iphoneos') \
? presets.iosArm64 : presets.iosX64
fromPreset(iosPreset, 'ios')
fromPreset(iosTarget, 'ios')
ios {
binaries {
framework('BC_lib'){
linkerOpts "-Fsrc/nativeInterop/frameworks"
}
}
compilations.main {
cinterops {
...
}
}
...
}
}
It built successfully, but now I'm not sure if I'm overwriting the two targets... I understand one of them is for the iOS device and the other one is for the simulator, but what happens when iosPreset and iosTarget gets the same name 'ios' ? Is there a better way of targeting both arm64 and iosX64 and applying these same compilations to both of them? Im not quite sure of these formPreset calls would do in different situations =/
@ArthurBrum Well, the plugin allows you to run fromPreset
several time with the same arguments. It does so because the fromPreset
method has a full version allowing one to configure a target. E.g.:
fromPreset(presets.iosX64, "ios") {
// Configuration goes here.
}
So the plugin allows configuring the same target several times.
But if you call fromPreset
twice with different presets and the same name, you'll get an error because a target name must be unique. Since your build runs successfully, most probably in your case iosPreset
just equals to iosTarget
.
You do can create both device and simulator targets but it may be inconvenient due to IDE limitations. You said that you write a Kotlin library. Do you plan to publish this library to Maven and then depend on it in another Kotlin/Native project? Or just build a framework from this library and include it into an iOS app?
Second option, just build a framework to be included into iOS apps. But I just notice I get architecture errors when trying to execute on real device (running on simulator goes ok)
Knowing your use case is important because currently IDE support has an important limitation: navigation/completion for iOS SDKs works only for leaf source sets (see this section to learn more about project structure). In other words, if you have both device and simulator targets in you project and share some code between them using a shared source set, you'll get no IDE support for iOS SDKs in this shared code.
There are some workarounds for this issue. In your case you don't need to always create both device and simulator targets. Since Gradle build is often started from Xcode, you can infer if this build is for a device or a simulator and create an appropriate target. This part of your build script does exactly this thing:
def iosTarget = System.getenv('SDK_NAME')?.startsWith('iphoneos') ? presets.iosArm64 : presets.iosX64
fromPreset(iosPreset, 'ios') { ... }
It uses the environment variable SDK_NAME
set by Xcode to infer a platform we need to build for and create a target for this platform. If this environment variable isn't set (e.g. if we run Gradle from terminal), it creates a target for a simulator. Then you put your iOS code into leaf source sets (iosMain
and iosTest
), so you get the IDE support for it.
The downside of such an approach is that Gradle will recompile the framework every time you switch from device to simulator and vice versa.
Hey @ilmat192! Sorry to bother, but could you take a look at: https://github.com/JetBrains/kotlin-native/issues/3851#issuecomment-586638966 I thinks it is related, and since you know better about cinterop... I thought about asking you, just in case
I'm closing this one as solved. Feel free to reopen if something left here.
Please someone help me. I cant find good documentation for what I'm trying to do, and I really have to do this at my job. Summing up the problem: I'm trying to build a multiplatform library to be used for android and iOS applications. But the hard part is that I have to consume another library. On the ios side I'm trying to import the framework using cinterop, but its proving to be a very difficult task.
Let me show the current status of things:
Main project build.gradle
KMP project build.gradle
external_lib.def
As it should be clear by now, I'm no good at using gradle, so I'm desperately asking for help. I have tried several solutions from other issues of this github, but none solved or made sense in my case, since I'm a bit loss with my build.gradle file.
I tried this: https://github.com/JetBrains/kotlin-native/issues/3299#issuecomment-527024708 But got:
Key testDebugExecutable is missing in the map.
Following this: https://medium.com/androidiots/the-magic-of-kotlin-native-part-2-49097c2dea1a I got to add the "libraryPaths" part of the .def file, but now sure if it was supposed to be there or in the gradle file.. or even if it should be in the -F parameter used in the gradle.build file...
Also, I'll have to use several frameworks from Apple, not just UIKit one, so if someone could put me in the right direction to not only link them, but also export them in my generated framework, I would be really grateful.