@@ -24,10 +24,13 @@ import org.jetbrains.kotlin.base.kapt3.KaptFlag
24
24
import org.jetbrains.kotlin.base.kapt3.KaptOptions
25
25
import org.jetbrains.kotlin.cli.common.ExitCode
26
26
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
27
+ import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
28
+ import org.jetbrains.kotlin.cli.common.arguments.validateArguments
27
29
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
28
30
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
29
31
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
30
32
import org.jetbrains.kotlin.cli.jvm.plugins.ServiceLoaderLite
33
+ import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
31
34
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
32
35
import org.jetbrains.kotlin.config.JVMAssertionsMode
33
36
import org.jetbrains.kotlin.config.JvmDefaultMode
@@ -45,6 +48,11 @@ import java.nio.file.Paths
45
48
import javax.annotation.processing.Processor
46
49
import javax.tools.*
47
50
51
+ data class PluginOption (val pluginId : PluginId , val optionName : OptionName , val optionValue : OptionValue )
52
+
53
+ typealias PluginId = String
54
+ typealias OptionName = String
55
+ typealias OptionValue = String
48
56
49
57
@Suppress(" MemberVisibilityCanBePrivate" )
50
58
class KotlinCompilation {
@@ -56,7 +64,7 @@ class KotlinCompilation {
56
64
}
57
65
58
66
/* * Arbitrary arguments to be passed to kapt */
59
- var kaptArgs: MutableMap <String , String > = mutableMapOf ()
67
+ var kaptArgs: MutableMap <OptionName , OptionValue > = mutableMapOf ()
60
68
61
69
/* *
62
70
* Paths to directories or .jar files that contain classes
@@ -75,6 +83,11 @@ class KotlinCompilation {
75
83
*/
76
84
var compilerPlugins: List <ComponentRegistrar > = emptyList()
77
85
86
+ /* *
87
+ * Commandline processors for compiler plugins that should be added to the compilation
88
+ */
89
+ var commandLineProcessors: List <CommandLineProcessor > = emptyList()
90
+
78
91
/* * Source files to be compiled */
79
92
var sources: List <SourceFile > = emptyList()
80
93
@@ -213,7 +226,12 @@ class KotlinCompilation {
213
226
var sanitizeParentheses: Boolean = false
214
227
215
228
/* * Paths to output directories for friend modules (whose internals should be visible) */
216
- var friendPaths: MutableList <File > = mutableListOf ()
229
+ var friendPaths: List <File > = emptyList()
230
+
231
+ /* * Additional string arguments to the Kotlin compiler */
232
+ var kotlincArguments: List <String > = emptyList()
233
+ /* * Options to be passed to compiler plugins: -P plugin:<pluginId>:<optionName>=<value>*/
234
+ var pluginOptions: List <PluginOption > = emptyList()
217
235
218
236
/* *
219
237
* Path to the JDK to be used
@@ -355,87 +373,119 @@ class KotlinCompilation {
355
373
= sourcesGeneratedByAnnotationProcessor + compiledClassAndResourceFiles + generatedStubFiles
356
374
}
357
375
376
+
358
377
// setup common arguments for the two kotlinc calls
359
- private fun commonK2JVMArgs () = K2JVMCompilerArguments ().also { it ->
360
- it .destination = classesDir.absolutePath
361
- it .classpath = commonClasspaths().joinToString(separator = File .pathSeparator)
378
+ private fun commonK2JVMArgs () = K2JVMCompilerArguments ().also { args ->
379
+ args .destination = classesDir.absolutePath
380
+ args .classpath = commonClasspaths().joinToString(separator = File .pathSeparator)
362
381
363
- it .pluginClasspaths = pluginClasspaths.map(File ::getAbsolutePath).toTypedArray()
382
+ args .pluginClasspaths = pluginClasspaths.map(File ::getAbsolutePath).toTypedArray()
364
383
365
384
if (jdkHome != null ) {
366
- it .jdkHome = jdkHome!! .absolutePath
385
+ args .jdkHome = jdkHome!! .absolutePath
367
386
}
368
387
else {
369
388
log(" Using option -no-jdk. Kotlinc won't look for a JDK." )
370
- it .noJdk = true
389
+ args .noJdk = true
371
390
}
372
391
373
- it .verbose = verbose
374
- it .includeRuntime = includeRuntime
392
+ args .verbose = verbose
393
+ args .includeRuntime = includeRuntime
375
394
376
395
// the compiler should never look for stdlib or reflect in the
377
396
// kotlinHome directory (which is null anyway). We will put them
378
397
// in the classpath manually if they're needed
379
- it .noStdlib = true
380
- it .noReflect = true
398
+ args .noStdlib = true
399
+ args .noReflect = true
381
400
382
401
if (moduleName != null )
383
- it .moduleName = moduleName
402
+ args .moduleName = moduleName
384
403
385
- it .jvmTarget = jvmTarget
386
- it .javaParameters = javaParameters
387
- it .useIR = useIR
404
+ args .jvmTarget = jvmTarget
405
+ args .javaParameters = javaParameters
406
+ args .useIR = useIR
388
407
389
408
if (javaModulePath != null )
390
- it .javaModulePath = javaModulePath!! .toString()
409
+ args .javaModulePath = javaModulePath!! .toString()
391
410
392
- it .additionalJavaModules = additionalJavaModules.map(File ::getAbsolutePath).toTypedArray()
393
- it .noCallAssertions = noCallAssertions
394
- it .noParamAssertions = noParamAssertions
395
- it .noReceiverAssertions = noReceiverAssertions
396
- it .strictJavaNullabilityAssertions = strictJavaNullabilityAssertions
397
- it .noOptimize = noOptimize
411
+ args .additionalJavaModules = additionalJavaModules.map(File ::getAbsolutePath).toTypedArray()
412
+ args .noCallAssertions = noCallAssertions
413
+ args .noParamAssertions = noParamAssertions
414
+ args .noReceiverAssertions = noReceiverAssertions
415
+ args .strictJavaNullabilityAssertions = strictJavaNullabilityAssertions
416
+ args .noOptimize = noOptimize
398
417
399
418
if (constructorCallNormalizationMode != null )
400
- it .constructorCallNormalizationMode = constructorCallNormalizationMode
419
+ args .constructorCallNormalizationMode = constructorCallNormalizationMode
401
420
402
421
if (assertionsMode != null )
403
- it .assertionsMode = assertionsMode
422
+ args .assertionsMode = assertionsMode
404
423
405
424
if (buildFile != null )
406
- it .buildFile = buildFile!! .toString()
425
+ args .buildFile = buildFile!! .toString()
407
426
408
- it .inheritMultifileParts = inheritMultifileParts
409
- it .useTypeTable = useTypeTable
427
+ args .inheritMultifileParts = inheritMultifileParts
428
+ args .useTypeTable = useTypeTable
410
429
411
430
if (declarationsOutputPath != null )
412
- it .declarationsOutputPath = declarationsOutputPath!! .toString()
431
+ args .declarationsOutputPath = declarationsOutputPath!! .toString()
413
432
414
- it .singleModule = singleModule
433
+ args .singleModule = singleModule
415
434
416
435
if (javacArguments.isNotEmpty())
417
- it .javacArguments = javacArguments.toTypedArray()
436
+ args .javacArguments = javacArguments.toTypedArray()
418
437
419
438
if (supportCompatqualCheckerFrameworkAnnotations != null )
420
- it .supportCompatqualCheckerFrameworkAnnotations = supportCompatqualCheckerFrameworkAnnotations
439
+ args .supportCompatqualCheckerFrameworkAnnotations = supportCompatqualCheckerFrameworkAnnotations
421
440
422
- it .jvmDefault = jvmDefault
423
- it .strictMetadataVersionSemantics = strictMetadataVersionSemantics
424
- it .sanitizeParentheses = sanitizeParentheses
441
+ args .jvmDefault = jvmDefault
442
+ args .strictMetadataVersionSemantics = strictMetadataVersionSemantics
443
+ args .sanitizeParentheses = sanitizeParentheses
425
444
426
445
if (friendPaths.isNotEmpty())
427
- it .friendPaths = friendPaths.map(File ::getAbsolutePath).toTypedArray()
446
+ args .friendPaths = friendPaths.map(File ::getAbsolutePath).toTypedArray()
428
447
429
448
if (scriptResolverEnvironment.isNotEmpty())
430
- it.scriptResolverEnvironment = scriptResolverEnvironment.map { (key, value) -> " $key =\" $value \" " }.toTypedArray()
431
-
432
- it.noExceptionOnExplicitEqualsForBoxedNull = noExceptionOnExplicitEqualsForBoxedNull
433
- it.skipRuntimeVersionCheck = skipRuntimeVersionCheck
434
- it.suppressWarnings = suppressWarnings
435
- it.allWarningsAsErrors = allWarningsAsErrors
436
- it.reportOutputFiles = reportOutputFiles
437
- it.reportPerf = reportPerformance
449
+ args.scriptResolverEnvironment = scriptResolverEnvironment.map { (key, value) -> " $key =\" $value \" " }.toTypedArray()
450
+
451
+ args.noExceptionOnExplicitEqualsForBoxedNull = noExceptionOnExplicitEqualsForBoxedNull
452
+ args.skipRuntimeVersionCheck = skipRuntimeVersionCheck
453
+ args.suppressWarnings = suppressWarnings
454
+ args.allWarningsAsErrors = allWarningsAsErrors
455
+ args.reportOutputFiles = reportOutputFiles
456
+ args.reportPerf = reportPerformance
457
+ args.javaPackagePrefix = javaPackagePrefix
458
+ args.suppressMissingBuiltinsError = suppressMissingBuiltinsError
459
+
460
+ /* *
461
+ * It's not possible to pass dynamic [CommandLineProcessor] instancess directly to the [K2JVMCompiler]
462
+ * because the compiler discoveres them on the classpath through a service locator, so we need to apply
463
+ * the same trick as with [ComponentRegistrar]s: We put our own static [CommandLineProcessor] on the
464
+ * classpath which in turn calls the user's dynamic [CommandLineProcessor] instances.
465
+ */
466
+ MainCommandLineProcessor .threadLocalParameters.set(
467
+ MainCommandLineProcessor .ThreadLocalParameters (commandLineProcessors)
468
+ )
469
+
470
+ /* *
471
+ * Our [MainCommandLineProcessor] only has access to the CLI options that belong to its own plugin ID.
472
+ * So in order to be able to access CLI options that are meant for other [CommandLineProcessor]s we
473
+ * wrap these CLI options, send them to our own plugin ID and later unwrap them again to forward them
474
+ * to the correct [CommandLineProcessor].
475
+ */
476
+ args.pluginOptions = pluginOptions.map { (pluginId, optionName, optionValue) ->
477
+ " plugin:${MainCommandLineProcessor .pluginId} :${MainCommandLineProcessor .encodeForeignOptionName(pluginId, optionName)} =$optionValue "
478
+ }.toTypedArray()
479
+
480
+ /* Parse extra CLI arguments that are given as strings so users can specify arguments that are not yet
481
+ implemented here as well-typed properties. */
482
+ parseCommandLineArguments(kotlincArguments, args)
483
+
484
+ validateArguments(args.errors)?.let {
485
+ throw IllegalArgumentException (" Errors parsing kotlinc CLI arguments:\n $it " )
486
+ }
438
487
}
488
+
439
489
/* * Performs the 1st and 2nd compilation step to generate stubs and run annotation processors */
440
490
private fun stubsAndApt (sourceFiles : List <File >): ExitCode {
441
491
if (annotationProcessors.isEmpty()) {
@@ -467,7 +517,7 @@ class KotlinCompilation {
467
517
*
468
518
*/
469
519
MainComponentRegistrar .threadLocalParameters.set(
470
- MainComponentRegistrar .Parameters (
520
+ MainComponentRegistrar .ThreadLocalParameters (
471
521
annotationProcessors.map { IncrementalProcessor (it, DeclaredProcType .NON_INCREMENTAL ) },
472
522
kaptOptions,
473
523
compilerPlugins
@@ -555,14 +605,13 @@ class KotlinCompilation {
555
605
* the list is set to empty
556
606
*/
557
607
MainComponentRegistrar .threadLocalParameters.set(
558
- MainComponentRegistrar .Parameters (
608
+ MainComponentRegistrar .ThreadLocalParameters (
559
609
listOf (),
560
610
KaptOptions .Builder (),
561
611
compilerPlugins
562
612
)
563
613
)
564
614
565
-
566
615
val sources = sourceFiles +
567
616
kaptKotlinGeneratedDir.listFilesRecursively() +
568
617
kaptSourceDir.listFilesRecursively()
@@ -572,7 +621,7 @@ class KotlinCompilation {
572
621
return ExitCode .OK
573
622
574
623
// in this step also include source files generated by kapt in the previous step
575
- val k2JvmArgs = commonK2JVMArgs().also {jvmArgs->
624
+ val k2JvmArgs = commonK2JVMArgs().also { jvmArgs->
576
625
jvmArgs.pluginClasspaths = (jvmArgs.pluginClasspaths ? : emptyArray()) + arrayOf(getResourcesPath())
577
626
jvmArgs.freeArgs = sources.map(File ::getAbsolutePath).distinct()
578
627
}
@@ -777,7 +826,9 @@ class KotlinCompilation {
777
826
778
827
private fun commonClasspaths () = mutableListOf<File >().apply {
779
828
addAll(classpaths)
780
- addAll(listOfNotNull(kotlinStdLibJar, kotlinReflectJar, kotlinScriptRuntimeJar))
829
+ addAll(listOfNotNull(kotlinStdLibJar, kotlinStdLibCommonJar, kotlinStdLibJdkJar,
830
+ kotlinReflectJar, kotlinScriptRuntimeJar
831
+ ))
781
832
782
833
if (inheritClassPath) {
783
834
addAll(hostClasspaths)
0 commit comments