Skip to content

Commit 1828917

Browse files
authored
update: libcurl tutorial (#4783)
1 parent 5ad96da commit 1828917

File tree

3 files changed

+62
-52
lines changed

3 files changed

+62
-52
lines changed
-67.3 KB
Loading
138 KB
Loading

docs/topics/native/native-app-with-c-and-libcurl.md

Lines changed: 62 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
[//]: # (title: Create an app using C Interop and libcurl – tutorial)
1+
[//]: # (title: Create an app using C interop and libcurl – tutorial)
22

33
This tutorial demonstrates how to use IntelliJ IDEA to create a command-line application. You'll learn how to create
4-
a simple HTTP client that can run natively on specified platforms using Kotlin/Native and the `libcurl` library.
4+
a simple HTTP client that can run natively on specified platforms using Kotlin/Native and the libcurl library.
55

66
The output will be an executable command-line app that you can run on macOS and Linux and make simple HTTP GET requests.
77

@@ -13,15 +13,19 @@ Kotlin/Native can use the [Gradle](https://gradle.org) build system through the
1313

1414
## Before you start
1515

16-
1. Download and install the latest version of [IntelliJ IDEA](https://www.jetbrains.com/idea/) with the latest [Kotlin plugin](releases.md).
16+
1. Download and install the latest version of [IntelliJ IDEA](https://www.jetbrains.com/idea/).
1717
2. Clone the [project template](https://github.com/Kotlin/kmp-native-wizard)
18-
by selecting **File** | **New** | **Project from Version Control** in IntelliJ IDEA.
18+
by selecting **File** | **New** | **Project from Version Control** in IntelliJ IDEA and using this URL:
19+
20+
```none
21+
https://github.com/Kotlin/kmp-native-wizard
22+
```
1923

2024
3. Explore the project structure:
2125

2226
![Native application project structure](native-project-structure.png){width=700}
2327

24-
The template includes a project with the files and folders you need to get you started. It's important to understand
28+
The template includes a project with the files and folders you need to get started. It's important to understand
2529
that an application written in Kotlin/Native can target different platforms if the code does not have platform-specific
2630
requirements. Your code is placed in the `nativeMain` directory with a corresponding `nativeTest`. For this tutorial,
2731
keep the folder structure as is.
@@ -54,7 +58,7 @@ Kotlin/Native can use the [Gradle](https://gradle.org) build system through the
5458

5559
```
5660

57-
* Targets are defined using `macosX64`, `macosArm64`, `linuxX64`, `linuxArm64`, and `mingwX64` for macOS, Linux,
61+
* Targets are defined using `macosArm64`, `macosX64`, `linuxArm64`, `linuxX64`, and `mingwX64` for macOS, Linux,
5862
and Windows. See the complete list of [supported platforms](native-target-support.md).
5963
* The entry itself defines a series of properties to indicate how the binary is generated and the entry
6064
point of the applications. These can be left as default values.
@@ -73,15 +77,17 @@ for pretty much anything you may need. Kotlin/Native is already shipped with a s
7377
which provide some additional common functionality to the standard library.
7478

7579
An ideal scenario for interop is to call C functions as if you are calling Kotlin functions, following the same
76-
signature and conventions. This is when the `cinterop` tool comes in handy. It takes a C library and generates the
80+
signature and conventions. This is when the cinterop tool comes in handy. It takes a C library and generates the
7781
corresponding Kotlin bindings, so that the library can be used as if it were Kotlin code.
7882

79-
To generate these bindings, create a library definition `.def` file that contains some information about the necessary
80-
headers. In this app, you'll need the `libcurl` library to make some HTTP calls. To create a definition file:
83+
To generate these bindings, each library needs a definition file, usually with the same name as the library.
84+
This is a property file that describes exactly how the library should be consumed.
85+
86+
In this app, you'll need the libcurl library to make some HTTP calls. To create its definition file:
8187
8288
1. Select the `src` folder and create a new directory with **File | New | Directory**.
83-
2. Name new directory **nativeInterop/cinterop**. This is the default convention for header file locations, though it can
84-
be overridden in the `build.gradle.kts` file if you use a different location.
89+
2. Name the new directory **nativeInterop/cinterop**. This is the default convention for header file locations,
90+
though it can be overridden in the `build.gradle.kts` file if you use a different location.
8591
3. Select this new subfolder and create a new `libcurl.def` file with **File | New | File**.
8692
4. Update your file with the following code:
8793
@@ -94,28 +100,26 @@ headers. In this app, you'll need the `libcurl` library to make some HTTP calls.
94100
linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu -lcurl
95101
```
96102
97-
* `headers` is the list of header files to generate Kotlin stubs. You can add multiple files to this entry,
98-
separating each with a `\` on a new line. In this case, it's only `curl.h`. The referenced files need to be available
99-
on the system path (in this case, it's `/usr/include/curl`).
103+
* `headers` is the list of header files to generate Kotlin stubs for. You can add multiple files to this entry,
104+
separating each with a space. In this case, it's only `curl.h`. The referenced files need to be available
105+
on the specified path (in this case, it's `/usr/include/curl`).
100106
* `headerFilter` shows what exactly is included. In C, all the headers are also included when one file references
101107
another one with the `#include` directive. Sometimes it's not necessary, and you can add this parameter
102-
[using glob patterns](https://en.wikipedia.org/wiki/Glob_(programming)) to fine-tune things.
108+
[using glob patterns](https://en.wikipedia.org/wiki/Glob_(programming)) to make adjustments.
103109

104-
`headerFilter` is an optional argument and is mostly used when the library is installed as a system library. You don't
105-
want to fetch external dependencies (such as system `stdint.h` header) into the interop library. It may be important to
106-
optimize the library size and fix potential conflicts between the system and the provided Kotlin/Native compilation
107-
environment.
110+
You can use `headerFilter` if you don't want to fetch external dependencies (such as system `stdint.h` header) into
111+
the interop library. Also, it may be useful for library size optimization and fixing potential conflicts between the
112+
system and the provided Kotlin/Native compilation environment.
108113
109-
* The next lines are about providing linker and compiler options, which can vary depending on different target platforms.
110-
In this case, they are macOS (the `.osx` suffix) and Linux (the `.linux` suffix). Parameters without a suffix are also
111-
possible (for example, `linkerOpts=`) and applied to all platforms.
114+
* If the behavior for a certain platform needs to be modified, you can use a format like `compilerOpts.osx` or `compilerOpts.linux`
115+
to provide platform-specific values to the options. In this case, they are macOS (the `.osx` suffix) and Linux (the `.linux` suffix).
116+
Parameters without a suffix are also possible (for example, `linkerOpts=`) and applied to all platforms.
112117
113-
The convention is that each library gets its definition file, usually with the same name as the library. For more
114-
information on all the options available to `cinterop`, see [the Interop section](native-c-interop.md).
118+
For the full list of available options, see [Definition file](native-definition-file.md#properties).
115119
116120
> You need to have the `curl` library binaries on your system to make the sample work. On macOS and Linux, they are usually
117-
> included. On Windows, you can build it from [sources](https://curl.haxx.se/download.html) (you'll need Visual Studio or
118-
> Windows SDK Commandline tools). For more details, see the [related blog post](https://jonnyzzz.com/blog/2018/10/29/kn-libcurl-windows/).
121+
> included. On Windows, you can build it from [sources](https://curl.se/download.html) (you'll need Microsoft Visual Studio or
122+
> Windows SDK command-line tools). For more details, see the [related blog post](https://jonnyzzz.com/blog/2018/10/29/kn-libcurl-windows/).
119123
> Alternatively, you may want to consider a [MinGW/MSYS2](https://www.msys2.org/) `curl` binary.
120124
>
121125
{style="note"}
@@ -127,11 +131,11 @@ entry to the `build.gradle.kts` file:
127131

128132
```kotlin
129133
nativeTarget.apply {
130-
compilations.getByName("main") { // NL
131-
cinterops { // NL
132-
val libcurl by creating // NL
133-
} // NL
134-
} // NL
134+
compilations.getByName("main") {
135+
cinterops {
136+
val libcurl by creating
137+
}
138+
}
135139
binaries {
136140
executable {
137141
entryPoint = "main"
@@ -140,24 +144,24 @@ nativeTarget.apply {
140144
}
141145
```
142146

143-
The new lines are marked with `// NL`. First, `cinterops` is added, and then an entry for each `def` file. By default,
144-
the name of the file is used. You can override this with additional parameters:
147+
First, `cinterops` is added, and then an entry for a definition file. By default, the name of the file is used.
148+
You can override this with additional parameters:
145149

146150
```kotlin
147-
val libcurl by creating {
148-
definitionFile.set(project.file("src/nativeInterop/cinterop/libcurl.def"))
149-
packageName("com.jetbrains.handson.http")
150-
compilerOpts("-I/path")
151-
includeDirs.allHeaders("path")
151+
cinterops {
152+
val libcurl by creating {
153+
definitionFile.set(project.file("src/nativeInterop/cinterop/libcurl.def"))
154+
packageName("com.jetbrains.handson.http")
155+
compilerOpts("-I/path")
156+
includeDirs.allHeaders("path")
157+
}
152158
}
153159
```
154160

155-
See the [Interoperability with C](native-c-interop.md) section for more details on the available options.
156-
157161
## Write the application code
158162

159-
Now you have the library and the corresponding Kotlin stubs and can use them from your application. For this tutorial,
160-
convert the [simple.c](https://curl.haxx.se/libcurl/c/simple.html) example to Kotlin.
163+
Now that you have the library and the corresponding Kotlin stubs, you can use them from your application.
164+
For this tutorial, convert the [simple.c](https://curl.se/libcurl/c/simple.html) example to Kotlin.
161165

162166
In the `src/nativeMain/kotlin/` folder, update your `Main.kt` file with the following code:
163167

@@ -181,31 +185,37 @@ fun main(args: Array<String>) {
181185
```
182186

183187
As you can see, explicit variable declarations are eliminated in the Kotlin version, but everything else is pretty much
184-
the same as the C version. All the calls you'd expect in the `libcurl` library are available in the Kotlin equivalent.
188+
the same as the C version. All the calls you'd expect in the libcurl library are available in the Kotlin equivalent.
185189
186190
> This is a line-by-line literal translation. You could also write this in a more Kotlin idiomatic way.
187191
>
192+
{type="tip"}
188193
189194
## Compile and run the application
190195
191-
1. Compile the application. To do that, call `runDebugExecutableNative` in the list of run Gradle tasks or use the following
196+
1. Compile the application. To do that, run the `runDebugExecutableNative` Gradle task from the task list or use the following
192197
command in the terminal:
198+
199+
```bash
200+
./gradlew runDebugExecutableNative
201+
```
193202
194-
```bash
195-
./gradlew runDebugExecutableNative
196-
```
197-
In this case, the `cinterop` generated part is implicitly included in the build.
203+
In this case, the part generated by the cinterop tool is implicitly included in the build.
198204
199-
2. If there are no errors during compilation, click the green **Run** icon in the gutter beside the `main()` method or
200-
use the **Alt+Enter** shortcut to invoke the launch menu in IntelliJ IDEA.
205+
2. If there are no errors during compilation, click the green **Run** icon in the gutter next to the `main()` function or
206+
use the <shortcut>Shift + Cmd + R</shortcut>/<shortcut>Shift + F10</shortcut> shortcut.
201207
202-
IntelliJ IDEA opens the **Run** tab and shows the output — the contents of `https://example.com`:
208+
IntelliJ IDEA opens the **Run** tab and shows the output — the contents of [example.com](https://example.com/):
203209
204210
![Application output with HTML-code](native-output.png){width=700}
205211
206212
You can see the actual output because the call `curl_easy_perform` prints the result to the standard output. You could
207213
hide this using `curl_easy_setopt`.
208214
209-
> You can get the full code [here](https://github.com/Kotlin/kotlin-hands-on-intro-kotlin-native).
215+
> You can get the full project code in our [GitHub repository](https://github.com/Kotlin/kotlin-hands-on-intro-kotlin-native).
210216
>
211217
{style="note"}
218+
219+
## What's next
220+
221+
Learn more about [Kotlin's interoperability with C](native-c-interop.md).

0 commit comments

Comments
 (0)