[Gradle] Initial 'externalTargetApi' w/ compilable Android prototype
^KT-54766 Verification Pending
This commit is contained in:
committed by
Space Team
parent
33adebe5bf
commit
9599c16d95
@@ -9,9 +9,16 @@ dependencies {
|
||||
compileOnly(project(":kotlin-gradle-plugin"))
|
||||
}
|
||||
|
||||
/* This module is just for local development / prototyping and demos */
|
||||
if (!kotlinBuildProperties.isTeamcityBuild) {
|
||||
tasks.register("install") {
|
||||
dependsOn(tasks.named("publishToMavenLocal"))
|
||||
configureKotlinCompileTasksGradleCompatibility()
|
||||
|
||||
kotlin {
|
||||
sourceSets.all {
|
||||
languageSettings.optIn("org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi")
|
||||
}
|
||||
}
|
||||
|
||||
/* This module is just for local development / prototyping and demos */
|
||||
if (!kotlinBuildProperties.isTeamcityBuild) {
|
||||
publish()
|
||||
standardPublicJars()
|
||||
}
|
||||
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION", "DuplicatedCode")
|
||||
|
||||
package org.jetbrains.kotlin.gradle.android
|
||||
|
||||
import com.android.build.gradle.AppExtension
|
||||
import com.android.build.gradle.internal.publishing.AndroidArtifacts
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.attributes.java.TargetJvmEnvironment
|
||||
import org.gradle.api.attributes.java.TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.kpm.external.ExternalVariantApi
|
||||
import org.jetbrains.kotlin.gradle.kpm.external.project
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinTargetDescriptor.DecoratedExternalTargetFactory
|
||||
|
||||
@OptIn(ExternalVariantApi::class)
|
||||
fun KotlinMultiplatformExtension.androidTargetPrototype(): PrototypeAndroidTarget {
|
||||
val project = this.project
|
||||
val androidExtension = project.extensions.getByType<AppExtension>()
|
||||
|
||||
/*
|
||||
Set a variant filter and only allow 'debug'.
|
||||
Reason: This prototype will not deal w/ buildTypes or flavors.
|
||||
Only 'debug' will be supported. As of agreed w/ AGP team, this is the initial goal
|
||||
for the APIs.
|
||||
*/
|
||||
androidExtension.variantFilter { variant ->
|
||||
if (variant.name != "debug") {
|
||||
variant.ignore = true
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Create our 'AndroidTarget':
|
||||
This uses the 'KotlinPlatformType.jvm' instead of androidJvm, since from the perspective of
|
||||
Kotlin, this is just another 'jvm' like target (using the jvm compiler)
|
||||
*/
|
||||
val androidTarget = createExternalKotlinTarget<PrototypeAndroidTarget> {
|
||||
targetName = "android"
|
||||
platformType = KotlinPlatformType.jvm
|
||||
decoratedExternalTargetFactory = DecoratedExternalTargetFactory { externalTarget ->
|
||||
PrototypeAndroidTarget(externalTarget, PrototypeAndroidDsl(31))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Whilst using the .all hook, we only expect the single 'debug' variant to be available through this API.
|
||||
*/
|
||||
androidExtension.applicationVariants.all { applicationVariant ->
|
||||
project.logger.quiet("Setting up applicationVariant: ${applicationVariant.name}")
|
||||
|
||||
/*
|
||||
Create Compilations: main, unitTest and instrumentedTest
|
||||
(as proposed in the new Multiplatform/Android SourceSetLayout v2)
|
||||
*/
|
||||
val mainCompilation = androidTarget.createAndroidCompilation("main")
|
||||
val unitTestCompilation = androidTarget.createAndroidCompilation("unitTest")
|
||||
val instrumentedTestCompilation = androidTarget.createAndroidCompilation("instrumentedTest")
|
||||
|
||||
/*
|
||||
Associate unitTest/instrumentedTest compilations with main
|
||||
*/
|
||||
unitTestCompilation.associateWith(mainCompilation)
|
||||
instrumentedTestCompilation.associateWith(mainCompilation)
|
||||
|
||||
/*
|
||||
Setup dependsOn edges as in Multiplatform/Android SourceSetLayout v2:
|
||||
android/main dependsOn commonMain
|
||||
android/unitTest dependsOn commonTest
|
||||
android/instrumentedTest *does not depend on a common SourceSet*
|
||||
*/
|
||||
mainCompilation.defaultSourceSet.dependsOn(sourceSets.getByName("commonMain"))
|
||||
unitTestCompilation.defaultSourceSet.dependsOn(sourceSets.getByName("commonTest"))
|
||||
|
||||
/*
|
||||
Wire the Kotlin Compilations output (.class files) into the Android artifacts
|
||||
by using the 'registerPreJavacGeneratedBytecode' function
|
||||
*/
|
||||
applicationVariant.registerPreJavacGeneratedBytecode(mainCompilation.output.classesDirs)
|
||||
applicationVariant.unitTestVariant.registerPreJavacGeneratedBytecode(unitTestCompilation.output.classesDirs)
|
||||
applicationVariant.testVariant.registerPreJavacGeneratedBytecode(instrumentedTestCompilation.output.classesDirs)
|
||||
|
||||
|
||||
/*
|
||||
Add dependencies coming from Kotlin to Android by adding all dependencies from Kotlin to the variants
|
||||
compileConfiguration or runtimeConfiguration
|
||||
*/
|
||||
applicationVariant.compileConfiguration.extendsFrom(mainCompilation.configurations.compileDependencyConfiguration)
|
||||
applicationVariant.runtimeConfiguration.extendsFrom(mainCompilation.configurations.runtimeDependencyConfiguration)
|
||||
applicationVariant.unitTestVariant.compileConfiguration.extendsFrom(unitTestCompilation.configurations.compileDependencyConfiguration)
|
||||
applicationVariant.unitTestVariant.runtimeConfiguration.extendsFrom(unitTestCompilation.configurations.runtimeDependencyConfiguration)
|
||||
applicationVariant.testVariant.compileConfiguration.extendsFrom(instrumentedTestCompilation.configurations.compileDependencyConfiguration)
|
||||
applicationVariant.testVariant.runtimeConfiguration.extendsFrom(instrumentedTestCompilation.configurations.runtimeDependencyConfiguration)
|
||||
|
||||
|
||||
/*
|
||||
Add the 'android boot classpath' to the compilation dependencies to compile against
|
||||
*/
|
||||
mainCompilation.configurations.compileDependencyConfiguration.dependencies.add(
|
||||
project.dependencies.create(project.androidBootClasspath())
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
Setup apiElements configuration:
|
||||
Usage: JAVA_API
|
||||
jvmEnvironment: Android
|
||||
variants:
|
||||
- classes (provides access to the compiled .class files)
|
||||
artifactType: CLASSES_JAR
|
||||
*/
|
||||
project.configurations.getByName(androidTarget.apiElementsConfigurationName).apply {
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_API))
|
||||
attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
|
||||
outgoing.variants.create("classes").let { variant ->
|
||||
variant.attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
|
||||
variant.artifact(mainCompilation.output.classesDirs.singleFile) {
|
||||
it.builtBy(mainCompilation.output.classesDirs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Setup runtimeElements configuration:
|
||||
Usage: JAVA_RUNTIME
|
||||
jvmEnvironment: Android
|
||||
variants:
|
||||
- classes (provides access to the compiled .class files)
|
||||
artifactType: CLASSES_JAR
|
||||
*/
|
||||
project.configurations.getByName(androidTarget.runtimeElementsConfigurationName).apply {
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage.JAVA_RUNTIME))
|
||||
attributes.attribute(TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
|
||||
outgoing.variants.create("classes").let { variant ->
|
||||
variant.attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
|
||||
variant.artifact(mainCompilation.output.classesDirs.singleFile) {
|
||||
it.builtBy(mainCompilation.output.classesDirs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
"Disable" configurations from plain Android plugin
|
||||
This hack will not be necessary in the final implementation
|
||||
*/
|
||||
project.configurations.findByName("${applicationVariant.name}ApiElements")?.isCanBeConsumed = false
|
||||
project.configurations.findByName("${applicationVariant.name}RuntimeElements")?.isCanBeConsumed = false
|
||||
}
|
||||
|
||||
return androidTarget
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
||||
|
||||
package org.jetbrains.kotlin.gradle.android
|
||||
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
import org.jetbrains.kotlin.gradle.plugin.HasCompilerOptions
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilation
|
||||
|
||||
class PrototypeAndroidCompilation(delegate: Delegate) : ExternalKotlinCompilation(delegate) {
|
||||
override val kotlinOptions: KotlinCommonOptions
|
||||
get() = super.kotlinOptions as KotlinJvmOptions
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val compilerOptions: HasCompilerOptions<KotlinJvmCompilerOptions>
|
||||
get() = super.compilerOptions as HasCompilerOptions<KotlinJvmCompilerOptions>
|
||||
|
||||
var androidCompilationSpecificStuff = 10
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.gradle.android
|
||||
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.DecoratedExternalKotlinTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinTarget
|
||||
|
||||
data class PrototypeAndroidDsl(
|
||||
var compileSdk: Int
|
||||
)
|
||||
|
||||
class PrototypeAndroidTarget(
|
||||
private val target: ExternalKotlinTarget,
|
||||
val androidDsl: PrototypeAndroidDsl
|
||||
) : DecoratedExternalKotlinTarget(target) {
|
||||
internal val kotlin = target.project.extensions.getByType<KotlinMultiplatformExtension>()
|
||||
|
||||
@Suppress("unchecked_cast")
|
||||
override val compilations: NamedDomainObjectContainer<PrototypeAndroidCompilation>
|
||||
get() = target.compilations as NamedDomainObjectContainer<PrototypeAndroidCompilation>
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.gradle.android
|
||||
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
internal fun Project.androidBootClasspath(): FileCollection {
|
||||
return project.files(Callable { project.extensions.getByType<BaseExtension>().bootClasspath })
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.gradle.android
|
||||
|
||||
import com.android.build.gradle.internal.publishing.AndroidArtifacts
|
||||
import org.gradle.api.attributes.java.TargetJvmEnvironment
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilationDescriptor
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.ExternalKotlinCompilationDescriptor.DecoratedKotlinCompilationFactory
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.external.createCompilation
|
||||
|
||||
internal fun PrototypeAndroidTarget.createAndroidCompilation(name: String): PrototypeAndroidCompilation {
|
||||
return createCompilation {
|
||||
compilationName = name
|
||||
defaultSourceSet = kotlin.sourceSets.maybeCreate(camelCase("prototype", targetName, name))
|
||||
decoratedKotlinCompilationFactory = DecoratedKotlinCompilationFactory(::PrototypeAndroidCompilation)
|
||||
compileTaskName = camelCase("prototype", "compile", targetName, name)
|
||||
|
||||
/*
|
||||
Replace Kotlin's compilation association (main <-> test) with noop,
|
||||
since Android goes through adding a dependency on the project itself
|
||||
*/
|
||||
compilationAssociator = ExternalKotlinCompilationDescriptor.CompilationAssociator { first, second ->
|
||||
first.configurations.compileDependencyConfiguration.extendsFrom(
|
||||
second.configurations.apiConfiguration,
|
||||
second.configurations.implementationConfiguration,
|
||||
second.configurations.compileOnlyConfiguration
|
||||
)
|
||||
}
|
||||
|
||||
/* Configure the compilation before it is accessible for user code */
|
||||
configure { compilation ->
|
||||
/* Setup attributes for the compile dependencies */
|
||||
compilation.configurations.compileDependencyConfiguration.apply {
|
||||
attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
|
||||
attributes.attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
|
||||
}
|
||||
|
||||
/* Setup attributes for the runtime dependencies */
|
||||
compilation.configurations.runtimeDependencyConfiguration?.apply {
|
||||
attributes.attribute(AndroidArtifacts.ARTIFACT_TYPE, AndroidArtifacts.ArtifactType.CLASSES_JAR.type)
|
||||
attributes.attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.objects.named(TargetJvmEnvironment.ANDROID))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.jetbrains.kotlin.gradle.android
|
||||
|
||||
fun camelCase(vararg parts: String): String {
|
||||
if (parts.isEmpty()) return ""
|
||||
return parts.joinToString("") { it.capitalize() }.decapitalize()
|
||||
}
|
||||
Reference in New Issue
Block a user