blob: 7ede2547318f8b5413b87496275a70b1ec12ae16 [file] [view] [edit]
# Kotlin Build Tools API (BTA)
An experimental interface for build systems (Gradle plugin, Maven plugin, etc.) to invoke Kotlin compilation without a direct compiler
dependency. Build systems should use the API from `kotlin-build-tools-api`, load the implementation in an isolated ClassLoader, and avoid
accessing compiler internals directly.
## Modules
| Module | Purpose |
|------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
| [`kotlin-build-tools-api`](kotlin-build-tools-api) | Public interfaces only; no implementation; `explicitApi()`; API dump checked in |
| [`kotlin-build-tools-impl`](kotlin-build-tools-impl) | Default implementation; version-coupled to the compiler; must run in isolated ClassLoader |
| [`kotlin-build-tools-compat`](kotlin-build-tools-compat) | Adapter for compilers < 2.3.0 (wraps deprecated `CompilationService`) |
| [`kotlin-build-tools-cri-impl`](kotlin-build-tools-cri-impl) | Protobuf serialization for Compiler Reference Index; shipped as shadow JAR |
| [`kotlin-build-tools-jdk-utils`](kotlin-build-tools-jdk-utils) | Internal utility for Java 9+ platform ClassLoader detection; do not use outside BTA modules |
| [`kotlin-build-tools-generator`](kotlin-build-tools-generator) | KotlinPoet-based code generator producing compiler argument classes from `:compiler:arguments` and API version file |
| [`kotlin-build-statistics`](kotlin-build-statistics) | Shared library for build metric collection (times, performance, GC, attributes); used by impl and KGP |
| [`util-kotlinpoet`](util-kotlinpoet) | KotlinPoet utility helpers shared by code generators in the BTA area |
| [`kotlin-build-tools-api-tests`](kotlin-build-tools-api-tests) | Main integration test suite (JUnit 5, multiple named test suites) |
| [`kotlin-build-tools-api-forward-compatibility-tests`](kotlin-build-tools-api-forward-compatibility-tests) | Tests the forward compatibility guarantee (X+1) |
## Architecture: ClassLoader Isolation
The impl JAR must be loaded in an isolated ClassLoader to prevent classpath conflicts with the consumer:
```kotlin
val toolchains = KotlinToolchains.loadImplementation(implClasspath) // implClasspath: List<Path>
```
- `loadImplementation(List<Path>)` — preferred API; wraps the classpath in a `URLClassLoader` backed by `SharedApiClassesClassLoader`
automatically
- `loadImplementation(ClassLoader)` — lower-level overload for custom ClassLoader setups; the ClassLoader's parent should be
`SharedApiClassesClassLoader`
- The impl JAR version must match the compiler version (`kotlin-build-tools-impl` is version-coupled to the compiler)
- For compilers < 2.3.0, include `kotlin-build-tools-compat` in the impl classpath → see [
`kotlin-build-tools-compat/README.md`](kotlin-build-tools-compat/README.md)
## Key Abstractions
All in `kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/`:
- `KotlinToolchains` — factory entry point; creates `BuildSession` instances (`KotlinToolchains.kt`)
- `BuildSession` (`AutoCloseable`) — manages caches, thread pools, and daemon connections
- `Toolchain` (sealed interface) — `JvmPlatformToolchain`, `CriToolchain`, `AbiValidationToolchain`
- `BuildOperation<R>` / `BuildOperation.Builder` — type-safe operation configuration (`BuildOperation.kt`)
- `ExecutionPolicy` — `InProcess` vs `WithDaemon` (`ExecutionPolicy.kt`)
- `KotlinLogger` — pluggable logging interface (`KotlinLogger.kt`)
## Generated Files
Do not edit generated files manually — regenerate them with the tasks below.
Two kinds — both must be regenerated after relevant changes:
```bash
# Regenerate generated sources (compiler argument classes and API version file; after changing compiler arguments in :compiler:arguments)
./gradlew :compiler:build-tools:kotlin-build-tools-api:generateBtaSources
./gradlew :compiler:build-tools:kotlin-build-tools-impl:generateBtaSources
./gradlew :compiler:build-tools:kotlin-build-tools-compat:generateBtaSources
# Regenerate API binary compatibility dump (after any public API change)
./gradlew :compiler:build-tools:kotlin-build-tools-api:apiDump
```
## Compatibility Model
```
BTA version X is guaranteed to work with implementation versions [X-3, X+1]
```
- **Backward compat (X-3):** tested in `kotlin-build-tools-api-tests` compatibility suites (one suite per listed version)
- **Forward compat (X+1):** tested in `kotlin-build-tools-api-forward-compatibility-tests`
- When adding an API change that may break compatibility, add tests to both modules and run locally to verify
## Running Tests
```bash
# Run all tests (testExample is excluded from check — run it explicitly if needed)
./gradlew :compiler:build-tools:kotlin-build-tools-api-tests:check
# Run against a specific BTA impl version (pattern: testCompatibility<version>)
./gradlew :compiler:build-tools:kotlin-build-tools-api-tests:testCompatibility2.3.20
# Run against current snapshot impl
./gradlew :compiler:build-tools:kotlin-build-tools-api-tests:testCompatibilitySnapshot
# Classpath/module-path escaping edge cases
./gradlew :compiler:build-tools:kotlin-build-tools-api-tests:testEscapableCharacters
# Verify restricted arguments are rejected correctly
./gradlew :compiler:build-tools:kotlin-build-tools-api-tests:testRestrictedArguments
# Individual named test suites follow the pattern :test<SuiteName>
# The full list is in `businessLogicTestSuits` in kotlin-build-tools-api-tests/build.gradle.kts
# Forward compatibility tests
./gradlew :compiler:build-tools:kotlin-build-tools-api-forward-compatibility-tests:check
```
## Writing Tests
See [`kotlin-build-tools-api-tests/README.md`](kotlin-build-tools-api-tests/README.md) for full conventions. Key rules:
- All tests extend `BaseTest` (`src/main/kotlin/BaseTest.kt`)
- All compilation tests extend `BaseCompilationTest` (`src/main/kotlin/compilation/BaseCompilationTest.kt`)
- Add `@DisplayName` to both test class and methods
- Add `@TestMetadata` pointing to the relevant test data directory for IDE navigation
- Keep test classes small — tests run in parallel
- Use the scenario DSL for incremental compilation tests; see `src/testExample/kotlin/ExampleIncrementalScenarioTest.kt`
- Annotate strategy-agnostic tests with `@DefaultStrategyAgnosticCompilationTest`
- Add a new test suite by appending its name to `businessLogicTestSuits` in `build.gradle.kts`
- Compatibility suites (`testCompatibility*`): add tests sparingly — they run once per listed version
## Key Conventions and Pitfalls
- Every public API addition in `kotlin-build-tools-api` must include KDoc documentation
- Do not add implementation dependencies to `kotlin-build-tools-api` — it must stay implementation-free
- Do not use `kotlin-build-tools-jdk-utils` outside BTA modules (requires `@KotlinBuildToolsInternalJdkUtils` opt-in)
- After changing compiler arguments, always regenerate both `generateBtaSources` and `apiDump`