# Kotlin Compiler

> Compile Kotlin 2.5 with elide kotlinc or in a project build, with plugins, toolchains and ABI jars.

Elide bundles Kotlin 2.5.0-Beta1. A runtime-only distribution reports that `kotlinc` needs the full distribution.

## Compile source files

```kotlin
// Hello.kt
fun main() = println("Hello!")
```

```bash
elide kotlinc -- -d out Hello.kt
elide java -- -cp out HelloKt
```

<img src="https://elide.help/assets/demos/kotlinc.gif" alt="Compiling and running Kotlin source with Elide" width="1591" height="546" loading="lazy" decoding="async" class="rounded-lg border border-border my-6 w-full" />

`kotlinc` options go after `--`; Elide options go before it. `elide kotlinc --help` lists Elide's,
`elide kotlinc -- -help` lists `kotlinc`'s.

## Elide options

| Option | Purpose |
| --- | --- |
| `--incremental` | Keep incremental state in `.dev/artifacts/kotlinc/incremental/`, keyed by output path. |
| `--incremental-cache-dir DIR` | Store incremental state in `DIR`. |
| `--plugins LIST` | Enable exactly these built-in plugins: `metro`, `serialization`, `atomicfu`, `power-assert`. |
| `--metro`, `--no-metro` | Force the Metro DI plugin on or off. |
| `--tests` | Enable the test plugins (power-assert). |
| `--max-errors N` | Errors shown; `0` shows all. Warnings are de-duplicated and never limited. |
| `--report-used-deps PATH` | Write the classpath entries the output references (Bazel strict deps). |
| `--persistent_worker` | Run as a Bazel persistent worker, singleplex or multiplex. |
| `--abi-only` | Experimental: write only an ABI jar to `-d`. |

### ABI jars

```bash
elide kotlinc --abi-only -- -d header.jar src/**/*.kt
```

The jar holds public and protected signatures, `@Metadata`, ABI-relevant `inline` bodies, `const` values and
default-argument markers. An unchanged ABI gives a byte-identical jar, so body edits keep dependents cached.

`ELIDE_KOTLINC_ABI_STRIP=1` skips body code generation. Leave it unset when the ABI includes plugin-generated
declarations, such as kotlinx.serialization's `$serializer`. Workers accept it per request.

## Build projects

`elide build` compiles Kotlin source sets found by convention or declared in `elide.pkl`.

```pkl
kotlin {
  apiLevel = "auto"
  languageLevel = "auto"
  compilerOptions {
    allWarningsAsErrors = true
    optIn { "kotlin.time.ExperimentalTime" }
    freeCompilerArgs { "-Xcontext-parameters" }
  }
}
```

| Property | Meaning | Default |
| --- | --- | --- |
| `kotlin.apiLevel`, `kotlin.languageLevel` | `"1.9"` … `"2.5"`, `"latest"` or `"stable"`. | `"auto"` |
| `compilerOptions.optIn` | Markers passed as `-opt-in`. | none |
| `compilerOptions.progressiveMode`, `.extraWarnings`, `.allWarningsAsErrors`, `.suppressWarnings`, `.verbose` | The matching `kotlinc` switches. | `false` |
| `compilerOptions.freeCompilerArgs` | Extra compiler arguments. | none |
| `compilerOptions.apiVersion`, `.languageVersion`, `.jvmTarget` | Per-compile versions; `"auto"` follows the project. | `"auto"` |
| `compilerOptions.javaParameters` | Emit parameter metadata for Java reflection. | `false` |
| `compilerOptions.jvmTargetValidationMode` | `"ERROR"`, `"WARNING"` or `"IGNORE"` on Kotlin/Java target mismatch. | `"ERROR"` |
| `compilerOptions.includeRuntime`, `.noStdlib`, `.noJdk` | Bundle the Kotlin runtime; drop the stdlib or JDK from the classpath. | `false` |
| `compilerOptions.incremental` | Incremental project builds. | `true` |

Each compile writes its arguments to `kotlinc.args` beside its output.

### Plugins and features

| `kotlin.features` | Effect | Default |
| --- | --- | --- |
| `kotlinx` | KotlinX libraries on Kotlin dependency roots. | `true` |
| `defaultPlugins` | Built-in plugin suite. | `true` |
| `serialization` | kotlinx.serialization plugin and runtime. | `kotlinx && defaultPlugins` |
| `coroutines` | kotlinx.coroutines runtime. | `kotlinx` |
| `atomicfu` | kotlinx.atomicfu plugin and runtime. | `kotlinx && defaultPlugins` |
| `powerAssert` | Power Assert plugin. | `defaultPlugins` |
| `metro` | Metro DI plugin. | `defaultPlugins` |
| `reflection` | Implicit `kotlin-reflect`. | `true` |
| `testing` | Kotlin test libraries on test sets. | `true` |

```pkl
kotlin {
  features {
    metro = false
  }
  plugins {
    ["org.jetbrains.kotlinx.serialization"] {
      ["mode"] = "json"
    }
  }
}

dependencies {
  maven {
    kotlinPlugins { "com.example:my-compiler-plugin:1.0.0" }
  }
}
```

- Each `plugins` entry becomes `-P plugin:<id>:<key>=<value>`, sorted by id and key.
- Third-party plugins go in the `kotlinPlugins` bucket.
- A built-in plugin missing from the distribution is skipped with a warning, with its options.
- Implicit Kotlin libraries go only to dependency roots with Kotlin sources. `reflection = false` drops
  `kotlin-reflect`; `compilerOptions.noStdlib = true` drops it and the stdlib. Declared dependencies stay.
- `project("core").friend()` exposes a sibling's `internal` declarations; see
  [Workspaces](https://elide.help/docs/elide-pkl-reference#workspaces).

### Choose a toolchain

```pkl
import "elide:Kotlin.pkl" as Kotlin

kotlin {
  toolchain = "embedded"                                       // the default
  // toolchain = new Kotlin.ManagedKotlinToolchain { version = "2.4.0" }
  // toolchain = new Kotlin.CustomKotlinToolchain { path = "/opt/kotlinc" }
}
```

| Toolchain | Behavior |
| --- | --- |
| `"embedded"` | Elide's bundled Kotlin. |
| `ManagedKotlinToolchain` | Downloads that version (prereleases too) with its stdlib, reflect, test libraries and Kotlin plugins. KotlinX, Metro and other third-party versions are unchanged; check they match. |
| `CustomKotlinToolchain` | A local Kotlin distribution; built-in plugins it lacks are skipped. |

The toolchain applies to project builds; `elide kotlinc` always uses the bundled compiler.

KAPT and KSP are unsupported. Kotlin that uses Java-generated types must take them from an upstream source set or
project.
