Skip to content

Commit

Permalink
doc(docs.topics.native.mappingPrimitiveDataTypesFromC): add notes
Browse files Browse the repository at this point in the history
  • Loading branch information
alfredo-toledano committed Nov 30, 2024
1 parent 2af4135 commit 0304395
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 82 deletions.
10 changes: 10 additions & 0 deletions docs/topics/native/lib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef LIB2_H_INCLUDED
#define LIB2_H_INCLUDED

void ints(char c, short d, int e, long f);
void uints(unsigned char c, unsigned short d, unsigned int e, unsigned long f);
void doubles(float a, double b);

#endif

// if you use C++ and overloaded functions -> `extern "C"` block is missing -- https://stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c --
139 changes: 57 additions & 82 deletions docs/topics/native/mapping-primitive-data-types-from-c.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,55 @@
[//]: # (title: Mapping primitive data types from C – tutorial)

> The C libraries import is [Experimental](components-stability.md#stability-levels-explained).
> All Kotlin declarations generated by the `cinterop` tool from C libraries
> should have the `@ExperimentalForeignApi` annotation.
>
> Native platform libraries shipped with Kotlin/Native (like Foundation, UIKit, and POSIX),
> require opt-in only for some APIs. In such cases, you get an IDE warning.
>
{type="warning"}

In this tutorial, you will learn what C data types are visible in Kotlin/Native and vice versa. You will:
- See what [Data types are in C language](#types-in-c-language).
- Create a [tiny C Library](#example-c-library) that uses those types in exports.
- [Inspect generated Kotlin APIs from a C library](#inspect-generated-kotlin-apis-for-a-c-library).
- Find how [Primitive types in Kotlin](#primitive-types-in-kotlin) are mapped to C.

## Types in C language

What types are there in the C language? Let's take the
[C data types](https://en.wikipedia.org/wiki/C_data_types) article from Wikipedia as a basis.
There are following types in the C programming language:
- basic types `char, int, float, double` with modifiers `signed, unsigned, short, long`
- structures, unions, arrays
- pointers
- function pointers

There are also more specific types:
- boolean type (from [C99](https://en.wikipedia.org/wiki/C99))
- `size_t` and `ptrdiff_t` (also `ssize_t`)
- fixed width integer types, such as `int32_t` or `uint64_t` (from [C99](https://en.wikipedia.org/wiki/C99))

There are also the following type qualifiers in the C language: `const`, `volatile`, `restrict`, `atomic`.

The best way to see what C data types are visible in Kotlin is to try it.
* goal
* what C data types are visible | Kotlin/Native <- & -> vice versa
* see what [Data types | C language](#types-in-c-language)
* create a [tiny C Library](#example-c-library) / uses those types | exports
* [inspect generated Kotlin APIs -- from a -- C library](#inspect-generated-kotlin-apis-for-a-c-library)
* [primitive types in Kotlin -- are mapped to -- C](#primitive-types-in-kotlin)

## Types | C language

* see [C data types article](https://en.wikipedia.org/wiki/C_data_types)
- basic types `char, int, float, double` / modifiers `signed, unsigned, short, long`
- structures, unions, arrays
- pointers
- function pointers
- other specific types
- boolean type (from [C99](https://en.wikipedia.org/wiki/C99))
- `size_t` and `ptrdiff_t` (also `ssize_t`)
- fixed width integer types, such as `int32_t` or `uint64_t` (from [C99](https://en.wikipedia.org/wiki/C99))

* type qualifiers
* `const`,
* `volatile`,
* `restrict`,
* `atomic`

## Example C library

Create a `lib.h` file to see how C functions are mapped into Kotlin:
* see `lib.h`
* goal
* how C functions -- are mapped into -- Kotlin

```c
#ifndef LIB2_H_INCLUDED
#define LIB2_H_INCLUDED

void ints(char c, short d, int e, long f);
void uints(unsigned char c, unsigned short d, unsigned int e, unsigned long f);
void doubles(float a, double b);

#endif
```

The file is missing the `extern "C"` block, which is not needed for this example, but may be
necessary if you use C++ and overloaded functions. The
[C++ compatibility thread](https://stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c) on Stackoverflow
contains more details on this.

For every set of `.h` files,
you will be using the [`cinterop` tool](native-c-interop.md)
from Kotlin/Native to generate a Kotlin/Native library,
or `.klib`. The generated library will bridge calls from Kotlin/Native to C. It includes
respective Kotlin declarations for the definitions form the `.h` files.
It is only necessary to have a `.h` file to run the `cinterop` tool. And you do not need to create a
`lib.c` file, unless you want to compile and run the example.
More details on this are covered in the [C interop](native-c-interop.md) page. It is enough for
the tutorial to create the `lib.def` file with the following content:
* [`cinterop` tool](native-c-interop.md)
* from `.h` -- you can generate a -- Kotlin/Native library (== `.klib` ) /
* calls from Kotlin/Native -- are bridged to -- C
* TODO:
* It includes respective Kotlin declarations for the definitions form the `.h` files.
It is only necessary to have a `.h` file to run the `cinterop` tool.
And you do not need to create a `lib.c` file, unless you want to compile and run the example.
More details on this are covered in the [C interop](native-c-interop.md) page.
It is enough for the tutorial to create the `lib.def` file with the following content:

```c
headers = lib.h
```

You may include all declarations directly into the `.def` file after a `---` separator.
It can be helpful to include macros or other C defines into the code generated by the `cinterop` tool.
Method bodies are compiled and fully included into the binary too. Use
that feature to have a runnable example without a need for a C compiler.
To implement that, you need to add implementations to the C functions from the `lib.h` file,
and place these functions into a `.def` file.
Method bodies are compiled and fully included into the binary too.
Use that feature to have a runnable example without a need for a C compiler.
To implement that, you need to add implementations to the C functions from the `lib.h` file, and place these functions into a `.def` file.
You will have the following `interop.def` result:

```c
Expand All @@ -89,6 +65,8 @@ The `interop.def` file is enough to compile and run the application or open it i
Now it is time to create project files, open the project in
[IntelliJ IDEA](https://jetbrains.com/idea) and run it.
* TODO:
## Inspect generated Kotlin APIs for a C library
While it is possible to use the command line, either directly or
Expand Down Expand Up @@ -236,27 +214,24 @@ as it is usually an 8-bit signed value.

## Fix the code

You've seen all definitions and it is the time to fix the code.
Run the `runDebugExecutableNative` Gradle task [in IDE](native-get-started.md)
or use the following command to run the code:

```bash
./gradlew runDebugExecutableNative
```
* run

The final code in the `hello.kt` file may look like that:
```bash
./gradlew runDebugExecutableNative
```
* final code | `hello.kt`

```kotlin
import interop.*

fun main() {
println("Hello Kotlin/Native!")

ints(1, 2, 3, 4)
uints(5, 6, 7, 8)
doubles(9.0f, 10.0)
}
```
```kotlin
import interop.*
fun main() {
println("Hello Kotlin/Native!")
ints(1, 2, 3, 4)
uints(5, 6, 7, 8)
doubles(9.0f, 10.0)
}
```

## Next steps

Expand Down

0 comments on commit 0304395

Please sign in to comment.