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