-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kotlin/Native tutorial. Writing a framework and dynamic library #1091
Conversation
…for Kotlin/Native
## Generated Framework Headers | ||
|
||
Each of created frameworks contains the header file in `<Framework>/Headers/Demo.h`. | ||
The file does not depend on the target platform (at least with Kotlin/Native v.0.8.1). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it is correct wrt some primitive type mappings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should definitely be correct for the code above. But it is not correct when Kotlin code has e.g. NSInteger
in public signatures.
@property (readonly) NSString *field; | ||
@end; | ||
|
||
__attribute__((objc_subclassing_restricted)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exact generated bindings content may change without a warning, and we shalln't put too much emphasis on how what is inside, but on hw to use it.
</div> | ||
|
||
The Kotlin code is turned into nearly the similar looking | ||
code in Swift. There are some small differences, so far. We create the Kotlin `object DemoObject` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we shall cover passing nullable primitives as well (see https://kotlinlang.slack.com/archives/C3SGXARS6/p1533824954000609).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added nullable types and lambdas
|
||
It may turn out tricky to configure the Objective-C or Swift project in XCode or | ||
JetBrains AppCode. You should include the Framework into the *General* tab of Target settings | ||
of XCode project. Also, you may need to fix the `@rpath` to include our Framework folder in the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better document how "to fix" rpath.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. added iOS explanation as well
where you run the compiler: | ||
- macOS: `demo_api.h` and `libdemo.dylib` | ||
- Linux: `demo_api.h` and `libdemo.so` | ||
- Windows: `demo_api.h` and `demo.dll` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Windows .def file is produced as well. Seems due to small bug it was produced inside Windows temporary files, but it will be fixed with JetBrains/kotlin-native#1859.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in the dynamic libraries branch and #1084
You may want to check [the thread](https://stackoverflow.com/questions/1675351/typedef-struct-vs-struct-definitions) | ||
for an explanation of that pattern. | ||
|
||
We see from that definitions that Kotlin object `DemoObject` is mapped into |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As with Objective-C manual not sure if diving into details of generated C headers is a good idea.
Now we call the following commands to compile the code into Frameworks | ||
for macOS, iOS and iOS emulator respectively: | ||
```bash | ||
kotlinc lib.kt -produce dynamic -output macOS/Demo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not produce framework
for macOS too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is on the list of 3 commands, what do I miss?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your first command produces dynamic library (macOS/Demo.dylib
), while other commands produce frameworks (iOS*/Demo.framework
). Is it OK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed. It was a typoe
|
||
[Demo forIntegersB:1 s:1 i:3 l:4]; | ||
|
||
NSString* ret = [Demo stringsStr:(@"That is string")]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(@"That is string")
Are brackets required here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
function `demoObject`, which allows us to get the only instance of the object and to call | ||
`DemoObject` methods on it. | ||
The standard pattern is used to create an instance of the `DemoClazz` class. We call | ||
the `[[ DemoDemoClazz alloc] init]` on Objective-C. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another standard pattern can be used here: [DemoDemoClazz new]
. It is available for calling constructor without parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
The Kotlin code is turned into nearly the similar looking | ||
code in Swift. There are some small differences, so far. We create the Kotlin `object DemoObject` | ||
as a class in Swift to access it's methods. We may see from the Objective-C attributes | ||
in `<Framework>/Headers/Demo.h` that it is the way to access the object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not exactly clear from this sentence that DemoObject()
doesn't create new instance of DemoObject
but returns the existing single one. I would prefer to avoid the word "create".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
|
||
Kotlin/Native supports C interop too. Checkout the [Kotlin/Native as a Dynamic Library](dynamic-libraries.html) | ||
tutorial for that, or have a look at the | ||
[C Interop](https://github.com/JetBrains/kotlin-native/blob/master/OBJC_INTEROP.md) documentation article |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this link correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OBJC_INTEROP.md
doesn't seem to cover anything related to C interop or -produce dynamic
. What do I miss?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
with Kotlin objects from C language. Kotlin/Native has an interop with Objective-C and | ||
Swift, and integrates with their reference counters. You may want to find more details | ||
in the [documentation](https://github.com/JetBrains/kotlin-native/blob/master/OBJC_INTEROP.md) | ||
or to check the related [TUTORIAL_KOTLIN_macOS_FRAMEWORK_LINK]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does anything prevent this link from being [apple-framework.html]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll just remove that. The next sentence is just the about the same thing
|
||
Kotlin/Native object references does not support multi-threaded access. It | ||
might be necessary to host the returned `demo_ExportedSymbols*` pointer | ||
per thread. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@olonho Isn't demo_ExportedSymbols*
the same for all threads?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to the question
|
||
## Using Generated Headers from C | ||
|
||
The usage from C not complicated and strait forward. We create a `main.c` file with the following |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strait forward
Is it correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, fixed
//create Kotlin object instance | ||
demo_kref_demo_DemoClazz newInstance | ||
= lib->kotlin.root.demo.DemoClazz.DemoClazz(); | ||
long result = lib->kotlin.root.demo.DemoClazz.foo(newInstance, 42); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
long
!= demo_KLong
. It is better to use either demo_KLong
or long long
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
On macOS 10.13 with Xcode, we compile the C code and link it with the dynamic library | ||
with the following command: | ||
```bash | ||
gcc main.c libdemo.dylib |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On macOS there is no gcc anymore, it is wrapper for clang
. It makes some sense to use the latter directly here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
…s for Kotlin/Native
Merge branch 'tutorial-kn-dynamic-libraries' into tutorial-kn-apple-framework
…ble types and lambdas, restructure code and explanations, include more about @rpath and XCode setup
are mapped directly. | ||
are mapped directly. Non-nullable primitive types are mapped transparently. | ||
Nullable primitive types are mapped into `NSNumber*`. | ||
You may see both higher order functions `acceptFunF` and `supplyFun` are included, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the second one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
returned that function back in the samples above, thanks for noticing that
are mapped directly. Non-nullable primitive types are mapped transparently. | ||
Nullable primitive types are mapped into `NSNumber*`. | ||
You may see both higher order functions `acceptFunF` and `supplyFun` are included, | ||
and accept Objective-C lambdas. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure people often name Objective-C blocks this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll use blocks
too here, thanks!
We add the Framework in the `Embedded Binaries` section of the `General` section of | ||
the *target* configuration. We need to fix the `Framework Search Paths` in the | ||
`Build Settings` of the *target* configuration. We shall use the `iOS_emu` folder | ||
or the `ios_arm64` target for the run in the iOS emulator. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't get the meaning of this sentence. Is it entirely correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewrote it entirely, thanks!
|
||
## XCode for iOS Targets | ||
|
||
We add the Framework in the `Embedded Binaries` section of the `General` section of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is Embedded Binaries
feature available for macOS target?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, for bugger Mac you normally include frameworks with the application and configure @rpath
appropriately
```bash | ||
kotlinc lib.kt -produce framework -target macos_x64 -output macOS/Demo | ||
kotlinc lib.kt -produce framework -target ios_arm64 -output iOS/Demo | ||
kotlinc lib.kt -produce framework -target ios_x64 -output iOS_emu/Demo | ||
``` | ||
|
||
The `kotlinc` generates three frameworks for us, named `Demo.framework` under | ||
`macOS`, `iOS` and `iOS_emu` folders respectively. | ||
The `kotlinc` generates three Frameworks for us, named `Demo.framework` under |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of using capital "F" in "Framework"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
|
||
Kotlin/Native has garbage collection, but it does not help to deal | ||
with Kotlin objects from C language. Kotlin/Native has an interop with Objective-C and | ||
Swift, and integrates with their reference counters. You may want to find more details | ||
in the [documentation](https://github.com/JetBrains/kotlin-native/blob/master/OBJC_INTEROP.md) | ||
or to check the related [TUTORIAL_KOTLIN_macOS_FRAMEWORK_LINK]. | ||
|
||
NOTE. It is possible to have several Kotlin/Native dynamic libraries in one application, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it really work on macOS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed that line for now. It is hard to test, but looks possible
d2bbab8
to
e89bc8d
Compare
bit of proofreading on it
bit of proofreading
https://youtrack.jetbrains.com/issue/EVAN-5132
Ready for the factual check. English will be improved later