From 9b2a03b6cdc1d5f0f5ffe3cd05da7dc8c81d63f4 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Tue, 25 Sep 2018 15:55:45 +0300 Subject: [PATCH] Refresh interop docs. (#2130) --- FAQ.md | 7 +-- INTEROP.md | 122 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/FAQ.md b/FAQ.md index dd1079000be..9cf4ba92045 100644 --- a/FAQ.md +++ b/FAQ.md @@ -1,8 +1,9 @@ ### Q: How do I run my program? -A: Define a top level function `fun main(args: Array)`, please ensure it's not -in a package. Also compiler switch `-entry` could be used to make any function taking -`Array` and return `Unit` as an entry point. +A: Define a top level function `fun main(args: Array)` or just `fun main()` if you are not interested +in passed arguments, please ensure it's not in a package. +Also compiler switch `-entry` could be used to make any function taking `Array` or no arguments +and return `Unit` as an entry point. ### Q: What is Kotlin/Native memory management model? diff --git a/INTEROP.md b/INTEROP.md index 55fc7733838..89e9fe9fcc3 100644 --- a/INTEROP.md +++ b/INTEROP.md @@ -20,60 +20,49 @@ imported into an IDE for the purpose of code completion and navigation. Interoperability with Swift/Objective-C is provided too and covered in a separate document [OBJC_INTEROP.md](OBJC_INTEROP.md). +## Platform libraries ## + + Note that in many cases there's no need to use custom interoperability library creation mechanisms described below, +as for APIs available on the platform standartized bindings called [platform libraries](PLATFORM_LIBS.md) +could be used. For example, POSIX on Linux/macOS platforms, Win32 on Windows platform, or Apple frameworks +on macOS/iOS are available this way. + ## Simple example ## -Build the dependencies and compiler (see `README.md`). - -Prepare stubs for the system sockets library: +Install libgit2 and prepare stubs for the git library:
```bash -cd samples/socket -../../dist/bin/cinterop -def src/main/c_interop/sockets.def \ - -o sockets +cd samples/gitchurn +../../dist/bin/cinterop -def src/main/c_interop/libgit2.def \ + -compilerOpts -I/usr/local/include -o libgit2 ```
-Compile the echo server: +Compile the client:
```bash -../../dist/bin/kotlinc src/main/kotlin/EchoServer.kt \ - -library sockets -o EchoServer +../../dist/bin/kotlinc src/main/kotlin \ + -library libgit2 -o GitChurn ```
- -This whole process is automated in the `build.sh` script, which also supports cross-compilation -to supported cross-targets with `TARGET=raspberrypi ./build.sh` (the `cross_dist` target must -be executed first). - -Run the server: +Run the client:
```bash -./EchoServer.kexe 3000 & +./GitChurn.kexe ../.. ```
-Test the server by connecting to it, for example with telnet: - -
- -```bash -telnet localhost 3000 -``` - -
- -Write something to the console and watch the server echo it back. ## Creating bindings for a new library ## @@ -83,8 +72,9 @@ Structurally it's a simple property file, which looks like this:
```c -headers = zlib.h -compilerOpts = -std=c99 +headers = png.h +headerFilter = png.h +package = png ```
@@ -96,14 +86,14 @@ in the sysroot search paths, headers may be needed):
```bash -cinterop -def zlib.def -copt -I/opt/local/include -o zlib +cinterop -def png.def -compilerOpts -I/usr/local/include -o png ```
-This command will produce a `zlib.klib` compiled library and -`zlib-build/kotlin` directory containing Kotlin source code for the library. +This command will produce a `png.klib` compiled library and +`png-build/kotlin` directory containing Kotlin source code for the library. If the behavior for a certain platform needs to be modified, you can use a format like `compilerOpts.osx` or `compilerOpts.linux` to provide platform-specific values @@ -178,9 +168,39 @@ excludeDependentModules = true When both `excludeDependentModules` and `headerFilter` are used, they are applied as an intersection. +### C compiler and linker options ### + + Options passed to the C compiler (used to analyze headers, such as preprocessor definitions) and the linker +(used to link final executables) can be passed in the definition file as `compilerOpts` and `linkerOpts` +respectively. For example + +
+ +```c +compilerOpts = -DFOO=bar +linkerOpts = -lpng +``` + +
+ +Target-specific options, only applicable to the certain target can be specified as well, such as + +
+ + ```c + compilerOpts = -DBAR=bar + compilerOpts.linux_x64 = -DFOO=foo1 + compilerOpts.mac_x64 = -DFOO=foo2 + ``` + +
+ +and so, C headers on Linux will be analyzed with `-DBAR=bar -DFOO=foo1` and on macOS with `-DBAR=bar -DFOO=foo2`. +Note that any definition file option can have both common and the platform-specific part. + ### Adding custom declarations ### -Sometimes it is required to add custom C declarations to the library before + Sometimes it is required to add custom C declarations to the library before generating bindings (e.g., for [macros](#macros)). Instead of creating an additional header file with these declarations, you can include them directly to the end of the `.def` file, after a separating line, containing only the @@ -351,7 +371,7 @@ or
```kotlin -val bytePtr = placement.allocArray(5): +val bytePtr = placement.allocArray(5) ```
@@ -635,9 +655,12 @@ The `.def` file supports several options for adjusting the generated bindings. values correspondingly. If the enum is not included into any of these lists, then it is generated according to the heuristics. +* `noStringConversion` property value is space-separated lists of the functions whose + `const char*` parameters shall not be autoconverted as Kotlin string + ### Portability ### -Sometimes the C libraries have function parameters or struct fields of a + Sometimes the C libraries have function parameters or struct fields of a platform-dependent type, e.g. `long` or `size_t`. Kotlin itself doesn't provide neither implicit integer casts nor C-style integer casts (e.g. `(size_t) intValue`), so to make writing portable code in such cases easier, @@ -671,3 +694,32 @@ fun zeroMemory(buffer: COpaquePointer, size: Int) { Also, the type parameter can be inferred automatically and so may be omitted in some cases. + + +### Object pinning ### + + Kotlin objects could be pinned, i.e. their position in memory is guaranteed to be stable +until unpinned, and pointers to such objects inner data could be passed to the C functions. For example + +
+ +```kotlin +fun readData(fd: Int): String { + val buffer = ByteArray(1024) + buffer.usePinned { pinned -> + while (true) { + val length = recv(fd, pinned.addressOf(0), buffer.size.convert(), 0).toInt() + + if (length <= 0) { + break + } + // Now `buffer` has raw data obtained from the `recv()` call. + } + } +} +``` + +
+ +Here we use service function `usePinned`, which pins an object, executes block and unpins it on normal and +exception paths. \ No newline at end of file