Tips for improving compilation time
The Kotlin/Native compiler is constantly receiving updates that improve its performance. With the latest Kotlin/Native compiler and a properly configured build environment, you can significantly improve the compilation times of your projects with Kotlin/Native targets.
Read on for our tips on how to speed up the Kotlin/Native compilation process.
General recommendations
Use the latest version of Kotlin
This way, you always get the latest performance improvements. The most recent Kotlin version is 2.1.0.
Avoid creating huge classes
Try to avoid huge classes that take a long time to compile and load during execution.
Preserve downloaded and cached components between builds
When compiling projects, Kotlin/Native downloads the required components and caches some results of its work to the $USER_HOME/.konan
directory. The compiler uses this directory for subsequent compilations, making them take less time to complete.
When building in containers (such as Docker) or with continuous integration systems, the compiler may have to create the ~/.konan
directory from scratch for each build. To avoid this step, configure your environment to preserve ~/.konan
between builds. For example, redefine its location using the kotlin.data.dir
Gradle property.
Alternatively, you can use the -Xkonan-data-dir
compiler option to configure your custom path to the directory via the cinterop
and konanc
tools.
Gradle configuration
The first compilation with Gradle usually takes more time than subsequent ones due to the need to download the dependencies, build caches, and perform additional steps. You should build your project at least twice to get an accurate reading of the actual compilation times.
Below are some recommendations for configuring Gradle for better compilation performance.
Increase Gradle heap size
To increase the Gradle heap size, add org.gradle.jvmargs=-Xmx3g
to your gradle.properties
file.
If you use parallel builds, you might need to choose the right number of workers with the org.gradle.workers.max
property or the --max-workers
command-line option. The default value is the number of CPU processors.
Build only necessary binaries
Don't run Gradle tasks that build the whole project, such as build
or assemble
, unless you really need to. These tasks build the same code more than once, increasing the compilation times. In typical cases, such as running tests from IntelliJ IDEA or starting the app from Xcode, the Kotlin tooling avoids executing unnecessary tasks.
If you have a non-typical case or build configuration, you might need to choose the task yourself:
linkDebug*
. To run your code during development, you usually need only one binary, so running the correspondinglinkDebug*
task should be enough.embedAndSignAppleFrameworkForXcode
. Since iOS simulators and devices have different processor architectures, it's a common approach to distribute a Kotlin/Native binary as a universal (fat) framework.However, during local development, it's faster to build the
.framework
file only for the platform you're using. To build a platform-specific framework, use the embedAndSignAppleFrameworkForXcode task.
Build only for necessary targets
Similarly to the recommendation above, don't build a binary for all native platforms at once. For example, compiling an XCFramework (using an *XCFramework
task) builds the same code for all targets, which takes proportionally more time than building for a single target.
If you do need XCFrameworks for your setup, you can reduce the number of targets. For example, you don't need iosX64
if you don't run this project on iOS simulators on Intel-based Macs.
Don't build unnecessary release binaries
Kotlin/Native supports two build modes, debug and release. Release is highly optimized, and this takes a lot of time: compilation of release binaries takes an order of magnitude more time than debug binaries.
Apart from an actual release, all these optimizations might be unnecessary in a typical development cycle. If you use a task with Release
in its name during the development process, consider replacing it with Debug
. Similarly, instead of running assembleXCFramework
, you can run assembleSharedDebugXCFramework
, for example.
Don't disable Gradle daemon
Don't disable the Gradle daemon without having a good reason. By default, Kotlin/Native runs from the Gradle daemon. When it's enabled, the same JVM process is used, and there is no need to warm it up for each compilation.
Don't use transitive export
Using transitiveExport = true
disables dead code elimination in many cases, so the compiler has to process a lot of unused code. It increases the compilation time. Instead, use the export
method explicitly for exporting the required projects and dependencies.
Don't export modules too much
Try to avoid unnecessary module export. Each exported module negatively affects compilation time and binary size.
Use Gradle build caching
Enable the Gradle build cache feature:
Local build cache. For local caching, add
org.gradle.caching=true
to yourgradle.properties
file or run the build with the--build-cache
option in the command line.Remote build cache. Learn how to configure the remote build cache for continuous integration environments.
Use Gradle configuration cache
To use the Gradle configuration cache, add org.gradle.configuration-cache=true
to your gradle.properties
file.
Enable previously disabled features
There are Kotlin/Native properties that disable the Gradle daemon and compiler caches:
kotlin.native.disableCompilerDaemon=true
kotlin.native.cacheKind=none
kotlin.native.cacheKind.$target=none
, where$target
is a Kotlin/Native compilation target, for exampleiosSimulatorArm64
.
If you had issues with these features before and added these lines to your gradle.properties
file or Gradle arguments, remove them and check whether the build completes successfully. It is possible that these properties were added previously to work around issues that have already been fixed.
Try incremental compilation of klib artifacts
With incremental compilation, if only a part of the klib
artifact produced by the project module changes, just a part of klib
is further recompiled into a binary.
This feature is Experimental. To enable it, add the kotlin.incremental.native=true
option to your gradle.properties
file. If you face any problems, create an issue in YouTrack.
Windows configuration
Windows Security may slow down the Kotlin/Native compiler. You can avoid this by adding the .konan
directory, which is located in %USERPROFILE%
by default, to Windows Security exclusions. Learn how to add exclusions to Windows Security.