diff --git a/build.gradle.kts b/build.gradle.kts index b5c5be44ecc..4d514a8b880 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -480,6 +480,7 @@ tasks { ":compiler:container:test", ":compiler:tests-java8:test", ":compiler:tests-spec:remoteRunTests") + dependsOn(":plugins:jvm-abi-gen:test") } create("jsCompilerTest") { diff --git a/plugins/jvm-abi-gen/build.gradle.kts b/plugins/jvm-abi-gen/build.gradle.kts new file mode 100644 index 00000000000..f07159aeb17 --- /dev/null +++ b/plugins/jvm-abi-gen/build.gradle.kts @@ -0,0 +1,39 @@ + +description = "ABI generation for Kotlin/JVM" + +plugins { + kotlin("jvm") + id("jps-compatible") +} + +dependencies { + compileOnly(project(":compiler:util")) + compileOnly(project(":compiler:cli")) + compileOnly(project(":compiler:backend")) + compileOnly(project(":compiler:frontend")) + compileOnly(project(":compiler:frontend.java")) + compileOnly(project(":compiler:plugin-api")) + compileOnly(project(":kotlin-build-common")) + + runtimeOnly(project(":kotlin-compiler")) + + testCompile(commonDep("junit:junit")) + testCompile(projectTests(":compiler:incremental-compilation-impl")) +} + +sourceSets { + "main" { projectDefault() } + "test" { projectDefault() } +} + +projectTest { + workingDir = rootDir + dependsOn(":dist") +} + +sourcesJar() +javadocJar() +dist() +publish() + +testsJar() \ No newline at end of file diff --git a/plugins/jvm-abi-gen/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor b/plugins/jvm-abi-gen/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor new file mode 100644 index 00000000000..e4b198b9215 --- /dev/null +++ b/plugins/jvm-abi-gen/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor @@ -0,0 +1,6 @@ +# +# Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license +# that can be found in the license/LICENSE.txt file. +# + +org.jetbrains.kotlin.jvm.abi.JvmAbiCommandLineProcessor \ No newline at end of file diff --git a/plugins/jvm-abi-gen/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar b/plugins/jvm-abi-gen/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar new file mode 100644 index 00000000000..5a1dabc0503 --- /dev/null +++ b/plugins/jvm-abi-gen/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar @@ -0,0 +1,6 @@ +# +# Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license +# that can be found in the license/LICENSE.txt file. +# + +org.jetbrains.kotlin.jvm.abi.JvmAbiComponentRegistrar \ No newline at end of file diff --git a/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiAnalysisHandlerExtension.kt b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiAnalysisHandlerExtension.kt new file mode 100644 index 00000000000..fe0c099071a --- /dev/null +++ b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiAnalysisHandlerExtension.kt @@ -0,0 +1,82 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.jvm.abi + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.backend.common.output.OutputFile +import org.jetbrains.kotlin.cli.common.output.writeAll +import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.modules.TargetId +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension +import org.jetbrains.org.objectweb.asm.* +import java.io.File + +class JvmAbiAnalysisHandlerExtension( + private val compilerConfiguration: CompilerConfiguration +) : AnalysisHandlerExtension { + override fun analysisCompleted( + project: Project, + module: ModuleDescriptor, + bindingTrace: BindingTrace, + files: Collection + ): AnalysisResult? { + val bindingContext = bindingTrace.bindingContext + if (bindingContext.diagnostics.any { it.severity == Severity.ERROR }) return null + + val targetId = TargetId( + name = compilerConfiguration[CommonConfigurationKeys.MODULE_NAME] ?: module.name.asString(), + type = "java-production" + ) + + val generationState = GenerationState.Builder( + project, + AbiBinaries, + module, + bindingContext, + files.toList(), + compilerConfiguration + ).targetId(targetId).build() + KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION) + + val outputDir = compilerConfiguration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)!! + generationState.factory.writeAll( + outputDir, + fun(file: OutputFile, sources: List, output: File) { + // todo report + } + ) + + return null + } + + private object AbiBinaries : ClassBuilderFactory { + override fun getClassBuilderMode(): ClassBuilderMode = + ClassBuilderMode.FULL + + override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder = + AbstractClassBuilder.Concrete(ClassWriter(0)) + + override fun asText(builder: ClassBuilder): String = + throw UnsupportedOperationException("AbiBinaries generator asked for text") + + override fun asBytes(builder: ClassBuilder): ByteArray { + val visitor = builder.visitor as ClassWriter + return visitor.toByteArray() + } + + override fun close() {} + } +} diff --git a/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiCommandLineProcessor.kt b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiCommandLineProcessor.kt new file mode 100644 index 00000000000..9185676fb36 --- /dev/null +++ b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiCommandLineProcessor.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.jvm.abi + +import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption +import org.jetbrains.kotlin.compiler.plugin.CliOption +import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException +import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor +import org.jetbrains.kotlin.config.CompilerConfiguration + +class JvmAbiCommandLineProcessor : CommandLineProcessor { + companion object { + const val COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.jvm.abi" + + val OUTPUT_DIR_OPTION: CliOption = + CliOption("outputDir", "", "Output path for the generated files", required = true) + } + + override val pluginId: String + get() = COMPILER_PLUGIN_ID + + override val pluginOptions: Collection + get() = listOf(OUTPUT_DIR_OPTION) + + override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) { + when (option) { + OUTPUT_DIR_OPTION -> configuration.put(JvmAbiConfigurationKeys.OUTPUT_DIR, value) + else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}") + } + } +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiComponentRegistrar.kt b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiComponentRegistrar.kt new file mode 100644 index 00000000000..5c49fb983be --- /dev/null +++ b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiComponentRegistrar.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.jvm.abi + +import com.intellij.mock.MockProject +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension +import java.io.File + +class JvmAbiComponentRegistrar : ComponentRegistrar { + override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) { + @Suppress("NAME_SHADOWING") + val configuration = configuration.copy() + configuration.get(JvmAbiConfigurationKeys.OUTPUT_DIR)?.let { + val dir = File(it) + configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, dir) + } + val extension = JvmAbiAnalysisHandlerExtension(configuration) + AnalysisHandlerExtension.registerExtension(project, extension) + } +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiConfigurationKeys.kt b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiConfigurationKeys.kt new file mode 100644 index 00000000000..3c3e3f3560d --- /dev/null +++ b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/JvmAbiConfigurationKeys.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.jvm.abi + +import org.jetbrains.kotlin.config.CompilerConfigurationKey + +object JvmAbiConfigurationKeys { + val OUTPUT_DIR: CompilerConfigurationKey = + CompilerConfigurationKey.create(JvmAbiCommandLineProcessor.OUTPUT_DIR_OPTION.description) + +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 24785387644..ef3208fcd59 100644 --- a/settings.gradle +++ b/settings.gradle @@ -198,6 +198,7 @@ include ":kotlin-build-common", ":libraries:kotlin-prepush-hook", ":libraries:tools:mutability-annotations-compat", ":include:kotlin-compiler", + ":plugins:jvm-abi-gen", // plugin markers: ':kotlin-gradle-plugin:plugin-marker', @@ -335,6 +336,7 @@ project(':examples:scripting-jvm-embeddable-host').projectDir = "$rootDir/librar project(':pill:generate-all-tests').projectDir = "$rootDir/plugins/pill/generate-all-tests" as File project(':kotlin-imports-dumper-compiler-plugin').projectDir = "$rootDir/plugins/imports-dumper" as File project(':libraries:kotlin-prepush-hook').projectDir = "$rootDir/libraries/tools/kotlin-prepush-hook" as File +project(':plugins:jvm-abi-gen').projectDir = "$rootDir/plugins/jvm-abi-gen" as File // plugin markers: project(':kotlin-gradle-plugin:plugin-marker').projectDir = file("$rootDir/libraries/tools/kotlin-gradle-plugin/plugin-marker")