• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4import org.gradle.internal.os.OperatingSystem
5import utils.Utils
6
7apply plugin: 'java'
8apply plugin: 'idea'
9apply plugin: 'jacoco'
10apply plugin: 'com.google.protobuf'
11
12apply from: 'copyAdditionalJctfCommonFiles.gradle'
13
14repositories {
15    mavenCentral()
16}
17
18buildscript {
19    repositories {
20        mavenCentral()
21    }
22    dependencies {
23        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
24    }
25}
26
27// Custom source set for example tests and generated tests.
28sourceSets {
29    test {
30        java {
31            srcDirs = [
32                'src/test/java',
33                'build/generated/test/java',
34            ]
35        }
36    }
37    debugTestResources {
38        java {
39            srcDirs = ['src/test/debugTestResources']
40        }
41        output.resourcesDir = 'build/classes/debugTestResources'
42    }
43    debugTestResourcesJava8 {
44        java {
45            srcDirs = ['src/test/debugTestResourcesJava8']
46        }
47        output.resourcesDir = 'build/classes/debugTestResourcesJava8'
48    }
49    examples {
50        java {
51            srcDirs = ['src/test/examples', 'build/generated/source/proto/examples/javalite/' ]
52        }
53        proto {
54            srcDirs = [
55                    'src/test/examples',
56            ]
57        }
58        output.resourcesDir = 'build/classes/examples'
59    }
60    examplesAndroidN {
61        java {
62            srcDirs = ['src/test/examplesAndroidN']
63        }
64        output.resourcesDir = 'build/classes/examplesAndroidN'
65    }
66    examplesAndroidO {
67        java {
68            srcDirs = ['src/test/examplesAndroidO']
69        }
70        output.resourcesDir = 'build/classes/examplesAndroidO'
71    }
72    jctfCommon {
73        java {
74            srcDirs = [
75                'third_party/jctf/Harness/src',
76                'third_party/jctf/LibTests/src/com/google/jctf/test/categories',
77                'third_party/jctf/LibTests/src/com/google/jctf/test/helper',
78                'third_party/jctf/LibTests/src/com/google/jctf/testHelpers',
79                'third_party/jctf/LibTests/src/org',
80                'build/additionalJctfCommonFiles'
81            ]
82        }
83        resources {
84            srcDirs = ['third_party/jctf/LibTests/resources']
85        }
86    }
87    jctfTests {
88        java {
89            srcDirs = [
90                'third_party/jctf/LibTests/src/com/google/jctf/test/lib',
91                // 'third_party/jctf/VMTests/src',
92            ]
93        }
94    }
95}
96
97dependencies {
98    compile 'net.sf.jopt-simple:jopt-simple:4.6'
99    compile group: 'com.google.guava', name: 'guava', version: '19.0'
100    compile group: 'it.unimi.dsi', name: 'fastutil', version: '7.2.0'
101    compile group: 'org.apache.commons', name: 'commons-compress', version: '1.12'
102    compile group: 'org.ow2.asm', name: 'asm', version: '5.1'
103    compile group: 'org.ow2.asm', name: 'asm-commons', version: '5.1'
104    compile group: 'org.ow2.asm', name: 'asm-tree', version: '5.1'
105    compile group: 'org.ow2.asm', name: 'asm-util', version: '5.1'
106    testCompile sourceSets.examples.output
107    testCompile 'junit:junit:4.12'
108    testCompile group: 'org.smali', name: 'smali', version: '2.2b4'
109    testCompile files('third_party/jasmin/jasmin-2.4.jar')
110    testCompile files('third_party/jdwp-tests/apache-harmony-jdwp-tests-host.jar')
111    jctfCommonCompile 'junit:junit:4.12'
112    jctfTestsCompile 'junit:junit:4.12'
113    jctfTestsCompile sourceSets.jctfCommon.output
114    examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: '5.1'
115    examplesCompile 'com.google.protobuf:protobuf-lite:3.0.0'
116    examplesRuntime 'com.google.protobuf:protobuf-lite:3.0.0'
117}
118
119protobuf {
120    protoc {
121        // Download from repositories
122        artifact = 'com.google.protobuf:protoc:3.0.0'
123    }
124    plugins {
125        javalite {
126            artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
127        }
128    }
129    generateProtoTasks {
130        all().each { task ->
131            task.builtins {
132                // Disable the java code generator, as we want javalite only.
133                remove java
134            }
135            task.plugins {
136                javalite {}
137            }
138        }
139    }
140}
141
142def osString = OperatingSystem.current().isLinux() ? "linux" :
143        OperatingSystem.current().isMacOsX() ? "mac" : "windows"
144
145def cloudDependencies = [
146        "tests"      : [
147                "2017-07-07/art.tar.gz",
148                "2016-12-19/art.tar.gz"
149        ],
150        "third_party": [
151                "android_jar/lib-v14.tar.gz",
152                "android_jar/lib-v19.tar.gz",
153                "android_jar/lib-v21.tar.gz",
154                "android_jar/lib-v24.tar.gz",
155                "android_jar/lib-v25.tar.gz",
156                "android_jar/lib-v26.tar.gz",
157                "proguard/proguard5.2.1.tar.gz",
158                "gradle/gradle.tar.gz",
159                "jdwp-tests.tar.gz",
160                "jasmin.tar.gz",
161                "jctf.tar.gz",
162                "android_cts_baseline.tar.gz",
163        ],
164        // All dex-vms have a fixed OS of Linux, as they are only supported on Linux, and will be run in a Docker
165        // container on other platforms where supported.
166        "tools"      : [
167                "linux/art.tar.gz",
168                "linux/art-5.1.1.tar.gz",
169                "linux/art-6.0.1.tar.gz",
170                "linux/art-7.0.0.tar.gz",
171                "linux/dalvik.tar.gz",
172                "${osString}/dx.tar.gz",
173        ]
174]
175
176cloudDependencies.each { entry ->
177    entry.value.each { entryFile ->
178        task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
179            def gzFile = "${entry.key}/${entryFile}"
180            def sha1File = "${gzFile}.sha1"
181            inputs.file sha1File
182            outputs.file gzFile
183            List<String> dlFromStorageArgs = ["-n", "-b", "r8-deps", "-u", "-s", "${sha1File}"]
184            if (OperatingSystem.current().isWindows()) {
185                executable "download_from_google_storage.bat"
186                args dlFromStorageArgs
187            } else {
188                executable "bash"
189                args "-c", "download_from_google_storage " + String.join(" ", dlFromStorageArgs)
190            }
191        }
192    }
193}
194
195def x20Dependencies = [
196    "third_party": [
197        "gmail/gmail_android_170604.16.tar.gz",
198        "gmscore/v4.tar.gz",
199        "gmscore/v5.tar.gz",
200        "gmscore/v6.tar.gz",
201        "gmscore/v7.tar.gz",
202        "gmscore/v8.tar.gz",
203        "gmscore/gmscore_v9.tar.gz",
204        "gmscore/gmscore_v10.tar.gz",
205        "gmscore/latest.tar.gz",
206        "photos/2017-06-06.tar.gz",
207        "youtube/youtube.android_12.10.tar.gz",
208        "youtube/youtube.android_12.17.tar.gz",
209        "youtube/youtube.android_12.22.tar.gz",
210        "proguardsettings.tar.gz",
211        "proguard/proguard_internal_159423826.tar.gz",
212        "framework.tar.gz",
213        "goyt.tar.gz",
214    ],
215]
216
217x20Dependencies.each { entry ->
218    entry.value.each { entryFile ->
219        task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
220            def gzFile = "${entry.key}/${entryFile}"
221            def sha1File = "${gzFile}.sha1"
222            inputs.file sha1File
223            outputs.file gzFile
224            executable "bash"
225            args "-c", "tools/download_from_x20.py ${sha1File}"
226        }
227    }
228}
229
230task downloadProguard {
231    cloudDependencies.each { entry ->
232        entry.value.each { entryFile ->
233            if (entryFile.contains("proguard")) {
234                dependsOn "download_deps_${entry.key}/${entryFile}"
235            }
236        }
237    }
238}
239
240task downloadDx {
241    cloudDependencies.each { entry ->
242        entry.value.each { entryFile ->
243            if (entryFile.contains("dx.tar")) {
244                dependsOn "download_deps_${entry.key}/${entryFile}"
245            }
246        }
247    }
248}
249
250task downloadAndroidCts {
251    cloudDependencies.each { entry ->
252        entry.value.each { entryFile ->
253            if (entryFile.contains("android_cts_baseline")) {
254                dependsOn "download_deps_${entry.key}/${entryFile}"
255            }
256        }
257    }
258}
259
260task downloadDeps {
261    cloudDependencies.each { entry ->
262        entry.value.each { entryFile ->
263            dependsOn "download_deps_${entry.key}/${entryFile}"
264        }
265    }
266    if (!project.hasProperty('no_internal')) {
267        x20Dependencies.each { entry ->
268            entry.value.each { entryFile ->
269                dependsOn "download_deps_${entry.key}/${entryFile}"
270            }
271        }
272    }
273}
274
275allprojects {
276    sourceCompatibility = JavaVersion.VERSION_1_8
277    targetCompatibility = JavaVersion.VERSION_1_8
278}
279
280tasks.withType(JavaCompile) {
281    options.compilerArgs << '-Xlint:unchecked'
282}
283
284compileJctfCommonJava {
285    dependsOn 'copyAdditionalJctfCommonFiles'
286    options.compilerArgs = ['-Xlint:none']
287}
288
289compileJctfTestsJava {
290    dependsOn 'jctfCommonClasses'
291    options.compilerArgs = ['-Xlint:none']
292}
293
294task R8(type: Jar) {
295    from sourceSets.main.output
296    baseName 'r8'
297    manifest {
298        attributes 'Main-Class': 'com.android.tools.r8.R8'
299    }
300    // In order to build without dependencies, pass the exclude_deps property using:
301    // gradle -Pexclude_deps R8
302    if (!project.hasProperty('exclude_deps')) {
303        // Also include dependencies
304        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
305    }
306}
307
308task D8(type: Jar) {
309    from sourceSets.main.output
310    baseName 'd8'
311    manifest {
312      attributes 'Main-Class': 'com.android.tools.r8.D8'
313    }
314    // In order to build without dependencies, pass the exclude_deps property using:
315    // gradle -Pexclude_deps D8
316    if (!project.hasProperty('exclude_deps')) {
317        // Also include dependencies
318        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
319    }
320}
321
322task CompatDx(type: Jar) {
323    from sourceSets.main.output
324    baseName 'compatdx'
325    manifest {
326      attributes 'Main-Class': 'com.android.tools.r8.compatdx.CompatDx'
327    }
328    // In order to build without dependencies, pass the exclude_deps property using:
329    // gradle -Pexclude_deps CompatDx
330    if (!project.hasProperty('exclude_deps')) {
331        // Also include dependencies
332        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
333    }
334}
335
336task D8Logger(type: Jar) {
337    from sourceSets.main.output
338    baseName 'd8logger'
339    manifest {
340      attributes 'Main-Class': 'com.android.tools.r8.D8Logger'
341    }
342    // In order to build without dependencies, pass the exclude_deps property using:
343    // gradle -Pexclude_deps D8Logger
344    if (!project.hasProperty('exclude_deps')) {
345        // Also include dependencies
346        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
347    }
348}
349
350task disasm(type: Jar) {
351    from sourceSets.main.output
352    baseName 'disasm'
353    manifest {
354        attributes 'Main-Class': 'com.android.tools.r8.Disassemble'
355    }
356    // In order to build without dependencies, pass the exclude_deps property using:
357    // gradle -Pexclude_deps D8
358    if (!project.hasProperty('exclude_deps')) {
359        // Also include dependencies
360        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
361    }
362}
363
364task bisect(type: Jar) {
365    from sourceSets.main.output
366    baseName 'bisect'
367    manifest {
368      attributes 'Main-Class': 'com.android.tools.r8.bisect.Bisect'
369    }
370    // In order to build without dependencies, pass the exclude_deps property using:
371    // gradle -Pexclude_deps R8
372    if (!project.hasProperty('exclude_deps')) {
373        // Also include dependencies
374        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
375    }
376}
377
378task DexSegments(type: Jar) {
379    from sourceSets.main.output
380    baseName 'dexsegments'
381    manifest {
382      attributes 'Main-Class': 'com.android.tools.r8.DexSegments'
383    }
384    // In order to build without dependencies, pass the exclude_deps property using:
385    // gradle -Pexclude_deps DexSegments
386    if (!project.hasProperty('exclude_deps')) {
387        // Also include dependencies
388        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
389    }
390}
391
392task sourceJar(type: Jar, dependsOn: classes) {
393    classifier = 'src'
394    from sourceSets.main.allSource
395}
396
397task jctfCommonJar(type: Jar) {
398    from sourceSets.jctfCommon.output
399    baseName 'jctfCommon'
400}
401
402artifacts {
403    archives sourceJar
404}
405
406task createArtTests(type: Exec) {
407    def outputDir = "build/generated/test/java/com/android/tools/r8/art"
408    def createArtTestsScript = "tools/create_art_tests.py"
409    inputs.file "tests/2017-07-07/art.tar.gz"
410    inputs.file createArtTestsScript
411    outputs.dir outputDir
412    dependsOn downloadDeps
413    commandLine "python", createArtTestsScript
414    workingDir = projectDir
415}
416
417task createJctfTests(type: Exec) {
418    def outputDir = "build/generated/test/java/com/android/tools/r8/jctf"
419    def script = "tools/create_jctf_tests.py"
420    inputs.file script
421    outputs.dir outputDir
422    dependsOn downloadDeps
423    commandLine "python", script
424    workingDir = projectDir
425}
426
427compileTestJava {
428    dependsOn createArtTests
429    dependsOn createJctfTests
430}
431
432task buildDebugInfoExamplesDex {
433    def examplesDir = file("src/test/java")
434    def hostJar = "debuginfo_examples.jar"
435    def hostDexJar = "debuginfo_examples_dex.jar"
436    task "compile_debuginfo_examples"(type: JavaCompile) {
437        source = fileTree(dir: examplesDir, include: "com/android/tools/r8/debuginfo/*Test.java")
438        destinationDir = file("build/test/debuginfo_examples/classes")
439        classpath = sourceSets.main.compileClasspath
440        sourceCompatibility = JavaVersion.VERSION_1_7
441        targetCompatibility = JavaVersion.VERSION_1_7
442        options.compilerArgs += ["-Xlint:-options"]
443    }
444    task "jar_debuginfo_examples"(type: Jar, dependsOn: "compile_debuginfo_examples") {
445        archiveName = hostJar
446        destinationDir = file("build/test/")
447        from "build/test/debuginfo_examples/classes"
448        include "**/*.class"
449    }
450    task "dex_debuginfo_examples"(type: Exec,
451            dependsOn: ["jar_debuginfo_examples", "downloadDeps"]) {
452        if (OperatingSystem.current().isWindows()) {
453            executable file("tools/windows/dx/bin/dx.bat")
454        } else {
455            executable file("tools/linux/dx/bin/dx");
456        }
457        args "--dex"
458        args "--output=build/test/${hostDexJar}"
459        args "build/test/${hostJar}"
460        inputs.file file("build/test/${hostJar}")
461        outputs.file file("build/test/${hostDexJar}")
462    }
463    dependsOn dex_debuginfo_examples
464}
465
466task buildDebugTestResourcesJars {
467    def resourcesDir = file("src/test/debugTestResources")
468    def hostJar = "debug_test_resources.jar"
469    task "compile_debugTestResources"(type: JavaCompile) {
470        source = fileTree(dir: resourcesDir, include: '**/*.java')
471        destinationDir = file("build/test/debugTestResources/classes")
472        classpath = sourceSets.main.compileClasspath
473        sourceCompatibility = JavaVersion.VERSION_1_7
474        targetCompatibility = JavaVersion.VERSION_1_7
475        options.compilerArgs += ["-g", "-Xlint:-options"]
476    }
477    task "jar_debugTestResources"(type: Jar, dependsOn: "compile_debugTestResources") {
478        archiveName = hostJar
479        destinationDir = file("build/test/")
480        from "build/test/debugTestResources/classes"
481        include "**/*.class"
482    }
483    def java8ResourcesDir = file("src/test/debugTestResourcesJava8")
484    def java8HostJar = "debug_test_resources_java8.jar"
485    task "compile_debugTestResourcesJava8"(type: JavaCompile) {
486        source = fileTree(dir: java8ResourcesDir, include: '**/*.java')
487        destinationDir = file("build/test/debugTestResourcesJava8/classes")
488        classpath = sourceSets.main.compileClasspath
489        sourceCompatibility = JavaVersion.VERSION_1_8
490        targetCompatibility = JavaVersion.VERSION_1_8
491        options.compilerArgs += ["-g", "-Xlint:-options"]
492    }
493    task "jar_debugTestResourcesJava8"(type: Jar, dependsOn: "compile_debugTestResourcesJava8") {
494        archiveName = java8HostJar
495        destinationDir = file("build/test/")
496        from "build/test/debugTestResourcesJava8/classes"
497        include "**/*.class"
498    }
499    dependsOn downloadDeps
500    dependsOn jar_debugTestResources
501    dependsOn jar_debugTestResourcesJava8
502}
503
504task buildExampleJars {
505    dependsOn downloadProguard
506    def examplesDir = file("src/test/examples")
507    def protoSourceDir = file("build/generated/source/proto/examples/javalite")
508    def proguardScript
509    if (OperatingSystem.current().isWindows()) {
510        proguardScript = "third_party/proguard/proguard5.2.1/bin/proguard.bat"
511    } else {
512        proguardScript = "third_party/proguard/proguard5.2.1/bin/proguard.sh"
513    }
514    task extractExamplesRuntime(type: Sync) {
515        dependsOn configurations.examplesRuntime
516        from configurations.examplesRuntime.collect { zipTree(it) }
517        include "**/*.class"
518        includeEmptyDirs false
519        into "$buildDir/runtime/examples/"
520    }
521
522    task "compile_examples"(type: JavaCompile, dependsOn: "generateExamplesProto") {
523        source examplesDir, protoSourceDir
524        include "**/*.java"
525        destinationDir = file("build/test/examples/classes")
526        classpath = sourceSets.examples.compileClasspath
527        sourceCompatibility = JavaVersion.VERSION_1_7
528        targetCompatibility = JavaVersion.VERSION_1_7
529        options.compilerArgs += ["-Xlint:-options"]
530    }
531    examplesDir.eachDir { dir ->
532        def name = dir.getName();
533        def exampleOutputDir = file("build/test/examples");
534        def jarName = "${name}.jar"
535        dependsOn "jar_example_${name}"
536        dependsOn "extractExamplesRuntime"
537        def runtimeDependencies = copySpec { }
538        if (!fileTree(dir: dir, include: '**/*.proto').empty) {
539            // If we have any proto use, we have to include those classes and the runtime.
540            runtimeDependencies = copySpec {
541                from "$buildDir/runtime/examples/"
542                include "com/google/protobuf/**/*.class"
543            }
544        }
545        // The "throwing" test verifies debugging/stack info on the post-proguarded output.
546        def proguardConfigPath = "${dir}/proguard.cfg"
547        if (new File(proguardConfigPath).exists()) {
548            task "pre_proguard_example_${name}"(type: Jar, dependsOn: "compile_examples") {
549                archiveName = "${name}_pre_proguard.jar"
550                destinationDir = exampleOutputDir
551                from "build/test/examples/classes"
552                include name + "/**/*.class"
553                with runtimeDependencies
554                includeEmptyDirs false
555            }
556            def jarPath = files(tasks.getByPath("pre_proguard_example_${name}")).files.first();
557            def proguardJarPath = "${exampleOutputDir}/${jarName}"
558            def proguardMapPath = "${exampleOutputDir}/${name}/${name}.map"
559            task "jar_example_${name}"(type: Exec, dependsOn: "pre_proguard_example_${name}") {
560                inputs.files tasks.getByPath("pre_proguard_example_${name}")
561                inputs.file  proguardConfigPath
562                // Enable these to get stdout and stderr redirected to files...
563                // standardOutput = new FileOutputStream('proguard.stdout')
564                // errorOutput = new FileOutputStream('proguard.stderr')
565                def proguardArguments = "-verbose -dontwarn java.** -injars ${jarPath}" +
566                        " -outjars ${proguardJarPath}" +
567                        " -include ${proguardConfigPath}" +
568                        " -printmapping ${proguardMapPath}"
569                if (OperatingSystem.current().isWindows()) {
570                    executable "${proguardScript}"
571                    args "${proguardArguments}"
572                } else {
573                    executable "bash"
574                    args "-c", "${proguardScript} '${proguardArguments}'"
575                }
576                outputs.file proguardJarPath
577            }
578        } else {
579            task "jar_example_${name}"(type: Jar, dependsOn: "compile_examples") {
580                archiveName = jarName
581                destinationDir = exampleOutputDir
582                from "build/test/examples/classes"
583                include name + "/**/*.class"
584                with runtimeDependencies
585                includeEmptyDirs false
586            }
587        }
588    }
589}
590
591task buildExampleAndroidNJars {
592    dependsOn downloadDeps
593    def examplesDir = file("src/test/examplesAndroidN")
594    task "compile_examplesAndroidN"(type: JavaCompile) {
595        source = fileTree(dir: examplesDir, include: '**/*.java')
596        destinationDir = file("build/test/examplesAndroidN/classes")
597        classpath = sourceSets.main.compileClasspath
598        sourceCompatibility = JavaVersion.VERSION_1_8
599        targetCompatibility = JavaVersion.VERSION_1_8
600        options.compilerArgs += ["-Xlint:-options"]
601    }
602    examplesDir.eachDir { dir ->
603        def name = dir.getName();
604        def exampleOutputDir = file("build/test/examplesAndroidN");
605        def jarName = "${name}.jar"
606        dependsOn "jar_examplesAndroidN_${name}"
607        task "jar_examplesAndroidN_${name}"(type: Jar, dependsOn: "compile_examplesAndroidN") {
608            archiveName = jarName
609            destinationDir = exampleOutputDir
610            from "build/test/examplesAndroidN/classes"
611            include "**/" + name + "/**/*.class"
612        }
613    }
614}
615
616
617task buildExampleAndroidOJars {
618    dependsOn downloadDeps
619    def examplesDir = file("src/test/examplesAndroidO")
620    // NOTE: we want to enable a scenario when test needs to reference some
621    // classes generated by legacy (1.6) Java compiler to test some specific
622    // behaviour. To do so we compile all the java files located in sub-directory
623    // called 'legacy' with Java 1.6, then compile the rest of the files with
624    // Java 1.8 and a reference to previously generated 1.6 classes.
625
626    // Compiling all classes in dirs 'legacy' with old Java version.
627    task "compile_examplesAndroidO_Legacy"(type: JavaCompile) {
628        source = fileTree(dir: examplesDir, include: '**/legacy/**/*.java')
629        destinationDir = file("build/test/examplesAndroidOLegacy/classes")
630        classpath = sourceSets.main.compileClasspath
631        sourceCompatibility = JavaVersion.VERSION_1_6
632        targetCompatibility = JavaVersion.VERSION_1_6
633        options.compilerArgs += ["-Xlint:-options", "-parameters"]
634    }
635    // Compiling the rest of the files as Java 1.8 code.
636    task "compile_examplesAndroidO"(type: JavaCompile) {
637        dependsOn "compile_examplesAndroidO_Legacy"
638        source = fileTree(dir: examplesDir, include: '**/*.java', exclude: '**/legacy/**/*.java')
639        destinationDir = file("build/test/examplesAndroidO/classes")
640        classpath = sourceSets.main.compileClasspath
641        classpath += files("build/test/examplesAndroidOLegacy/classes")
642        sourceCompatibility = JavaVersion.VERSION_1_8
643        targetCompatibility = JavaVersion.VERSION_1_8
644        options.compilerArgs += ["-Xlint:-options", "-parameters"]
645    }
646    examplesDir.eachDir { dir ->
647        def name = dir.getName();
648        def destinationDir = file("build/test/examplesAndroidO/classes");
649        if (file("src/test/examplesAndroidO/" + name + "/TestGenerator.java").isFile()) {
650            task "generate_examplesAndroidO_${name}"(type: JavaExec,
651                    dependsOn: "compile_examplesAndroidO") {
652                main = name + ".TestGenerator"
653                classpath = files(destinationDir, sourceSets.main.compileClasspath)
654                args destinationDir
655            }
656        } else {
657            task "generate_examplesAndroidO_${name}" () {}
658        }
659    }
660    examplesDir.eachDir { dir ->
661        def name = dir.getName();
662        def exampleOutputDir = file("build/test/examplesAndroidO");
663        def jarName = "${name}.jar"
664        dependsOn "jar_examplesAndroidO_${name}"
665        task "jar_examplesAndroidO_${name}"(type: Jar, dependsOn: ["compile_examplesAndroidO",
666                "generate_examplesAndroidO_${name}"]) {
667            archiveName = jarName
668            destinationDir = exampleOutputDir
669            from "build/test/examplesAndroidO/classes"        // Java 1.8 classes
670            from "build/test/examplesAndroidOLegacy/classes"  // Java 1.6 classes
671            include "**/" + name + "/**/*.class"
672            // Do not include generator into the test runtime jar, it is not useful.
673            // Otherwise, shrinking will need ASM jars.
674            exclude "**/TestGenerator*"
675        }
676    }
677}
678
679task buildExamples {
680    if (OperatingSystem.current().isMacOsX() || OperatingSystem.current().isWindows()) {
681        logger.lifecycle("WARNING: Testing (including building examples) is only partially supported on your " +
682                "platform (" + OperatingSystem.current().getName() + ").")
683    } else if (!OperatingSystem.current().isLinux()) {
684      logger.lifecycle("WARNING: Testing (including building examples) is not supported on your platform. " +
685          "It is fully supported on Linux and partially supported on Mac OS and Windows")
686      return;
687    }
688    dependsOn buildDebugTestResourcesJars
689    dependsOn buildExampleJars
690    dependsOn buildExampleAndroidNJars
691    dependsOn buildExampleAndroidOJars
692    def examplesDir = file("src/test/examples")
693    def noDexTests = [
694        "multidex",
695        "multidex002",
696        "multidex004",
697    ]
698    examplesDir.eachDir { dir ->
699        def name = dir.getName();
700        if (!(name in noDexTests)) {
701            dependsOn "dex_example_${name}"
702            def exampleOutputDir = file("build/test/examples/" + name);
703            def dexPath = file("${exampleOutputDir}")
704            def debug = (name == "throwing")
705            if (!dexPath.exists()) {
706                dexPath.mkdirs()
707            }
708            task "dex_example_${name}"(type: dx.Dx, dependsOn: "jar_example_${name}") {
709                source = files(tasks.getByPath("jar_example_${name}")).asFileTree
710                destination = dexPath
711                debug = debug
712            }
713        }
714    }
715}
716
717task buildSmali {
718    def smaliDir = file("src/test/smali")
719    smaliDir.eachDirRecurse() { dir ->
720        def name = dir.getName();
721        def relativeDir = smaliDir.toPath().relativize(dir.toPath());
722        def smaliOutputDir = file("build/test/smali/" + relativeDir);
723        smaliOutputDir.mkdirs()
724        outputs.dir smaliOutputDir
725        def taskName = "smali_build_${relativeDir.toString().replace('/', '_')}"
726        def smaliFiles = fileTree(dir: dir, include: '*.smali')
727        def javaFiles = fileTree(dir: dir, include: '*.java')
728        def destDir = smaliOutputDir;
729        def destFile = destDir.toPath().resolve("${name}.dex").toFile()
730        def intermediateFileName = "${name}-intermediate.dex";
731        def intermediateFile = destDir.toPath().resolve(intermediateFileName).toFile()
732        if (javaFiles.empty) {
733            if (!smaliFiles.empty) {
734                dependsOn "${taskName}_smali"
735                task "${taskName}_smali"(type: smali.Smali) {
736                    source = smaliFiles
737                    destination = destFile
738                }
739            }
740        } else {
741            dependsOn "${taskName}_dexmerger"
742            task "${taskName}_smali"(type: smali.Smali) {
743                source = smaliFiles
744                destination = intermediateFile
745            }
746            task "${taskName}_java"(type: JavaCompile) {
747                source = javaFiles
748                destinationDir destDir
749                classpath = sourceSets.main.compileClasspath
750                sourceCompatibility = JavaVersion.VERSION_1_7
751                targetCompatibility = JavaVersion.VERSION_1_7
752                options.compilerArgs += ["-Xlint:-options"]
753            }
754            task "${taskName}_jar"(type: Jar, dependsOn: "${taskName}_java") {
755                archiveName = "Test.jar"
756                destinationDir = destDir
757                from fileTree(dir: destDir, include: 'Test.class')
758            }
759            task "${taskName}_dx"(type: dx.Dx, dependsOn: "${taskName}_jar") {
760                source = fileTree(dir: destDir, include: 'Test.jar')
761                destination = destDir
762            }
763            task "${taskName}_dexmerger"(
764                    type: dx.DexMerger, dependsOn: ["${taskName}_dx", "${taskName}_smali"]) {
765                source = fileTree(dir: destDir, include: ["classes.dex", intermediateFileName])
766                destination = destFile
767            }
768        }
769    }
770}
771
772tasks.withType(Test) {
773    def userDefinedCoresPerFork = System.getenv('R8_GRADLE_CORES_PER_FORK')
774    def coresPerFork = userDefinedCoresPerFork ? userDefinedCoresPerFork.toInteger() : 3
775    // See https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html.
776    maxParallelForks = Runtime.runtime.availableProcessors().intdiv(coresPerFork) ?: 1
777    forkEvery = 0
778    // Use the Concurrent Mark Sweep GC (CMS) to keep memory usage at a resonable level.
779    jvmArgs = ["-XX:+UseConcMarkSweepGC"]
780    if (project.hasProperty('disable_assertions')) {
781        enableAssertions = false
782    }
783}
784
785task buildPreNJdwpTestsJar(type: Jar) {
786    baseName = 'jdwp-tests-preN'
787    from zipTree('third_party/jdwp-tests/apache-harmony-jdwp-tests-host.jar')
788    // Exclude the classes containing java8
789    exclude 'org/apache/harmony/jpda/tests/jdwp/InterfaceType/*.class'
790    exclude 'org/apache/harmony/jpda/tests/jdwp/ObjectReference/InvokeMethodDefault*.class'
791    includeEmptyDirs = false
792}
793
794test {
795    testLogging.exceptionFormat = 'full'
796    if (project.hasProperty('print_test_stdout')) {
797        testLogging.showStandardStreams = true
798    }
799    if (project.hasProperty('dex_vm')) {
800        println "Running with non default vm: " + project.property('dex_vm')
801        systemProperty 'dex_vm', project.property('dex_vm')
802        if (project.property('dex_vm') == '5.1.1' || project.property('dex_vm') == '6.0.1') {
803            // R8 and D8 compute the dex file version number based on the input.
804            // Jack generates dex files with version 37 which art 5.1.1 and 6.0.1 will not run.
805            // Therefore we skip the jack generated art tests with those art versions.
806            exclude "com/android/tools/r8/art/jack/**"
807        }
808    }
809    if (project.hasProperty('one_line_per_test')) {
810        beforeTest { desc ->
811            println "Start executing test ${desc.name} [${desc.className}]"
812        }
813        afterTest { desc, result ->
814            println "Done executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
815        }
816    }
817    if (project.hasProperty('no_internal')) {
818        exclude "com/android/tools/r8/internal/**"
819    }
820    if (project.hasProperty('only_internal')) {
821        include "com/android/tools/r8/internal/**"
822    }
823    if (project.hasProperty('tool')) {
824        if (project.property('tool') == 'r8') {
825            exclude "com/android/tools/r8/art/*/d8/**"
826            exclude "com/android/tools/r8/jctf/d8/**"
827        } else {
828            assert(project.property('tool') == 'd8')
829            exclude "com/android/tools/r8/art/*/r8/**"
830            exclude "com/android/tools/r8/jctf/r8/**"
831        }
832    }
833    if (!project.hasProperty('all_tests')) {
834        exclude "com/android/tools/r8/art/dx/**"
835        exclude "com/android/tools/r8/art/jack/**"
836    }
837    // TODO(tamaskenez) enable jctf on all_tests when consolidated
838    if (!project.hasProperty('jctf') && !project.hasProperty('only_jctf')) {
839        exclude "com/android/tools/r8/jctf/**"
840    }
841    if (project.hasProperty('only_jctf')) {
842        include "com/android/tools/r8/jctf/**"
843    }
844    if (project.hasProperty('jctf_compile_only')) {
845        println "JCTF: compiling only"
846        systemProperty 'jctf_compile_only', '1'
847    }
848
849    if (OperatingSystem.current().isLinux()
850            || OperatingSystem.current().isMacOsX()
851            || OperatingSystem.current().isWindows()) {
852        if (OperatingSystem.current().isMacOsX()) {
853            logger.lifecycle("WARNING: Testing in only partially supported on Mac OS. " +
854                "Art only runs on Linux and tests requiring Art runs in a Docker container, which must be present. " +
855                "See tools/docker/README.md for details.")
856        }
857        if (OperatingSystem.current().isWindows()) {
858            logger.lifecycle("WARNING: Testing in only partially supported on Windows. " +
859                    "Art only runs on Linux and tests requiring Art will be skipped")
860        }
861        dependsOn downloadDeps
862        dependsOn buildExamples
863        dependsOn buildSmali
864        dependsOn jctfCommonJar
865        dependsOn jctfTestsClasses
866        dependsOn buildDebugInfoExamplesDex
867        dependsOn buildPreNJdwpTestsJar
868    } else {
869        logger.lifecycle("WARNING: Testing in not supported on your platform. Testing is only fully supported on " +
870            "Linux and partially supported on Mac OS and Windows. Art does not run on other platforms.")
871    }
872}
873
874// The Art tests we use for R8 are pre-build and downloaded from Google Cloud Storage.
875//
876// To build and upload a new set of the Art tests for use with R8 follow these steps:
877//
878// First of all an Android checkout is required. Currently it must be located
879// in $HOME/android/master.
880//
881// TODO(ricow): simplify this
882//
883// Before: update the checked in art, see scripts/update-host-art.sh
884//
885// 1. Get an android checkout in $HOME/android/master and apply the patch from
886//    https://android-review.googlesource.com/#/c/294187/
887//
888// 2. run the following commands in the Android checkout directory:
889//
890//    source build/envsetup.sh
891//    lunch aosp_angler-userdebug # or lunch aosp_angler-eng
892//    m desugar
893//    m -j30 test-art-host
894//    DESUGAR=false ANDROID_COMPILE_WITH_JACK=false art/test.py --host -t 001-HelloWorld
895//
896//    Without running the test.py command the classes.jar file used by desugar in
897//    $HOME/android/master/out/host/common/obj/JAVA_LIBRARIES/core-oj-hostdex_intermediates/
898//    seems to be missing - there is probably also a make target to build it more directly
899//
900// 3. In the R8 project root directory, make sure we have a clean state before starting:
901//    tools/gradle.py downloadDeps
902//    tools/gradle.py clean
903//    rm -rf tests/art
904//
905// 4. Now build in the R8 checkout (-P hack to not generate dirs when not running this target)
906//    Make sure you have smali on your path, please use the build binary in the
907//    out/host/linux-x86/bin directory of the android checkout. Currently this is version pre 2.2.1,
908//    if that is updated the call to smali in "task "${smaliToDexTask}"(type: Exec)" below might
909//    need to change as smali got a completely new command line interface in version 2.2.1.
910//
911//    PATH=$HOME/android/master/out/host/linux-x86/bin:$PATH tools/gradle.py -Pandroid_source buildArtTests
912//
913// 4a. If any failures are produced in step 4, figure out what went wrong and add an entry in
914//     skippedTests with an explanation. Rerun from step 3.
915//
916// 5. Run the tests:
917//    tools/gradle.py clean
918//    tools/test.py
919//
920// 5a. If any more tests fail, either fix the issue or add them to the failuresToTriage list (note
921//     that you need to change "_" to "-" from stdout). Rerun from step 5 if anything was added to
922//     failuresToTriage.
923//
924// 6. To upload a new version to Google Cloud Storage:
925//    cd tests
926//    upload_to_google_storage.py -a --bucket r8-deps art
927//
928// 7. Update the manifest file describing the Android repo used:
929//    repo manifest -o <r8-checkout-root>/tools/linux/aosp_master_manifest.xml -r
930
931enum DexTool {
932    JACK,
933    DX
934}
935
936def androidCheckoutDir = file("${System.env.HOME}/android/master")
937def androidCheckoutJack = file("${androidCheckoutDir}/out/host/linux-x86/bin/jack");
938def androidCheckoutJackServer = file("${androidCheckoutDir}/out/host/linux-x86/bin/jack-admin");
939
940def artTestDir = file("${androidCheckoutDir}/art/test")
941
942if (project.hasProperty('android_source')) {
943    task buildArtTests {
944        outputs.upToDateWhen { false }
945        def toBeTriaged = [
946                "903-hello-tagging",
947                "904-object-allocation",
948                "905-object-free",
949                "906-iterate-heap",
950                "907-get-loaded-classes",
951                "908-gc-start-finish",
952                "954-invoke-polymorphic-verifier",
953                "955-methodhandles-smali",
954                "596-monitor-inflation",
955        ]
956        def skippedTests = toBeTriaged + [
957                // This test produces no jar.
958                "000-nop",
959                // This does not build, as it tests the error when the application exceeds more
960                // than 65536 methods
961                "089-many-methods",
962                // Requires some jack beta jar
963                "956-methodhandles",
964        ]
965
966        def skippedTestsDx = [
967                // Tests with custom build scripts, where javac is not passed the options
968                // -source 1.7 -target 1.7.
969                "462-checker-inlining-across-dex-files",
970                "556-invoke-super",
971                "569-checker-pattern-replacement",
972                // These tests use jack even when --build-with-javac-dx is specified.
973                "004-JniTest",
974                "048-reflect-v8",
975                "146-bad-interface",
976                "563-checker-invoke-super",
977                "580-checker-string-fact-intrinsics",  // java.lang.StringFactory
978                "604-hot-static-interface",
979                "957-methodhandle-transforms",
980                "958-methodhandle-emulated-stackframe",
981                "959-invoke-polymorphic-accessors",
982                "961-default-iface-resolution-gen",
983                "962-iface-static",
984                "963-default-range-smali",
985                "964-default-iface-init-gen",
986                "965-default-verify",
987                "966-default-conflict",
988                "967-default-ame",
989                "968-default-partial-compile-gen",
990                "969-iface-super",
991                "970-iface-super-resolution-gen",
992                "971-iface-super",
993                // These tests does not build with --build-with-javac-dx
994                "004-NativeAllocations", // Javac error
995                "031-class-attributes",
996                "138-duplicate-classes-check",
997                "157-void-class", // Javac error
998                "580-checker-string-factory-intrinsics",
999                "612-jit-dex-cache",
1000                "613-inlining-dex-cache",
1001                "900-hello-plugin",  // --experimental agents
1002                "901-hello-ti-agent",  // --experimental agents
1003                "902-hello-transformation",  // --experimental agents
1004                "909-attach-agent",  // --experimental agents
1005                "946-obsolete-throw", // -source 1.7 -target 1.7, but use lambda
1006                "950-redefine-intrinsic", // -source 1.7 -target 1.7, but use method references
1007                "951-threaded-obsolete", // -source 1.7 -target 1.7, but use lambda
1008                "960-default-smali",  // --experimental default-methods
1009                // These tests force the build to use jack
1010                "953-invoke-polymorphic-compiler",
1011                "958-methodhandle-stackframe",
1012        ]
1013
1014        def artTestBuildDir = file("${projectDir}/tests/art")
1015
1016        if (androidCheckoutDir.exists()) {
1017            dependsOn downloadDeps
1018            artTestBuildDir.mkdirs()
1019            // Ensure Jack server is running.
1020            "${androidCheckoutJackServer} start-server".execute()
1021            artTestDir.eachDir { dir ->
1022                def name = dir.getName();
1023                def markerFile = dir.toPath().resolve("info.txt").toFile();
1024                if (markerFile.exists() && !(name in skippedTests)) {
1025                    if (!(name in skippedTestsDx)) {
1026                        dependsOn buildArtTest(androidCheckoutDir, artTestBuildDir, dir, DexTool.DX);
1027                    }
1028                    dependsOn buildArtTest(androidCheckoutDir, artTestBuildDir, dir, DexTool.JACK);
1029                }
1030            }
1031        }
1032        doFirst {
1033            if (!androidCheckoutDir.exists()) {
1034                throw new InvalidUserDataException(
1035                        "This task requires an Android checkout in ${androidCheckoutDir}");
1036            } else if (!androidCheckoutJack.exists() ||
1037                    !androidCheckoutJackServer.exists()) {
1038                throw new InvalidUserDataException(
1039                        "This task requires that tools for host testing have been build in the " +
1040                                "Android checkout in ${androidCheckoutDir}");
1041            }
1042        }
1043        doLast {
1044            copy {
1045                from file("${androidCheckoutDir}/out/host/linux-x86/nativetest64")
1046                into file("${artTestBuildDir}/lib64")
1047                include 'lib*.so'
1048            }
1049            copy {
1050                from file("${androidCheckoutDir}/out/host/linux-x86/lib64")
1051                into file("${artTestBuildDir}/lib64")
1052                include 'libart.so'
1053                include 'libbacktrace.so'
1054                include 'libbase.so'
1055                include 'libc++.so'
1056                include 'libcutils.so'
1057                include 'liblz4.so'
1058                include 'liblzma.so'
1059                include 'libnativebridge.so'
1060                include 'libnativeloader.so'
1061                include 'libsigchain.so'
1062                include 'libunwind.so'
1063                include 'libziparchive.so'
1064            }
1065            copy {
1066                from file("${androidCheckoutDir}/out/host/linux-x86/nativetest")
1067                into file("${artTestBuildDir}/lib")
1068                include 'lib*.so'
1069            }
1070            copy {
1071                from file("${androidCheckoutDir}/out/host/linux-x86/lib")
1072                into file("${artTestBuildDir}/lib")
1073                include 'libart.so'
1074                include 'libbacktrace.so'
1075                include 'libbase.so'
1076                include 'libc++.so'
1077                include 'libcutils.so'
1078                include 'liblz4.so'
1079                include 'liblzma.so'
1080                include 'libnativebridge.so'
1081                include 'libnativeloader.so'
1082                include 'libsigchain.so'
1083                include 'libunwind.so'
1084                include 'libziparchive.so'
1085            }
1086        }
1087    }
1088}
1089
1090def buildArtTest(androidCheckoutDir, artTestBuildDir, dir, dexTool) {
1091    def artTestDir = file("${androidCheckoutDir}/art/test")
1092    def artRunTestScript = file("${artTestDir}/run-test")
1093    def dxExecutable = new File("tools/linux/dx/bin/dx");
1094    def dexMergerExecutable = Utils.dexMergerExecutable()
1095    def dexToolName = dexTool == DexTool.DX ? "dx" : "jack"
1096
1097    def name = dir.getName()
1098    def buildTask = "build_art_test_${dexToolName}_${name}"
1099    def sanitizeTask = "sanitize_art_test_${dexToolName}_${name}"
1100    def copyCheckTask = "copy_check_art_test_${dexToolName}_${name}"
1101    def smaliToDexTask = "smali_to_dex_${dexToolName}_${name}"
1102
1103    def buildInputs = fileTree(dir: dir, include: '**/*')
1104    def testDir = file("${artTestBuildDir}/${dexToolName}/${name}")
1105    def outputJar = testDir.toPath().resolve("${name}.jar").toFile()
1106    testDir.mkdirs()
1107    if (dexTool == DexTool.DX) {
1108        task "$buildTask"(type: Exec) {
1109            outputs.upToDateWhen { false }
1110            inputs.file buildInputs
1111            executable "${artRunTestScript}"
1112            args "--host"
1113            args "--build-only"
1114            args "--build-with-javac-dx"
1115            args "--output-path", "${testDir}"
1116            args "${name}"
1117            environment DX: "${dxExecutable.absolutePath}"
1118            environment DXMERGER: "${dexMergerExecutable.absolutePath}"
1119            environment ANDROID_BUILD_TOP: "${androidCheckoutDir}"
1120            outputs.file outputJar
1121        }
1122    } else {
1123        assert dexTool == DexTool.JACK
1124        def javaLibs = "${androidCheckoutDir}/out/host/common/obj/JAVA_LIBRARIES"
1125        def jackClasspath = "${javaLibs}/core-libart-hostdex_intermediates/classes.jack:" +
1126                "${javaLibs}/core-oj-hostdex_intermediates/classes.jack"
1127        task "$buildTask"(type: Exec) {
1128            outputs.upToDateWhen { false }
1129            inputs.file buildInputs
1130            executable "${artRunTestScript}"
1131            args "--host"
1132            args "--build-only"
1133            args "--output-path", "${testDir}"
1134            args "${name}"
1135            environment JACK: "${androidCheckoutDir}/out/host/linux-x86/bin/jack"
1136            environment JACK_CLASSPATH: jackClasspath
1137            environment DXMERGER: "${dexMergerExecutable.absolutePath}"
1138            environment ANDROID_BUILD_TOP: "${androidCheckoutDir}"
1139            outputs.file outputJar
1140        }
1141    }
1142    task "${sanitizeTask}"(type: Exec, dependsOn: buildTask) {
1143        outputs.upToDateWhen { false }
1144        executable "/bin/bash"
1145        args "-c"
1146        args "rm -rf ${testDir}/smali_*.dex ${testDir}/*-ex.dex ${testDir}/*-ex.jar" +
1147                " ${testDir}/classes-ex ${testDir}/check"
1148    }
1149
1150    task "${smaliToDexTask}"(type: Exec) {
1151        workingDir "${testDir}/smali"
1152        executable "/bin/bash"
1153        // This is the command line options for smali prior to 2.2.1, where smali got a new
1154        // command line interface.
1155        args "-c", "smali a *.smali"
1156        // This is the command line options for smali 2.2.1 and later.
1157        // args "-c", "smali -o out.dex *.smali"
1158    }
1159
1160    task "${copyCheckTask}"(type: Copy, dependsOn: sanitizeTask) {
1161        def smali_dir = file("${dir}/smali")
1162        outputs.upToDateWhen { false }
1163        if (smali_dir.exists() && dexTool == DexTool.DX) {
1164            dependsOn smaliToDexTask
1165        }
1166        from("${artTestDir}/${name}") {
1167            include 'check'
1168        }
1169        into testDir
1170    }
1171
1172    return copyCheckTask
1173}
1174
1175task javadocD8(type: Javadoc) {
1176  classpath = sourceSets.main.compileClasspath
1177  source = sourceSets.main.allJava
1178  include '**/com/android/tools/r8/BaseCommand.java'
1179  include '**/com/android/tools/r8/BaseOutput.java'
1180  include '**/com/android/tools/r8/CompilationException.java'
1181  include '**/com/android/tools/r8/CompilationMode.java'
1182  include '**/com/android/tools/r8/D8.java'
1183  include '**/com/android/tools/r8/D8Command.java'
1184  include '**/com/android/tools/r8/D8Output.java'
1185  include '**/com/android/tools/r8/Resource.java'
1186}
1187