Skip to content
← All posts

KMP 101 · Part 2

KMP 101: Understanding How Kotlin Compiles to Multiple Platforms

By 4 min read Updated

In the last post (🔗 KMP 101: An Introduction to the multiplatform paradigm), we explored the multiplatform paradigm and how KMP stands out in the ecosystem.

In this article, we’ll unpack the basics of the Kotlin compiler and its ability to compile to multiple platforms.


An introduction to the Kotlin compiler

A compiler is a piece of software that converts code from one programming language into another. Compilers are often used to turn programs written in high-level languages into low-level languages.

Kotlin, like some other compilers such as LLVM and GCC, has an architecture split into a frontend and a backend, which communicate through an Intermediate Representation (IR).

Understanding the Kotlin compiler frontend

Responsible for analyzing and preparing the .kt source code for compilation, Kotlin ships with two frontend versions: K1 and K2.

K1: codename FE10 (Frontend 1.0)

The K1 frontend, also known as FE10, is the original Kotlin compiler frontend and is the default in use today.

Key characteristics:

  • Lexical analysis (Lexer): breaks the Kotlin source code into tokens, the fundamental building blocks of the language.
  • Syntactic analysis (Parser): organizes the tokens into a syntactic structure, usually a syntax tree (AST), that represents the logical structure of the code.
  • PSI/AST trees: uses the Abstract Syntax Tree (AST) and the Program Structure Interface (PSI) to represent and manipulate the code structure, which is essential for later analyses.
  • Semantic analysis: checks that language elements such as types and scopes are used correctly, making sure the code follows Kotlin’s semantic rules.

Frontend K1

K2: codename FIR (Frontend Intermediate Representation)

K2, also known as FIR, is the next major update to the Kotlin compiler and is set to replace K1/FE10.

The first beta of K2 arrived with Kotlin 1.9.20, released in November 2023, and the final version is planned for Kotlin 2.0.0, which we expect in 2024. This new system brings several important improvements, such as more speed, a more organized structure, and a clearer way to understand the code.

KotlinConf2023 K1 vs K2

Data from the KotlinConf’23 - Keynote

A few of those improvements:

  • Completely rebuilt: K2 was built from scratch, with speed and easy future updates in mind.
  • Better code analysis: it has a more advanced method for inspecting code, helping it identify and use important information in a smarter way.
  • Plugin support: includes support for a variety of plugins, such as kapt, serialization, all-open, and others.
  • Cross-platform compatibility: supports JVM, Native, Wasm, and JS, optimized for multiplatform projects.

Frontend K2 FIR

Understanding the Kotlin compiler backend

Once the frontend has processed and prepared the source code, the backend takes on a crucial role.

The backend is responsible for converting the intermediate representation (IR) into machine code, performing optimizations and generating the output specific to the target platform (such as *.class, *.js, *.so, *.wasm).

Designed to be multiplatform, Kotlin can be compiled to run on a wide range of devices and operating systems. Each Kotlin compiler backend is specially optimized for a target platform, making it possible for developers to write code that can run in many different environments.

  • Kotlin/JVM: this is the most traditional backend and generates bytecode compatible with the Java Virtual Machine (JVM). It’s ideal for applications that will run in JVM-supported environments, including Android, Desktop, and server applications.
  • Kotlin/Native: using the LLVM toolchain, this backend compiles Kotlin code directly into native machine code. It supports a wide range of platforms, such as iOS, macOS, Windows, Linux, and embedded systems, allowing applications to run directly on the hardware.
  • Kotlin/JS: specialized for web development, this backend converts Kotlin code into JavaScript, making it compatible with web browsers and JavaScript-based server environments such as Node.js.
  • Kotlin/Wasm: a more recent addition that’s still in development, this backend lets you compile Kotlin to WebAssembly (Wasm), making it easier to run high-performance Kotlin applications in web browsers.

Native development

Intermediate Representation (IR)

The IR is a way of representing the source code inside the compiler that is independent of both the source programming language and the target machine architecture. It serves as a middle ground between the high-level code and the low-level machine code.

This data structure lets the Kotlin compiler manipulate code in a more abstract way, making it easier to generate code for multiple platforms. This is especially beneficial for Kotlin, which is designed to be multiplatform.

Conclusions

Understanding how Kotlin compiles to different platforms isn’t something you need to do every day or memorize. Still, having an overview of this process has its advantages.

This understanding gives you a sense of Kotlin’s versatility and efficiency, offering you the confidence that your code can run across multiple ecosystems. On top of that, a basic appreciation of what happens “under the hood” can be incredibly useful when debugging code and making sense of error messages, saving you hours of frustration.


🤖 This article was written with the help of ChatGPT 4, using the Web plugin.

The sources and content are reviewed to ensure the relevance of the information provided, as well as the sources used in each prompt.

However, if you find any incorrect information or believe a credit is missing, please get in touch!


References