blob: 78e7e94ec6476446492be64ba9b0013f3ca5ffe2 [file] [log] [blame]
// Copyright (c) 2016, 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.internal.os.OperatingSystem
import utils.Utils
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'com.google.protobuf'
apply plugin: 'com.github.johnrengelman.shadow'
apply from: 'copyAdditionalJctfCommonFiles.gradle'
if (project.hasProperty('with_code_coverage')) {
apply plugin: 'jacoco'
}
repositories {
maven { url 'https://maven.google.com' }
mavenCentral()
}
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
}
}
// Custom source set for example tests and generated tests.
sourceSets {
test {
java {
srcDirs = [
'src/test/java',
'build/generated/test/java',
]
}
}
debugTestResources {
java {
srcDirs = ['src/test/debugTestResources']
}
output.resourcesDir = 'build/classes/debugTestResources'
}
debugTestResourcesJava8 {
java {
srcDirs = ['src/test/debugTestResourcesJava8']
}
output.resourcesDir = 'build/classes/debugTestResourcesJava8'
}
debugTestResourcesKotlin {
java {
srcDirs = ['src/test/debugTestResourcesKotlin']
}
output.resourcesDir = 'build/classes/debugTestResourcesKotlin'
}
examples {
java {
srcDirs = ['src/test/examples', 'build/generated/source/proto/examples/javalite/' ]
}
proto {
srcDirs = [
'src/test/examples',
]
}
output.resourcesDir = 'build/classes/examples'
}
examplesAndroidN {
java {
srcDirs = ['src/test/examplesAndroidN']
}
output.resourcesDir = 'build/classes/examplesAndroidN'
}
examplesAndroidO {
java {
srcDirs = ['src/test/examplesAndroidO']
}
output.resourcesDir = 'build/classes/examplesAndroidO'
}
jctfCommon {
java {
srcDirs = [
'third_party/jctf/Harness/src',
'third_party/jctf/LibTests/src/com/google/jctf/test/categories',
'third_party/jctf/LibTests/src/com/google/jctf/test/helper',
'third_party/jctf/LibTests/src/com/google/jctf/testHelpers',
'third_party/jctf/LibTests/src/org',
'build/additionalJctfCommonFiles'
]
}
resources {
srcDirs = ['third_party/jctf/LibTests/resources']
}
}
jctfTests {
java {
srcDirs = [
'third_party/jctf/LibTests/src/com/google/jctf/test/lib',
// 'third_party/jctf/VMTests/src',
]
}
}
}
configurations {
supportLibs
}
dependencies {
compile 'net.sf.jopt-simple:jopt-simple:4.6'
compile 'com.googlecode.json-simple:json-simple:1.1.1'
compile group: 'com.google.guava', name: 'guava', version: '19.0'
compile group: 'it.unimi.dsi', name: 'fastutil', version: '7.2.0'
compile group: 'org.apache.commons', name: 'commons-compress', version: '1.12'
compile group: 'org.ow2.asm', name: 'asm', version: '5.1'
compile group: 'org.ow2.asm', name: 'asm-commons', version: '5.1'
compile group: 'org.ow2.asm', name: 'asm-tree', version: '5.1'
compile group: 'org.ow2.asm', name: 'asm-util', version: '5.1'
testCompile sourceSets.examples.output
testCompile 'junit:junit:4.12'
testCompile group: 'org.smali', name: 'smali', version: '2.2b4'
testCompile files('third_party/jasmin/jasmin-2.4.jar')
testCompile files('third_party/jdwp-tests/apache-harmony-jdwp-tests-host.jar')
jctfCommonCompile 'junit:junit:4.12'
jctfTestsCompile 'junit:junit:4.12'
jctfTestsCompile sourceSets.jctfCommon.output
examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: '5.1'
examplesCompile 'com.google.protobuf:protobuf-lite:3.0.0'
examplesRuntime 'com.google.protobuf:protobuf-lite:3.0.0'
supportLibs 'com.android.support:support-v4:25.4.0'
supportLibs 'junit:junit:4.12'
supportLibs 'com.android.support.test.espresso:espresso-core:3.0.0'
debugTestResourcesKotlinCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.1.3'
}
protobuf {
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.0.0'
}
plugins {
javalite {
artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
}
}
generateProtoTasks {
all().each { task ->
task.builtins {
// Disable the java code generator, as we want javalite only.
remove java
}
task.plugins {
javalite {}
}
}
}
}
def osString = OperatingSystem.current().isLinux() ? "linux" :
OperatingSystem.current().isMacOsX() ? "mac" : "windows"
def cloudDependencies = [
"tests" : [
"2017-07-27/art.tar.gz",
"2016-12-19/art.tar.gz"
],
"third_party": [
"android_jar/lib-v14.tar.gz",
"android_jar/lib-v19.tar.gz",
"android_jar/lib-v21.tar.gz",
"android_jar/lib-v24.tar.gz",
"android_jar/lib-v25.tar.gz",
"android_jar/lib-v26.tar.gz",
"proguard/proguard5.2.1.tar.gz",
"gradle/gradle.tar.gz",
"jdwp-tests.tar.gz",
"jasmin.tar.gz",
"jctf.tar.gz",
"kotlin.tar.gz",
"android_cts_baseline.tar.gz",
],
// All dex-vms have a fixed OS of Linux, as they are only supported on Linux, and will be run in a Docker
// container on other platforms where supported.
"tools" : [
"linux/art.tar.gz",
"linux/art-5.1.1.tar.gz",
"linux/art-6.0.1.tar.gz",
"linux/art-7.0.0.tar.gz",
"linux/dalvik.tar.gz",
"${osString}/dx.tar.gz",
]
]
cloudDependencies.each { entry ->
entry.value.each { entryFile ->
task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
def gzFile = "${entry.key}/${entryFile}"
def sha1File = "${gzFile}.sha1"
inputs.file sha1File
outputs.file gzFile
List<String> dlFromStorageArgs = ["-n", "-b", "r8-deps", "-u", "-s", "${sha1File}"]
if (OperatingSystem.current().isWindows()) {
executable "download_from_google_storage.bat"
args dlFromStorageArgs
} else {
executable "bash"
args "-c", "download_from_google_storage " + String.join(" ", dlFromStorageArgs)
}
}
}
}
def x20Dependencies = [
"third_party": [
"gmail/gmail_android_170604.16.tar.gz",
"gmscore/v4.tar.gz",
"gmscore/v5.tar.gz",
"gmscore/v6.tar.gz",
"gmscore/v7.tar.gz",
"gmscore/v8.tar.gz",
"gmscore/gmscore_v9.tar.gz",
"gmscore/gmscore_v10.tar.gz",
"gmscore/latest.tar.gz",
"photos/2017-06-06.tar.gz",
"youtube/youtube.android_12.10.tar.gz",
"youtube/youtube.android_12.17.tar.gz",
"youtube/youtube.android_12.22.tar.gz",
"proguardsettings.tar.gz",
"proguard/proguard_internal_159423826.tar.gz",
"framework.tar.gz",
"goyt.tar.gz",
],
]
x20Dependencies.each { entry ->
entry.value.each { entryFile ->
task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
def gzFile = "${entry.key}/${entryFile}"
def sha1File = "${gzFile}.sha1"
inputs.file sha1File
outputs.file gzFile
executable "bash"
args "-c", "tools/download_from_x20.py ${sha1File}"
}
}
}
task downloadProguard {
cloudDependencies.each { entry ->
entry.value.each { entryFile ->
if (entryFile.contains("proguard")) {
dependsOn "download_deps_${entry.key}/${entryFile}"
}
}
}
}
task downloadDx {
cloudDependencies.each { entry ->
entry.value.each { entryFile ->
if (entryFile.contains("dx.tar")) {
dependsOn "download_deps_${entry.key}/${entryFile}"
}
}
}
}
task downloadAndroidCts {
cloudDependencies.each { entry ->
entry.value.each { entryFile ->
if (entryFile.contains("android_cts_baseline")) {
dependsOn "download_deps_${entry.key}/${entryFile}"
}
}
}
}
task downloadDeps {
cloudDependencies.each { entry ->
entry.value.each { entryFile ->
dependsOn "download_deps_${entry.key}/${entryFile}"
}
}
if (!project.hasProperty('no_internal')) {
x20Dependencies.each { entry ->
entry.value.each { entryFile ->
dependsOn "download_deps_${entry.key}/${entryFile}"
}
}
}
}
allprojects {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked'
}
compileJctfCommonJava {
dependsOn 'copyAdditionalJctfCommonFiles'
options.compilerArgs = ['-Xlint:none']
}
compileJctfTestsJava {
dependsOn 'jctfCommonClasses'
options.compilerArgs = ['-Xlint:none']
}
task R8(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
from sourceSets.main.output
baseName 'r8'
classifier = null
version = null
manifest {
attributes 'Main-Class': 'com.android.tools.r8.R8'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps R8
if (!project.hasProperty('exclude_deps')) {
// Relocating dependencies to avoid conflicts. Keep this as precise as possible
// to avoid rewriting unrelated strings.
relocate 'com.google.common', 'com.android.tools.r8.com.google.common'
relocate 'com.google.thirdparty', 'com.android.tools.r8.com.google.thirdparty'
relocate 'joptsimple', 'com.android.tools.r8.joptsimple'
relocate 'org.apache.commons', 'com.android.tools.r8.org.apache.commons'
relocate 'org.objectweb.asm', 'com.android.tools.r8.org.objectweb.asm'
relocate 'org.junit', 'com.android.tools.r8.org.junit'
relocate 'org.hamcrest', 'com.android.tools.r8.org.hamcrest'
relocate 'org.json.simple', 'com.android.tools.r8.org.json.simple'
relocate 'it.unimi.dsi.fastutil', 'com.android.tools.r8.it.unimi.dsi.fastutil'
relocate 'junit', 'com.android.tools.r8.junit'
// Also include dependencies
configurations = [project.configurations.compile]
}
}
task D8(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
from sourceSets.main.output
baseName 'd8'
classifier = null
version = null
manifest {
attributes 'Main-Class': 'com.android.tools.r8.D8'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps D8
if (!project.hasProperty('exclude_deps')) {
// Relocating dependencies to avoid conflicts. Keep this as precise as possible
// to avoid rewriting unrelated strings.
relocate 'com.google.common', 'com.android.tools.r8.com.google.common'
relocate 'com.google.thirdparty', 'com.android.tools.r8.com.google.thirdparty'
relocate 'joptsimple', 'com.android.tools.r8.joptsimple'
relocate 'org.apache.commons', 'com.android.tools.r8.org.apache.commons'
relocate 'org.objectweb.asm', 'com.android.tools.r8.org.objectweb.asm'
relocate 'org.junit', 'com.android.tools.r8.org.junit'
relocate 'org.hamcrest', 'com.android.tools.r8.org.hamcrest'
relocate 'org.json.simple', 'com.android.tools.r8.org.json.simple'
relocate 'it.unimi.dsi.fastutil', 'com.android.tools.r8.it.unimi.dsi.fastutil'
relocate 'junit', 'com.android.tools.r8.junit'
// Also include dependencies
configurations = [project.configurations.compile]
}
}
task CompatDx(type: Jar) {
from sourceSets.main.output
baseName 'compatdx'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.compatdx.CompatDx'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps CompatDx
if (!project.hasProperty('exclude_deps')) {
// Also include dependencies
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
task D8Logger(type: Jar) {
from sourceSets.main.output
baseName 'd8logger'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.D8Logger'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps D8Logger
if (!project.hasProperty('exclude_deps')) {
// Also include dependencies
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
task disasm(type: Jar) {
from sourceSets.main.output
baseName 'disasm'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.Disassemble'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps D8
if (!project.hasProperty('exclude_deps')) {
// Also include dependencies
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
task bisect(type: Jar) {
from sourceSets.main.output
baseName 'bisect'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.bisect.Bisect'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps R8
if (!project.hasProperty('exclude_deps')) {
// Also include dependencies
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
task DexSegments(type: Jar) {
from sourceSets.main.output
baseName 'dexsegments'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.DexSegments'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps DexSegments
if (!project.hasProperty('exclude_deps')) {
// Also include dependencies
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
task ExtractMarker(type: Jar) {
from sourceSets.main.output
baseName 'extractmarker'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.ExtractMarker'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps ExtractMarker
if (!project.hasProperty('exclude_deps')) {
// Also include dependencies
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
}
task sourceJar(type: Jar, dependsOn: classes) {
classifier = 'src'
from sourceSets.main.allSource
}
task jctfCommonJar(type: Jar) {
from sourceSets.jctfCommon.output
baseName 'jctfCommon'
}
artifacts {
archives sourceJar
}
task createArtTests(type: Exec) {
def outputDir = "build/generated/test/java/com/android/tools/r8/art"
def createArtTestsScript = "tools/create_art_tests.py"
inputs.file "tests/2017-07-27/art.tar.gz"
inputs.file createArtTestsScript
outputs.dir outputDir
dependsOn downloadDeps
commandLine "python", createArtTestsScript
workingDir = projectDir
}
task createJctfTests(type: Exec) {
def outputDir = "build/generated/test/java/com/android/tools/r8/jctf"
def script = "tools/create_jctf_tests.py"
inputs.file script
outputs.dir outputDir
dependsOn downloadDeps
commandLine "python", script
workingDir = projectDir
}
compileTestJava {
dependsOn createArtTests
dependsOn createJctfTests
}
task buildDebugInfoExamplesDex {
def examplesDir = file("src/test/java")
def hostJar = "debuginfo_examples.jar"
def hostDexJar = "debuginfo_examples_dex.jar"
task "compile_debuginfo_examples"(type: JavaCompile) {
source = fileTree(dir: examplesDir, include: "com/android/tools/r8/debuginfo/*Test.java")
destinationDir = file("build/test/debuginfo_examples/classes")
classpath = sourceSets.main.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
options.compilerArgs += ["-Xlint:-options"]
}
task "jar_debuginfo_examples"(type: Jar, dependsOn: "compile_debuginfo_examples") {
archiveName = hostJar
destinationDir = file("build/test/")
from "build/test/debuginfo_examples/classes"
include "**/*.class"
}
task "dex_debuginfo_examples"(type: Exec,
dependsOn: ["jar_debuginfo_examples", "downloadDeps"]) {
if (OperatingSystem.current().isWindows()) {
executable file("tools/windows/dx/bin/dx.bat")
} else {
executable file("tools/linux/dx/bin/dx");
}
args "--dex"
args "--output=build/test/${hostDexJar}"
args "build/test/${hostJar}"
inputs.file file("build/test/${hostJar}")
outputs.file file("build/test/${hostDexJar}")
}
dependsOn dex_debuginfo_examples
}
task buildDebugTestResourcesJars {
def resourcesDir = file("src/test/debugTestResources")
def hostJar = "debug_test_resources.jar"
task "compile_debugTestResources"(type: JavaCompile) {
source = fileTree(dir: resourcesDir, include: '**/*.java')
destinationDir = file("build/test/debugTestResources/classes")
classpath = sourceSets.main.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
options.compilerArgs += ["-g", "-Xlint:-options"]
}
task "jar_debugTestResources"(type: Jar, dependsOn: "compile_debugTestResources") {
archiveName = hostJar
destinationDir = file("build/test/")
from "build/test/debugTestResources/classes"
include "**/*.class"
}
def java8ResourcesDir = file("src/test/debugTestResourcesJava8")
def java8HostJar = "debug_test_resources_java8.jar"
task "compile_debugTestResourcesJava8"(type: JavaCompile) {
source = fileTree(dir: java8ResourcesDir, include: '**/*.java')
destinationDir = file("build/test/debugTestResourcesJava8/classes")
classpath = sourceSets.main.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
options.compilerArgs += ["-g", "-Xlint:-options"]
}
task "jar_debugTestResourcesJava8"(type: Jar, dependsOn: "compile_debugTestResourcesJava8") {
archiveName = java8HostJar
destinationDir = file("build/test/")
from "build/test/debugTestResourcesJava8/classes"
include "**/*.class"
}
def kotlinResourcesDir = file("src/test/debugTestResourcesKotlin")
def kotlinHostJar = "debug_test_resources_kotlin.jar"
task "jar_debugTestResourcesKotlin"(type: Exec) {
if (OperatingSystem.current().isWindows()) {
executable file("third_party/kotlin/kotlinc/bin/kotlinc.bat")
} else {
executable file("third_party/kotlin/kotlinc/bin/kotlinc");
}
args "-include-runtime"
args "-d"
args "build/test/${kotlinHostJar}"
args fileTree(dir: kotlinResourcesDir, include: '**/*.kt')
}
dependsOn downloadDeps
dependsOn jar_debugTestResources
dependsOn jar_debugTestResourcesJava8
dependsOn jar_debugTestResourcesKotlin
}
// Proto lite generated code yields warnings when compiling with javac.
// We change the options passed to javac to ignore it.
compileExamplesJava.options.compilerArgs = ["-Xlint:none"]
task buildExampleJars {
dependsOn downloadProguard
def examplesDir = file("src/test/examples")
def protoSourceDir = file("build/generated/source/proto/examples/javalite")
def proguardScript
if (OperatingSystem.current().isWindows()) {
proguardScript = "third_party/proguard/proguard5.2.1/bin/proguard.bat"
} else {
proguardScript = "third_party/proguard/proguard5.2.1/bin/proguard.sh"
}
task extractExamplesRuntime(type: Sync) {
dependsOn configurations.examplesRuntime
from configurations.examplesRuntime.collect { zipTree(it) }
include "**/*.class"
includeEmptyDirs false
into "$buildDir/runtime/examples/"
}
task "compile_examples"(type: JavaCompile, dependsOn: "generateExamplesProto") {
source examplesDir, protoSourceDir
include "**/*.java"
destinationDir = file("build/test/examples/classes")
classpath = sourceSets.examples.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
options.compilerArgs = ["-Xlint:none"]
}
examplesDir.eachDir { dir ->
def name = dir.getName();
def exampleOutputDir = file("build/test/examples");
def jarName = "${name}.jar"
dependsOn "jar_example_${name}"
dependsOn "extractExamplesRuntime"
def runtimeDependencies = copySpec { }
if (!fileTree(dir: dir, include: '**/*.proto').empty) {
// If we have any proto use, we have to include those classes and the runtime.
runtimeDependencies = copySpec {
from "$buildDir/runtime/examples/"
include "com/google/protobuf/**/*.class"
}
}
// The "throwing" test verifies debugging/stack info on the post-proguarded output.
def proguardConfigPath = "${dir}/proguard.cfg"
if (new File(proguardConfigPath).exists()) {
task "pre_proguard_example_${name}"(type: Jar, dependsOn: "compile_examples") {
archiveName = "${name}_pre_proguard.jar"
destinationDir = exampleOutputDir
from "build/test/examples/classes"
include name + "/**/*.class"
with runtimeDependencies
includeEmptyDirs false
}
def jarPath = files(tasks.getByPath("pre_proguard_example_${name}")).files.first();
def proguardJarPath = "${exampleOutputDir}/${jarName}"
def proguardMapPath = "${exampleOutputDir}/${name}/${name}.map"
task "jar_example_${name}"(type: Exec, dependsOn: "pre_proguard_example_${name}") {
inputs.files tasks.getByPath("pre_proguard_example_${name}")
inputs.file proguardConfigPath
// Enable these to get stdout and stderr redirected to files...
// standardOutput = new FileOutputStream('proguard.stdout')
// errorOutput = new FileOutputStream('proguard.stderr')
def proguardArguments = "-verbose -dontwarn java.** -injars ${jarPath}" +
" -outjars ${proguardJarPath}" +
" -include ${proguardConfigPath}" +
" -printmapping ${proguardMapPath}"
if (OperatingSystem.current().isWindows()) {
executable "${proguardScript}"
args "${proguardArguments}"
} else {
executable "bash"
args "-c", "${proguardScript} '${proguardArguments}'"
}
outputs.file proguardJarPath
}
} else {
task "jar_example_${name}"(type: Jar, dependsOn: "compile_examples") {
archiveName = jarName
destinationDir = exampleOutputDir
from "build/test/examples/classes"
include name + "/**/*.class"
with runtimeDependencies
includeEmptyDirs false
}
}
}
}
task buildExampleAndroidNJars {
dependsOn downloadDeps
def examplesDir = file("src/test/examplesAndroidN")
task "compile_examplesAndroidN"(type: JavaCompile) {
source = fileTree(dir: examplesDir, include: '**/*.java')
destinationDir = file("build/test/examplesAndroidN/classes")
classpath = sourceSets.main.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
options.compilerArgs += ["-Xlint:-options"]
}
examplesDir.eachDir { dir ->
def name = dir.getName();
def exampleOutputDir = file("build/test/examplesAndroidN");
def jarName = "${name}.jar"
dependsOn "jar_examplesAndroidN_${name}"
task "jar_examplesAndroidN_${name}"(type: Jar, dependsOn: "compile_examplesAndroidN") {
archiveName = jarName
destinationDir = exampleOutputDir
from "build/test/examplesAndroidN/classes"
include "**/" + name + "/**/*.class"
}
}
}
task buildExampleAndroidOJars {
dependsOn downloadDeps
def examplesDir = file("src/test/examplesAndroidO")
// NOTE: we want to enable a scenario when test needs to reference some
// classes generated by legacy (1.6) Java compiler to test some specific
// behaviour. To do so we compile all the java files located in sub-directory
// called 'legacy' with Java 1.6, then compile the rest of the files with
// Java 1.8 and a reference to previously generated 1.6 classes.
// Compiling all classes in dirs 'legacy' with old Java version.
task "compile_examplesAndroidO_Legacy"(type: JavaCompile) {
source = fileTree(dir: examplesDir, include: '**/legacy/**/*.java')
destinationDir = file("build/test/examplesAndroidOLegacy/classes")
classpath = sourceSets.main.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
options.compilerArgs += ["-Xlint:-options", "-parameters"]
}
// Compiling the rest of the files as Java 1.8 code.
task "compile_examplesAndroidO"(type: JavaCompile) {
dependsOn "compile_examplesAndroidO_Legacy"
source = fileTree(dir: examplesDir, include: '**/*.java', exclude: '**/legacy/**/*.java')
destinationDir = file("build/test/examplesAndroidO/classes")
classpath = sourceSets.main.compileClasspath
classpath += files("build/test/examplesAndroidOLegacy/classes")
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
options.compilerArgs += ["-Xlint:-options", "-parameters"]
}
examplesDir.eachDir { dir ->
def name = dir.getName();
def destinationDir = file("build/test/examplesAndroidO/classes");
if (file("src/test/examplesAndroidO/" + name + "/TestGenerator.java").isFile()) {
task "generate_examplesAndroidO_${name}"(type: JavaExec,
dependsOn: "compile_examplesAndroidO") {
main = name + ".TestGenerator"
classpath = files(destinationDir, sourceSets.main.compileClasspath)
args destinationDir
}
} else {
task "generate_examplesAndroidO_${name}" () {}
}
}
examplesDir.eachDir { dir ->
def name = dir.getName();
def exampleOutputDir = file("build/test/examplesAndroidO");
def jarName = "${name}.jar"
dependsOn "jar_examplesAndroidO_${name}"
task "jar_examplesAndroidO_${name}"(type: Jar, dependsOn: ["compile_examplesAndroidO",
"generate_examplesAndroidO_${name}"]) {
archiveName = jarName
destinationDir = exampleOutputDir
from "build/test/examplesAndroidO/classes" // Java 1.8 classes
from "build/test/examplesAndroidOLegacy/classes" // Java 1.6 classes
include "**/" + name + "/**/*.class"
// Do not include generator into the test runtime jar, it is not useful.
// Otherwise, shrinking will need ASM jars.
exclude "**/TestGenerator*"
}
}
}
task buildExamples {
if (OperatingSystem.current().isMacOsX() || OperatingSystem.current().isWindows()) {
logger.lifecycle("WARNING: Testing (including building examples) is only partially supported on your " +
"platform (" + OperatingSystem.current().getName() + ").")
} else if (!OperatingSystem.current().isLinux()) {
logger.lifecycle("WARNING: Testing (including building examples) is not supported on your platform. " +
"It is fully supported on Linux and partially supported on Mac OS and Windows")
return;
}
dependsOn buildDebugTestResourcesJars
dependsOn buildExampleJars
dependsOn buildExampleAndroidNJars
dependsOn buildExampleAndroidOJars
def examplesDir = file("src/test/examples")
def noDexTests = [
"multidex",
"multidex002",
"multidex004",
]
examplesDir.eachDir { dir ->
def name = dir.getName();
if (!(name in noDexTests)) {
dependsOn "dex_example_${name}"
def exampleOutputDir = file("build/test/examples/" + name);
def dexPath = file("${exampleOutputDir}")
def debug = (name == "throwing")
if (!dexPath.exists()) {
dexPath.mkdirs()
}
task "dex_example_${name}"(type: dx.Dx, dependsOn: "jar_example_${name}") {
source = files(tasks.getByPath("jar_example_${name}")).asFileTree
destination = dexPath
debug = debug
}
}
}
}
task buildSmali {
def smaliDir = file("src/test/smali")
smaliDir.eachDirRecurse() { dir ->
def name = dir.getName();
def relativeDir = smaliDir.toPath().relativize(dir.toPath());
def smaliOutputDir = file("build/test/smali/" + relativeDir);
smaliOutputDir.mkdirs()
outputs.dir smaliOutputDir
def taskName = "smali_build_${relativeDir.toString().replace('/', '_')}"
def smaliFiles = fileTree(dir: dir, include: '*.smali')
def javaFiles = fileTree(dir: dir, include: '*.java')
def destDir = smaliOutputDir;
def destFile = destDir.toPath().resolve("${name}.dex").toFile()
def intermediateFileName = "${name}-intermediate.dex";
def intermediateFile = destDir.toPath().resolve(intermediateFileName).toFile()
if (javaFiles.empty) {
if (!smaliFiles.empty) {
dependsOn "${taskName}_smali"
task "${taskName}_smali"(type: smali.Smali) {
source = smaliFiles
destination = destFile
}
}
} else {
dependsOn "${taskName}_dexmerger"
task "${taskName}_smali"(type: smali.Smali) {
source = smaliFiles
destination = intermediateFile
}
task "${taskName}_java"(type: JavaCompile) {
source = javaFiles
destinationDir destDir
classpath = sourceSets.main.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
options.compilerArgs += ["-Xlint:-options"]
}
task "${taskName}_jar"(type: Jar, dependsOn: "${taskName}_java") {
archiveName = "Test.jar"
destinationDir = destDir
from fileTree(dir: destDir, include: 'Test.class')
}
task "${taskName}_dx"(type: dx.Dx, dependsOn: "${taskName}_jar") {
source = fileTree(dir: destDir, include: 'Test.jar')
destination = destDir
}
task "${taskName}_dexmerger"(
type: dx.DexMerger, dependsOn: ["${taskName}_dx", "${taskName}_smali"]) {
source = fileTree(dir: destDir, include: ["classes.dex", intermediateFileName])
destination = destFile
}
}
}
}
tasks.withType(Test) {
def userDefinedCoresPerFork = System.getenv('R8_GRADLE_CORES_PER_FORK')
def coresPerFork = userDefinedCoresPerFork ? userDefinedCoresPerFork.toInteger() : 3
// See https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html.
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(coresPerFork) ?: 1
forkEvery = 0
// Use the Concurrent Mark Sweep GC (CMS) to keep memory usage at a resonable level.
jvmArgs = ["-XX:+UseConcMarkSweepGC"]
if (project.hasProperty('disable_assertions')) {
enableAssertions = false
}
}
task buildPreNJdwpTestsJar(type: Jar) {
baseName = 'jdwp-tests-preN'
from zipTree('third_party/jdwp-tests/apache-harmony-jdwp-tests-host.jar')
// Exclude the classes containing java8
exclude 'org/apache/harmony/jpda/tests/jdwp/InterfaceType/*.class'
exclude 'org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault*.class'
includeEmptyDirs = false
}
task supportLibDir() {
doLast {
File dir = file("build/supportlibraries")
dir.mkdir()
}
}
configurations.supportLibs.files.each { file ->
if (file.getName().endsWith(".aar")) {
def name = "extract_"+file.getName()
task "${name}"(type: Copy) {
dependsOn supportLibDir
from zipTree(file)
into "build/supportlibraries"
eachFile { FileCopyDetails fcp ->
if (fcp.relativePath.pathString.equals("classes.jar")) {
// remap the file to the root with correct name
fcp.relativePath = new RelativePath(true, file.getName().replace(".aar", ".jar"))
} else {
fcp.exclude()
}
}
}
}
}
task supportLibList() {
configurations.supportLibs.files.each {
if (it.getName().endsWith(".aar")) {
dependsOn "extract_"+it.getName()
}
}
doLast {
file("build/generated").mkdir()
def file = file("build/generated/supportlibraries.txt")
file.createNewFile()
file.text = ""
configurations.supportLibs.files.each {
if (it.getName().endsWith(".aar")) {
def outName = it.getName().replace(".aar", ".jar")
file.text += ("build/supportlibraries/"
+ outName + "\n")
} else {
file.text += (it.getPath() + "\n")
}
}
}
}
task AospJarTest(type: Exec) {
dependsOn CompatDx, downloadDeps
def script = "tools/test_aosp_jar.py"
inputs.file script
commandLine "python", script, "--no-build"
workingDir = projectDir
}
test {
dependsOn supportLibList
testLogging.exceptionFormat = 'full'
if (project.hasProperty('print_test_stdout')) {
testLogging.showStandardStreams = true
}
if (project.hasProperty('dex_vm') && project.property('dex_vm') != 'default') {
println "Running with non default vm: " + project.property('dex_vm')
systemProperty 'dex_vm', project.property('dex_vm')
if (project.property('dex_vm') == '5.1.1' || project.property('dex_vm') == '6.0.1') {
// R8 and D8 compute the dex file version number based on the input.
// Jack generates dex files with version 37 which art 5.1.1 and 6.0.1 will not run.
// Therefore we skip the jack generated art tests with those art versions.
exclude "com/android/tools/r8/art/jack/**"
}
}
if (project.hasProperty('one_line_per_test')) {
beforeTest { desc ->
println "Start executing test ${desc.name} [${desc.className}]"
}
afterTest { desc, result ->
println "Done executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
}
}
if (project.hasProperty('no_internal')) {
exclude "com/android/tools/r8/internal/**"
}
if (project.hasProperty('only_internal')) {
include "com/android/tools/r8/internal/**"
}
if (project.hasProperty('tool')) {
if (project.property('tool') == 'r8') {
exclude "com/android/tools/r8/art/*/d8/**"
exclude "com/android/tools/r8/jctf/d8/**"
} else {
assert(project.property('tool') == 'd8')
exclude "com/android/tools/r8/art/*/r8/**"
exclude "com/android/tools/r8/jctf/r8/**"
}
}
if (!project.hasProperty('all_tests')) {
exclude "com/android/tools/r8/art/dx/**"
exclude "com/android/tools/r8/art/jack/**"
}
// TODO(tamaskenez) enable jctf on all_tests when consolidated
if (!project.hasProperty('jctf') && !project.hasProperty('only_jctf')) {
exclude "com/android/tools/r8/jctf/**"
}
if (project.hasProperty('only_jctf')) {
include "com/android/tools/r8/jctf/**"
}
if (project.hasProperty('jctf_compile_only')) {
println "JCTF: compiling only"
systemProperty 'jctf_compile_only', '1'
}
if (project.hasProperty('test_dir')) {
systemProperty 'test_dir', project.property('test_dir')
}
if (project.hasProperty('aosp_jar')) {
dependsOn AospJarTest
}
if (OperatingSystem.current().isLinux()
|| OperatingSystem.current().isMacOsX()
|| OperatingSystem.current().isWindows()) {
if (OperatingSystem.current().isMacOsX()) {
logger.lifecycle("WARNING: Testing in only partially supported on Mac OS. " +
"Art only runs on Linux and tests requiring Art runs in a Docker container, which must be present. " +
"See tools/docker/README.md for details.")
}
if (OperatingSystem.current().isWindows()) {
logger.lifecycle("WARNING: Testing in only partially supported on Windows. " +
"Art only runs on Linux and tests requiring Art will be skipped")
}
dependsOn downloadDeps
dependsOn buildExamples
dependsOn buildSmali
dependsOn jctfCommonJar
dependsOn jctfTestsClasses
dependsOn buildDebugInfoExamplesDex
dependsOn buildPreNJdwpTestsJar
} else {
logger.lifecycle("WARNING: Testing in not supported on your platform. Testing is only fully supported on " +
"Linux and partially supported on Mac OS and Windows. Art does not run on other platforms.")
}
}
// The Art tests we use for R8 are pre-build and downloaded from Google Cloud Storage.
//
// To build and upload a new set of the Art tests for use with R8 follow these steps:
//
// First of all an Android checkout is required. Currently it must be located
// in $HOME/android/master.
//
// TODO(ricow): simplify this
//
// Before: update the checked in art, see scripts/update-host-art.sh
//
// 1. Get an android checkout in $HOME/android/master and apply the patch from
// https://android-review.googlesource.com/#/c/294187/
//
// 2. run the following commands in the Android checkout directory:
//
// source build/envsetup.sh
// lunch aosp_angler-userdebug # or lunch aosp_angler-eng
// m desugar
// m -j30 test-art-host
// DESUGAR=false ANDROID_COMPILE_WITH_JACK=false art/test.py --host -t 001-HelloWorld
//
// Without running the test.py command the classes.jar file used by desugar in
// $HOME/android/master/out/host/common/obj/JAVA_LIBRARIES/core-oj-hostdex_intermediates/
// seems to be missing - there is probably also a make target to build it more directly
//
// 3. In the R8 project root directory, make sure we have a clean state before starting:
// tools/gradle.py downloadDeps
// tools/gradle.py clean
// rm -rf tests/art
//
// 4. Now build in the R8 checkout (-P hack to not generate dirs when not running this target)
// Make sure you have smali on your path, please use the build binary in the
// out/host/linux-x86/bin directory of the android checkout. Currently this is version pre 2.2.1,
// if that is updated the call to smali in "task "${smaliToDexTask}"(type: Exec)" below might
// need to change as smali got a completely new command line interface in version 2.2.1.
//
// PATH=$HOME/android/master/out/host/linux-x86/bin:$PATH tools/gradle.py -Pandroid_source buildArtTests
//
// 4a. If any failures are produced in step 4, figure out what went wrong and add an entry in
// skippedTests with an explanation. Rerun from step 3.
//
// 5. Run the tests:
// tools/gradle.py clean
// tools/test.py
//
// 5a. If any more tests fail, either fix the issue or add them to the failuresToTriage list (note
// that you need to change "_" to "-" from stdout). Rerun from step 5 if anything was added to
// failuresToTriage.
//
// 6. To upload a new version to Google Cloud Storage:
// cd tests
// upload_to_google_storage.py -a --bucket r8-deps art
//
// 7. Update the manifest file describing the Android repo used:
// repo manifest -o <r8-checkout-root>/tools/linux/aosp_master_manifest.xml -r
enum DexTool {
JACK,
DX
}
def androidCheckoutDir = file("${System.env.HOME}/android/master")
def androidCheckoutJack = file("${androidCheckoutDir}/out/host/linux-x86/bin/jack");
def androidCheckoutJackServer = file("${androidCheckoutDir}/out/host/linux-x86/bin/jack-admin");
def artTestDir = file("${androidCheckoutDir}/art/test")
if (project.hasProperty('android_source')) {
task buildArtTests {
outputs.upToDateWhen { false }
def toBeTriaged = [
"903-hello-tagging",
"904-object-allocation",
"905-object-free",
"906-iterate-heap",
"907-get-loaded-classes",
"908-gc-start-finish",
"954-invoke-polymorphic-verifier",
"955-methodhandles-smali",
"596-monitor-inflation",
]
def skippedTests = toBeTriaged + [
// This test produces no jar.
"000-nop",
// This does not build, as it tests the error when the application exceeds more
// than 65536 methods
"089-many-methods",
// Requires some jack beta jar
"956-methodhandles",
]
def skippedTestsDx = [
// Tests with custom build scripts, where javac is not passed the options
// -source 1.7 -target 1.7.
"462-checker-inlining-across-dex-files",
"556-invoke-super",
"569-checker-pattern-replacement",
// These tests use jack even when --build-with-javac-dx is specified.
"004-JniTest",
"048-reflect-v8",
"146-bad-interface",
"563-checker-invoke-super",
"580-checker-string-fact-intrinsics", // java.lang.StringFactory
"604-hot-static-interface",
"957-methodhandle-transforms",
"958-methodhandle-emulated-stackframe",
"959-invoke-polymorphic-accessors",
"961-default-iface-resolution-gen",
"962-iface-static",
"963-default-range-smali",
"964-default-iface-init-gen",
"965-default-verify",
"966-default-conflict",
"967-default-ame",
"968-default-partial-compile-gen",
"969-iface-super",
"970-iface-super-resolution-gen",
"971-iface-super",
// These tests does not build with --build-with-javac-dx
"004-NativeAllocations", // Javac error
"031-class-attributes",
"138-duplicate-classes-check",
"157-void-class", // Javac error
"580-checker-string-factory-intrinsics",
"612-jit-dex-cache",
"613-inlining-dex-cache",
"900-hello-plugin", // --experimental agents
"901-hello-ti-agent", // --experimental agents
"902-hello-transformation", // --experimental agents
"909-attach-agent", // --experimental agents
"946-obsolete-throw", // -source 1.7 -target 1.7, but use lambda
"950-redefine-intrinsic", // -source 1.7 -target 1.7, but use method references
"951-threaded-obsolete", // -source 1.7 -target 1.7, but use lambda
"960-default-smali", // --experimental default-methods
// These tests force the build to use jack
"953-invoke-polymorphic-compiler",
"958-methodhandle-stackframe",
]
def artTestBuildDir = file("${projectDir}/tests/art")
if (androidCheckoutDir.exists()) {
dependsOn downloadDeps
artTestBuildDir.mkdirs()
// Ensure Jack server is running.
"${androidCheckoutJackServer} start-server".execute()
artTestDir.eachDir { dir ->
def name = dir.getName();
def markerFile = dir.toPath().resolve("info.txt").toFile();
if (markerFile.exists() && !(name in skippedTests)) {
if (!(name in skippedTestsDx)) {
dependsOn buildArtTest(androidCheckoutDir, artTestBuildDir, dir, DexTool.DX);
}
dependsOn buildArtTest(androidCheckoutDir, artTestBuildDir, dir, DexTool.JACK);
}
}
}
doFirst {
if (!androidCheckoutDir.exists()) {
throw new InvalidUserDataException(
"This task requires an Android checkout in ${androidCheckoutDir}");
} else if (!androidCheckoutJack.exists() ||
!androidCheckoutJackServer.exists()) {
throw new InvalidUserDataException(
"This task requires that tools for host testing have been build in the " +
"Android checkout in ${androidCheckoutDir}");
}
}
doLast {
copy {
from file("${androidCheckoutDir}/out/host/linux-x86/nativetest64")
into file("${artTestBuildDir}/lib64")
include 'lib*.so'
}
copy {
from file("${androidCheckoutDir}/out/host/linux-x86/lib64")
into file("${artTestBuildDir}/lib64")
include 'libart.so'
include 'libbacktrace.so'
include 'libbase.so'
include 'libc++.so'
include 'libcutils.so'
include 'liblz4.so'
include 'liblzma.so'
include 'libnativebridge.so'
include 'libnativeloader.so'
include 'libsigchain.so'
include 'libunwind.so'
include 'libziparchive.so'
}
copy {
from file("${androidCheckoutDir}/out/host/linux-x86/nativetest")
into file("${artTestBuildDir}/lib")
include 'lib*.so'
}
copy {
from file("${androidCheckoutDir}/out/host/linux-x86/lib")
into file("${artTestBuildDir}/lib")
include 'libart.so'
include 'libbacktrace.so'
include 'libbase.so'
include 'libc++.so'
include 'libcutils.so'
include 'liblz4.so'
include 'liblzma.so'
include 'libnativebridge.so'
include 'libnativeloader.so'
include 'libsigchain.so'
include 'libunwind.so'
include 'libziparchive.so'
}
}
}
}
def buildArtTest(androidCheckoutDir, artTestBuildDir, dir, dexTool) {
def artTestDir = file("${androidCheckoutDir}/art/test")
def artRunTestScript = file("${artTestDir}/run-test")
def dxExecutable = new File("tools/linux/dx/bin/dx");
def dexMergerExecutable = Utils.dexMergerExecutable()
def dexToolName = dexTool == DexTool.DX ? "dx" : "jack"
def name = dir.getName()
def buildTask = "build_art_test_${dexToolName}_${name}"
def sanitizeTask = "sanitize_art_test_${dexToolName}_${name}"
def copyCheckTask = "copy_check_art_test_${dexToolName}_${name}"
def smaliToDexTask = "smali_to_dex_${dexToolName}_${name}"
def buildInputs = fileTree(dir: dir, include: '**/*')
def testDir = file("${artTestBuildDir}/${dexToolName}/${name}")
def outputJar = testDir.toPath().resolve("${name}.jar").toFile()
testDir.mkdirs()
if (dexTool == DexTool.DX) {
task "$buildTask"(type: Exec) {
outputs.upToDateWhen { false }
inputs.file buildInputs
executable "${artRunTestScript}"
args "--host"
args "--build-only"
args "--build-with-javac-dx"
args "--output-path", "${testDir}"
args "${name}"
environment DX: "${dxExecutable.absolutePath}"
environment DXMERGER: "${dexMergerExecutable.absolutePath}"
environment ANDROID_BUILD_TOP: "${androidCheckoutDir}"
outputs.file outputJar
}
} else {
assert dexTool == DexTool.JACK
def javaLibs = "${androidCheckoutDir}/out/host/common/obj/JAVA_LIBRARIES"
def jackClasspath = "${javaLibs}/core-libart-hostdex_intermediates/classes.jack:" +
"${javaLibs}/core-oj-hostdex_intermediates/classes.jack"
task "$buildTask"(type: Exec) {
outputs.upToDateWhen { false }
inputs.file buildInputs
executable "${artRunTestScript}"
args "--host"
args "--build-only"
args "--output-path", "${testDir}"
args "${name}"
environment JACK: "${androidCheckoutDir}/out/host/linux-x86/bin/jack"
environment JACK_CLASSPATH: jackClasspath
environment DXMERGER: "${dexMergerExecutable.absolutePath}"
environment ANDROID_BUILD_TOP: "${androidCheckoutDir}"
outputs.file outputJar
}
}
task "${sanitizeTask}"(type: Exec, dependsOn: buildTask) {
outputs.upToDateWhen { false }
executable "/bin/bash"
args "-c"
args "rm -rf ${testDir}/smali_*.dex ${testDir}/*-ex.dex ${testDir}/*-ex.jar" +
" ${testDir}/classes-ex ${testDir}/check"
}
task "${smaliToDexTask}"(type: Exec) {
workingDir "${testDir}/smali"
executable "/bin/bash"
// This is the command line options for smali prior to 2.2.1, where smali got a new
// command line interface.
args "-c", "smali a *.smali"
// This is the command line options for smali 2.2.1 and later.
// args "-c", "smali -o out.dex *.smali"
}
task "${copyCheckTask}"(type: Copy, dependsOn: sanitizeTask) {
def smali_dir = file("${dir}/smali")
outputs.upToDateWhen { false }
if (smali_dir.exists() && dexTool == DexTool.DX) {
dependsOn smaliToDexTask
}
from("${artTestDir}/${name}") {
include 'check'
}
into testDir
}
return copyCheckTask
}
task javadocD8(type: Javadoc) {
classpath = sourceSets.main.compileClasspath
source = sourceSets.main.allJava
include '**/com/android/tools/r8/BaseCommand.java'
include '**/com/android/tools/r8/BaseOutput.java'
include '**/com/android/tools/r8/CompilationException.java'
include '**/com/android/tools/r8/CompilationMode.java'
include '**/com/android/tools/r8/D8.java'
include '**/com/android/tools/r8/D8Command.java'
include '**/com/android/tools/r8/D8Output.java'
include '**/com/android/tools/r8/Resource.java'
}