blob: 12c9b6f6c1980df8ebea4c03bff5eb408bd314d6 [file] [log] [blame]
Yohann Rousselbb571622017-11-09 10:47:36 +01001// Copyright (c) 2017, 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.
4
5package com.android.tools.apiusagesample;
6
Yohann Rousselbb571622017-11-09 10:47:36 +01007import com.android.tools.r8.CompilationMode;
8import com.android.tools.r8.D8;
9import com.android.tools.r8.D8Command;
Yohann Roussel76f1c542017-11-22 22:36:16 +010010import com.android.tools.r8.origin.PathOrigin;
Yohann Roussel078c9942017-11-28 15:55:46 +010011import com.android.tools.r8.CompilationFailedException;
Yohann Rousselbb571622017-11-09 10:47:36 +010012import com.android.tools.r8.utils.OutputMode;
13import java.io.IOException;
14import java.nio.file.FileVisitResult;
15import java.nio.file.Files;
16import java.nio.file.Path;
17import java.nio.file.Paths;
18import java.nio.file.SimpleFileVisitor;
19import java.nio.file.attribute.BasicFileAttributes;
20import java.util.ArrayList;
21import java.util.List;
22import java.util.concurrent.ExecutorService;
23import java.util.concurrent.Executors;
24
25public class D8Compiler {
26 private int minSdkVersion;
27 private Path bootclasspath;
28 private List<Path> classpath;
29 private static ExecutorService pool = Executors.newFixedThreadPool(4);
30
31 private D8Compiler(int minSdkVersion, Path bootclasspath, List<Path> classpath) {
32 this.minSdkVersion = minSdkVersion;
33 this.bootclasspath = bootclasspath;
34 this.classpath = classpath;
35 }
36
37 /**
38 * java ...Compiler output input minSdkVersion mainDexClasses bootclasspath [classpathEntries]+
39 */
40 public static void main(String[] args) throws Throwable {
41 try {
42 int argIndex = 0;
43 Path outputDir = Paths.get(args[argIndex++]);
44 Path input = Paths.get(args[argIndex++]);
45 int minSdkVersion = Integer.parseInt(args[argIndex++]);
46 Path mainDexClasses = Paths.get(args[argIndex++]);
47 Path bootclasspath = Paths.get(args[argIndex++]);
48
49 List<Path> classpath = new ArrayList<>(args.length - argIndex);
50 while (argIndex < args.length) {
51 classpath.add(Paths.get(args[argIndex++]));
52 }
53
54 D8Compiler compiler = new D8Compiler(minSdkVersion, bootclasspath, classpath);
55
56 List<Path> toMerge = new ArrayList<>(3);
57
58 int intermediateIndex = 0;
59 for (Path entry : classpath) {
60 Path output = outputDir.resolve(entry.getFileName() + "." + (intermediateIndex++));
61 Files.createDirectory(output);
62 toMerge.add(output);
63 compiler.compile(output, entry);
64 }
65
66 Path output = outputDir.resolve("main." + (intermediateIndex++));
67 Files.createDirectory(output);
68 toMerge.add(output);
69 compiler.compile(output, input);
70
71 compiler.merge(outputDir, mainDexClasses, toMerge);
72 } finally {
73 // Terminate pool threads to prevent the VM to wait on then before exiting.
74 pool.shutdown();
75 }
76 }
77
78 private void compile(Path output, Path input) throws Throwable {
79 D8Command.Builder builder =
Yohann Roussel078c9942017-11-28 15:55:46 +010080 D8Command.builder(new D8DiagnosticsHandler())
Yohann Rousselbb571622017-11-09 10:47:36 +010081 // Compile in debug and merge in release to assert access to both modes
82 .setMode(CompilationMode.DEBUG)
83 .setMinApiLevel(minSdkVersion)
84 .setIntermediate(true)
85 .setEnableDesugaring(true)
86 .setOutputPath(output);
87
88 builder.addLibraryResourceProvider(CachingArchiveClassFileProvider.getProvider(bootclasspath));
89
90 for (Path entry : classpath) {
91 builder.addClasspathResourceProvider(CachingArchiveClassFileProvider.getProvider(entry));
92 }
93
94 if (Files.isRegularFile(input)) {
95 builder.setOutputMode(OutputMode.Indexed);
96 builder.addProgramFiles(input);
97 } else {
98 builder.setOutputMode(OutputMode.FilePerInputClass);
99 Files.walkFileTree(input, new SimpleFileVisitor<Path>() {
100 @Override
101 public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes)
102 throws IOException {
Yohann Roussel76f1c542017-11-22 22:36:16 +0100103 builder.addClassProgramData(Files.readAllBytes(path), new PathOrigin(path));
Yohann Rousselbb571622017-11-09 10:47:36 +0100104 return FileVisitResult.CONTINUE;
105 }
106 });
107 }
108
109 D8.run(builder.build(), pool);
110 }
111
112 private void merge(Path outputDir, Path mainDexClasses,
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100113 List<Path> toMerge) throws IOException, CompilationFailedException {
Yohann Roussel078c9942017-11-28 15:55:46 +0100114 D8Command.Builder merger = D8Command.builder(new D8DiagnosticsHandler());
Yohann Rousselbb571622017-11-09 10:47:36 +0100115 merger.setEnableDesugaring(false);
116
117 for (Path mergeInput : toMerge) {
118 Files.walkFileTree(mergeInput, new SimpleFileVisitor<Path>() {
119 @Override
120 public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes)
121 throws IOException {
Yohann Roussel76f1c542017-11-22 22:36:16 +0100122 merger.addDexProgramData(Files.readAllBytes(path), new PathOrigin(path));
Yohann Rousselbb571622017-11-09 10:47:36 +0100123 return FileVisitResult.CONTINUE;
124 }
125 });
126 }
127 if (mainDexClasses != null) {
128 merger.addMainDexListFiles(mainDexClasses);
129 }
130 merger.setMinApiLevel(minSdkVersion)
131 .setMode(CompilationMode.RELEASE)
132 .setOutputPath(outputDir)
133 .setEnableDesugaring(false)
134 .setIntermediate(false);
135 D8.run(merger.build());
136 }
137}