Add plugin for JVM ABI classes generation
#KT-25128 Fixed ABI class generation is implemented as a compiler plugin. Command-line usage: 1. Add a path to 'jvm-abi-gen.jar' to the plguin classpath argument (`-Xplugin`). By default the jar is located at 'kotlinc/lib/jvm-abi-gen.jar' in the kotlinc distribution archive. 2. Specify an output directory for ABI classes via `-Pplugin:org.jetbrains.kotlin.jvm.abi:outputDir=<DIR>`.
This commit is contained in:
@@ -480,6 +480,7 @@ tasks {
|
|||||||
":compiler:container:test",
|
":compiler:container:test",
|
||||||
":compiler:tests-java8:test",
|
":compiler:tests-java8:test",
|
||||||
":compiler:tests-spec:remoteRunTests")
|
":compiler:tests-spec:remoteRunTests")
|
||||||
|
dependsOn(":plugins:jvm-abi-gen:test")
|
||||||
}
|
}
|
||||||
|
|
||||||
create("jsCompilerTest") {
|
create("jsCompilerTest") {
|
||||||
|
|||||||
@@ -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()
|
||||||
+6
@@ -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
|
||||||
+6
@@ -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
|
||||||
+82
@@ -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<KtFile>
|
||||||
|
): 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<File>, 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() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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", "<path>", "Output path for the generated files", required = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val pluginId: String
|
||||||
|
get() = COMPILER_PLUGIN_ID
|
||||||
|
|
||||||
|
override val pluginOptions: Collection<CliOption>
|
||||||
|
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}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String> =
|
||||||
|
CompilerConfigurationKey.create<String>(JvmAbiCommandLineProcessor.OUTPUT_DIR_OPTION.description)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -198,6 +198,7 @@ include ":kotlin-build-common",
|
|||||||
":libraries:kotlin-prepush-hook",
|
":libraries:kotlin-prepush-hook",
|
||||||
":libraries:tools:mutability-annotations-compat",
|
":libraries:tools:mutability-annotations-compat",
|
||||||
":include:kotlin-compiler",
|
":include:kotlin-compiler",
|
||||||
|
":plugins:jvm-abi-gen",
|
||||||
|
|
||||||
// plugin markers:
|
// plugin markers:
|
||||||
':kotlin-gradle-plugin:plugin-marker',
|
':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(':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(':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(':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:
|
// plugin markers:
|
||||||
project(':kotlin-gradle-plugin:plugin-marker').projectDir = file("$rootDir/libraries/tools/kotlin-gradle-plugin/plugin-marker")
|
project(':kotlin-gradle-plugin:plugin-marker').projectDir = file("$rootDir/libraries/tools/kotlin-gradle-plugin/plugin-marker")
|
||||||
|
|||||||
Reference in New Issue
Block a user