blob: c1107e61be071db69cdc9f8389759031220b0628 [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.io.File
import java.net.URI
import java.nio.file.Paths
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.SourceSet
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.register
import org.gradle.nativeplatform.platform.OperatingSystem
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
class DependenciesPlugin: Plugin<Project> {
override fun apply(target: Project) {
val dependenciesPath = "file:" +
target.getRoot().resolve("third_party").resolve("dependencies").getAbsolutePath()
val dependenciesNewPath = "file:" +
target.getRoot().resolve("third_party").resolve("dependencies_new").getAbsolutePath()
val repositories = target.getRepositories()
repositories.maven { name = "LOCAL_MAVEN_REPO"; url = URI(dependenciesPath) }
repositories.maven { name = "LOCAL_MAVEN_REPO_NEW"; url = URI(dependenciesNewPath) }
}
}
enum class Jdk(val folder : String) {
JDK_8("jdk8"),
JDK_9("openjdk-9.0.4"),
JDK_11("jdk-11"),
JDK_17("jdk-17"),
JDK_20("jdk-20");
fun isJdk8() : Boolean {
return this == JDK_8
}
fun getThirdPartyDependency() : ThirdPartyDependency {
val os: OperatingSystem = DefaultNativePlatform.getCurrentOperatingSystem()
val subFolder : String
val fileName : String
if (os.isLinux) {
subFolder = if(isJdk8()) "linux-x86" else "linux"
fileName = "java"
} else if (os.isMacOsX) {
subFolder = if(isJdk8()) "darwin-x86" else "osx"
fileName = "java"
} else {
assert(os.isWindows())
if (isJdk8()) {
throw RuntimeException("No Jdk8 on Windows")
}
subFolder = "windows"
fileName = "java.bat"
}
return ThirdPartyDependency(
name,
Paths.get("third_party", "openjdk", folder, subFolder, "bin", fileName).toFile(),
Paths.get("third_party", "openjdk", folder, "$subFolder.tar.gz.sha1").toFile())
}
}
fun Project.getRoot() : File {
var parent = this.projectDir
while (!parent.getName().equals("d8_r8")) {
parent = parent.getParentFile()
}
return parent.getParentFile()
}
fun Project.header(title : String) : String {
return "****** ${title} ******"
}
fun Project.ensureThirdPartyDependencies(name : String, deps : List<ThirdPartyDependency>) : Task {
val outputFiles : MutableList<File> = mutableListOf()
val depsTasks = deps.map({
tasks.register<DownloadDependencyTask>("download-third-party-${it.packageName}") {
setDependency(
it.packageName,
getRoot().resolve(it.sha1File),
getRoot().resolve(it.path).parentFile,
it.type)
outputFiles.add(it.path)
}})
return tasks.register("ensure-third-party-$name") {
dependsOn(depsTasks)
outputs.files(outputFiles)
}.get()
}
/**
* Builds a jar for each subfolder in an test source set.
*
* <p> As an example, src/test/examplesJava9 contains subfolders: backport, collectionof, ..., .
* These are compiled to individual jars and placed in <repo-root>/build/test/examplesJava9/ as:
* backport.jar, collectionof.jar, ..., .
*
* Calling this from a project will amend the task graph with the task named
* getExamplesJarsTaskName(examplesName) such that it can be referenced from the test runners.
*/
fun Project.buildExampleJars(name : String) : Task {
val outputFiles : MutableList<File> = mutableListOf()
val jarTasks : MutableList<Task> = mutableListOf()
val testSourceSet = extensions
.getByType(JavaPluginExtension::class.java)
.sourceSets
// The TEST_SOURCE_SET_NAME is the source set defined by writing java { sourcesets.test { ... }}
.getByName(SourceSet.TEST_SOURCE_SET_NAME)
val destinationDir = getRoot().resolveAll("build", "test", name)
val classesOutput = destinationDir.resolve("classes")
testSourceSet.java.destinationDirectory.set(classesOutput)
testSourceSet.resources.destinationDirectory.set(destinationDir)
testSourceSet
.java
.sourceDirectories
.files
.forEach { srcDir ->
srcDir.listFiles(File::isDirectory)?.forEach { exampleDir ->
var generationTask : Task? = null
if (exampleDir.resolve("TestGenerator.java").isFile) {
generationTask = tasks.register<JavaExec>(
"generate-$name-${exampleDir.name}") {
dependsOn("compileTestJava")
mainClass.set("${exampleDir.name}.TestGenerator")
classpath = files(
classesOutput,
testSourceSet.compileClasspath)
args(classesOutput.toString())
}.get()
}
jarTasks.add(tasks.register<Jar>(
"jar-$name-${exampleDir.name}") {
dependsOn("compileTestJava")
if (generationTask != null) {
dependsOn(generationTask)
}
archiveFileName.set("${exampleDir.name}.jar")
destinationDirectory.set(destinationDir)
from(classesOutput) {
include("${exampleDir.name}/**/*.class")
exclude("**/TestGenerator*")
}
}.get())
}
}
return tasks.register(getExampleJarsTaskName(name)) {
dependsOn(jarTasks.toTypedArray())
outputs.files(outputFiles)
}.get()
}
fun Project.getExampleJarsTaskName(name: String) : String {
return "build-example-jars-$name"
}
fun Project.resolve(thirdPartyDependency: ThirdPartyDependency) : ConfigurableFileCollection {
return files(project.getRoot().resolve(thirdPartyDependency.path))
}
/**
* When using composite builds, referecing tasks in other projects do not give a Task but a
* TaskReference. To get outputs from other tasks we need to have a proper task and gradle do not
* provide a way of getting a Task from a TaskReference. We use a trick where create a synthetic
* task that depends on the task of interest, allowing us to look at the graph and obtain the
* actual reference. Remove this code if gradle starts supporting this natively.
*/
fun Project.projectTask(project : String, taskName : String) : Task {
val name = "$project-reference-$taskName";
val task = tasks.register(name) {
dependsOn(gradle.includedBuild(project).task(":$taskName"))
}.get();
return task.taskDependencies
.getDependencies(tasks.getByName(name)).iterator().next();
}
fun File.resolveAll(vararg xs: String) : File {
var that = this;
for (x in xs) {
that = that.resolve(x)
}
return that
}
fun Project.getJavaHome(jdk : Jdk) : File {
// TODO(b/270105162): Make sure this works on other platforms.
return getRoot().resolveAll("third_party", "openjdk", jdk.folder, "linux")
}
fun Project.getCompilerPath(jdk : Jdk) : String {
// TODO(b/270105162): Make sure this works on other platforms.
return getJavaHome(jdk).resolveAll("bin", "javac").toString()
}
fun Project.getJavaPath(jdk : Jdk) : String {
// TODO(b/270105162): Make sure this works on other platforms.
return getJavaHome(jdk).resolveAll("bin", "java").toString()
}
fun Project.baseCompilerCommandLine(
jar: File, deps: File, compiler: String, args: List<String> = listOf(),
) : List<String> {
// Execute r8 commands against a stable r8 with dependencies.
// TODO(b/139725780): See if we can remove or lower the heap size (-Xmx8g).
return listOf(
getJavaPath(Jdk.JDK_17),
"-Xmx8g",
"-ea",
"-cp",
"$jar:$deps",
"com.android.tools.r8.SwissArmyKnife",
compiler) + args
}
fun Project.baseCompilerCommandLine(
jar: File, compiler: String, args: List<String> = listOf(),
) : List<String> {
// Execute r8 commands against a stable r8 with dependencies.
// TODO(b/139725780): See if we can remove or lower the heap size (-Xmx8g).
return listOf(
getJavaPath(Jdk.JDK_17),
"-Xmx8g",
"-ea",
"-cp",
"$jar",
"com.android.tools.r8.SwissArmyKnife",
compiler) + args
}
fun Project.createR8LibCommandLine(
r8Compiler: File,
input: File,
output: File,
pgConf: List<File>,
excludingDepsVariant: Boolean,
lib: List<File> = listOf(),
classpath: List<File> = listOf()
) : List<String> {
val pgList = pgConf.flatMap({ listOf("--pg-conf", "$it") })
val libList = lib.flatMap({ listOf("--lib", "$it") })
val cpList = classpath.flatMap({ listOf("--classpath", "$it") })
val exclList = if (excludingDepsVariant) listOf("--excldeps-variant") else listOf()
return listOf(
"python3",
"${getRoot().resolve("tools").resolve("create_r8lib.py")}",
"--r8compiler",
"${r8Compiler}",
"--r8jar",
"${input}",
"--output",
"${output}",
) + exclList + pgList + libList + cpList
}
object JvmCompatibility {
val sourceCompatibility = JavaVersion.VERSION_11
val targetCompatibility = JavaVersion.VERSION_11
}
object Versions {
const val asmVersion = "9.5"
const val errorproneVersion = "2.18.0"
const val fastUtilVersion = "7.2.1"
const val gsonVersion = "2.7"
const val guavaVersion = "31.1-jre"
const val javassist = "3.29.2-GA"
const val junitVersion = "4.13-beta-2"
const val kotlinVersion = "1.8.10"
const val kotlinMetadataVersion = "0.6.2"
const val mockito = "2.10.0"
const val smaliVersion = "3.0.3"
}
object Deps {
val asm by lazy { "org.ow2.asm:asm:${Versions.asmVersion}" }
val asmUtil by lazy { "org.ow2.asm:asm-util:${Versions.asmVersion}" }
val asmCommons by lazy { "org.ow2.asm:asm-commons:${Versions.asmVersion}" }
val fastUtil by lazy { "it.unimi.dsi:fastutil:${Versions.fastUtilVersion}"}
val gson by lazy { "com.google.code.gson:gson:${Versions.gsonVersion}"}
val guava by lazy { "com.google.guava:guava:${Versions.guavaVersion}" }
val javassist by lazy { "org.javassist:javassist:${Versions.javassist}"}
val junit by lazy { "junit:junit:${Versions.junitVersion}"}
val kotlinMetadata by lazy {
"org.jetbrains.kotlinx:kotlinx-metadata-jvm:${Versions.kotlinMetadataVersion}" }
val kotlinStdLib by lazy { "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlinVersion}" }
val kotlinReflect by lazy { "org.jetbrains.kotlin:kotlin-reflect:${Versions.kotlinVersion}" }
val mockito by lazy { "org.mockito:mockito-core:${Versions.mockito}" }
val smali by lazy { "com.android.tools.smali:smali:${Versions.smaliVersion}" }
val errorprone by lazy { "com.google.errorprone:error_prone_core:${Versions.errorproneVersion}" }
}
object ThirdPartyDeps {
val androidJars = getThirdPartyAndroidJars()
val androidVMs = getThirdPartyAndroidVms()
val apiDatabase = ThirdPartyDependency(
"apiDatabase",
Paths.get(
"third_party",
"api_database",
"api_database",
"resources",
"new_api_database.ser").toFile(),
Paths.get("third_party", "api_database", "api_database.tar.gz.sha1").toFile())
val compilerApi = ThirdPartyDependency(
"compiler-api",
Paths.get(
"third_party",
"binary_compatibility_tests",
"compiler_api_tests",
"tests.jar").toFile(),
Paths.get(
"third_party",
"binary_compatibility_tests",
"compiler_api_tests.tar.gz.sha1").toFile())
val dagger = ThirdPartyDependency(
"dagger",
Paths.get("third_party", "dagger", "2.41", "dagger-2.41.jar").toFile(),
Paths.get("third_party", "dagger", "2.41.tar.gz.sha1").toFile())
val ddmLib = ThirdPartyDependency(
"ddmlib",
Paths.get("third_party", "ddmlib", "ddmlib.jar").toFile(),
Paths.get("third_party", "ddmlib.tar.gz.sha1").toFile())
val jacoco = ThirdPartyDependency(
"jacoco",
Paths.get("third_party", "jacoco", "0.8.6", "lib", "jacocoagent.jar").toFile(),
Paths.get("third_party", "jacoco", "0.8.6.tar.gz.sha1").toFile()
)
val jasmin = ThirdPartyDependency(
"jasmin",
Paths.get("third_party", "jasmin", "jasmin-2.4.jar").toFile(),
Paths.get("third_party", "jasmin.tar.gz.sha1").toFile())
val java8Runtime = ThirdPartyDependency(
"openjdk-rt-1.8",
Paths.get("third_party", "openjdk", "openjdk-rt-1.8", "rt.jar").toFile(),
Paths.get("third_party", "openjdk", "openjdk-rt-1.8.tar.gz.sha1").toFile()
)
val jdks = getJdks()
val jdk11Test = ThirdPartyDependency(
"jdk-11-test",
Paths.get("third_party", "openjdk", "jdk-11-test", "Makefile").toFile(),
Paths.get("third_party", "openjdk", "jdk-11-test.tar.gz.sha1").toFile()
)
val jdwpTests = ThirdPartyDependency(
"jdwp-tests",
Paths.get("third_party", "jdwp-tests", "apache-harmony-jdwp-tests-host.jar").toFile(),
Paths.get("third_party", "jdwp-tests.tar.gz.sha1").toFile())
val kotlinCompilers = getThirdPartyKotlinCompilers()
val proguards = getThirdPartyProguards()
}
fun getThirdPartyAndroidJars() : List<ThirdPartyDependency> {
return listOf(
"libcore_latest",
"lib-master",
"lib-v14",
"lib-v15",
"lib-v19",
"lib-v21",
"lib-v22",
"lib-v23",
"lib-v24",
"lib-v25",
"lib-v26",
"lib-v27",
"lib-v28",
"lib-v29",
"lib-v30",
"lib-v31",
"lib-v32",
"lib-v33",
"lib-v34"
).map(::getThirdPartyAndroidJar)
}
fun getThirdPartyAndroidJar(version : String) : ThirdPartyDependency {
return ThirdPartyDependency(
version,
Paths.get("third_party", "android_jar", version, "android.jar").toFile(),
Paths.get("third_party", "android_jar", "$version.tar.gz.sha1").toFile())
}
fun getThirdPartyAndroidVms() : List<ThirdPartyDependency> {
return listOf(
listOf("host", "art-master"),
listOf("host", "art-14.0.0-dp1"),
listOf("host", "art-13.0.0"),
listOf("host", "art-12.0.0-beta4"),
listOf("art-10.0.0"),
listOf("art-5.1.1"),
listOf("art-6.0.1"),
listOf("art-7.0.0"),
listOf("art-8.1.0"),
listOf("art-9.0.0"),
listOf("art"),
listOf("dalvik-4.0.4"),
listOf("dalvik")).map(::getThirdPartyAndroidVm)
}
fun getThirdPartyAndroidVm(version : List<String>) : ThirdPartyDependency {
val output = Paths.get("tools", "linux", *version.toTypedArray(), "bin", "art").toFile()
return ThirdPartyDependency(
version.last(),
output,
Paths.get(
"tools",
"linux",
*version.slice(0..version.size - 2).toTypedArray(),
"${version.last()}.tar.gz.sha1").toFile())
}
fun getJdks() : List<ThirdPartyDependency> {
val os: OperatingSystem = DefaultNativePlatform.getCurrentOperatingSystem()
if (os.isLinux || os.isMacOsX) {
return Jdk.values().map{ it.getThirdPartyDependency()}
} else {
return Jdk.values().filter{ !it.isJdk8() }.map{ it.getThirdPartyDependency()}
}
}
fun getThirdPartyProguards() : List<ThirdPartyDependency> {
val os: OperatingSystem = DefaultNativePlatform.getCurrentOperatingSystem()
return listOf("proguard5.2.1", "proguard6.0.1", "proguard-7.0.0")
.map { ThirdPartyDependency(
it,
Paths.get(
"third_party",
"proguard",
it,
"bin",
if (os.isWindows) "proguard.bat" else "proguard.sh").toFile(),
Paths.get("third_party", "proguard", "${it}.tar.gz.sha1").toFile())}
}
fun getThirdPartyKotlinCompilers() : List<ThirdPartyDependency> {
return listOf(
"kotlin-compiler-1.3.72",
"kotlin-compiler-1.4.20",
"kotlin-compiler-1.5.0",
"kotlin-compiler-1.6.0",
"kotlin-compiler-1.7.0",
"kotlin-compiler-1.8.0",
"kotlin-compiler-dev")
.map { ThirdPartyDependency(
it,
Paths.get(
"third_party",
"kotlin",
it,
"kotlinc",
"lib",
"kotlin-stdlib.jar").toFile(),
Paths.get("third_party", "kotlin", "${it}.tar.gz.sha1").toFile())}
}