blob: 061bcbc5853b22cb5689af178eb3b1f7bc7cc7b7 [file] [log] [blame] [edit]
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.github.jengelman.gradle.plugins.shadow.transformers.CacheableTransformer
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import kotlinx.metadata.jvm.KotlinModuleMetadata
import kotlinx.metadata.jvm.UnstableMetadataApi
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import org.gradle.kotlin.dsl.support.serviceOf
description = "Kotlin Full Reflection Library"
buildscript {
dependencies {
classpath(libs.kotlinx.metadataJvm)
}
}
plugins {
`java-library`
}
configureJavaOnlyToolchain(JdkMajorVersion.JDK_1_8)
publish()
val core = "$rootDir/core"
val relocatedCoreSrc = "${layout.buildDirectory.get().asFile}/core-relocated"
val proguardDeps by configurations.creating
val proguardAdditionalInJars by configurations.creating
val embedded by configurations
embedded.isTransitive = false
configurations.getByName("compileOnly").extendsFrom(embedded)
dependencies {
api(kotlinStdlib())
proguardDeps(kotlinStdlib())
proguardAdditionalInJars(project(":kotlin-annotations-jvm"))
embedded(project(":kotlin-reflect-api")) { isTransitive = false }
embedded(project(":core:metadata")) { isTransitive = false }
embedded(project(":core:metadata.jvm")) { isTransitive = false }
embedded(project(":core:compiler.common")) { isTransitive = false }
embedded(project(":core:compiler.common.jvm")) { isTransitive = false }
embedded(project(":core:deserialization.common")) { isTransitive = false }
embedded(project(":core:deserialization.common.jvm")) { isTransitive = false }
embedded(project(":core:descriptors")) { isTransitive = false }
embedded(project(":core:descriptors.jvm")) { isTransitive = false }
embedded(project(":core:deserialization")) { isTransitive = false }
embedded(project(":core:descriptors.runtime")) { isTransitive = false }
embedded(project(":core:util.runtime")) { isTransitive = false }
embedded("javax.inject:javax.inject:1") { isTransitive = false }
embedded(protobufLite()) { isTransitive = false }
compileOnly("org.jetbrains:annotations:13.0")
}
@CacheableTransformer
@OptIn(UnstableMetadataApi::class)
class KotlinModuleShadowTransformer(private val logger: Logger) : Transformer {
@Suppress("ArrayInDataClass")
private data class Entry(val path: String, val bytes: ByteArray)
private val data = mutableListOf<Entry>()
override fun getName() = "KotlinModuleShadowTransformer"
override fun canTransformResource(element: FileTreeElement): Boolean =
element.path.substringAfterLast(".") == KOTLIN_MODULE
override fun transform(context: TransformerContext) {
fun relocate(content: String): String =
context.relocators.fold(content) { acc, relocator -> relocator.applyToSourceContent(acc) }
logger.info("Transforming ${context.path}")
val metadata = KotlinModuleMetadata.read(context.`is`.readBytes())
val module = metadata.kmModule
val packageParts = module.packageParts.toMap()
module.packageParts.clear()
packageParts.map { (fqName, parts) ->
require(parts.multiFileClassParts.isEmpty()) { parts.multiFileClassParts } // There are no multi-file class parts in core
val fileFacades = parts.fileFacades.toList()
parts.fileFacades.clear()
fileFacades.mapTo(parts.fileFacades) { relocate(it) }
relocate(fqName) to parts
}.toMap(module.packageParts)
data += Entry(context.path, metadata.write())
}
override fun hasTransformedResource(): Boolean = data.isNotEmpty()
override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {
for ((path, bytes) in data) {
os.putNextEntry(ZipEntry(path))
os.write(bytes)
}
data.clear()
}
companion object {
const val KOTLIN_MODULE = "kotlin_module"
}
}
val reflectShadowJar by task<ShadowJar> {
archiveClassifier.set("shadow")
configurations = listOf(embedded)
exclude("**/*.proto")
exclude("org/jetbrains/annotations/Nls*.class")
if (kotlinBuildProperties.relocation) {
mergeServiceFiles()
transform(KotlinModuleShadowTransformer(logger))
relocate("org.jetbrains.kotlin", "kotlin.reflect.jvm.internal.impl")
relocate("javax.inject", "kotlin.reflect.jvm.internal.impl.javax.inject")
}
}
val stripMetadata by tasks.registering {
dependsOn(reflectShadowJar)
val inputJar = provider { reflectShadowJar.get().outputs.files.singleFile }
val outputJar = fileFrom(base.libsDirectory.asFile.get(), "${base.archivesName.get()}-$version-stripped.jar")
inputs.file(inputJar).withNormalizer(ClasspathNormalizer::class.java)
outputs.file(outputJar)
outputs.cacheIf { true }
doLast {
stripMetadata(
logger = logger,
classNamePattern = "kotlin/reflect/jvm/internal/impl/.*",
inFile = inputJar.get(),
outFile = outputJar,
preserveFileTimestamps = false
)
}
}
val proguard by task<CacheableProguardTask> {
dependsOn(stripMetadata)
injars(mapOf("filter" to "!META-INF/versions/**"), stripMetadata.get().outputs.files)
injars(mapOf("filter" to "!META-INF/**,!**/*.kotlin_builtins"), proguardAdditionalInJars)
outjars(fileFrom(base.libsDirectory.asFile.get(), "${base.archivesName.get()}-$version-proguard.jar"))
javaLauncher.set(project.getToolchainLauncherFor(chooseJdk_1_8ForJpsBuild(JdkMajorVersion.JDK_1_8)))
libraryjars(mapOf("filter" to "!META-INF/versions/**"), proguardDeps)
libraryjars(
project.files(
javaLauncher.map {
firstFromJavaHomeThatExists(
"jre/lib/rt.jar",
"../Classes/classes.jar",
jdkHome = it.metadata.installationPath.asFile
)!!
}
)
)
configuration("$core/reflection.jvm/reflection.pro")
}
val relocateCoreSources by task<Copy> {
val relocatedCoreSrc = relocatedCoreSrc
val fs = serviceOf<FileSystemOperations>()
doFirst {
fs.delete {
delete(relocatedCoreSrc)
}
}
from("$core/descriptors/src")
from("$core/descriptors.common/src")
from("$core/descriptors.jvm/src")
from("$core/descriptors.runtime/src")
from("$core/deserialization/src")
from("$core/deserialization/deserialization.common/src")
from("$core/util.runtime/src")
exclude("META-INF/services/**")
into(relocatedCoreSrc)
includeEmptyDirs = false
eachFile {
path = path.replace("org/jetbrains/kotlin", "kotlin/reflect/jvm/internal/impl")
}
filter { line ->
line.replace("org.jetbrains.kotlin", "kotlin.reflect.jvm.internal.impl")
}
filter(org.apache.tools.ant.filters.FixCrLfFilter::class, "eol" to org.apache.tools.ant.filters.FixCrLfFilter.CrLf.newInstance("lf"))
outputs.cacheIf { true }
}
noDefaultJar()
java {
withSourcesJar()
}
configurePublishedComponent {
addVariantsFromConfiguration(configurations[JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME]) { }
}
val sourcesJar = tasks.named<Jar>("sourcesJar") {
archiveClassifier.set("sources")
dependsOn(relocateCoreSources)
from(relocatedCoreSrc)
from("$core/reflection.jvm/src")
}
addArtifact("archives", sourcesJar)
addArtifact("sources", sourcesJar)
val intermediate = when {
kotlinBuildProperties.proguard -> proguard
kotlinBuildProperties.relocation -> stripMetadata
else -> reflectShadowJar
}
val result by task<Jar> {
dependsOn(intermediate)
from {
zipTree(intermediate.get().singleOutputFile(layout))
}
from(zipTree(provider { reflectShadowJar.get().archiveFile.get().asFile })) {
include("META-INF/versions/**")
}
manifestAttributes(
manifest,
component = "Main",
multiRelease = true
)
}
javadocJar()
dexMethodCount {
jarFile.fileProvider(result.map { it.outputs.files.singleFile })
ownPackages.set(listOf("kotlin.reflect"))
}
artifacts {
listOf("archives", "runtimeElements").forEach { configurationName ->
add(configurationName, result.map { it.outputs.files.singleFile })
}
}