blob: d0a5968cfcb418247b15bcb1c6787f79010dca43 [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 com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import net.ltgt.gradle.errorprone.ErrorProneToolChain
import org.gradle.internal.os.OperatingSystem
import tasks.GetJarsFromConfiguration
import utils.Utils
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'com.google.protobuf'
apply plugin: 'com.cookpad.android.licensetools'
apply plugin: 'net.ltgt.errorprone-base'
apply plugin: "net.ltgt.apt"
// Ensure importing into IntelliJ IDEA use the same output directories as Gradle. In tests we
// use the output path for tests (ultimately through ToolHelper.getClassPathForTests()) and
// therefore these paths need to be the same. See https://youtrack.jetbrains.com/issue/IDEA-175172
// for context.
idea {
module {
outputDir file('build/classes/main')
testOutputDir file('build/classes/test')
}
}
def errorProneConfiguration = [
'-XepDisableAllChecks',
// D8 want to use reference equality, thus disable the checker explicitly
'-Xep:ReferenceEquality:OFF',
'-Xep:ClassCanBeStatic:ERROR',
'-Xep:OperatorPrecedence:ERROR',
'-Xep:RemoveUnusedImports:ERROR',
'-Xep:MissingOverride:ERROR',
'-Xep:IntLongMath:ERROR',
'-Xep:EqualsHashCode:ERROR',
'-Xep:InconsistentOverloads:ERROR',
'-Xep:ArrayHashCode:ERROR',
'-Xep:EqualsIncompatibleType:ERROR',
'-Xep:NonOverridingEquals:ERROR',
'-Xep:FallThrough:ERROR',
'-Xep:MissingCasesInEnumSwitch:ERROR',
'-Xep:MissingDefault:ERROR',
'-Xep:MultipleTopLevelClasses:ERROR',
'-Xep:NarrowingCompoundAssignment:ERROR',
'-Xep:BoxedPrimitiveConstructor:ERROR']
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()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
classpath 'com.cookpad.android.licensetools:license-tools-plugin:0.23.0'
// TODO(ager): shadow does not support java9 class files yet. Once it does,
// we should use the offial version instead of our fork using ASM 6.0 to
// support java9.
// classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
classpath files("third_party/shadow/shadow-2.0.1.jar")
classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
classpath "net.ltgt.gradle:gradle-apt-plugin:0.12"
}
}
// Custom source set for example tests and generated tests.
sourceSets {
test {
java {
srcDirs = [
'src/test/java',
'build/generated/test/java',
]
}
}
bsPatch {
java {
srcDirs = [
'src/bspatch/java',
'src/main/java'
]
}
}
apiUsageSample {
java {
srcDirs = ['src/test/apiUsageSample']
}
output.resourcesDir = 'build/classes/apiUsageSample'
}
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'
}
examplesKotlin {
java {
srcDirs = ['src/test/examplesKotlin']
}
output.resourcesDir = 'build/classes/examplesKotlin'
}
examplesAndroidN {
java {
srcDirs = ['src/test/examplesAndroidN']
}
output.resourcesDir = 'build/classes/examplesAndroidN'
}
examplesAndroidO {
java {
srcDirs = ['src/test/examplesAndroidO']
}
output.resourcesDir = 'build/classes/examplesAndroidO'
}
examplesAndroidP {
java {
srcDirs = ['src/test/examplesAndroidP']
}
output.resourcesDir = 'build/classes/examplesAndroidP'
}
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',
]
}
}
kotlinR8TestResources {
java {
srcDirs = ['src/test/kotlinR8TestResources']
}
output.resourcesDir = 'build/classes/kotlinR8TestResources'
}
}
configurations {
supportLibs
}
dependencies {
compile 'net.sf.jopt-simple:jopt-simple:4.6'
compile 'com.googlecode.json-simple:json-simple:1.1'
// Include all of guava when compiling the code, but exclude annotations that we don't
// need from the packaging.
compileOnly('com.google.guava:guava:23.0')
compile('com.google.guava:guava:23.0', {
exclude group: 'com.google.errorprone'
exclude group: 'com.google.code.findbugs'
exclude group: 'com.google.j2objc'
exclude group: 'org.codehaus.mojo'
})
compile group: 'it.unimi.dsi', name: 'fastutil', version: '7.2.0'
compile group: 'org.ow2.asm', name: 'asm', version: '6.0'
compile group: 'org.ow2.asm', name: 'asm-commons', version: '6.0'
compile group: 'org.ow2.asm', name: 'asm-tree', version: '6.0'
compile group: 'org.ow2.asm', name: 'asm-analysis', version: '6.0'
compile group: 'org.ow2.asm', name: 'asm-util', version: '6.0'
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')
testCompile files('third_party/ddmlib/ddmlib.jar')
bsPatchCompile group: 'org.apache.commons', name: 'commons-compress', version: '1.12'
jctfCommonCompile 'junit:junit:4.12'
jctfTestsCompile 'junit:junit:4.12'
jctfTestsCompile sourceSets.jctfCommon.output
examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: '6.0'
examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: '6.0'
// Import Guava for @Nullable annotation
examplesCompile 'com.google.guava:guava:23.0'
examplesCompile 'com.google.protobuf:protobuf-lite:3.0.0'
examplesCompileOnly "com.google.auto.value:auto-value:1.5"
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'
apiUsageSampleCompile sourceSets.main.output
debugTestResourcesKotlinCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.2.0'
examplesKotlinCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.2.0'
kotlinR8TestResourcesCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.2.0'
apt 'com.google.auto.value:auto-value:1.5'
}
configurations.bsPatchCompile.extendsFrom configurations.compile
licenseTools {
licensesYaml = file('LIBRARY-LICENSE')
}
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-10-04/art",
"2016-12-19/art"
],
"third_party": [
"android_jar/lib-v14",
"android_jar/lib-v15",
"android_jar/lib-v19",
"android_jar/lib-v21",
"android_jar/lib-v22",
"android_jar/lib-v23",
"android_jar/lib-v24",
"android_jar/lib-v25",
"android_jar/lib-v26",
"proguard/proguard5.2.1",
"gradle/gradle",
"jdwp-tests",
"jasmin",
"jctf",
"kotlin",
"android_cts_baseline",
"shadow",
"ddmlib",
],
// 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",
"linux/art-5.1.1",
"linux/art-6.0.1",
"linux/art-7.0.0",
"linux/dalvik",
"linux/dalvik-4.0.4",
"${osString}/dx",
]
]
cloudDependencies.each { entry ->
entry.value.each { entryFile ->
task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
def outputDir = "${entry.key}/${entryFile}"
def gzFile = "${outputDir}.tar.gz"
def sha1File = "${gzFile}.sha1"
inputs.file sha1File
outputs.file gzFile
outputs.dir outputDir
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",
"gmscore/v4",
"gmscore/v5",
"gmscore/v6",
"gmscore/v7",
"gmscore/v8",
"gmscore/gmscore_v9",
"gmscore/gmscore_v10",
"gmscore/latest",
"photos/2017-06-06",
"youtube/youtube.android_12.10",
"youtube/youtube.android_12.17",
"youtube/youtube.android_12.22",
"proguardsettings",
"proguard/proguard_internal_159423826",
"framework",
"goyt",
],
]
x20Dependencies.each { entry ->
entry.value.each { entryFile ->
task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
def outputDir = "${entry.key}/${entryFile}"
def gzFile = "${outputDir}.tar.gz"
def sha1File = "${gzFile}.sha1"
inputs.file sha1File
outputs.file gzFile
outputs.dir outputDir
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.endsWith("/dx")) {
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'
}
if (!project.hasProperty('without_error_prone')) {
compileJava {
// Enable error prone for D8/R8 sources.
toolChain ErrorProneToolChain.create(project)
options.compilerArgs += errorProneConfiguration
}
}
compileJctfCommonJava {
dependsOn 'copyAdditionalJctfCommonFiles'
options.compilerArgs = ['-Xlint:none']
}
compileJctfTestsJava {
dependsOn 'jctfCommonClasses'
options.compilerArgs = ['-Xlint:none']
}
task consolidatedLicense {
// checkLicenses verifies that the list of libraries referenced in 'LIBRARY-LICENSE' is
// corresponding to the effective list of embedded libraries.
dependsOn 'checkLicenses'
def license = new File(new File(buildDir, 'generatedLicense'), 'LICENSE')
inputs.files files('LICENSE', 'LIBRARY-LICENSE') + fileTree(dir: 'library-licensing')
outputs.files license
doLast {
license.getParentFile().mkdirs()
license.createNewFile()
license.text = "This file lists all licenses for code distributed.\n"
license.text += "All non-library code has the following 3-Clause BSD license.\n"
license.text += "\n"
license.text += "\n"
license.text += file('LICENSE').text
license.text += "\n"
license.text += "\n"
license.text += "Summary of distributed libraries:\n"
license.text += "\n"
license.text += file('LIBRARY-LICENSE').text
license.text += "\n"
license.text += "\n"
license.text += "Licenses details:\n"
fileTree(dir: 'library-licensing').getFiles().stream().sorted().forEach { file ->
license.text += "\n"
license.text += "\n"
license.text += file.text
}
}
}
static configureRelocations(ShadowJar task) {
task.relocate('com.google.common', 'com.android.tools.r8.com.google.common')
task.relocate('com.google.thirdparty', 'com.android.tools.r8.com.google.thirdparty')
task.relocate('joptsimple', 'com.android.tools.r8.joptsimple')
task.relocate('org.apache.commons', 'com.android.tools.r8.org.apache.commons')
task.relocate('org.objectweb.asm', 'com.android.tools.r8.org.objectweb.asm')
task.relocate('org.json.simple', 'com.android.tools.r8.org.json.simple')
task.relocate('it.unimi.dsi.fastutil', 'com.android.tools.r8.it.unimi.dsi.fastutil')
}
task repackageDeps(type: ShadowJar) {
configurations = [project.configurations.compile]
configureRelocations(it)
baseName 'deps'
}
task repackageSources(type: ShadowJar) {
from sourceSets.main.output
configureRelocations(it)
baseName 'sources'
}
task R8(type: ShadowJar) {
from consolidatedLicense.outputs.files
exclude { path ->
path.getRelativePath().getPathString().startsWith("META-INF")
}
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')) {
from repackageSources.outputs.files
from repackageDeps.outputs.files
} else {
from sourceSets.main.output
}
}
task D8(type: ShadowJar) {
from consolidatedLicense.outputs.files
exclude { path ->
path.getRelativePath().getPathString().startsWith("META-INF")
}
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')) {
from repackageSources.outputs.files
from repackageDeps.outputs.files
} else {
from sourceSets.main.output
}
}
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 DexFileMerger(type: Jar) {
from sourceSets.main.output
baseName 'dexfilemerger'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.dexfilemerger.DexFileMerger'
}
// 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 CompatProguard(type: Jar) {
from sourceSets.main.output
baseName 'compatproguard'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.compatproguard.CompatProguard'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps CompatProguard
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 maindex(type: Jar) {
from sourceSets.main.output
baseName 'maindex'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.GenerateMainDexList'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps maindex
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 bspatch(type: Jar) {
from sourceSets.bsPatch.output
baseName 'bspatch'
manifest {
attributes 'Main-Class': 'com.android.tools.r8.dex.BSPatch'
}
// In order to build without dependencies, pass the exclude_deps property using:
// gradle -Pexclude_deps maindex
if (!project.hasProperty('exclude_deps')) {
// Also include dependencies
from {
configurations.bsPatchCompile.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-10-04/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 buildD8ApiUsageSample(type: Jar) {
from sourceSets.apiUsageSample.output
baseName 'd8_api_usage_sample'
destinationDir file('tests')
}
task buildR8ApiUsageSample(type: Jar) {
from sourceSets.apiUsageSample.output
baseName 'r8_api_usage_sample'
destinationDir file('tests')
}
task buildApiSampleJars {
dependsOn buildD8ApiUsageSample
dependsOn buildR8ApiUsageSample
}
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 if (OperatingSystem.current().isMacOsX()) {
executable file("tools/mac/dx/bin/dx");
} 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: kotlin.Kotlinc) {
source = fileTree(dir: kotlinResourcesDir, include: '**/*.kt')
destination = file("build/test/${kotlinHostJar}")
}
dependsOn downloadDeps
dependsOn jar_debugTestResources
dependsOn jar_debugTestResourcesJava8
dependsOn jar_debugTestResourcesKotlin
}
task buildExampleKotlinJars {
def kotlinSrcDir = file("src/test/examplesKotlin")
kotlinSrcDir.eachDir { dir ->
def name = dir.getName();
dependsOn "compile_example_kotlin_${name}"
task "compile_example_kotlin_${name}"(type: kotlin.Kotlinc) {
source = fileTree(dir: file("src/test/examplesKotlin/${name}"), include: '**/*.kt')
destination = file("build/test/examplesKotlin/${name}.jar")
}
}
}
// 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 = ["-g:source,lines", "-Xlint:none"]
}
task "compile_examples_debuginfo_all"(type: JavaCompile, dependsOn: "generateExamplesProto") {
source examplesDir, protoSourceDir
include "**/*.java"
destinationDir = file("build/test/examples/classes_debuginfo_all")
classpath = sourceSets.examples.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
options.compilerArgs = ["-g", "-Xlint:none"]
}
task "compile_examples_debuginfo_none"(type: JavaCompile, dependsOn: "generateExamplesProto") {
source examplesDir, protoSourceDir
include "**/*.java"
destinationDir = file("build/test/examples/classes_debuginfo_none")
classpath = sourceSets.examples.compileClasspath
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
options.compilerArgs = ["-g:none", "-Xlint:none"]
}
examplesDir.eachDir { dir ->
def name = dir.getName();
def exampleOutputDir = file("build/test/examples");
def jarName = "${name}.jar"
dependsOn "jar_example_${name}"
dependsOn "jar_example_${name}_debuginfo_all"
dependsOn "jar_example_${name}_debuginfo_none"
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
}
// TODO: Consider performing distinct proguard compilations.
task "jar_example_${name}_debuginfo_all"(type: Copy, dependsOn: "jar_example_${name}") {
from "${exampleOutputDir}/${name}.jar"
into "${exampleOutputDir}"
rename(".*", "${name}_debuginfo_all.jar")
}
task "jar_example_${name}_debuginfo_none"(type: Copy, dependsOn: "jar_example_${name}") {
from "${exampleOutputDir}/${name}.jar"
into "${exampleOutputDir}"
rename(".*", "${name}_debuginfo_none.jar")
}
} else {
task "jar_example_${name}"(type: Jar, dependsOn: "compile_examples") {
archiveName = "${name}.jar"
destinationDir = exampleOutputDir
from "build/test/examples/classes"
include name + "/**/*.class"
with runtimeDependencies
includeEmptyDirs false
}
task "jar_example_${name}_debuginfo_all"(type: Jar, dependsOn: "compile_examples_debuginfo_all") {
archiveName = "${name}_debuginfo_all.jar"
destinationDir = exampleOutputDir
from "build/test/examples/classes_debuginfo_all"
include name + "/**/*.class"
with runtimeDependencies
includeEmptyDirs false
}
task "jar_example_${name}_debuginfo_none"(type: Jar, dependsOn: "compile_examples_debuginfo_none") {
archiveName = "${name}_debuginfo_none.jar"
destinationDir = exampleOutputDir
from "build/test/examples/classes_debuginfo_none"
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 buildExampleAndroidPJars {
dependsOn downloadDeps
def examplesDir = file("src/test/examplesAndroidP")
task "compile_examplesAndroidP"(type: JavaCompile) {
source = fileTree(dir: examplesDir, include: '**/*.java')
destinationDir = file("build/test/examplesAndroidP/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 destinationDir = file("build/test/examplesAndroidP/classes");
if (file("src/test/examplesAndroidP/" + name + "/TestGenerator.java").isFile()) {
task "generate_examplesAndroidP_${name}"(type: JavaExec,
dependsOn: "compile_examplesAndroidP") {
main = name + ".TestGenerator"
classpath = files(destinationDir, sourceSets.main.compileClasspath)
args destinationDir
}
} else {
task "generate_examplesAndroidP_${name}" () {}
}
}
examplesDir.eachDir { dir ->
def name = dir.getName();
def exampleOutputDir = file("build/test/examplesAndroidP");
def jarName = "${name}.jar"
dependsOn "jar_examplesAndroidP_${name}"
task "jar_examplesAndroidP_${name}"(type: Jar,
dependsOn: ["compile_examplesAndroidP",
"generate_examplesAndroidP_${name}"]) {
archiveName = jarName
destinationDir = exampleOutputDir
from "build/test/examplesAndroidP/classes" // Java 1.8 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 buildExampleJava9Jars {
def examplesDir = file("src/test/examplesJava9")
examplesDir.eachDir { dir ->
def name = dir.getName();
def exampleOutputDir = file("build/test/examplesJava9");
def jarName = "${name}.jar"
dependsOn "jar_examplesJava9_${name}"
task "jar_examplesJava9_${name}"(type: Jar) {
archiveName = jarName
destinationDir = exampleOutputDir
from "src/test/examplesJava9" // Java 1.9 classes
include "**/" + name + "/**/*.class"
}
}
}
task buildExamplesKotlin {
if (OperatingSystem.current().isMacOsX() || OperatingSystem.current().isWindows()) {
logger.lifecycle("WARNING: Testing (including building kotlin examples) is only partially" +
" supported on your platform (" + OperatingSystem.current().getName() + ").")
} else if (!OperatingSystem.current().isLinux()) {
logger.lifecycle("WARNING: Testing (including building kotlin examples) is not supported " +
"on your platform. It is fully supported on Linux and partially supported on " +
"Mac OS and Windows")
return;
}
def examplesDir = file("src/test/examplesKotlin")
examplesDir.eachDir { dir ->
def name = dir.getName();
dependsOn "dex_example_kotlin_${name}"
def exampleOutputDir = file("build/test/examplesKotlin/" + name);
def dexPath = file("${exampleOutputDir}")
task "dex_example_kotlin_${name}"(type: dx.Dx,
dependsOn: "compile_example_kotlin_${name}") {
doFirst {
if (!dexPath.exists()) {
dexPath.mkdirs()
}
}
source = files(tasks.getByPath("compile_example_kotlin_${name}")).asFileTree
destination = dexPath
debug = false
}
}
}
task buildKotlinR8TestResources {
def examplesDir = file("src/test/kotlinR8TestResources")
examplesDir.eachDir { dir ->
def name = dir.getName()
def taskName = "jar_kotlinR8TestResources_${name}"
task "${taskName}"(type: kotlin.Kotlinc) {
source = fileTree(dir: file("${examplesDir}/${name}"), include: '**/*.kt')
destination = file("build/test/kotlinR8TestResources/${name}.jar")
}
dependsOn taskName
}
}
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
dependsOn buildExampleAndroidPJars
dependsOn buildExampleJava9Jars
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 buildPreNJdwpTestsDex(type: Exec, dependsOn: "buildPreNJdwpTestsJar") {
def inFile = buildPreNJdwpTestsJar.archivePath
def outFile = new File(buildPreNJdwpTestsJar.destinationDir, buildPreNJdwpTestsJar.baseName + '-dex.jar')
inputs.file inFile
outputs.file outFile
if (OperatingSystem.current().isWindows()) {
executable file("tools/windows/dx/bin/dx.bat")
} else if (OperatingSystem.current().isMacOsX()) {
executable file("tools/mac/dx/bin/dx");
} else {
executable file("tools/linux/dx/bin/dx");
}
args "--dex"
args "--output=${outFile}"
args inFile
}
task getJarsFromSupportLibs(type: GetJarsFromConfiguration) {
setConfiguration(configurations.supportLibs)
}
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 getJarsFromSupportLibs
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').startsWith('4.4.4') ||
project.property('dex_vm').startsWith('5.1.1') ||
project.property('dex_vm').startsWith('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 buildExamplesKotlin
dependsOn buildKotlinR8TestResources
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.
// After Android O, Jack is no longer alive, do not forget to uncomment call to buildArtTest for
// Jack if you build an android version using Jack.
//
// 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);
}
// After Android O, Jack is no longer alive
//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) {
// Directory that contains smali files is either smali, or smali/art
def smali_dir = file("${dir}/smali/art")
if (smali_dir.exists()) {
workingDir "${testDir}/smali/art"
} else {
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) {
title "D8 API"
classpath = sourceSets.main.compileClasspath
source = sourceSets.main.allJava
include '**/com/android/tools/r8/ArchiveClassFileProvider.java'
include '**/com/android/tools/r8/ArchiveProgramResourceProvider.java'
include '**/com/android/tools/r8/BaseCommand.java'
include '**/com/android/tools/r8/BaseCompilerCommand.java'
include '**/com/android/tools/r8/ClassFileResourceProvider.java'
include '**/com/android/tools/r8/CompilationFailedException.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/DexIndexedConsumer.java'
include '**/com/android/tools/r8/DexFilePerClassFileConsumer.java'
include '**/com/android/tools/r8/Diagnostic.java'
include '**/com/android/tools/r8/DiagnosticsHandler.java'
include '**/com/android/tools/r8/DirectoryClassFileProvider.java'
include '**/com/android/tools/r8/OutputMode.java'
include '**/com/android/tools/r8/ProgramConsumer.java'
include '**/com/android/tools/r8/ProgramResource.java'
include '**/com/android/tools/r8/ProgramResourceProvider.java'
include '**/com/android/tools/r8/Resource.java'
include '**/com/android/tools/r8/ResourceException.java'
include '**/com/android/tools/r8/StringConsumer.java'
include '**/com/android/tools/r8/StringResource.java'
include '**/com/android/tools/r8/Version.java'
include '**/com/android/tools/r8/origin/*.java'
}
task javadocR8(type: Javadoc) {
title "R8 API"
classpath = sourceSets.main.compileClasspath
source = sourceSets.main.allJava
include '**/com/android/tools/r8/ArchiveClassFileProvider.java'
include '**/com/android/tools/r8/ArchiveProgramResourceProvider.java'
include '**/com/android/tools/r8/BaseCommand.java'
include '**/com/android/tools/r8/BaseCompilerCommand.java'
include '**/com/android/tools/r8/ClassFileConsumer.java'
include '**/com/android/tools/r8/ClassFileResourceProvider.java'
include '**/com/android/tools/r8/CompilationFailedException.java'
include '**/com/android/tools/r8/CompilationMode.java'
include '**/com/android/tools/r8/R8.java'
include '**/com/android/tools/r8/R8Command.java'
include '**/com/android/tools/r8/DexIndexedConsumer.java'
include '**/com/android/tools/r8/Diagnostic.java'
include '**/com/android/tools/r8/DiagnosticsHandler.java'
include '**/com/android/tools/r8/DirectoryClassFileProvider.java'
include '**/com/android/tools/r8/OutputMode.java'
include '**/com/android/tools/r8/ProgramConsumer.java'
include '**/com/android/tools/r8/ProgramResource.java'
include '**/com/android/tools/r8/ProgramResourceProvider.java'
include '**/com/android/tools/r8/Resource.java'
include '**/com/android/tools/r8/ResourceException.java'
include '**/com/android/tools/r8/StringConsumer.java'
include '**/com/android/tools/r8/StringResource.java'
include '**/com/android/tools/r8/Version.java'
include '**/com/android/tools/r8/origin/*.java'
}
task copyMavenDeps(type: Copy) {
from configurations.compile into "$buildDir/deps"
from configurations.testCompile into "$buildDir/deps"
}
// This task allows to build class files from Java 9 source in order to use them as inputs of
// D8/R8 tests. Class files are generated in the same place than source files and must be commited
// to the D8 repository because there is no way to generate them on all computers due to the need of
// Java 9.
// Use the following command to rebuild class files of tests:
// ./tools/gradle.py -Pjava9Home=<java 9 home> buildJava9Tests
task buildJava9Tests {
def javacOutputFolder = getTemporaryDir();
def examplesDir = file("src/test/examplesJava9")
task "compile_Java9examples"(type: JavaCompile) {
doFirst {
if (!project.hasProperty('java9Home') || project.property('java9Home').isEmpty()) {
throw new GradleException("Set java9Home property.")
}
}
source = fileTree(dir: examplesDir, include: '**/*.java')
destinationDir = javacOutputFolder
classpath = sourceSets.main.compileClasspath
options.compilerArgs += ["-Xlint:-options"]
sourceCompatibility = JavaVersion.VERSION_1_9
targetCompatibility = JavaVersion.VERSION_1_9
options.fork = true
if (project.hasProperty('java9Home')) {
options.forkOptions.javaHome = file(getProperty('java9Home'))
}
doLast {
def classfileFrom = copySpec {
from javacOutputFolder
include "**/*.class"
}
copy {
into examplesDir
with classfileFrom
}
delete javacOutputFolder
}
}
dependsOn compile_Java9examples
}