Splitting buildSrc into multiple projects
:buildSrc:plugins contains the plugins applied by projects
:buildSrc:private contains implementation
This allows the contents of plugins/ to not be added to the classpath that Gradle uses for evaluating projects, which means that changes to those classes don't necessarily invalidate the UP-TO-DATE status of other tasks applied by other plugins in those projects (most notably compileKotlin)
Bug: 140265324
Test: ./gradlew projects
Test: cd paging && ./gradlew checkApi
Test: Treehugger runs busytown/androidx.sh
Test: # demonstrate that unrelated changes in buildSrc no longer invalidate compileKotlin tasks unnecessarily
# build kotlin
./gradlew :core:core:compileDebugKotlin
# make some unrelated changes in buildSrc:
sed -i 's/ignoreCase = true/ignoreCase = false/g' buildSrc/private/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
# build kotlin again
./gradlew :core:core:compileDebugKotlin
# see that the tasks were up-to-date
Test: # demonstrate that making a relevant change in buildSrc does invalidate kotlinCompile tasks
1: # change jvmTarget
sed -i 's/jvmTarget = "1.8"/jvmTarget = "9"/' buildSrc/impl/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
2: # run another build
./gradlew :core:core:compileDebugKotlin
3: # see that this task was out-of-date
Change-Id: I8fb321ca59f9eb0518f730748489a34f376de605
diff --git a/buildSrc-tests/build.gradle b/buildSrc-tests/build.gradle
index 75dad66..17d4740 100644
--- a/buildSrc-tests/build.gradle
+++ b/buildSrc-tests/build.gradle
@@ -27,7 +27,7 @@
dependencies {
implementation(gradleApi())
testImplementation(libs.junit)
- implementation(project.files(new File(BuildServerConfigurationKt.getRootOutDirectory(project), "buildSrc/build/libs/buildSrc.jar")))
+ implementation(project.files(new File(BuildServerConfigurationKt.getRootOutDirectory(project), "buildSrc/private/build/libs/private.jar")))
}
// Also do style checking of the buildSrc project from within this project too
@@ -51,4 +51,4 @@
// Broken in AGP 7.0-alpha15 due to b/180408027
tasks["lint"].configure { t ->
t.enabled = false
-}
\ No newline at end of file
+}
diff --git a/buildSrc/apply/applyAndroidXComposeImplPlugin.gradle b/buildSrc/apply/applyAndroidXComposeImplPlugin.gradle
index d6119a6..b3cdbe7 100644
--- a/buildSrc/apply/applyAndroidXComposeImplPlugin.gradle
+++ b/buildSrc/apply/applyAndroidXComposeImplPlugin.gradle
@@ -2,7 +2,7 @@
buildscript {
dependencies {
- classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/build/buildSrc.jar"))
+ classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/private/build/libs/private.jar"))
}
}
diff --git a/buildSrc/apply/applyAndroidXDocsImplPlugin.gradle b/buildSrc/apply/applyAndroidXDocsImplPlugin.gradle
index b429e58..2800850 100644
--- a/buildSrc/apply/applyAndroidXDocsImplPlugin.gradle
+++ b/buildSrc/apply/applyAndroidXDocsImplPlugin.gradle
@@ -2,7 +2,7 @@
buildscript {
dependencies {
- classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/build/buildSrc.jar"))
+ classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/private/build/libs/private.jar"))
}
}
diff --git a/buildSrc/apply/applyAndroidXImplPlugin.gradle b/buildSrc/apply/applyAndroidXImplPlugin.gradle
index 6dabde0..e4441dc 100644
--- a/buildSrc/apply/applyAndroidXImplPlugin.gradle
+++ b/buildSrc/apply/applyAndroidXImplPlugin.gradle
@@ -2,7 +2,7 @@
buildscript {
dependencies {
- classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/build/buildSrc.jar"))
+ classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/private/build/libs/private.jar"))
}
}
diff --git a/buildSrc/apply/applyAndroidXPlaygroundRootImplPlugin.gradle b/buildSrc/apply/applyAndroidXPlaygroundRootImplPlugin.gradle
index c3e7988..eb6b13a 100644
--- a/buildSrc/apply/applyAndroidXPlaygroundRootImplPlugin.gradle
+++ b/buildSrc/apply/applyAndroidXPlaygroundRootImplPlugin.gradle
@@ -2,7 +2,7 @@
buildscript {
dependencies {
- classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/build/buildSrc.jar"))
+ classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/private/build/libs/private.jar"))
}
}
diff --git a/buildSrc/apply/applyAndroidXRootImplPlugin.gradle b/buildSrc/apply/applyAndroidXRootImplPlugin.gradle
index fbb73e3..eb77a06 100644
--- a/buildSrc/apply/applyAndroidXRootImplPlugin.gradle
+++ b/buildSrc/apply/applyAndroidXRootImplPlugin.gradle
@@ -2,7 +2,7 @@
buildscript {
dependencies {
- classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/build/buildSrc.jar"))
+ classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/private/build/libs/private.jar"))
}
}
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 707fd6e..4af4322 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -24,7 +24,6 @@
ext.supportRootFolder = project.projectDir.getParentFile()
apply from: "repos.gradle"
apply plugin: "kotlin"
-apply from: "kotlin-dsl-dependency.gradle"
allprojects {
repos.addMavenRepositories(repositories)
@@ -46,157 +45,6 @@
}
}
-configurations {
- // Dependencies added to these configurations get copied into the corresponding configuration
- // (cacheableApi gets copied into api, etc).
- // Because we cache the resolutions of these configurations, performance is faster when
- // artifacts are put into these configurations than when those artifacts are put into their
- // corresponding configuration.
- cacheableApi
- cacheableImplementation {
- extendsFrom(project.configurations.cacheableApi)
- }
- cacheableRuntimeOnly
-}
-
dependencies {
- cacheableApi(libs.androidGradlePluginz)
- cacheableImplementation(libs.dexMemberList)
- cacheableApi(libs.kotlinGradlePluginz)
- cacheableImplementation(gradleApi())
- cacheableApi(libs.dokkaGradlePluginz)
- // needed by inspection plugin
- cacheableImplementation(libs.protobufGradlePluginz)
- cacheableImplementation(libs.wireGradlePluginz)
- cacheableImplementation(libs.shadow)
- // dependencies that aren't used by buildSrc directly but that we resolve here so that the
- // root project doesn't need to re-resolve them and their dependencies on every build
- cacheableRuntimeOnly(libs.hiltAndroidGradlePluginz)
- // room kotlintestapp uses the ksp plugin but it does not publish a plugin marker yet
- cacheableApi(libs.kspGradlePluginz)
- cacheableApi(libs.japicmpPluginz)
- // dependencies whose resolutions we don't need to cache
- compileOnly(findGradleKotlinDsl()) // Only one file in this configuration, no need to cache it
- implementation(project("jetpad-integration")) // Doesn't have a .pom, so not slow to load
-}
-
-// Exclude dokka coming from AGP. We don't need it and it conflicts with dackka: b/195305339
-configurations.configureEach { conf ->
- conf.exclude(group:"org.jetbrains.dokka", module:"dokka-core")
-}
-
-apply plugin: "java-gradle-plugin"
-
-sourceSets {
- ["public", "private", "plugins"].each { subdir ->
- main.java.srcDirs += "${subdir}/src/main/kotlin"
- main.resources.srcDirs += "${subdir}/src/main/resources"
- }
-
-
- main.java.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/kotlin"
- main.resources.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/resources"
-
- main.java.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main/kotlin"
- main.resources.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main" +
- "/resources"
-
- main.java.srcDirs += "${supportRootFolder}/compose/material/material/icons/generator/src/main" +
- "/kotlin"
-}
-
-gradlePlugin {
- plugins {
- benchmark {
- id = "androidx.benchmark"
- implementationClass = "androidx.benchmark.gradle.BenchmarkPlugin"
- }
- inspection {
- id = "androidx.inspection"
- implementationClass = "androidx.inspection.gradle.InspectionPlugin"
- }
- }
-}
-
-// Saves configuration into destFile
-// Each line of destFile will be the absolute filepath of one of the files in configuration
-def saveConfigurationResolution(configuration, destFile) {
- def resolvedConfiguration = configuration.resolvedConfiguration
- def files = resolvedConfiguration.files
- def paths = files.collect { f -> f.toString() }
- def serialized = paths.join("\n")
- destFile.text = serialized
-}
-
-// Parses a file into a list of Dependency objects representing a ResolvedConfiguration
-def parseConfigurationResolution(savedFile, throwOnError) {
- def savedText = savedFile.text
- def filenames = savedText.split("\n")
- def valid = true
- def dependencies = filenames.collect { filename ->
- if (!project.file(filename).exists()) {
- if (throwOnError) {
- throw new GradleException("\nFile " + filename + " listed as a resolved dependency in " + savedFile + " does not exist!\n\nFor more information, see b/187075069")
- } else {
- valid = false
- }
- }
- project.dependencies.create(project.files(filename))
- }
- if (!valid) {
- return null
- }
- return dependencies
-}
-
-// Resolves a Configuration into a list of Dependency objects
-def resolveConfiguration(configuration) {
- def resolvedName = configuration.name
- def cacheDir = new File(project.buildDir, "/" + resolvedName)
- def inputsFile = new File(cacheDir, "/deps")
- def outputsFile = new File(cacheDir, "/result")
-
- def inputText = fingerprintConfiguration(configuration)
- def parsed = null
- if (inputsFile.exists() && inputsFile.text == inputText) {
- // Try to parse the previously resolved configuration, but don't give up if it mentions a
- // nonexistent file. If something has since deleted one of the referenced files, we will
- // try to reresolve that file later
- parsed = parseConfigurationResolution(outputsFile, false)
- }
- // If the configuration has changed or if any of its files have been deleted, reresolve it
- if (parsed == null) {
- cacheDir.mkdirs()
- saveConfigurationResolution(configuration, outputsFile)
- inputsFile.text = inputText
- // confirm that the resolved configuration parses successfully
- parsed = parseConfigurationResolution(outputsFile, true)
- }
- return parsed
-}
-
-// Computes a unique string from a Configuration based on its dependencies
-// This is used for up-to-date checks
-def fingerprintConfiguration(configuration) {
- def dependencies = configuration.allDependencies
- def dependencyTexts = dependencies.collect { dep -> dep.group + ":" + dep.name + ":" + dep.version }
- return dependencyTexts.join("\n")
-}
-
-// Imports the contents of fromConf into toConf
-// Uses caching to often short-circuit the resolution of fromConf
-def loadConfigurationQuicklyInto(fromConf, toConf) {
- def resolved = resolveConfiguration(fromConf)
- resolved.each { dep ->
- project.dependencies.add(toConf.name, dep)
- }
-}
-
-loadConfigurationQuicklyInto(configurations.cacheableApi, configurations.api)
-loadConfigurationQuicklyInto(configurations.cacheableImplementation, configurations.implementation)
-loadConfigurationQuicklyInto(configurations.cacheableRuntimeOnly, configurations.runtimeOnly)
-
-project.tasks.withType(Jar) { task ->
- task.reproducibleFileOrder = true
- task.preserveFileTimestamps = false
+ api(project("plugins"))
}
diff --git a/buildSrc/plugins/build.gradle b/buildSrc/plugins/build.gradle
new file mode 100644
index 0000000..6779c30
--- /dev/null
+++ b/buildSrc/plugins/build.gradle
@@ -0,0 +1 @@
+apply from: "../shared.gradle"
diff --git a/buildSrc/private/build.gradle b/buildSrc/private/build.gradle
new file mode 100644
index 0000000..6779c30
--- /dev/null
+++ b/buildSrc/private/build.gradle
@@ -0,0 +1 @@
+apply from: "../shared.gradle"
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
index 44c3b9f..eba54c5 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt
@@ -16,13 +16,13 @@
package androidx.build
+import androidx.build.Multiplatform.Companion.isMultiplatformEnabled
import androidx.build.checkapi.shouldConfigureApiTasks
import groovy.lang.Closure
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.provider.Property
import java.util.ArrayList
-
/**
* Extension for [AndroidXImplPlugin] that's responsible for holding configuration options.
*/
@@ -159,7 +159,13 @@
var benchmarkRunAlsoInterpreted = false
- var multiplatform = false
+ var multiplatform: Boolean
+ set(value) {
+ Multiplatform.setEnabledForProject(project, value)
+ }
+ get() {
+ return project.isMultiplatformEnabled()
+ }
fun shouldEnforceKotlinStrictApiMode(): Boolean {
return !legacyDisableKotlinStrictApiMode &&
diff --git a/buildSrc/public/README.md b/buildSrc/public/README.md
index 17062a3..a3e8122 100644
--- a/buildSrc/public/README.md
+++ b/buildSrc/public/README.md
@@ -1,3 +1,5 @@
-This is the :buildSrc:public project
+This directory contains code that other projects in this repository expect to be able to import and reference from their build.gradle files
-It contains code that other projects in this repository expect to be able to import and reference from their build.gradle files
+The files in this directory are used by the buildSrc:plugins and buildSrc:private projects.
+
+The files in this directory are essentially a project and can be turned into a real Gradle project if needed; at the moment, they are simply included in the corresponding builds because that runs more quickly.
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt b/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt
index c422169..b3f1195 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/Multiplatform.kt
@@ -17,8 +17,8 @@
package androidx.build
import androidx.build.COMPOSE_MPP_ENABLED
-import androidx.build.AndroidXExtension
import org.gradle.api.Project
+import org.gradle.kotlin.dsl.extra
/**
* Setting this property enables multiplatform builds of Compose
@@ -27,14 +27,12 @@
class Multiplatform {
companion object {
- @JvmStatic
fun Project.isMultiplatformEnabled(): Boolean {
- return properties.get(COMPOSE_MPP_ENABLED)?.toString()?.toBoolean()
- ?: androidxExtension()?.multiplatform ?: false
+ return properties.get(COMPOSE_MPP_ENABLED)?.toString()?.toBoolean() ?: false
}
- private fun Project.androidxExtension(): AndroidXExtension? {
- return extensions.findByType(AndroidXExtension::class.java)
+ fun setEnabledForProject(project: Project, enabled: Boolean) {
+ project.extra.set(COMPOSE_MPP_ENABLED, enabled)
}
}
}
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
index 00d00a3..155a1d9 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt
@@ -54,7 +54,7 @@
* Returns the root project's platform-specific SDK path as a file.
*/
fun Project.getSdkPath(): File {
- if (rootProject.plugins.hasPlugin(AndroidXPlaygroundRootPlugin::class.java) ||
+ if (rootProject.plugins.hasPlugin("androix.build.AndroidXPlaygroundRootImplPlugin") ||
System.getenv("COMPOSE_DESKTOP_GITHUB_BUILD") != null
) {
// This is not full checkout, use local settings instead.
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/SingleFileCopy.kt b/buildSrc/public/src/main/kotlin/androidx/build/SingleFileCopy.kt
similarity index 100%
rename from buildSrc/private/src/main/kotlin/androidx/build/SingleFileCopy.kt
rename to buildSrc/public/src/main/kotlin/androidx/build/SingleFileCopy.kt
diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle
index 28bcb0f..3d32906 100644
--- a/buildSrc/settings.gradle
+++ b/buildSrc/settings.gradle
@@ -15,6 +15,8 @@
*/
include ":jetpad-integration"
+include ":plugins"
+include ":private"
enableFeaturePreview("VERSION_CATALOGS")
diff --git a/buildSrc/shared.gradle b/buildSrc/shared.gradle
new file mode 100644
index 0000000..a82ce62
--- /dev/null
+++ b/buildSrc/shared.gradle
@@ -0,0 +1,166 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+apply plugin: "kotlin"
+apply from: "../kotlin-dsl-dependency.gradle"
+
+buildscript {
+ project.ext.supportRootFolder = project.projectDir.getParentFile().getParentFile()
+ apply from: "../repos.gradle"
+ repos.addMavenRepositories(repositories)
+ dependencies {
+ classpath(libs.kotlinGradlePluginz)
+ }
+}
+
+configurations {
+ // Dependencies added to these configurations get copied into the corresponding configuration
+ // (cacheableApi gets copied into api, etc).
+ // Because we cache the resolutions of these configurations, performance is faster when
+ // artifacts are put into these configurations than when those artifacts are put into their
+ // corresponding configuration.
+ cacheableApi
+ cacheableImplementation {
+ extendsFrom(project.configurations.cacheableApi)
+ }
+ cacheableRuntimeOnly
+}
+
+dependencies {
+ cacheableApi(libs.androidGradlePluginz)
+ cacheableImplementation(libs.dexMemberList)
+ cacheableApi(libs.kotlinGradlePluginz)
+ cacheableImplementation(gradleApi())
+ cacheableApi(libs.dokkaGradlePluginz)
+ // needed by inspection plugin
+ cacheableImplementation(libs.protobufGradlePluginz)
+ cacheableImplementation(libs.wireGradlePluginz)
+ cacheableImplementation(libs.shadow)
+ // dependencies that aren't used by buildSrc directly but that we resolve here so that the
+ // root project doesn't need to re-resolve them and their dependencies on every build
+ cacheableRuntimeOnly(libs.hiltAndroidGradlePluginz)
+ // room kotlintestapp uses the ksp plugin but it does not publish a plugin marker yet
+ cacheableApi(libs.kspGradlePluginz)
+ cacheableApi(libs.japicmpPluginz)
+ // dependencies whose resolutions we don't need to cache
+ compileOnly(findGradleKotlinDsl()) // Only one file in this configuration, no need to cache it
+ implementation(project(":jetpad-integration")) // Doesn't have a .pom, so not slow to load
+}
+
+// Exclude dokka coming from AGP. We don't need it and it conflicts with dackka: b/195305339
+configurations.configureEach { conf ->
+ conf.exclude(group:"org.jetbrains.dokka", module:"dokka-core")
+}
+
+apply plugin: "java-gradle-plugin"
+
+sourceSets {
+ main.java.srcDirs += "../public/src/main/kotlin"
+ main.resources.srcDirs += "../public/src/main/resources"
+
+
+ main.java.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/kotlin"
+ main.resources.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/resources"
+
+ main.java.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main/kotlin"
+ main.resources.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main" +
+ "/resources"
+
+ main.java.srcDirs += "${supportRootFolder}/compose/material/material/icons/generator/src/main" +
+ "/kotlin"
+}
+
+gradlePlugin {
+ plugins {
+ benchmark {
+ id = "androidx.benchmark"
+ implementationClass = "androidx.benchmark.gradle.BenchmarkPlugin"
+ }
+ inspection {
+ id = "androidx.inspection"
+ implementationClass = "androidx.inspection.gradle.InspectionPlugin"
+ }
+ }
+}
+
+// Saves configuration into destFile
+// Each line of destFile will be the absolute filepath of one of the files in configuration
+def saveConfigurationResolution(configuration, destFile) {
+ def resolvedConfiguration = configuration.resolvedConfiguration
+ def files = resolvedConfiguration.files
+ def paths = files.collect { f -> f.toString() }
+ def serialized = paths.join("\n")
+ destFile.text = serialized
+}
+
+// Parses a file into a list of Dependency objects representing a ResolvedConfiguration
+def parseConfigurationResolution(savedFile, throwOnError) {
+ def savedText = savedFile.text
+ def filenames = savedText.split("\n")
+ def valid = true
+ def dependencies = filenames.collect { filename ->
+ if (!project.file(filename).exists()) {
+ if (throwOnError) {
+ throw new GradleException("\nFile " + filename + " listed as a resolved dependency in " + savedFile + " does not exist!\n\nFor more information, see b/187075069")
+ } else {
+ valid = false
+ }
+ }
+ project.dependencies.create(project.files(filename))
+ }
+ if (!valid) {
+ return null
+ }
+ return dependencies
+}
+
+// Resolves a Configuration into a list of Dependency objects
+def resolveConfiguration(configuration) {
+ def resolvedName = configuration.name
+ def cacheDir = new File(project.buildDir, "/" + resolvedName)
+ def inputsFile = new File(cacheDir, "/deps")
+ def outputsFile = new File(cacheDir, "/result")
+
+ def inputText = fingerprintConfiguration(configuration)
+ def parsed = null
+ if (inputsFile.exists() && inputsFile.text == inputText) {
+ // Try to parse the previously resolved configuration, but don't give up if it mentions a
+ // nonexistent file. If something has since deleted one of the referenced files, we will
+ // try to reresolve that file later
+ parsed = parseConfigurationResolution(outputsFile, false)
+ }
+ // If the configuration has changed or if any of its files have been deleted, reresolve it
+ if (parsed == null) {
+ cacheDir.mkdirs()
+ saveConfigurationResolution(configuration, outputsFile)
+ inputsFile.text = inputText
+ // confirm that the resolved configuration parses successfully
+ parsed = parseConfigurationResolution(outputsFile, true)
+ }
+ return parsed
+}
+
+// Computes a unique string from a Configuration based on its dependencies
+// This is used for up-to-date checks
+def fingerprintConfiguration(configuration) {
+ def dependencies = configuration.allDependencies
+ def dependencyTexts = dependencies.collect { dep -> dep.group + ":" + dep.name + ":" + dep.version }
+ return dependencyTexts.join("\n")
+}
+
+// Imports the contents of fromConf into toConf
+// Uses caching to often short-circuit the resolution of fromConf
+def loadConfigurationQuicklyInto(fromConf, toConf) {
+ def resolved = resolveConfiguration(fromConf)
+ resolved.each { dep ->
+ project.dependencies.add(toConf.name, dep)
+ }
+}
+
+loadConfigurationQuicklyInto(configurations.cacheableApi, configurations.api)
+loadConfigurationQuicklyInto(configurations.cacheableImplementation, configurations.implementation)
+loadConfigurationQuicklyInto(configurations.cacheableRuntimeOnly, configurations.runtimeOnly)
+
+project.tasks.withType(Jar) { task ->
+ task.reproducibleFileOrder = true
+ task.preserveFileTimestamps = false
+}
diff --git a/car/app/app/build.gradle b/car/app/app/build.gradle
index c6f85d4..0379226 100644
--- a/car/app/app/build.gradle
+++ b/car/app/app/build.gradle
@@ -34,6 +34,15 @@
import static androidx.build.dependencies.DependenciesKt.*
+buildscript {
+ dependencies {
+ // This dependency means that tasks in this project might become out-of-date whenever
+ // certain classes in buildSrc change, and should generally be avoided.
+ // See b/140265324 for more information
+ classpath(project.files("${project.rootProject.ext["outDir"]}/buildSrc/private/build/libs/private.jar"))
+ }
+}
+
plugins {
id("AndroidXPlugin")
id("com.android.library")