blob: 2bd2638247b57840ad914f1eaf20ebdb79e9ce2f [file] [log] [blame]
// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import java.nio.file.Paths
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
`kotlin-dsl`
id("dependencies-plugin")
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies { }
val keepAnnoCompileTask = projectTask("keepanno", "compileJava")
val keepAnnoSourcesTask = projectTask("keepanno", "sourcesJar")
val mainDepsJarTask = projectTask("main", "depsJar")
val swissArmyKnifeTask = projectTask("main", "swissArmyKnife")
val r8WithRelocatedDepsTask = projectTask("main", "r8WithRelocatedDeps")
val mainSourcesTask = projectTask("main", "sourcesJar")
val resourceShrinkerSourcesTask = projectTask("resourceshrinker", "sourcesJar")
val javaTestBaseJarTask = projectTask("testbase", "testJar")
val javaTestBaseDepsJar = projectTask("testbase", "depsJar")
val java8TestJarTask = projectTask("tests_java_8", "testJar")
val bootstrapTestsDepsJarTask = projectTask("tests_bootstrap", "depsJar")
val testsJava8SourceSetDependenciesTask = projectTask("tests_java_8", "sourceSetDependencyTask")
tasks {
withType<Exec> {
doFirst {
println("Executing command: ${commandLine.joinToString(" ")}")
}
}
withType<KotlinCompile> {
kotlinOptions {
jvmTarget = "17"
}
}
"clean" {
dependsOn(gradle.includedBuild("tests_bootstrap").task(":clean"))
dependsOn(gradle.includedBuild("tests_java_8").task(":clean"))
dependsOn(gradle.includedBuild("tests_java_9").task(":clean"))
dependsOn(gradle.includedBuild("tests_java_10").task(":clean"))
dependsOn(gradle.includedBuild("tests_java_11").task(":clean"))
dependsOn(gradle.includedBuild("tests_java_17").task(":clean"))
dependsOn(gradle.includedBuild("tests_java_21").task(":clean"))
}
val packageTests by registering(Jar::class) {
dependsOn(java8TestJarTask)
from(java8TestJarTask.outputs.files.map(::zipTree))
exclude("META-INF/*.kotlin_module", "**/*.kotlin_metadata")
destinationDirectory.set(getRoot().resolveAll("build", "libs"))
archiveFileName.set("r8tests.jar")
}
val packageTestDeps by registering(Jar::class) {
dependsOn(bootstrapTestsDepsJarTask, javaTestBaseDepsJar)
from(bootstrapTestsDepsJarTask.outputs.getFiles().map(::zipTree))
from(javaTestBaseDepsJar.outputs.getFiles().map(::zipTree))
exclude("META-INF/*.kotlin_module", "**/*.kotlin_metadata")
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
destinationDirectory.set(getRoot().resolveAll("build", "libs"))
archiveFileName.set("test_deps_all.jar")
}
val packageTestBase by registering(Jar::class) {
dependsOn(javaTestBaseJarTask)
from(javaTestBaseJarTask.outputs.files.map(::zipTree))
exclude("META-INF/*.kotlin_module", "**/*.kotlin_metadata")
destinationDirectory.set(getRoot().resolveAll("build", "libs"))
archiveFileName.set("r8test_base.jar")
}
val packageTestBaseExcludeKeep by registering(Jar::class) {
dependsOn(packageTestBase)
from(zipTree(packageTestBase.getSingleOutputFile()))
// TODO(b/328353718): we have com.android.tools.r8.Keep in both test_base and main
exclude("com/android/tools/r8/Keep.class")
archiveFileName.set("r8test_base_no_keep.jar")
}
fun Exec.executeRelocator(jarProvider: TaskProvider<*>, artifactName: String) {
dependsOn(r8WithRelocatedDepsTask, jarProvider)
val outputJar = file(Paths.get("build", "libs", artifactName))
outputs.file(outputJar)
val r8WithRelocatedDepsJar = r8WithRelocatedDepsTask.getSingleOutputFile()
val testJar = jarProvider.getSingleOutputFile()
inputs.files(r8WithRelocatedDepsJar, testJar)
commandLine = baseCompilerCommandLine(
r8WithRelocatedDepsJar,
"relocator",
listOf("--input",
"$testJar",
"--output",
"$outputJar",
"--map",
"kotlinx.metadata.**->com.android.tools.r8.jetbrains.kotlinx.metadata"))
}
// When testing R8 lib with relocated deps we must relocate kotlinx.metadata in the tests, since
// types from kotlinx.metadata are used on the R8 main/R8 test boundary.
//
// This is not needed when testing R8 lib excluding deps since we simply include the deps on the
// classpath at runtime.
val relocateTestsForR8LibWithRelocatedDeps by registering(Exec::class) {
executeRelocator(packageTests, "r8tests-relocated.jar")
}
val relocateTestBaseForR8LibWithRelocatedDeps by registering(Exec::class) {
executeRelocator(packageTestBase, "r8testbase-relocated.jar")
}
fun Exec.generateKeepRulesForR8Lib(
targetJarProvider: Task, testJarProviders: List<TaskProvider<*>>, artifactName: String) {
dependsOn(
mainDepsJarTask,
packageTestDeps,
r8WithRelocatedDepsTask,
targetJarProvider)
testJarProviders.forEach(::dependsOn)
val mainDepsJar = mainDepsJarTask.getSingleOutputFile()
val rtJar = resolve(ThirdPartyDeps.java8Runtime, "rt.jar").getSingleFile()
val r8WithRelocatedDepsJar = r8WithRelocatedDepsTask.getSingleOutputFile()
val targetJar = targetJarProvider.getSingleOutputFile()
val testDepsJar = packageTestDeps.getSingleOutputFile()
inputs.files(mainDepsJar, rtJar, r8WithRelocatedDepsJar, targetJar, testDepsJar)
inputs.files(testJarProviders.map{it.getSingleOutputFile()})
val output = file(Paths.get("build", "libs", artifactName))
outputs.file(output)
val argList = mutableListOf("--keep-rules",
"--allowobfuscation",
"--lib",
"$rtJar",
"--lib",
"$mainDepsJar",
"--lib",
"$testDepsJar",
"--target",
"$targetJar",
"--output",
"$output")
testJarProviders.forEach{
argList.add("--source")
argList.add("${it.getSingleOutputFile()}")
}
commandLine = baseCompilerCommandLine(
r8WithRelocatedDepsJar,
"tracereferences",
argList
)
}
val generateKeepRulesForR8LibWithRelocatedDeps by registering(Exec::class) {
generateKeepRulesForR8Lib(
r8WithRelocatedDepsTask,
listOf(relocateTestsForR8LibWithRelocatedDeps, relocateTestBaseForR8LibWithRelocatedDeps),
"generated-keep-rules-r8lib.txt")
}
val generateKeepRulesForR8LibNoDeps by registering(Exec::class) {
generateKeepRulesForR8Lib(
swissArmyKnifeTask,
listOf(packageTests, packageTestBase),
"generated-keep-rules-r8lib-exclude-deps.txt")
}
fun Exec.assembleR8Lib(
inputJarProvider: Task,
generatedKeepRulesProvider: TaskProvider<Exec>,
classpath: List<File>,
artifactName: String) {
dependsOn(generatedKeepRulesProvider, inputJarProvider, r8WithRelocatedDepsTask)
val inputJar = inputJarProvider.getSingleOutputFile()
val r8WithRelocatedDepsJar = r8WithRelocatedDepsTask.getSingleOutputFile()
val keepRuleFiles = listOf(
getRoot().resolveAll("src", "main", "keep.txt"),
generatedKeepRulesProvider.getSingleOutputFile(),
// TODO(b/294351878): Remove once enum issue is fixed
getRoot().resolveAll("src", "main", "keep_r8resourceshrinker.txt"))
inputs.files(listOf(r8WithRelocatedDepsJar, inputJar).union(keepRuleFiles).union(classpath))
val outputJar = getRoot().resolveAll("build", "libs", artifactName)
outputs.file(outputJar)
commandLine = createR8LibCommandLine(
r8WithRelocatedDepsJar,
inputJar,
outputJar,
keepRuleFiles,
excludingDepsVariant = classpath.isNotEmpty(),
debugVariant = false,
classpath = classpath)
}
val assembleR8LibNoDeps by registering(Exec::class) {
dependsOn(mainDepsJarTask)
val mainDepsJar = mainDepsJarTask.getSingleOutputFile()
assembleR8Lib(
swissArmyKnifeTask,
generateKeepRulesForR8LibNoDeps,
listOf(mainDepsJar),
"r8lib-exclude-deps.jar")
}
val assembleR8LibWithRelocatedDeps by registering(Exec::class) {
assembleR8Lib(
r8WithRelocatedDepsTask,
generateKeepRulesForR8LibWithRelocatedDeps,
listOf(),
"r8lib.jar")
}
val resourceshrinkercli by registering(Exec::class) {
dependsOn(r8WithRelocatedDepsTask)
val r8 = r8WithRelocatedDepsTask.getSingleOutputFile()
val keepTxt = getRoot().resolveAll("src", "main", "resourceshrinker_cli.txt")
val cliKeep = getRoot().resolveAll("src", "main", "keep_r8resourceshrinker.txt")
inputs.files(keepTxt, cliKeep)
val output = file(Paths.get("build", "libs", "resourceshrinkercli.jar"))
outputs.file(output)
commandLine = createR8LibCommandLine(
r8,
r8,
output,
listOf(keepTxt, cliKeep),
false,
false)
}
fun Task.generateTestKeepRulesForR8Lib(
r8LibJarProvider: TaskProvider<Exec>, artifactName: String) {
dependsOn(r8LibJarProvider)
val r8LibJar = r8LibJarProvider.getSingleOutputFile()
inputs.files(r8LibJar)
val output = rootProject.buildDir.resolveAll("libs", artifactName)
outputs.files(output)
doLast {
// TODO(b/299065371): We should be able to take in the partition map output.
output.writeText(
"""-keep class ** { *; }
-dontshrink
-dontoptimize
-keepattributes *
-applymapping $r8LibJar.map
""")
}
}
val generateTestKeepRulesR8LibWithRelocatedDeps by registering {
generateTestKeepRulesForR8Lib(assembleR8LibWithRelocatedDeps, "r8lib-tests-keep.txt")
}
val generateTestKeepRulesR8LibNoDeps by registering {
generateTestKeepRulesForR8Lib(assembleR8LibNoDeps, "r8lib-exclude-deps-tests-keep.txt")
}
fun Exec.rewriteTestsForR8Lib(
keepRulesFileProvider: TaskProvider<Task>,
r8JarProvider: Task,
testJarProvider: TaskProvider<*>,
artifactName: String,
addTestBaseClasspath: Boolean) {
dependsOn(
keepRulesFileProvider,
packageTestDeps,
relocateTestsForR8LibWithRelocatedDeps,
r8JarProvider,
r8WithRelocatedDepsTask,
testJarProvider,
packageTestBaseExcludeKeep)
val keepRulesFile = keepRulesFileProvider.getSingleOutputFile()
val rtJar = resolve(ThirdPartyDeps.java8Runtime, "rt.jar").getSingleFile()
val r8Jar = r8JarProvider.getSingleOutputFile()
val r8WithRelocatedDepsJar = r8WithRelocatedDepsTask.getSingleOutputFile()
val testBaseJar = packageTestBaseExcludeKeep.getSingleOutputFile()
val testDepsJar = packageTestDeps.getSingleOutputFile()
val testJar = testJarProvider.getSingleOutputFile()
inputs.files(keepRulesFile, rtJar, r8Jar, r8WithRelocatedDepsJar, testDepsJar, testJar)
val outputJar = getRoot().resolveAll("build", "libs", artifactName)
outputs.file(outputJar)
val args = mutableListOf(
"--classfile",
"--debug",
"--lib",
"$rtJar",
"--classpath",
"$r8Jar",
"--classpath",
"$testDepsJar",
"--output",
"$outputJar",
"--pg-conf",
"$keepRulesFile",
"$testJar")
if (addTestBaseClasspath) {
args.add("--classpath")
args.add("$testBaseJar")
}
commandLine = baseCompilerCommandLine(
r8WithRelocatedDepsJar,
"r8",
args)
}
val rewriteTestsForR8LibWithRelocatedDeps by registering(Exec::class) {
rewriteTestsForR8Lib(
generateTestKeepRulesR8LibWithRelocatedDeps,
r8WithRelocatedDepsTask,
relocateTestsForR8LibWithRelocatedDeps,
"r8libtestdeps-cf.jar",
true)
}
val rewriteTestBaseForR8LibWithRelocatedDeps by registering(Exec::class) {
rewriteTestsForR8Lib(
generateTestKeepRulesR8LibWithRelocatedDeps,
r8WithRelocatedDepsTask,
relocateTestBaseForR8LibWithRelocatedDeps,
"r8libtestbase-cf.jar",
false)
}
val rewriteTestsForR8LibNoDeps by registering(Exec::class) {
rewriteTestsForR8Lib(
generateTestKeepRulesR8LibNoDeps,
swissArmyKnifeTask,
packageTests,
"r8lib-exclude-deps-testdeps-cf.jar",
true)
}
val cleanUnzipTests by registering(Delete::class) {
dependsOn(packageTests)
val outputDir = file("${buildDir}/unpacked/test")
setDelete(outputDir)
}
val unzipTests by registering(Copy::class) {
dependsOn(cleanUnzipTests, packageTests)
val outputDir = file("${buildDir}/unpacked/test")
from(zipTree(packageTests.getSingleOutputFile()))
into(outputDir)
}
val unzipTestBase by registering(Copy::class) {
dependsOn(cleanUnzipTests, packageTestBase)
val outputDir = file("${buildDir}/unpacked/testbase")
from(zipTree(packageTestBase.getSingleOutputFile()))
into(outputDir)
}
fun Copy.unzipRewrittenTestsForR8Lib(
rewrittenTestJarProvider: TaskProvider<Exec>, outDirName: String) {
dependsOn(rewrittenTestJarProvider)
val outputDir = file("$buildDir/unpacked/$outDirName")
val rewrittenTestJar = rewrittenTestJarProvider.getSingleOutputFile()
from(zipTree(rewrittenTestJar))
into(outputDir)
}
val cleanUnzipRewrittenTestsForR8LibWithRelocatedDeps by registering(Delete::class) {
val outputDir = file("${buildDir}/unpacked/rewrittentests-r8lib")
setDelete(outputDir)
}
val unzipRewrittenTestsForR8LibWithRelocatedDeps by registering(Copy::class) {
dependsOn(cleanUnzipRewrittenTestsForR8LibWithRelocatedDeps)
unzipRewrittenTestsForR8Lib(rewriteTestsForR8LibWithRelocatedDeps, "rewrittentests-r8lib")
}
val cleanUnzipRewrittenTestsForR8LibNoDeps by registering(Delete::class) {
val outputDir = file("${buildDir}/unpacked/rewrittentests-r8lib-exclude-deps")
setDelete(outputDir)
}
val unzipRewrittenTestsForR8LibNoDeps by registering(Copy::class) {
dependsOn(cleanUnzipRewrittenTestsForR8LibNoDeps)
unzipRewrittenTestsForR8Lib(
rewriteTestsForR8LibNoDeps, "rewrittentests-r8lib-exclude-deps")
}
fun Test.testR8Lib(r8Lib: TaskProvider<Exec>, unzipRewrittenTests: TaskProvider<Copy>) {
println("NOTE: Number of processors " + Runtime.getRuntime().availableProcessors())
println("NOTE: Max parallel forks " + maxParallelForks)
dependsOn(
packageTestDeps,
r8Lib,
r8WithRelocatedDepsTask,
testsJava8SourceSetDependenciesTask,
rewriteTestBaseForR8LibWithRelocatedDeps,
unzipRewrittenTests,
unzipTests,
unzipTestBase,
gradle.includedBuild("shared").task(":downloadDeps"))
if (!project.hasProperty("no_internal")) {
dependsOn(gradle.includedBuild("shared").task(":downloadDepsInternal"))
}
val r8LibJar = r8Lib.getSingleOutputFile()
val r8LibMappingFile = file(r8LibJar.toString() + ".map")
val r8WithRelocatedDepsJar = r8WithRelocatedDepsTask.getSingleOutputFile()
configure(isR8Lib = true, r8Jar = r8WithRelocatedDepsJar, r8LibMappingFile = r8LibMappingFile)
// R8lib should be used instead of the main output and all the tests in r8 should be mapped and
// exists in r8LibTestPath.
classpath = files(
packageTestDeps.get().getOutputs().getFiles(),
r8LibJar,
unzipRewrittenTests.get().getOutputs().getFiles(),
rewriteTestBaseForR8LibWithRelocatedDeps.getSingleOutputFile())
testClassesDirs = unzipRewrittenTests.get().getOutputs().getFiles()
systemProperty("TEST_DATA_LOCATION", unzipTests.getSingleOutputFile())
systemProperty("TESTBASE_DATA_LOCATION", unzipTestBase.getSingleOutputFile())
systemProperty(
"BUILD_PROP_KEEPANNO_RUNTIME_PATH",
keepAnnoCompileTask.getOutputs().getFiles().getAsPath().split(File.pathSeparator)[0])
systemProperty("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR",
getRoot().resolveAll("build", "test", "examplesJava11", "classes"))
systemProperty("BUILD_PROP_R8_RUNTIME_PATH", r8LibJar)
systemProperty("R8_DEPS", mainDepsJarTask.getSingleOutputFile())
systemProperty("com.android.tools.r8.artprofilerewritingcompletenesscheck", "true")
reports.junitXml.outputLocation.set(getRoot().resolveAll("build", "test-results", "test"))
reports.html.outputLocation.set(getRoot().resolveAll("build", "reports", "tests", "test"))
}
val testR8LibWithRelocatedDeps by registering(Test::class) {
testR8Lib(assembleR8LibWithRelocatedDeps, unzipRewrittenTestsForR8LibWithRelocatedDeps)
}
val testR8LibNoDeps by registering(Test::class) {
testR8Lib(assembleR8LibNoDeps, unzipRewrittenTestsForR8LibNoDeps)
}
val packageSources by registering(Jar::class) {
dependsOn(mainSourcesTask)
dependsOn(resourceShrinkerSourcesTask)
dependsOn(keepAnnoSourcesTask)
from(mainSourcesTask.outputs.files.map(::zipTree))
from(resourceShrinkerSourcesTask.outputs.files.map(::zipTree))
from(keepAnnoSourcesTask.outputs.files.map(::zipTree))
archiveClassifier.set("sources")
archiveFileName.set("r8-src.jar")
destinationDirectory.set(getRoot().resolveAll("build", "libs"))
}
test {
if (project.hasProperty("r8lib")) {
dependsOn(testR8LibWithRelocatedDeps)
} else if (project.hasProperty("r8lib_no_deps")) {
dependsOn(testR8LibNoDeps)
} else {
dependsOn(gradle.includedBuild("tests_java_8").task(":test"))
dependsOn(gradle.includedBuild("tests_bootstrap").task(":test"))
}
}
}
fun Task.getSingleOutputFile(): File = getOutputs().getSingleOutputFile()
fun TaskOutputs.getSingleOutputFile(): File = getFiles().getSingleFile()
fun TaskProvider<*>.getSingleOutputFile(): File = get().getSingleOutputFile()