diff --git a/build.gradle.kts b/build.gradle.kts index af9d2d5..6774a2f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,8 +17,7 @@ import com.ncorti.ktfmt.gradle.KtfmtExtension import com.vanniktech.maven.publish.AndroidSingleVariantLibrary import com.vanniktech.maven.publish.MavenPublishBaseExtension import kotlinx.validation.ApiValidationExtension -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidExtension println("Building with Kotlin compiler version ${libs.versions.kotlin.get()}") @@ -106,14 +105,17 @@ subprojects { } } - tasks.withType { - compilerOptions { - // Allow warnings when running from IDE, makes it easier to experiment. - if (!isRunningFromIde) { - allWarningsAsErrors.set(true) + // AGP's built-in Kotlin registers the `kotlin` extension for every Android module. + // jvmTarget is not set here: with built-in Kotlin it defaults to each module's + // android.compileOptions.targetCompatibility. + plugins.withId("com.android.base") { + configure { + compilerOptions { + // Allow warnings when running from IDE, makes it easier to experiment. + if (!isRunningFromIde) { + allWarningsAsErrors.set(true) + } } - - jvmTarget.set(JvmTarget.JVM_1_8) } } } diff --git a/compose-tests/build.gradle.kts b/compose-tests/build.gradle.kts index 7c7e8eb..4c68ce0 100644 --- a/compose-tests/build.gradle.kts +++ b/compose-tests/build.gradle.kts @@ -1,9 +1,5 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { id("com.android.library") - kotlin("android") id("org.jetbrains.kotlin.plugin.compose") } @@ -32,12 +28,7 @@ android { testNamespace = "com.squareup.radiography.test.compose" } -tasks.withType { - compilerOptions { - jvmTarget.set(JvmTarget.JVM_11) - freeCompilerArgs.addAll("-opt-in=kotlin.RequiresOptIn") - } -} +kotlin { compilerOptions { freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn") } } dependencies { androidTestImplementation(project(":radiography")) diff --git a/compose-unsupported-tests/build.gradle.kts b/compose-unsupported-tests/build.gradle.kts index 3dd9d13..999d98e 100644 --- a/compose-unsupported-tests/build.gradle.kts +++ b/compose-unsupported-tests/build.gradle.kts @@ -1,9 +1,5 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { id("com.android.library") - kotlin("android") id("org.jetbrains.kotlin.plugin.compose") } @@ -32,12 +28,7 @@ android { testNamespace = "com.squareup.radiography.test.compose.unsupported" } -tasks.withType { - compilerOptions { - jvmTarget.set(JvmTarget.JVM_11) - freeCompilerArgs.addAll("-opt-in=kotlin.RequiresOptIn") - } -} +kotlin { compilerOptions { freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn") } } dependencies { androidTestImplementation(project(":radiography")) diff --git a/gradle.properties b/gradle.properties index 9adac4f..48b109b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,7 +35,3 @@ POM_LICENCE_DIST=repo POM_DEVELOPER_ID=square POM_DEVELOPER_NAME=Square, Inc. - -# AGP 9 enables built-in Kotlin by default; keep using the standalone Kotlin Gradle plugin for now. -android.builtInKotlin=false -android.newDsl=false diff --git a/radiography/build.gradle.kts b/radiography/build.gradle.kts index 59c6269..06984c8 100644 --- a/radiography/build.gradle.kts +++ b/radiography/build.gradle.kts @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import kotlinx.validation.KotlinApiBuildTask +import kotlinx.validation.KotlinApiCompareTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("com.android.library") - kotlin("android") id("com.vanniktech.maven.publish.base") } @@ -44,25 +45,64 @@ android { testNamespace = "com.squareup.radiography.test" } -tasks.withType { - compilerOptions { - freeCompilerArgs.addAll( - listOfNotNull( - "-opt-in=kotlin.RequiresOptIn", - - // Require explicit public modifiers and types. - // TODO this should be moved to a top-level `kotlin { explicitApi() }` once that's working - // for android projects, see https://youtrack.jetbrains.com/issue/KT-37652. - "-Xexplicit-api=strict" - .takeUnless { - // Tests aren't part of the public API, don't turn explicit API mode on for them. - name.contains("test", ignoreCase = true) - }, - ) +kotlin { + // Require explicit public modifiers and types. AGP's built-in Kotlin only applies this to + // production sources; tests aren't part of the public API. + explicitApi() + + compilerOptions { freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn") } +} + +// The binary-compatibility-validator plugin (applied in the root build script) only configures +// Android modules when the standalone org.jetbrains.kotlin.android plugin is applied, which AGP's +// built-in Kotlin support replaces. Until BCV (or KGP's own abiValidation) supports built-in +// Kotlin, reproduce BCV's kotlin-android wiring here using its public task types: apiBuild dumps +// the public API of the release compilation, apiCheck compares it with api/radiography.api, and +// apiDump updates that file. +val apiDir = layout.projectDirectory.dir("api") +val apiFileName = "${project.name}.api" + +// BCV only adds kotlin-metadata-jvm to its worker classpath when it sees a Kotlin plugin id. +dependencies.add( + "bcv-rt-jvm-cp", + "org.jetbrains.kotlin:kotlin-metadata-jvm:${libs.versions.kotlin.get()}", +) + +val apiBuild = + tasks.register("apiBuild") { + description = "Builds Kotlin API for the release compilation of ${project.name}." + // AGP's compilations don't populate output.classesDirs, so read the compile tasks' outputs. + inputClassesDirs.from( + tasks.named("compileReleaseKotlin").flatMap { it.destinationDirectory }, + tasks.named("compileReleaseJavaWithJavac").flatMap { it.destinationDirectory }, ) + inputDependencies.from( + kotlin.target.compilations.named("release").map { it.compileDependencyFiles } + ) + outputApiFile.set(layout.buildDirectory.file("api/$apiFileName")) + runtimeClasspath.from(configurations.named("bcv-rt-jvm-cp-resolver")) + } + +val apiCheck = + tasks.register("apiCheck") { + group = "verification" + description = + "Checks signatures of public API against the golden value in API folder for ${project.name}" + projectApiFile.set(apiDir.file(apiFileName)) + generatedApiFile.set(apiBuild.flatMap { it.outputApiFile }) } + +tasks.register("apiDump") { + description = "Syncs the API file for ${project.name}" + val from = apiBuild.flatMap { it.outputApiFile } + val to = apiDir.file(apiFileName) + inputs.file(from) + outputs.file(to) + doLast { from.get().asFile.copyTo(to.asFile, overwrite = true) } } +tasks.named("check") { dependsOn(apiCheck) } + dependencies { implementation(libs.curtains) // We don't want to bring any Compose dependencies in unless the consumer of this library is diff --git a/sample-compose/build.gradle.kts b/sample-compose/build.gradle.kts index a0b4776..8e1eb94 100644 --- a/sample-compose/build.gradle.kts +++ b/sample-compose/build.gradle.kts @@ -1,9 +1,5 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { id("com.android.application") - kotlin("android") id("org.jetbrains.kotlin.plugin.compose") } @@ -29,12 +25,7 @@ android { testNamespace = "com.squareup.radiography.sample.compose.test" } -tasks.withType { - compilerOptions { - jvmTarget.set(JvmTarget.JVM_1_8) - freeCompilerArgs.addAll("-opt-in=kotlin.RequiresOptIn") - } -} +kotlin { compilerOptions { freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn") } } dependencies { implementation(project(":radiography")) diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index b989b4e..3a9677e 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -14,10 +14,7 @@ * limitations under the License. */ -plugins { - id("com.android.application") - kotlin("android") -} +plugins { id("com.android.application") } android { compileSdk = 35 diff --git a/stoic-plugin/build.gradle.kts b/stoic-plugin/build.gradle.kts index 6a1e884..52dd427 100644 --- a/stoic-plugin/build.gradle.kts +++ b/stoic-plugin/build.gradle.kts @@ -13,10 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -plugins { - id("com.android.application") - kotlin("android") -} +plugins { id("com.android.application") } android { namespace = "radiography.stoic" @@ -38,7 +35,6 @@ android { dependencies { compileOnly("com.squareup.stoic:plugin-sdk:0.7.0") - implementation(kotlin("stdlib")) implementation(project(":radiography")) }