Kotlin/Native
Kotlin/Native compiles Kotlin to machine code. The result is a self-contained executable or library that doesn’t need a JVM.
[target.native]platforms = ["host"] # the machine you're building onkind = "executable" # or "library", "shared", "static", "framework"# entry-point = "com.example.app.main" # defaults to the top-level `fun main`; see also [[bin]]# linker-options = ["-lcurl"]
# [target.native.cinterop.sqlite] # bind a C library, see belowIn an existing project, kargo target add native writes this section for you: kind = "executable" when the sources have a top-level fun main, "library" otherwise (override with --app or --lib). See kargo target.
You don’t need to install anything. On the first native build Kargo downloads the Kotlin/Native distribution that matches [kotlin] version into ~/.kargo/toolchains/kotlin-native/<version>, plus its LLVM toolchain and sysroot into ~/.kargo/toolchains/konan. The first build therefore takes a few minutes; later builds are quick.
Output goes to target/<profile>/native/<platform>/.
$ kargo new tool -t native$ cd tool$ kargo run Compiling tool v0.1.0 (native)Hello, Kotlin!$ kargo build --release$ ./target/release/native/linux_x64/tool.kexe # tool.exe on WindowsPlatforms
Section titled “Platforms”platforms accepts these names (camelCase like linuxX64 and dashes like linux-x64 also work):
| Family | Platforms |
|---|---|
| Your machine | host |
| Linux | linux_x64, linux_arm64 |
| Windows | mingw_x64 |
| macOS | macos_x64, macos_arm64 |
| iOS | ios_arm64, ios_x64, ios_simulator_arm64 |
| watchOS / tvOS | watchos_arm64, watchos_simulator_arm64, tvos_arm64, tvos_simulator_arm64 |
| Android NDK | android_arm64, android_arm32, android_x64 |
Apple targets can only be built on macOS. kargo run runs the build for the host platform, so include host in platforms if you want to run the program locally.
Output kinds
Section titled “Output kinds”kind |
Produces |
|---|---|
executable |
A program with a main function |
library |
A .klib that other Kotlin/Native code can depend on |
shared |
A shared C library (.so, .dylib, .dll) plus a C header in include/ |
static |
A static C library (.a) plus a C header in include/ |
framework |
An Apple framework for Swift and Objective-C (Apple platforms only); kargo build --xcframework combines them |
See Calling Kotlin from C and from Swift. With [frameworks] compose, an iOS framework is a Compose for iOS UI; see Compose.
Several executables
Section titled “Several executables”Kotlin/Native needs one entry function per executable. With several top-level fun mains (each in its own package), run any of them with kargo run --entry-point com.example.tools.main, or declare a [[bin]] per program:
[[bin]]name = "migrate"path = "src/tools/Migrate.kt" # or entry-point = "com.example.tools.main"kargo build then also links target/<profile>/native/<platform>/bin/migrate.kexe (migrate.exe on Windows), and kargo run --bin migrate runs it. See Several programs in one project.
Using C libraries
Section titled “Using C libraries”platform.posix and the other platform libraries that ship with Kotlin/Native are always available. To call any other C library (sqlite, curl, SDL, your own code), declare it under [target.native.cinterop.<name>]. Kargo runs Kotlin/Native’s cinterop tool on it and puts the generated bindings on the compile path of your program and its tests.
[target.native]platforms = ["host"]
[target.native.cinterop.sqlite]headers = ["sqlite3.h"] # the headers to bind; no .def file neededpackage = "sqlite3" # Kotlin package of the bindingspkg-config = "sqlite3" # compiler and linker flags from sqlite3.pcimport kotlinx.cinterop.ExperimentalForeignApiimport kotlinx.cinterop.toKStringimport sqlite3.sqlite3_libversion
@OptIn(ExperimentalForeignApi::class)fun main() { println("SQLite " + sqlite3_libversion()?.toKString())}C interop covers the rest: options per platform, .def properties in kargo.toml, pkg-config, static linking, C sources compiled with your project ([target.native.c-sources]), and calling Kotlin from C and Swift.
Linker options
Section titled “Linker options”[target.native] linker-options passes flags to the linker of your program, for libraries that are not bound with cinterop. A [target.native.platform.<platform>] table adds options for one platform:
[target.native]platforms = ["linux_x64", "mingw_x64"]linker-options = ["-lm"]
[target.native.platform.mingw_x64]linker-options = ["-lws2_32"]Build speed
Section titled “Build speed”Most of a small Kotlin/Native build is the standard library: unless told otherwise, the compiler loads and lowers all of it again on every build. For debug builds Kargo tells it to link a precompiled copy instead, as the Gradle plugin does. Rebuilding a small program takes about half the time (10 seconds instead of 5 on one machine, 16 instead of 6 on a slower one).
$ kargo build Compiling tool v0.1.0 (native, linux_x64)note: building the Kotlin/Native standard library cache for linux_x64 (one time per Kotlin version, takes a few minutes); later builds are much faster Finished `dev` profile [unoptimized + debuginfo] target(s) in 97.17s- One-time cost. The first build that needs the cache builds it, which adds one to two minutes. It’s kept per Kotlin/Native version and platform in
~/.kargo/toolchains/kotlin-native/<version>/klib/cache, a few tens of megabytes each, andkargo toolchain remove native <version>removes it with the distribution. - Debug builds only.
--release(any profile withoptimize = true) optimizes the whole program, standard library included, so it can’t use precompiled code and builds as slowly as before.kargo checkandkind = "library"build a klib, which doesn’t link the standard library. - Debug info. Builds with
debug = true(the default indev) and builds without it each get their own cache. - Turning it off. Set
KARGO_NATIVE_CACHE=false(or0,no,off) to compile without it, for example when the toolchain directory is read-only. Switching it doesn’t trigger a rebuild, because the output is the same. - CI. The cache is under
~/.kargo, so a cached~/.kargokeeps it between runs. A job that starts from an empty home pays for building it on every run; setKARGO_NATIVE_CACHE=falsethere.
Moving the toolchain
Section titled “Moving the toolchain”Kotlin/Native’s dependency cache normally lives in ~/.konan. Kargo keeps it under ~/.kargo/toolchains/konan instead so everything Kargo downloads is in one place. Set KONAN_DATA_DIR to use a different directory.
Kotlin/Native downloads those dependencies on the first link of each platform. kargo toolchain install in a project downloads them right away for every platform in platforms that the host can build (Apple platforms need macOS), so a CI job or Docker image can build --offline afterwards, and kargo toolchain list says which platforms have them. Kargo also downloads them before the pre-build hooks of a project with the Native target, which may run the bundled clang, and before it compiles C sources. The LLVM directory is llvm-<version>-<arch>-<os>-dev-<n> on Linux and macOS but llvm-...-essentials-<n> on Windows, so a script that looks for it should accept both.
kargo toolchain list # see installed Kotlin/Native versionskargo toolchain install native 2.4.21 # pre-install, for example in a Docker imagekargo toolchain install # in a project: also the LLVM and sysroots of each platformkargo toolchain remove native 2.4.10 # free disk space