Skip to content

Commit 74d0dea

Browse files
committed
feat(tooling): early support wiring for ksp/kapt
Signed-off-by: Sam Gammon <[email protected]>
1 parent a718b56 commit 74d0dea

File tree

10 files changed

+143
-25
lines changed

10 files changed

+143
-25
lines changed

packages/builder/src/main/kotlin/elide/tooling/jvm/JvmBuildConfigurator.kt

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,13 @@ import java.io.IOException
2323
import java.nio.file.Files
2424
import java.nio.file.Path
2525
import java.util.*
26+
import kotlinx.coroutines.Dispatchers
27+
import kotlinx.coroutines.async
28+
import kotlinx.coroutines.awaitAll
29+
import kotlinx.coroutines.coroutineScope
2630
import kotlin.io.path.absolute
2731
import kotlin.io.path.absolutePathString
32+
import kotlin.io.path.createDirectories
2833
import kotlin.io.path.exists
2934
import kotlin.io.path.extension
3035
import kotlin.io.path.isDirectory
@@ -421,7 +426,8 @@ internal class JvmBuildConfigurator : BuildConfigurator {
421426

422427
val processorClasspath = resolver?.classpathProvider(
423428
object : ClasspathSpec {
424-
override val usage: MultiPathUsage = if (tests) MultiPathUsage.TestProcessors else MultiPathUsage.Processors
429+
override val usage: MultiPathUsage =
430+
if (tests) MultiPathUsage.TestProcessors else MultiPathUsage.Processors
425431
},
426432
)?.classpath()
427433

@@ -465,6 +471,15 @@ internal class JvmBuildConfigurator : BuildConfigurator {
465471
)
466472
}
467473
}
474+
if (state.manifest.kotlin?.features?.kapt != false) {
475+
staticDeps.add(
476+
builtinKotlinJarPath(
477+
state,
478+
JvmLibraries.KOTLIN_KAPT_RUNTIME,
479+
KotlinLanguage.VERSION,
480+
)
481+
)
482+
}
468483
if (state.manifest.kotlin?.features?.kotlinx != false) {
469484
if (state.manifest.kotlin?.features?.coroutines != false) {
470485
// add `org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm`
@@ -559,6 +574,41 @@ internal class JvmBuildConfigurator : BuildConfigurator {
559574
val args = Arguments.empty().toMutable().apply {
560575
// apply arguments
561576
addAllStrings(kotlincOpts.collect().toList())
577+
578+
if (state.manifest.kotlin?.features?.kapt == true && processorClasspath?.isNotEmpty() == true) {
579+
val kapt3 = "org.jetbrains.kotlin.kapt3"
580+
val kaptOutBase = state.layout.artifacts.resolve("codegen").resolve("kapt")
581+
val kaptSources = kaptOutBase.resolve("sources")
582+
val kaptClasses = kaptOutBase.resolve("classes")
583+
val kaptStubs = kaptOutBase.resolve("stubs")
584+
coroutineScope {
585+
listOf(kaptSources, kaptClasses, kaptStubs).map {
586+
async(Dispatchers.IO) {
587+
it.createDirectories()
588+
}
589+
}.awaitAll()
590+
}
591+
add("-P")
592+
add("plugin:$kapt3:aptMode=stubsAndApt")
593+
add("-P")
594+
add("plugin:$kapt3:correctErrorTypes=true")
595+
add("-P")
596+
add("plugin:$kapt3:sources=${kaptSources.absolutePathString()}")
597+
add("-P")
598+
add("plugin:$kapt3:classes=${kaptClasses.absolutePathString()}")
599+
add("-P")
600+
add("plugin:$kapt3:stubs=${kaptStubs.absolutePathString()}")
601+
if (state.manifest.kotlin?.compilerOptions?.freeCompilerArgs?.contains("-Xjvm-enable-preview") == true) {
602+
// preview mode must match for kapt
603+
add("-P")
604+
add("plugin:$kapt3:javacOption=--enable-preview=true")
605+
}
606+
processorClasspath.forEach { item ->
607+
add("-P")
608+
add("plugin:$kapt3:apclasspath=${item.path.absolutePathString()}")
609+
}
610+
}
611+
// add kapt classpath
562612
}.build()
563613

564614
logging.debug { "Kotlin compiler args: '${args.asArgumentList().joinToString(" ")}'" }

packages/builder/src/main/kotlin/elide/tooling/kotlin/KotlinCompiler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ public val kotlinc: Tool.CommandLineTool = Tool.describe(
426426
test: Boolean = false,
427427
enableSerialization: Boolean = true,
428428
enablePowerAssert: Boolean = test,
429-
): Set<KotlinBuiltinPlugin> {
429+
): List<KotlinBuiltinPlugin> {
430430
val defaultPlugins = KotlinCompilerConfig.getDefaultPlugins(test = test)
431431
defaultPlugins.forEach { plugin ->
432432
if (plugin == KotlinBuiltinPlugin.SERIALIZATION && !enableSerialization) {

packages/cli/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ val svmModules = "com.oracle.graal.graal_enterprise,com.oracle.svm.svm_enterpris
244244

245245
// JPMS add-on arguments for SVM builder stuff
246246
val jpmsSvmArgs = listOf(
247+
"jdk.compiler" to "com.sun.tools.javac.util",
248+
"jdk.compiler" to "com.sun.tools.javac.parser",
247249
"jdk.graal.compiler" to "jdk.graal.compiler.options",
248250
"java.base" to "jdk.internal.module",
249251
"jdk.internal.vm.ci" to "jdk.vm.ci.meta",

packages/cli/src/main/resources/META-INF/native-image/dev/elide/elide-cli/reachability-metadata.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,15 @@
14901490
}
14911491
]
14921492
},
1493+
{
1494+
"type": "com.sun.tools.javac.util.Context",
1495+
"methods": [
1496+
{
1497+
"name": "<init>",
1498+
"parameterTypes": []
1499+
}
1500+
]
1501+
},
14931502
{
14941503
"type": "dev.elide.cli.bridge.CliNativeBridge",
14951504
"allDeclaredMethods": true,
@@ -12100,6 +12109,9 @@
1210012109
{
1210112110
"type": "org.jetbrains.kotlin.extensions.CollectAdditionalSourcesExtension"
1210212111
},
12112+
{
12113+
"type": "org.jetbrains.kotlin.extensions.CollectAdditionalSourcesExtension[]"
12114+
},
1210312115
{
1210412116
"type": "org.jetbrains.kotlin.extensions.CompilerConfigurationExtension"
1210512117
},
@@ -12115,6 +12127,9 @@
1211512127
{
1211612128
"type": "org.jetbrains.kotlin.extensions.ProcessSourcesBeforeCompilingExtension"
1211712129
},
12130+
{
12131+
"type": "org.jetbrains.kotlin.extensions.ProcessSourcesBeforeCompilingExtension[]"
12132+
},
1211812133
{
1211912134
"type": "org.jetbrains.kotlin.extensions.StorageComponentContainerContributor"
1212012135
},
@@ -12131,6 +12146,9 @@
1213112146
{
1213212147
"type": "org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter[]"
1213312148
},
12149+
{
12150+
"type": "org.jetbrains.kotlin.kapt.base.javac.KaptJavaFileManager"
12151+
},
1213412152
{
1213512153
"type": "org.jetbrains.kotlin.load.java.ErasedOverridabilityCondition"
1213612154
},

packages/graalvm-kt/src/main/kotlin/elide/runtime/gvm/kotlin/KotlinCompilerConfig.kt

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
1616
import org.jetbrains.kotlin.config.ApiVersion
1717
import org.jetbrains.kotlin.config.LanguageVersion
1818
import java.nio.file.Path
19-
import java.util.EnumSet
2019
import kotlin.collections.orEmpty
2120
import kotlin.collections.toMutableList
2221
import kotlin.io.path.absolutePathString
2322
import elide.runtime.precompiler.Precompiler
2423
import elide.tooling.jvm.JvmLibraries
2524

2625
// Constant plugin names.
26+
private const val KAPT_PLUGIN_NAME = "kotlin-annotation-processing-embeddable"
2727
private const val SERIALIZATION_PLUGIN_NAME = "kotlin-serialization-compiler-plugin-embeddable"
2828
private const val POWERASSERT_PLUGIN_NAME = "kotlin-power-assert-compiler-plugin-embeddable"
2929
private const val REDACTED_PLUGIN_NAME = "redacted-compiler-plugin"
3030

31+
// Whether to use legacy plugin flags to kotlinc.
32+
private const val DEFAULT_USE_LEGACY_PLUGIN_MOUNT = true
33+
3134
/**
3235
* Configures the Kotlin compiler which is embedded within Elide.
3336
*
@@ -44,7 +47,7 @@ public data class KotlinCompilerConfig(
4447
public val languageVersion: LanguageVersion,
4548
public val plugins: List<KotlinPluginConfig> = emptyList(),
4649
public val testMode: Boolean = false,
47-
public val builtinPlugins: Set<KotlinBuiltinPlugin> = if (testMode) DEFAULT_PLUGINS_TEST else DEFAULT_PLUGINS,
50+
public val builtinPlugins: List<KotlinBuiltinPlugin> = if (testMode) DEFAULT_PLUGINS_TEST else DEFAULT_PLUGINS,
4851
) : Precompiler.Configuration {
4952
/**
5053
* Configures a Kotlin compiler plugin.
@@ -58,6 +61,22 @@ public data class KotlinCompilerConfig(
5861
*/
5962
@Suppress("MaxLineLength")
6063
public enum class KotlinBuiltinPlugin : KotlinPluginConfig {
64+
KAPT {
65+
override fun apply(args: K2JVMCompilerArguments, root: Path) {
66+
val artifact = root
67+
.resolve("kotlin")
68+
.resolve(KotlinLanguage.VERSION)
69+
.resolve("lib")
70+
.resolve("$KAPT_PLUGIN_NAME-${KotlinLanguage.VERSION}.jar")
71+
72+
initializePlugin(
73+
"org.jetbrains.kotlin.kapt3",
74+
args = args,
75+
artifact = artifact,
76+
)
77+
}
78+
},
79+
6180
SERIALIZATION {
6281
override fun apply(args: K2JVMCompilerArguments, root: Path) {
6382
val artifact = root
@@ -67,6 +86,7 @@ public data class KotlinCompilerConfig(
6786
.resolve("$SERIALIZATION_PLUGIN_NAME-${KotlinLanguage.VERSION}.jar")
6887

6988
initializePlugin(
89+
"kotlinx.serialization",
7090
args = args,
7191
artifact = artifact,
7292
)
@@ -82,6 +102,7 @@ public data class KotlinCompilerConfig(
82102
.resolve("$POWERASSERT_PLUGIN_NAME-${KotlinLanguage.VERSION}.jar")
83103

84104
initializePlugin(
105+
"kotlin-power-assert",
85106
args = args,
86107
artifact = artifact,
87108
options = powerAssertSymbols.map { "function" to it }.toList(),
@@ -98,6 +119,7 @@ public data class KotlinCompilerConfig(
98119
.resolve("$REDACTED_PLUGIN_NAME-${JvmLibraries.EMBEDDED_REDACTED_VERSION}.jar")
99120

100121
initializePlugin(
122+
"dev.zacsweers.redacted.compiler",
101123
args = args,
102124
artifact = artifact,
103125
options = buildList {
@@ -112,21 +134,41 @@ public data class KotlinCompilerConfig(
112134

113135
private companion object {
114136
@JvmStatic private fun initializePlugin(
137+
pluginId: String,
115138
args: K2JVMCompilerArguments,
116139
artifact: Path,
117-
options: List<Pair<String, String>> = emptyList()
140+
options: List<Pair<String, String>> = emptyList(),
141+
useLegacyMount: Boolean = DEFAULT_USE_LEGACY_PLUGIN_MOUNT,
118142
) {
119-
args.pluginConfigurations = (args
120-
.pluginConfigurations
121-
.orEmpty()
122-
.toMutableList() + buildString {
123-
append(artifact.absolutePathString())
124-
if (options.isNotEmpty()) {
125-
append("=")
126-
append(options.joinToString(",") { "${it.first}=${it.second}" })
143+
if (useLegacyMount) {
144+
args.pluginClasspaths = (
145+
args.pluginClasspaths
146+
.orEmpty()
147+
.toMutableList() + artifact.absolutePathString()
148+
).toTypedArray()
149+
150+
if (options.isNotEmpty()) args.pluginOptions = (
151+
args.pluginOptions
152+
.orEmpty()
153+
.toMutableList() + buildList {
154+
options.forEach { (key, value) ->
155+
add("plugin:$pluginId:$key=$value")
156+
}
157+
}
158+
).toTypedArray()
159+
} else {
160+
args.pluginConfigurations = (args
161+
.pluginConfigurations
162+
.orEmpty()
163+
.toMutableList() + buildString {
164+
append(artifact.absolutePathString())
165+
if (options.isNotEmpty()) {
166+
append("=")
167+
append(options.joinToString(",") { "${it.first}=${it.second}" })
168+
}
127169
}
128-
}
129-
).toTypedArray()
170+
).toTypedArray()
171+
}
130172
}
131173
}
132174
}
@@ -136,17 +178,18 @@ public data class KotlinCompilerConfig(
136178
public val DEFAULT: KotlinCompilerConfig = KotlinPrecompiler.currentConfig()
137179

138180
/** Default suite of Kotlin plugins to enable. */
139-
private val DEFAULT_PLUGINS: Set<KotlinBuiltinPlugin> = EnumSet.of(
181+
private val DEFAULT_PLUGINS: List<KotlinBuiltinPlugin> = listOf(
140182
KotlinBuiltinPlugin.SERIALIZATION,
183+
KotlinBuiltinPlugin.KAPT,
141184
KotlinBuiltinPlugin.REDACTED,
142185
)
143186

144187
/** Default suite of Kotlin plugins to enable in test mode. */
145-
private val DEFAULT_PLUGINS_TEST: Set<KotlinBuiltinPlugin> = DEFAULT_PLUGINS + EnumSet.of(
188+
private val DEFAULT_PLUGINS_TEST: List<KotlinBuiltinPlugin> = DEFAULT_PLUGINS + listOf(
146189
KotlinBuiltinPlugin.POWER_ASSERT,
147190
)
148191

149-
@JvmStatic public fun getDefaultPlugins(test: Boolean = false): Set<KotlinBuiltinPlugin> {
192+
@JvmStatic public fun getDefaultPlugins(test: Boolean = false): List<KotlinBuiltinPlugin> {
150193
return if (test) DEFAULT_PLUGINS_TEST else DEFAULT_PLUGINS
151194
}
152195

packages/tooling/src/main/kotlin/elide/tooling/jvm/JvmLibraries.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public object JvmLibraries {
4444
public const val JUNIT_PLATFORM_CONSOLE: String = "org.junit.platform:junit-platform-console"
4545
public const val JUNIT_JUPITER_PARAMS: String = "org.junit.jupiter:junit-jupiter-params"
4646
public const val OPENTEST: String = "org.opentest4j:opentest4j"
47+
public const val KOTLIN_KAPT_RUNTIME: String = "org.jetbrains.kotlin:kotlin-annotation-processing-runtime"
4748
public const val KOTLIN_TEST: String = "org.jetbrains.kotlin:kotlin-test"
4849
public const val KOTLIN_TEST_JUNIT5: String = "org.jetbrains.kotlin:kotlin-test-junit5"
4950
public const val KOTLINX_HTML: String = "org.jetbrains.kotlinx:kotlinx-html-jvm"

packages/tooling/src/main/kotlin/elide/tooling/project/manifest/ElidePackageManifest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,8 @@ public data class ElidePackageManifest(
507507
val injection: Boolean = true,
508508
val testing: Boolean = true,
509509
val kotlinx: Boolean = true,
510+
val kapt: Boolean = true,
511+
val ksp: Boolean = true,
510512
val enableDefaultPlugins: Boolean = true,
511513
val experimental: Boolean = true,
512514
val incremental: Boolean = true,

packages/tooling/src/main/pkl/Java.pkl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,11 @@
22
@ModuleInfo { minPklVersion = "0.28.1" }
33
module elide.java
44

5+
/// Controls settings relating to the Java compiler.
6+
class JavaCompiler {
7+
/// Extra flags to pass to the Java compiler.
8+
flags: Listing<String> = new {}
9+
}
10+
511
/// Configures Java language features and settings.
612
class JavaSettings {}

packages/tooling/src/main/pkl/Jvm.pkl

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module elide.jvm
55
import "Base.pkl" as common
66
import "Artifacts.pkl" as artifacts
77
import "Sources.pkl" as sources
8+
import "Java.pkl" as _java
89

910
/// JVM target levels as integers.
1011
typealias JvmTargetLevel = "latest" | "stable" | "auto" | Float(1.8) | Float(1.9) | Int8(isBetween(8, 29))
@@ -253,11 +254,6 @@ class JvmFeatures {
253254
automodules: Boolean = true
254255
}
255256

256-
/// Controls settings relating to the Java compiler.
257-
class JavaCompiler {
258-
/// Extra flags to pass to the Java compiler.
259-
flags: Listing<String> = new {}
260-
}
261257

262258
/// Controls settings relating to the Java language.
263259
class JavaLanguage {
@@ -268,7 +264,7 @@ class JavaLanguage {
268264
release: JvmTarget = "auto"
269265

270266
/// Configuration for the Java compiler.
271-
compiler: JavaCompiler = new {}
267+
compiler: _java.JavaCompiler = new {}
272268
}
273269

274270
/// Specifies settings which apply to JVM targets.

packages/tooling/src/main/pkl/Kotlin.pkl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class KotlinCompilerJvmOptions extends KotlinCompilerOptions {
7373
/// Specifies Kotlin-related features and options within Elide.
7474
class KotlinFeatureOptions {
7575
/// Enable or disable annotation processing with kapt.
76-
kapt: Boolean = false
76+
kapt: Boolean = true
7777

7878
/// Enable or disable annotation processing with KSP.
7979
ksp: Boolean = false

0 commit comments

Comments
 (0)