Update new gradle setup to compile r8lib with and without dependencies

Bug: b/270105162
Change-Id: I1fd6f44e956805ea69094eb22c93effaf622cb18
diff --git a/commonBuildSrc/settings.gradle.kts b/commonBuildSrc/settings.gradle.kts
index f346f85..d26745c 100644
--- a/commonBuildSrc/settings.gradle.kts
+++ b/commonBuildSrc/settings.gradle.kts
@@ -5,10 +5,10 @@
 pluginManagement {
     repositories {
         maven {
-            url = uri("file:../third_party/dependencies_new")
+            url = uri("file:../third_party/dependencies")
         }
         maven {
-            url = uri("file:../third_party/dependencies")
+            url = uri("file:../third_party/dependencies_new")
         }
     }
 }
@@ -16,10 +16,10 @@
 dependencyResolutionManagement {
     repositories {
         maven {
-            url = uri("file:../third_party/dependencies_new")
+            url = uri("file:../third_party/dependencies")
         }
         maven {
-            url = uri("file:../third_party/dependencies")
+            url = uri("file:../third_party/dependencies_new")
         }
     }
 }
diff --git a/commonBuildSrc/src/main/kotlin/Dependencies.kt b/commonBuildSrc/src/main/kotlin/Dependencies.kt
deleted file mode 100644
index 66e88d1..0000000
--- a/commonBuildSrc/src/main/kotlin/Dependencies.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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 org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.JavaVersion
-import java.io.File
-
-class DependenciesPlugin: Plugin<Project> {
-  override fun apply(target: Project) {
-    // Intentionally empty
-  }
-}
-
-fun Project.getRoot() : File {
-  var parent = this.projectDir
-  while (!parent.getName().equals("d8_r8")) {
-    parent = parent.getParentFile()
-  }
-  return parent.getParentFile()
-}
-
-fun File.resolveAll(vararg xs: String) : File {
-  var that = this;
-  for (x in xs) {
-    that = that.resolve(x)
-  }
-  return that
-}
-
-object JvmCompatibility {
-  val sourceCompatibility = JavaVersion.VERSION_11
-  val targetCompatibility = JavaVersion.VERSION_11
-}
-
-object Versions {
-  const val asmVersion = "9.5"
-  const val fastUtilVersion = "7.2.0"
-  const val gsonVersion = "2.7"
-  const val guavaVersion = "31.1-jre"
-  const val joptSimpleVersion = "4.6"
-  const val junitVersion = "4.13-beta-2"
-  const val kotlinVersion = "1.8.0"
-  const val kotlinMetadataVersion = "0.6.0"
-  const val smaliVersion = "3.0.3"
-  const val errorproneVersion = "2.18.0"
-}
-
-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 joptSimple by lazy { "net.sf.jopt-simple:jopt-simple:${Versions.joptSimpleVersion}" }
-  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 smali by lazy { "com.android.tools.smali:smali:${Versions.smaliVersion}" }
-  val errorprone by lazy { "com.google.errorprone:error_prone_core:${Versions.errorproneVersion}" }
-}
diff --git a/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
new file mode 100644
index 0000000..19b48ee
--- /dev/null
+++ b/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -0,0 +1,163 @@
+// 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 org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.JavaVersion
+import org.gradle.api.Task
+import org.gradle.api.tasks.Exec
+import java.io.File
+import java.nio.file.Path
+import java.nio.file.Paths
+class DependenciesPlugin: Plugin<Project> {
+
+  override fun apply(target: Project) {
+    // Intentionally empty
+  }
+}
+
+enum class Jdk(val folder : String) {
+  JDK_11("jdk-11"),
+  JDK_17("jdk-17"),
+  JDK_20("jdk-20");
+}
+
+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} ******"
+}
+
+/**
+ * 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(),
+  args : List<String> = 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 fastUtilVersion = "7.2.1"
+  const val gsonVersion = "2.7"
+  const val guavaVersion = "31.1-jre"
+  const val junitVersion = "4.13-beta-2"
+  const val kotlinVersion = "1.8.10"
+  const val kotlinMetadataVersion = "0.6.2"
+  const val smaliVersion = "3.0.3"
+  const val errorproneVersion = "2.18.0"
+  const val javassist = "3.29.2-GA"
+}
+
+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 smali by lazy { "com.android.tools.smali:smali:${Versions.smaliVersion}" }
+  val errorprone by lazy { "com.google.errorprone:error_prone_core:${Versions.errorproneVersion}" }
+}
diff --git a/d8_r8/gradle.properties b/d8_r8/gradle.properties
index ef0be28..1de43f9 100644
--- a/d8_r8/gradle.properties
+++ b/d8_r8/gradle.properties
@@ -12,6 +12,6 @@
 org.gradle.parallel=true
 org.gradle.caching=true
 
-# Do not download any jdks or detect them. We provide them
+# Do not download any jdks or detect them. We provide them.
 org.gradle.java.installations.auto-detect=false
 org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/keepanno/gradle.properties b/d8_r8/keepanno/gradle.properties
index ef0be28..1de43f9 100644
--- a/d8_r8/keepanno/gradle.properties
+++ b/d8_r8/keepanno/gradle.properties
@@ -12,6 +12,6 @@
 org.gradle.parallel=true
 org.gradle.caching=true
 
-# Do not download any jdks or detect them. We provide them
+# Do not download any jdks or detect them. We provide them.
 org.gradle.java.installations.auto-detect=false
 org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/keepanno/settings.gradle.kts b/d8_r8/keepanno/settings.gradle.kts
index c214cca..3238e39 100644
--- a/d8_r8/keepanno/settings.gradle.kts
+++ b/d8_r8/keepanno/settings.gradle.kts
@@ -3,23 +3,23 @@
 // BSD-style license that can be found in the LICENSE file.
 
 pluginManagement {
-    repositories {
-        maven {
-            url = uri("file:../../third_party/dependencies")
-        }
-        maven {
-            url = uri("file:../../third_party/dependencies_new")
-        }
+  repositories {
+    maven {
+      url = uri("file:../../third_party/dependencies")
     }
+    maven {
+      url = uri("file:../../third_party/dependencies_new")
+    }
+  }
 }
 
 dependencyResolutionManagement {
   repositories {
     maven {
-        url= uri("file:../../third_party/dependencies")
+      url = uri("file:../../third_party/dependencies")
     }
     maven {
-        url= uri("file:../../third_party/dependencies_new")
+      url = uri("file:../../third_party/dependencies_new")
     }
   }
 }
diff --git a/d8_r8/main/build.gradle.kts b/d8_r8/main/build.gradle.kts
index 10d4b2b..34a1c14 100644
--- a/d8_r8/main/build.gradle.kts
+++ b/d8_r8/main/build.gradle.kts
@@ -2,6 +2,7 @@
 // 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 net.ltgt.gradle.errorprone.errorprone
 
 plugins {
@@ -21,17 +22,100 @@
 
 dependencies {
   implementation(":keepanno")
-  implementation(Deps.asm)
-  implementation(Deps.asmUtil)
-  implementation(Deps.asmCommons)
-  implementation(Deps.fastUtil)
-  implementation(Deps.gson)
-  implementation(Deps.guava)
-  implementation(Deps.joptSimple)
-  implementation(Deps.kotlinMetadata)
+  compileOnly(Deps.asm)
+  compileOnly(Deps.asmUtil)
+  compileOnly(Deps.asmCommons)
+  compileOnly(Deps.fastUtil)
+  compileOnly(Deps.gson)
+  compileOnly(Deps.guava)
+  compileOnly(Deps.kotlinMetadata)
   errorprone(Deps.errorprone)
 }
 
+val keepAnnoJarTask = projectTask("keepanno", "jar")
+
+fun mainJarDependencies() : FileCollection {
+  return sourceSets
+    .main
+    .get()
+    .compileClasspath
+    .filter({ "$it".contains("third_party")
+              && "$it".contains("dependencies")
+              && !"$it".contains("errorprone")
+    })
+}
+
+tasks {
+  withType<Exec> {
+    doFirst {
+      println("Executing command: ${commandLine.joinToString(" ")}")
+    }
+  }
+
+  val swissArmyKnife by registering(Jar::class) {
+    from(sourceSets.main.get().output)
+    manifest {
+      attributes["Main-Class"] = "com.android.tools.r8.SwissArmyKnife"
+    }
+    exclude("META-INF/*.kotlin_module")
+    exclude("**/*.kotlin_metadata")
+    archiveFileName.set("r8-swissarmyknife.jar")
+  }
+
+  val depsJar by registering(Jar::class) {
+    dependsOn(keepAnnoJarTask)
+    println(header("R8 full dependencies"))
+    mainJarDependencies().forEach({ println(it) })
+    from(mainJarDependencies().map(::zipTree))
+    from(keepAnnoJarTask.outputs.files.map(::zipTree))
+    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+    archiveFileName.set("deps.jar")
+  }
+
+  val r8WithRelocatedDeps by registering(Exec::class) {
+    dependsOn(swissArmyKnife)
+    dependsOn(depsJar)
+    val swissArmy = swissArmyKnife.get().outputs.getFiles().getSingleFile()
+    val deps = depsJar.get().outputs.files.getSingleFile()
+    inputs.files(listOf(swissArmy, deps))
+    val output = file(Paths.get("build", "libs", "r8-deps-relocated.jar"))
+    outputs.file(output)
+    commandLine = baseCompilerCommandLine(
+      swissArmy,
+      deps,
+      "relocator",
+      listOf("--input",
+             "$swissArmy",
+             "--input",
+             "$deps",
+             "--output",
+             "$output",
+             "--map",
+             "com.google.common->com.android.tools.r8.com.google.common",
+             "--map",
+             "com.google.gson->com.android.tools.r8.com.google.gson",
+             "--map",
+             "com.google.thirdparty->com.android.tools.r8.com.google.thirdparty",
+             "--map",
+             "org.objectweb.asm->com.android.tools.r8.org.objectweb.asm",
+             "--map",
+             "it.unimi.dsi.fastutil->com.android.tools.r8.it.unimi.dsi.fastutil",
+             "--map",
+             "kotlin->com.android.tools.r8.jetbrains.kotlin",
+             "--map",
+             "kotlinx->com.android.tools.r8.jetbrains.kotlinx",
+             "--map",
+             "org.jetbrains->com.android.tools.r8.org.jetbrains",
+             "--map",
+             "org.intellij->com.android.tools.r8.org.intellij",
+             "--map",
+             "org.checkerframework->com.android.tools.r8.org.checkerframework",
+             "--map",
+             "com.google.j2objc->com.android.tools.r8.com.google.j2objc"
+      ))
+  }
+}
+
 tasks.withType<JavaCompile> {
   println("NOTE: Running with JDK: " + org.gradle.internal.jvm.Jvm.current().javaHome)
 
@@ -101,5 +185,4 @@
   // Moving away from identity and canonical items is not planned.
   options.errorprone.disable("ReferenceEquality")
   options.errorprone.disable("IdentityHashMapUsage")
-
 }
diff --git a/d8_r8/main/gradle.properties b/d8_r8/main/gradle.properties
index ef0be28..1de43f9 100644
--- a/d8_r8/main/gradle.properties
+++ b/d8_r8/main/gradle.properties
@@ -12,6 +12,6 @@
 org.gradle.parallel=true
 org.gradle.caching=true
 
-# Do not download any jdks or detect them. We provide them
+# Do not download any jdks or detect them. We provide them.
 org.gradle.java.installations.auto-detect=false
 org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/main/settings.gradle.kts b/d8_r8/main/settings.gradle.kts
index 347b7a4..4745501 100644
--- a/d8_r8/main/settings.gradle.kts
+++ b/d8_r8/main/settings.gradle.kts
@@ -3,25 +3,28 @@
 // BSD-style license that can be found in the LICENSE file.
 
 pluginManagement {
-    repositories {
-        maven {
-            url = uri("file:../../third_party/dependencies")
-        }
-        maven {
-            url = uri("file:../../third_party/dependencies_new")
-        }
+  repositories {
+    maven {
+      url = uri("file:../../third_party/dependencies")
     }
+    maven {
+      url = uri("file:../../third_party/dependencies_new")
+    }
+  }
 }
 
 dependencyResolutionManagement {
   repositories {
     maven {
-        url= uri("file:../../third_party/dependencies")
+      url = uri("file:../../third_party/dependencies")
     }
     maven {
-        url= uri("file:../../third_party/dependencies_new")
+      url = uri("file:../../third_party/dependencies_new")
     }
   }
 }
 
 rootProject.name = "r8"
+
+val root = rootProject.projectDir.parentFile
+includeBuild(root.resolve("keepanno"))
\ No newline at end of file
diff --git a/d8_r8/r8lib/build.gradle.kts b/d8_r8/r8lib/build.gradle.kts
new file mode 100644
index 0000000..c3eea8f
--- /dev/null
+++ b/d8_r8/r8lib/build.gradle.kts
@@ -0,0 +1,97 @@
+// 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
+
+plugins {
+  `kotlin-dsl`
+  id("dependencies-plugin")
+}
+
+java {
+  sourceCompatibility = JvmCompatibility.sourceCompatibility
+  targetCompatibility = JvmCompatibility.targetCompatibility
+}
+
+dependencies { }
+
+val r8WithRelocatedDepsTask = projectTask("main", "r8WithRelocatedDeps")
+val r8Jar = projectTask("main", "jar")
+val depsJarTask = projectTask("main", "depsJar")
+val allTestsJarRelocatedTask = projectTask("test", "allTestsJarRelocated")
+val allDepsJarTask = projectTask("test", "allDepsJar")
+
+tasks {
+  withType<Exec> {
+    doFirst {
+      println("Executing command: ${commandLine.joinToString(" ")}")
+    }
+  }
+
+  val generateKeepRules by registering(Exec::class) {
+    dependsOn(r8WithRelocatedDepsTask)
+    dependsOn(depsJarTask)
+    dependsOn(allTestsJarRelocatedTask)
+    dependsOn(allDepsJarTask)
+    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
+    val deps = depsJarTask.outputs.files.getSingleFile()
+    val tests = allTestsJarRelocatedTask.outputs.files.getSingleFile()
+    val testDeps = allDepsJarTask.outputs.files.getSingleFile()
+    inputs.files(listOf(r8, deps, tests, testDeps))
+    val output = file(Paths.get("build", "libs", "generated-keep-rules.txt"))
+    outputs.file(output)
+    commandLine = baseCompilerCommandLine(
+      r8,
+      "tracereferences",
+      listOf(
+        "--keep-rules",
+        "--allowobfuscation",
+        "--lib",
+        "${getRoot().resolveAll("third_party", "openjdk", "openjdk-rt-1.8", "rt.jar")}",
+        "--lib",
+        "${deps}",
+        "--lib",
+        "$testDeps",
+        "--target",
+        "$r8",
+        "--source",
+        "$tests",
+        "--output",
+        "$output"))
+  }
+
+  val r8LibWithRelocatedDeps by registering(Exec::class) {
+    dependsOn(generateKeepRules)
+    dependsOn(r8WithRelocatedDepsTask)
+    val r8 = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
+    val generatedKeepRules = generateKeepRules.get().outputs.files.getSingleFile()
+    inputs.files(listOf(r8, generatedKeepRules))
+    val output = file(Paths.get("build", "libs", "r8lib-deps-relocated.jar"))
+    outputs.file(output)
+    commandLine = createR8LibCommandLine(
+      r8,
+      r8,
+      output,
+      listOf(getRoot().resolveAll("src", "main", "keep.txt"), generatedKeepRules),
+      false)
+  }
+
+  val r8LibNoDeps by registering(Exec::class) {
+    dependsOn(depsJarTask)
+    dependsOn(r8WithRelocatedDepsTask)
+    val r8Compiler = r8WithRelocatedDepsTask.outputs.files.getSingleFile()
+    val r8Jar = r8Jar.outputs.files.getSingleFile()
+    val deps = depsJarTask.outputs.files.getSingleFile()
+    inputs.files(listOf(r8Compiler, r8Jar, deps))
+    val output = file(Paths.get("build", "libs", "r8lib-no-deps.jar"))
+    outputs.file(output)
+    commandLine = createR8LibCommandLine(
+      r8Compiler,
+      r8Jar,
+      output,
+      listOf(getRoot().resolveAll("src", "main", "keep.txt")),
+      true,
+      listOf(deps))
+  }
+}
diff --git a/d8_r8/r8lib/gradle.properties b/d8_r8/r8lib/gradle.properties
new file mode 100644
index 0000000..1de43f9
--- /dev/null
+++ b/d8_r8/r8lib/gradle.properties
@@ -0,0 +1,17 @@
+# 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.
+
+org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
+kotlin.daemon.jvmargs=-Xmx3g -Dkotlin.js.compiler.legacy.force_enabled=true
+systemProp.file.encoding=UTF-8
+
+# Enable new incremental compilation
+kotlin.incremental.useClasspathSnapshot=true
+
+org.gradle.parallel=true
+org.gradle.caching=true
+
+# Do not download any jdks or detect them. We provide them.
+org.gradle.java.installations.auto-detect=false
+org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/r8lib/settings.gradle.kts b/d8_r8/r8lib/settings.gradle.kts
new file mode 100644
index 0000000..cb9fc2e
--- /dev/null
+++ b/d8_r8/r8lib/settings.gradle.kts
@@ -0,0 +1,31 @@
+// 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.
+
+pluginManagement {
+  repositories {
+    maven {
+      url = uri("file:../../third_party/dependencies")
+    }
+    maven {
+      url = uri("file:../../third_party/dependencies_new")
+    }
+  }
+}
+
+dependencyResolutionManagement {
+  repositories {
+    maven {
+      url = uri("file:../../third_party/dependencies")
+    }
+    maven {
+      url = uri("file:../../third_party/dependencies_new")
+    }
+  }
+}
+
+rootProject.name = "r8lib"
+
+val root = rootProject.projectDir.parentFile
+includeBuild(root.resolve("main"))
+includeBuild(root.resolve("test"))
diff --git a/d8_r8/settings.gradle.kts b/d8_r8/settings.gradle.kts
index 9d2dfa1..f73899e 100644
--- a/d8_r8/settings.gradle.kts
+++ b/d8_r8/settings.gradle.kts
@@ -2,26 +2,26 @@
 // 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.
 
-// TODO(X): Move this file out the repository root when old gradle is removed.
+// TODO(b/270105162): Move this file out the repository root when old gradle is removed.
 
 pluginManagement {
-    repositories {
-        maven {
-            url = uri("file:../../third_party/dependencies")
-        }
-        maven {
-            url = uri("file:../../third_party/dependencies_new")
-        }
+  repositories {
+    maven {
+      url = uri("file:../third_party/dependencies")
     }
+    maven {
+      url = uri("file:../third_party/dependencies_new")
+    }
+  }
 }
 
 dependencyResolutionManagement {
   repositories {
     maven {
-        url= uri("file:../third_party/dependencies")
+      url = uri("file:../third_party/dependencies")
     }
     maven {
-        url= uri("file:../third_party/dependencies_new")
+      url = uri("file:../third_party/dependencies_new")
     }
   }
 }
@@ -29,6 +29,7 @@
 rootProject.name = "d8-r8"
 
 // Bootstrap building by downloading dependencies.
+
 fun String.execute() =
     org.codehaus.groovy.runtime.ProcessGroovyMethods.execute(this)
 
@@ -67,12 +68,18 @@
             + "\n${process.err()}\n${process.out()}")
 }
 
+val root = rootProject.projectDir
+
 // This project is temporarily located in d8_r8. When moved to root, the parent
 // folder should just be removed.
-includeBuild(rootProject.projectDir.parentFile.resolve("commonBuildSrc"))
-includeBuild("keepanno")
+includeBuild(root.parentFile.resolve("commonBuildSrc"))
+includeBuild(root.resolve("keepanno"))
 
 // We need to include src/main as a composite-build otherwise our test-modules
 // will compete with the test to compile the source files.
-includeBuild("main")
-includeBuild("test")
+includeBuild(root.resolve("main"))
+includeBuild(root.resolve("test"))
+
+// Include r8lib as standalone to have a nice separation between source artifacts and r8 compiled
+// artifacts
+includeBuild(root.resolve("r8lib"))
\ No newline at end of file
diff --git a/d8_r8/test/build.gradle.kts b/d8_r8/test/build.gradle.kts
index 34f153b..c7837c0 100644
--- a/d8_r8/test/build.gradle.kts
+++ b/d8_r8/test/build.gradle.kts
@@ -2,54 +2,71 @@
 // 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")
 }
 
-val root = getRoot();
-
 java {
-  sourceSets.test.configure {
-    java.srcDir(root.resolveAll("src", "test", "java"))
+  sourceCompatibility = JavaVersion.VERSION_17
+  targetCompatibility = JavaVersion.VERSION_17
+}
+
+dependencies { }
+
+val r8WithRelocatedDepsTask = projectTask("main", "r8WithRelocatedDeps")
+val java8TestJarTask = projectTask("tests_java_8", "testJar")
+val java8DepsJarTask = projectTask("tests_java_8", "depsJar")
+
+tasks {
+  withType<JavaCompile> {
+    options.setFork(true)
+    options.forkOptions.executable = getCompilerPath(Jdk.JDK_17)
+    options.forkOptions.javaHome = getJavaHome(Jdk.JDK_17)
   }
-  sourceCompatibility = JvmCompatibility.sourceCompatibility
-  targetCompatibility = JvmCompatibility.targetCompatibility
-}
 
-// We cannot use languageVersion.set(JavaLanguageVersion.of("8")) because gradle cannot figure
-// out that the jdk is 1_8 and will try to download it.
-tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
-  kotlinOptions {
-    jvmTarget = "11"
+  withType<KotlinCompile> {
+    kotlinOptions {
+      jvmTarget = "17"
+    }
   }
-}
 
+  val allTestsJar by registering(Jar::class) {
+    dependsOn(java8TestJarTask)
+    from(java8TestJarTask.outputs.getFiles().map(::zipTree))
+    exclude("META-INF/*.kotlin_module")
+    exclude("**/*.kotlin_metadata")
+    archiveFileName.set("all-tests.jar")
+  }
 
-dependencies {
-  implementation(":r8")
-  implementation(":keepanno")
-  implementation(Deps.asm)
-  implementation(Deps.gson)
-  implementation(Deps.guava)
-  implementation(Deps.junit)
-  implementation(Deps.kotlinStdLib)
-  implementation(Deps.kotlinReflect)
-  implementation(Deps.kotlinMetadata)
-  implementation(files(root.resolveAll("third_party", "ddmlib", "ddmlib.jar")))
-  implementation(
-    files(
-      root.resolveAll("third_party", "jdwp-tests", "apache-harmony-jdwp-tests-host.jar")))
-  implementation(files(root.resolveAll("third_party", "jasmin", "jasmin-2.4.jar")))
-  implementation(Deps.fastUtil)
-  implementation(Deps.smali)
-  implementation(Deps.asmUtil)
-}
+  val allDepsJar by registering(Jar::class) {
+    dependsOn(java8DepsJarTask)
+    from(java8DepsJarTask.outputs.getFiles().map(::zipTree))
+    exclude("META-INF/*.kotlin_module")
+    exclude("**/*.kotlin_metadata")
+    archiveFileName.set("all-deps.jar")
+  }
 
-tasks.named("test") {
-  dependsOn(gradle.includedBuild("tests_java_8").task(":compileJava"))
-}
-
-tasks.withType<Test> {
-  environment("USE_NEW_GRADLE_SETUP", "true")
+  val allTestsJarRelocated by registering(Exec::class) {
+    dependsOn(r8WithRelocatedDepsTask)
+    dependsOn(allTestsJar)
+    val r8 = r8WithRelocatedDepsTask.outputs.getFiles().getSingleFile()
+    val allTests = allTestsJar.get().outputs.files.getSingleFile()
+    inputs.files(listOf(r8, allTests))
+    val output = file(Paths.get("build", "libs", "all-tests-relocated.jar"))
+    outputs.file(output)
+    commandLine = baseCompilerCommandLine(
+      r8,
+      "relocator",
+      listOf("--input",
+             "$allTests",
+             "--output",
+             "$output",
+             "--map",
+             "kotlinx.metadata->com.android.tools.r8.jetbrains.kotlinx.metadata"))
+  }
 }
diff --git a/d8_r8/test/gradle.properties b/d8_r8/test/gradle.properties
index ef0be28..1de43f9 100644
--- a/d8_r8/test/gradle.properties
+++ b/d8_r8/test/gradle.properties
@@ -12,6 +12,6 @@
 org.gradle.parallel=true
 org.gradle.caching=true
 
-# Do not download any jdks or detect them. We provide them
+# Do not download any jdks or detect them. We provide them.
 org.gradle.java.installations.auto-detect=false
 org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/test/settings.gradle.kts b/d8_r8/test/settings.gradle.kts
index 5946a12..5b00aae 100644
--- a/d8_r8/test/settings.gradle.kts
+++ b/d8_r8/test/settings.gradle.kts
@@ -3,23 +3,23 @@
 // BSD-style license that can be found in the LICENSE file.
 
 pluginManagement {
-    repositories {
-        maven {
-            url = uri("file:../../third_party/dependencies")
-        }
-        maven {
-            url = uri("file:../../third_party/dependencies_new")
-        }
+  repositories {
+    maven {
+      url = uri("file:../../third_party/dependencies")
     }
+    maven {
+      url = uri("file:../../third_party/dependencies_new")
+    }
+  }
 }
 
 dependencyResolutionManagement {
   repositories {
     maven {
-        url= uri("file:../third_party/dependencies")
+      url = uri("file:../../third_party/dependencies")
     }
     maven {
-        url= uri("file:../third_party/dependencies_new")
+      url = uri("file:../../third_party/dependencies_new")
     }
   }
 }
@@ -27,4 +27,5 @@
 rootProject.name = "r8-tests"
 
 val root = rootProject.projectDir.parentFile
+includeBuild(root.resolve("main"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_8"))
diff --git a/d8_r8/test_modules/tests_java_8/build.gradle.kts b/d8_r8/test_modules/tests_java_8/build.gradle.kts
index 9908599..55ee7a8 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -14,49 +14,24 @@
 val root = getRoot()
 
 java {
-  sourceSets.main.configure {
+  sourceSets.test.configure {
     java.srcDir(root.resolveAll("src", "test", "java"))
   }
+  // We cannot use languageVersion.set(JavaLanguageVersion.of(8)) because gradle cannot figure
+  // out that the jdk is 1_8 and will try to download it.
   sourceCompatibility = JavaVersion.VERSION_1_8
   targetCompatibility = JavaVersion.VERSION_1_8
 }
 
-
-// We cannot use languageVersion.set(JavaLanguageVersion.of("8")) because gradle cannot figure
-// out that the jdk is 1_8 and will try to download it.
-tasks.withType<KotlinCompile> {
-  kotlinOptions {
-    jvmTarget = "1.8"
-  }
-}
-
-// The test module compilation depends on main and keep anno output, but we cannot directly
-// reference the task we only obtain a task reference. To obtain the actual reference by creating
-// a dummy.
-tasks.register("dummy-keepanno-reference") {
-  dependsOn(gradle.includedBuild("keepanno").task(":jar"))
-}
-val keepAnnoTask = tasks.getByName("dummy-keepanno-reference")
-  .taskDependencies
-  .getDependencies(tasks.getByName("dummy-keepanno-reference"))
-  .iterator()
-  .next()
-
-tasks.register("dummy-r8-reference") {
-  dependsOn(gradle.includedBuild("main").task(":jar"))
-}
-val r8Task = tasks.getByName("dummy-r8-reference")
-  .taskDependencies
-  .getDependencies(tasks.getByName("dummy-r8-reference"))
-  .iterator()
-  .next()
-
 dependencies {
-  implementation(keepAnnoTask.outputs.files)
-  implementation(r8Task.outputs.files)
+  // If we depend on keepanno by referencing the project source outputs we get an error regarding
+  // incompatible java class file version. By depending on the jar we circumvent that.
+  implementation(projectTask("keepanno", "jar").outputs.files)
+  implementation(projectTask("main", "jar").outputs.files)
   implementation(Deps.asm)
   implementation(Deps.gson)
   implementation(Deps.guava)
+  implementation(Deps.javassist)
   implementation(Deps.junit)
   implementation(Deps.kotlinStdLib)
   implementation(Deps.kotlinReflect)
@@ -71,18 +46,50 @@
   implementation(Deps.asmUtil)
 }
 
-tasks.withType<JavaCompile> {
-  dependsOn(keepAnnoTask)
-  dependsOn(r8Task)
-  options.setFork(true)
-  options.forkOptions.memoryMaximumSize = "3g"
-  options.forkOptions.jvmArgs = listOf(
-    "-Xss256m",
-    // Set the bootclass path so compilation is consistent with 1.8 target compatibility.
-    "-Xbootclasspath/a:third_party/openjdk/openjdk-rt-1.8/rt.jar")
+fun testDependencies() : FileCollection {
+  return sourceSets
+    .test
+    .get()
+    .compileClasspath
+    .filter({ "$it".contains("keepanno") ||
+      ("$it".contains("third_party")
+      && !"$it".contains("errorprone")
+      && !"$it".contains("gradle"))
+            })
 }
 
-tasks.withType<KotlinCompile> {
-    dependsOn(keepAnnoTask)
-    dependsOn(r8Task)
+tasks {
+  withType<JavaCompile> {
+    dependsOn(gradle.includedBuild("keepanno").task(":jar"))
+    dependsOn(gradle.includedBuild("main").task(":jar"))
+    options.setFork(true)
+    options.forkOptions.memoryMaximumSize = "3g"
+    options.forkOptions.jvmArgs = listOf(
+      "-Xss256m",
+      // Set the bootclass path so compilation is consistent with 1.8 target compatibility.
+      "-Xbootclasspath/a:third_party/openjdk/openjdk-rt-1.8/rt.jar")
+  }
+
+  withType<KotlinCompile> {
+    dependsOn(gradle.includedBuild("keepanno").task(":jar"))
+    dependsOn(gradle.includedBuild("main").task(":jar"))
+    kotlinOptions {
+      // We cannot use languageVersion.set(JavaLanguageVersion.of(8)) because gradle cannot figure
+      // out that the jdk is 1_8 and will try to download it.
+      jvmTarget = "1.8"
+    }
+  }
+
+  val testJar by registering(Jar::class) {
+    from(sourceSets.test.get().output)
+  }
+
+  val depsJar by registering(Jar::class) {
+    dependsOn(gradle.includedBuild("keepanno").task(":jar"))
+    println(header("Test Java 8 dependencies"))
+    testDependencies().forEach({ println(it) })
+    from(testDependencies().map(::zipTree))
+    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+    archiveFileName.set("deps.jar")
+  }
 }
diff --git a/d8_r8/test_modules/tests_java_8/gradle.properties b/d8_r8/test_modules/tests_java_8/gradle.properties
index ef0be28..1de43f9 100644
--- a/d8_r8/test_modules/tests_java_8/gradle.properties
+++ b/d8_r8/test_modules/tests_java_8/gradle.properties
@@ -12,6 +12,6 @@
 org.gradle.parallel=true
 org.gradle.caching=true
 
-# Do not download any jdks or detect them. We provide them
+# Do not download any jdks or detect them. We provide them.
 org.gradle.java.installations.auto-detect=false
 org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/test_modules/tests_java_8/settings.gradle.kts b/d8_r8/test_modules/tests_java_8/settings.gradle.kts
index 6ab7fac..592c7d2 100644
--- a/d8_r8/test_modules/tests_java_8/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/settings.gradle.kts
@@ -3,35 +3,32 @@
 // BSD-style license that can be found in the LICENSE file.
 
 pluginManagement {
-    repositories {
-        maven {
-            url = uri("file:../../../third_party/dependencies")
-        }
-        maven {
-            url = uri("file:../../../third_party/dependencies_new")
-        }
+  repositories {
+    maven {
+      url = uri("file:../../../third_party/dependencies")
     }
+    maven {
+      url = uri("file:../../../third_party/dependencies_new")
+    }
+  }
 }
 
 dependencyResolutionManagement {
   repositories {
     maven {
-        url= uri("file:../third_party/dependencies")
+      url = uri("file:../../../third_party/dependencies")
     }
     maven {
-        url= uri("file:../third_party/dependencies_new")
+      url = uri("file:../../../third_party/dependencies_new")
     }
   }
 }
 
-rootProject.name = "r8-java8-tests"
+rootProject.name = "tests_java_8"
 
-val d8Root = rootProject.projectDir.parentFile.parentFile
-val root = d8Root.parentFile
-
-includeBuild(root.resolve("commonBuildSrc"))
-includeBuild(d8Root.resolve("keepanno"))
+val root = rootProject.projectDir.parentFile.parentFile
+includeBuild(root.resolve("keepanno"))
 
 // We need to include src/main as a composite-build otherwise our test-modules
 // will compete with the test to compile the source files.
-includeBuild(d8Root.resolve("main"))
+includeBuild(root.resolve("main"))
diff --git a/tools/create_r8lib.py b/tools/create_r8lib.py
index 51e2fd6..1b6c52f 100755
--- a/tools/create_r8lib.py
+++ b/tools/create_r8lib.py
@@ -52,6 +52,11 @@
     '--r8jar',
     required=True,
     help='The R8 jar to compile')
+  parser.add_argument(
+    '--r8compiler',
+    required=True,
+    default='build/libs/r8_with_deps.jar',
+    help='The R8 compiler to use')
   return parser.parse_args()
 
 def get_r8_version(r8jar):
@@ -89,7 +94,7 @@
   cmd = [jdk.GetJavaExecutable(), '-Xmx8g', '-ea']
   if args.debug_agent:
     cmd.extend(['-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005'])
-  cmd.extend(['-cp', 'build/libs/r8_with_deps.jar', 'com.android.tools.r8.R8'])
+  cmd.extend(['-cp', args.r8compiler, 'com.android.tools.r8.R8'])
   cmd.append(args.r8jar)
   cmd.append('--classfile')
   cmd.extend(['--map-id-template', map_id_template])