blob: c22cadd411b0d1852c9aaa078311ebc37824fa4d [file] [log] [blame]
Søren Gjessec4e5e932017-09-04 17:01:23 +02001// 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.
4package com.android.tools.r8;
5
Ian Zerny1c6f9542022-03-02 13:46:25 +01006import com.android.tools.r8.dump.DumpOptions;
clementbera75174ac2019-09-04 09:14:44 +02007import com.android.tools.r8.errors.CompilationError;
Ian Zerny113faac2017-12-14 12:58:23 +01008import com.android.tools.r8.errors.Unreachable;
clementbera75174ac2019-09-04 09:14:44 +02009import com.android.tools.r8.graph.DexItemFactory;
Ian Zerny8f3ba442020-03-11 16:32:27 +010010import com.android.tools.r8.inspector.Inspector;
Clément Béra24cb20a2022-02-17 09:30:14 +000011import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
12import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
Clément Béra752cac12022-02-23 13:38:58 +000013import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
clementbera75174ac2019-09-04 09:14:44 +020014import com.android.tools.r8.origin.Origin;
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +020015import com.android.tools.r8.profile.art.ArtProfileConsumer;
16import com.android.tools.r8.profile.art.ArtProfileForRewriting;
17import com.android.tools.r8.profile.art.ArtProfileProvider;
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +020018import com.android.tools.r8.startup.StartupProfileProvider;
Mikaël Peltier20c9ca72017-10-03 10:09:39 +020019import com.android.tools.r8.utils.AndroidApiLevel;
Søren Gjessec4e5e932017-09-04 17:01:23 +020020import com.android.tools.r8.utils.AndroidApp;
Søren Gjesse75a09792021-04-07 12:41:33 +020021import com.android.tools.r8.utils.DumpInputFlags;
Søren Gjessec4e5e932017-09-04 17:01:23 +020022import com.android.tools.r8.utils.FileUtils;
Søren Gjesse9a7876d2020-01-13 14:32:26 +010023import com.android.tools.r8.utils.InternalOptions.DesugarState;
Christoffer Quist Adamsencbb6a802023-03-02 14:33:25 +010024import com.android.tools.r8.utils.ListUtils;
Morten Krogh-Jespersen58c98a92023-05-01 12:18:10 +020025import com.android.tools.r8.utils.PartitionMapZipContainer;
Christoffer Quist Adamsen0a3c16e2023-02-15 14:34:44 +010026import com.android.tools.r8.utils.ProgramConsumerUtils;
Yohann Roussel9a8d4372017-11-21 14:36:44 +010027import com.android.tools.r8.utils.Reporter;
Søren Gjesse943389f2020-03-13 10:40:25 +010028import com.android.tools.r8.utils.ThreadUtils;
Søren Gjessec4e5e932017-09-04 17:01:23 +020029import java.nio.file.Path;
Ian Zernyd01e99e2018-01-04 09:38:36 +010030import java.util.ArrayList;
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +020031import java.util.Arrays;
Ian Zerny8f3ba442020-03-11 16:32:27 +010032import java.util.Collection;
33import java.util.Collections;
Ian Zernyd01e99e2018-01-04 09:38:36 +010034import java.util.List;
Alan Leung4b5db8e2019-07-23 13:53:10 -070035import java.util.function.BiPredicate;
Ian Zerny8f3ba442020-03-11 16:32:27 +010036import java.util.function.Consumer;
Søren Gjesse95fce5f2019-12-16 10:33:51 +010037import java.util.function.Function;
Søren Gjessec4e5e932017-09-04 17:01:23 +020038
39/**
40 * Base class for commands and command builders for compiler applications/tools which besides an
Ian Zerny850f13d2018-01-04 11:25:38 +010041 * Android application (and optional main-dex list) also configure compilation output, compilation
42 * mode and min API level.
Ian Zernyafb08e12018-01-08 14:22:58 +010043 *
44 * <p>For concrete builders, see for example {@link D8Command.Builder} and {@link
45 * R8Command.Builder}.
Søren Gjessec4e5e932017-09-04 17:01:23 +020046 */
Mathias Rav3fb4a3a2018-05-29 15:41:36 +020047@Keep
Ian Zerny850f13d2018-01-04 11:25:38 +010048public abstract class BaseCompilerCommand extends BaseCommand {
Søren Gjessec4e5e932017-09-04 17:01:23 +020049
Søren Gjessec4e5e932017-09-04 17:01:23 +020050 private final CompilationMode mode;
Ian Zerny113faac2017-12-14 12:58:23 +010051 private final ProgramConsumer programConsumer;
Mads Agerd9ae2a82018-11-29 13:01:55 +010052 private final StringConsumer mainDexListConsumer;
Søren Gjessec4e5e932017-09-04 17:01:23 +020053 private final int minApiLevel;
Yohann Roussel9a8d4372017-11-21 14:36:44 +010054 private final Reporter reporter;
Søren Gjesse9a7876d2020-01-13 14:32:26 +010055 private final DesugarState desugarState;
Alan Leung4b5db8e2019-07-23 13:53:10 -070056 private final boolean includeClassesChecksum;
Yohann Roussel2284bc82018-04-26 15:45:35 +020057 private final boolean optimizeMultidexForLinearAlloc;
Alan Leung4b5db8e2019-07-23 13:53:10 -070058 private final BiPredicate<String, Long> dexClassChecksumFilter;
Søren Gjesse99e8a742020-01-07 13:59:38 +010059 private final List<AssertionsConfiguration> assertionsConfiguration;
Ian Zerny8f3ba442020-03-11 16:32:27 +010060 private final List<Consumer<Inspector>> outputInspections;
Søren Gjesse75a09792021-04-07 12:41:33 +020061 private final int threadCount;
62 private final DumpInputFlags dumpInputFlags;
Ian Zernyb23c47c2021-10-06 08:00:19 +020063 private final MapIdProvider mapIdProvider;
Ian Zerny1433d582021-10-12 09:44:48 +020064 private final SourceFileProvider sourceFileProvider;
Ian Zernybbd23922022-06-07 10:33:31 +020065 private final boolean isAndroidPlatformBuild;
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +020066 private final List<ArtProfileForRewriting> artProfilesForRewriting;
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +020067 private final List<StartupProfileProvider> startupProfileProviders;
Ian Zerny77440062022-08-26 13:49:08 +020068 private final ClassConflictResolver classConflictResolver;
Ian Zernyd9bd0762023-03-24 16:46:18 +010069 private final CancelCompilationChecker cancelCompilationChecker;
Søren Gjessec4e5e932017-09-04 17:01:23 +020070
71 BaseCompilerCommand(boolean printHelp, boolean printVersion) {
72 super(printHelp, printVersion);
Ian Zerny7efd28d2017-12-12 09:17:42 +010073 programConsumer = null;
Mads Agerd9ae2a82018-11-29 13:01:55 +010074 mainDexListConsumer = null;
Mads Ager642e7572017-10-03 15:43:09 +020075 mode = null;
76 minApiLevel = 0;
Morten Krogh-Jespersenff59ed32018-10-08 15:15:57 +020077 reporter = new Reporter();
Søren Gjesse9a7876d2020-01-13 14:32:26 +010078 desugarState = DesugarState.ON;
Alan Leung4b5db8e2019-07-23 13:53:10 -070079 includeClassesChecksum = false;
Yohann Roussel2284bc82018-04-26 15:45:35 +020080 optimizeMultidexForLinearAlloc = false;
Alan Leung4b5db8e2019-07-23 13:53:10 -070081 dexClassChecksumFilter = (name, checksum) -> true;
Søren Gjesse99e8a742020-01-07 13:59:38 +010082 assertionsConfiguration = new ArrayList<>();
Ian Zerny8f3ba442020-03-11 16:32:27 +010083 outputInspections = null;
Søren Gjesse943389f2020-03-13 10:40:25 +010084 threadCount = ThreadUtils.NOT_SPECIFIED;
Søren Gjesse75a09792021-04-07 12:41:33 +020085 dumpInputFlags = DumpInputFlags.noDump();
Ian Zernyb23c47c2021-10-06 08:00:19 +020086 mapIdProvider = null;
Ian Zerny1433d582021-10-12 09:44:48 +020087 sourceFileProvider = null;
Ian Zernybbd23922022-06-07 10:33:31 +020088 isAndroidPlatformBuild = false;
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +020089 artProfilesForRewriting = null;
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +020090 startupProfileProviders = null;
Ian Zerny77440062022-08-26 13:49:08 +020091 classConflictResolver = null;
Ian Zernyd9bd0762023-03-24 16:46:18 +010092 cancelCompilationChecker = null;
Søren Gjessec4e5e932017-09-04 17:01:23 +020093 }
94
95 BaseCompilerCommand(
96 AndroidApp app,
Søren Gjessec4e5e932017-09-04 17:01:23 +020097 CompilationMode mode,
Ian Zerny7efd28d2017-12-12 09:17:42 +010098 ProgramConsumer programConsumer,
Mads Agerd9ae2a82018-11-29 13:01:55 +010099 StringConsumer mainDexListConsumer,
Mads Ager642e7572017-10-03 15:43:09 +0200100 int minApiLevel,
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100101 Reporter reporter,
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100102 DesugarState desugarState,
Søren Gjessead54aa52019-07-16 15:30:01 +0200103 boolean optimizeMultidexForLinearAlloc,
Alan Leung4b5db8e2019-07-23 13:53:10 -0700104 boolean includeClassesChecksum,
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100105 BiPredicate<String, Long> dexClassChecksumFilter,
Ian Zerny8f3ba442020-03-11 16:32:27 +0100106 List<AssertionsConfiguration> assertionsConfiguration,
Søren Gjesse943389f2020-03-13 10:40:25 +0100107 List<Consumer<Inspector>> outputInspections,
Søren Gjesse75a09792021-04-07 12:41:33 +0200108 int threadCount,
Ian Zernyb23c47c2021-10-06 08:00:19 +0200109 DumpInputFlags dumpInputFlags,
Ian Zerny1433d582021-10-12 09:44:48 +0200110 MapIdProvider mapIdProvider,
Ian Zernybbd23922022-06-07 10:33:31 +0200111 SourceFileProvider sourceFileProvider,
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200112 boolean isAndroidPlatformBuild,
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200113 List<ArtProfileForRewriting> artProfilesForRewriting,
Ian Zerny77440062022-08-26 13:49:08 +0200114 List<StartupProfileProvider> startupProfileProviders,
Ian Zernyd9bd0762023-03-24 16:46:18 +0100115 ClassConflictResolver classConflictResolver,
116 CancelCompilationChecker cancelCompilationChecker) {
Søren Gjessec4e5e932017-09-04 17:01:23 +0200117 super(app);
Søren Gjessec4e5e932017-09-04 17:01:23 +0200118 assert minApiLevel > 0;
Ian Zerny7efd28d2017-12-12 09:17:42 +0100119 assert mode != null;
Søren Gjessec4e5e932017-09-04 17:01:23 +0200120 this.mode = mode;
Ian Zerny7efd28d2017-12-12 09:17:42 +0100121 this.programConsumer = programConsumer;
Mads Agerd9ae2a82018-11-29 13:01:55 +0100122 this.mainDexListConsumer = mainDexListConsumer;
Søren Gjessec4e5e932017-09-04 17:01:23 +0200123 this.minApiLevel = minApiLevel;
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100124 this.reporter = reporter;
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100125 this.desugarState = desugarState;
Yohann Roussel2284bc82018-04-26 15:45:35 +0200126 this.optimizeMultidexForLinearAlloc = optimizeMultidexForLinearAlloc;
Alan Leung4b5db8e2019-07-23 13:53:10 -0700127 this.includeClassesChecksum = includeClassesChecksum;
128 this.dexClassChecksumFilter = dexClassChecksumFilter;
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100129 this.assertionsConfiguration = assertionsConfiguration;
Ian Zerny8f3ba442020-03-11 16:32:27 +0100130 this.outputInspections = outputInspections;
Søren Gjesse943389f2020-03-13 10:40:25 +0100131 this.threadCount = threadCount;
Søren Gjesse75a09792021-04-07 12:41:33 +0200132 this.dumpInputFlags = dumpInputFlags;
Ian Zernyb23c47c2021-10-06 08:00:19 +0200133 this.mapIdProvider = mapIdProvider;
Ian Zerny1433d582021-10-12 09:44:48 +0200134 this.sourceFileProvider = sourceFileProvider;
Ian Zernybbd23922022-06-07 10:33:31 +0200135 this.isAndroidPlatformBuild = isAndroidPlatformBuild;
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200136 this.artProfilesForRewriting = artProfilesForRewriting;
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200137 this.startupProfileProviders = startupProfileProviders;
Ian Zerny77440062022-08-26 13:49:08 +0200138 this.classConflictResolver = classConflictResolver;
Ian Zernyd9bd0762023-03-24 16:46:18 +0100139 this.cancelCompilationChecker = cancelCompilationChecker;
Søren Gjessec4e5e932017-09-04 17:01:23 +0200140 }
141
Ian Zernyafb08e12018-01-08 14:22:58 +0100142 /**
143 * Get the compilation mode, e.g., {@link CompilationMode#DEBUG} or {@link
144 * CompilationMode#RELEASE}.
145 */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200146 public CompilationMode getMode() {
147 return mode;
148 }
149
Ian Zernyafb08e12018-01-08 14:22:58 +0100150 /** Get the minimum API level to compile against. */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200151 public int getMinApiLevel() {
152 return minApiLevel;
153 }
154
Clément Béra64a3c4c2020-11-10 08:16:17 +0000155 void dumpBaseCommandOptions(DumpOptions.Builder builder) {
156 builder
Christoffer Quist Adamsen0a3c16e2023-02-15 14:34:44 +0100157 .setBackend(ProgramConsumerUtils.getBackend(programConsumer))
Clément Béra64a3c4c2020-11-10 08:16:17 +0000158 .setCompilationMode(getMode())
159 .setMinApi(getMinApiLevel())
160 .setOptimizeMultidexForLinearAlloc(isOptimizeMultidexForLinearAlloc())
161 .setThreadCount(getThreadCount())
Christoffer Quist Adamsen9b0a9972022-08-26 13:38:54 +0200162 .setDesugarState(getDesugarState())
Christoffer Quist Adamsencbb6a802023-03-02 14:33:25 +0100163 .setArtProfileProviders(
164 ListUtils.map(
165 getArtProfilesForRewriting(), ArtProfileForRewriting::getArtProfileProvider))
Christoffer Quist Adamsen9b0a9972022-08-26 13:38:54 +0200166 .setStartupProfileProviders(getStartupProfileProviders());
Ian Zernye72cb782022-06-07 12:47:56 +0200167 if (getAndroidPlatformBuild()) {
168 builder.setAndroidPlatformBuild(true);
169 }
Clément Béra64a3c4c2020-11-10 08:16:17 +0000170 }
171
Ian Zernyafb08e12018-01-08 14:22:58 +0100172 /**
173 * Get the program consumer that will receive the compilation output.
174 *
175 * <p>Note that the concrete consumer reference is final, the consumer itself is likely stateful.
176 */
Ian Zerny7efd28d2017-12-12 09:17:42 +0100177 public ProgramConsumer getProgramConsumer() {
178 return programConsumer;
Søren Gjessec4e5e932017-09-04 17:01:23 +0200179 }
180
Mads Agerd9ae2a82018-11-29 13:01:55 +0100181 /**
182 * Get the main dex list consumer that will receive the final complete main dex list.
183 */
184 public StringConsumer getMainDexListConsumer() {
185 return mainDexListConsumer;
186 }
187
Ian Zernyafb08e12018-01-08 14:22:58 +0100188 /** Get the use-desugaring state. True if enabled, false otherwise. */
Yohann Rousseld2580102017-10-09 15:17:14 +0200189 public boolean getEnableDesugaring() {
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100190 return desugarState == DesugarState.ON;
191 }
192
193 DesugarState getDesugarState() {
194 return desugarState;
Mads Agerdbcc4ec2017-10-06 11:32:18 +0200195 }
196
Ian Zernyb23c47c2021-10-06 08:00:19 +0200197 public MapIdProvider getMapIdProvider() {
198 return mapIdProvider;
199 }
200
Ian Zerny1433d582021-10-12 09:44:48 +0200201 public SourceFileProvider getSourceFileProvider() {
202 return sourceFileProvider;
203 }
204
Alan Leung4b5db8e2019-07-23 13:53:10 -0700205 /** True if the output dex files has checksum information encoded in it. False otherwise. */
206 public boolean getIncludeClassesChecksum() {
207 return includeClassesChecksum;
208 }
209
210 /** Filter used to skip parsing of certain class in a dex file. */
211 public BiPredicate<String, Long> getDexClassChecksumFilter() {
212 return dexClassChecksumFilter;
213 }
214
Yohann Roussel2284bc82018-04-26 15:45:35 +0200215 /**
216 * If true, legacy multidex partitioning will be optimized to reduce LinearAlloc usage during
217 * Dalvik DexOpt.
218 */
219 public boolean isOptimizeMultidexForLinearAlloc() {
220 return optimizeMultidexForLinearAlloc;
221 }
222
Søren Gjesse99e8a742020-01-07 13:59:38 +0100223 public List<AssertionsConfiguration> getAssertionsConfiguration() {
Ian Zerny8f3ba442020-03-11 16:32:27 +0100224 return Collections.unmodifiableList(assertionsConfiguration);
225 }
226
227 public Collection<Consumer<Inspector>> getOutputInspections() {
228 return Collections.unmodifiableList(outputInspections);
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100229 }
230
Søren Gjesse943389f2020-03-13 10:40:25 +0100231 /** Get the number of threads to use for the compilation. */
232 public int getThreadCount() {
233 return threadCount;
234 }
235
Ian Zernybbd23922022-06-07 10:33:31 +0200236 public boolean getAndroidPlatformBuild() {
237 return isAndroidPlatformBuild;
238 }
239
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200240 List<ArtProfileForRewriting> getArtProfilesForRewriting() {
241 return artProfilesForRewriting;
Christoffer Quist Adamsenc5a31ec2022-09-01 11:36:04 +0200242 }
243
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200244 List<StartupProfileProvider> getStartupProfileProviders() {
245 return startupProfileProviders;
246 }
247
Ian Zerny77440062022-08-26 13:49:08 +0200248 ClassConflictResolver getClassConflictResolver() {
249 return classConflictResolver;
250 }
251
Ian Zernyd9bd0762023-03-24 16:46:18 +0100252 public CancelCompilationChecker getCancelCompilationChecker() {
253 return cancelCompilationChecker;
254 }
255
Søren Gjesse75a09792021-04-07 12:41:33 +0200256 DumpInputFlags getDumpInputFlags() {
257 return dumpInputFlags;
258 }
259
Ian Zernyafb08e12018-01-08 14:22:58 +0100260 Reporter getReporter() {
261 return reporter;
262 }
Søren Gjessead54aa52019-07-16 15:30:01 +0200263
Ian Zernyafb08e12018-01-08 14:22:58 +0100264 /**
265 * Base builder for compilation commands.
266 *
267 * @param <C> Command the builder is building, e.g., {@link R8Command} or {@link D8Command}.
268 * @param <B> Concrete builder extending this base, e.g., {@link R8Command.Builder} or {@link
269 * D8Command.Builder}.
270 */
Mathias Rav3fb4a3a2018-05-29 15:41:36 +0200271 @Keep
Ian Zernyafb08e12018-01-08 14:22:58 +0100272 public abstract static class Builder<C extends BaseCompilerCommand, B extends Builder<C, B>>
Søren Gjessec4e5e932017-09-04 17:01:23 +0200273 extends BaseCommand.Builder<C, B> {
274
Ian Zerny113faac2017-12-14 12:58:23 +0100275 private ProgramConsumer programConsumer = null;
Mads Agerd9ae2a82018-11-29 13:01:55 +0100276 private StringConsumer mainDexListConsumer = null;
Søren Gjessec4e5e932017-09-04 17:01:23 +0200277 private Path outputPath = null;
Ian Zerny113faac2017-12-14 12:58:23 +0100278 // TODO(b/70656566): Remove default output mode when deprecated API is removed.
Ian Zernyef028f52018-01-08 14:23:17 +0100279 private OutputMode outputMode = OutputMode.DexIndexed;
Ian Zerny113faac2017-12-14 12:58:23 +0100280
Søren Gjessec4e5e932017-09-04 17:01:23 +0200281 private CompilationMode mode;
Mathias Rav86d26022018-03-16 10:13:34 +0100282 private int minApiLevel = 0;
Søren Gjesse943389f2020-03-13 10:40:25 +0100283 private int threadCount = ThreadUtils.NOT_SPECIFIED;
Søren Gjesse4cdd55d2020-01-16 10:59:24 +0100284 protected DesugarState desugarState = DesugarState.ON;
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200285 private final List<StringResource> desugaredLibrarySpecificationResources = new ArrayList<>();
Alan Leung4b5db8e2019-07-23 13:53:10 -0700286 private boolean includeClassesChecksum = false;
Yohann Roussel2284bc82018-04-26 15:45:35 +0200287 private boolean optimizeMultidexForLinearAlloc = false;
Alan Leung4b5db8e2019-07-23 13:53:10 -0700288 private BiPredicate<String, Long> dexClassChecksumFilter = (name, checksum) -> true;
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200289 private final List<AssertionsConfiguration> assertionsConfiguration = new ArrayList<>();
290 private final List<Consumer<Inspector>> outputInspections = new ArrayList<>();
Morten Krogh-Jespersen946bea92021-03-18 20:29:42 +0100291 protected StringConsumer proguardMapConsumer = null;
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200292 protected PartitionMapConsumer partitionMapConsumer = null;
Christoffer Quist Adamsen06268302022-06-28 12:35:16 +0200293 private DumpInputFlags dumpInputFlags = DumpInputFlags.getDefault();
Ian Zernyb23c47c2021-10-06 08:00:19 +0200294 private MapIdProvider mapIdProvider = null;
Ian Zerny1433d582021-10-12 09:44:48 +0200295 private SourceFileProvider sourceFileProvider = null;
Ian Zernybbd23922022-06-07 10:33:31 +0200296 private boolean isAndroidPlatformBuild = false;
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200297 private final List<ArtProfileForRewriting> artProfilesForRewriting = new ArrayList<>();
298 private final List<StartupProfileProvider> startupProfileProviders = new ArrayList<>();
Ian Zerny77440062022-08-26 13:49:08 +0200299 private ClassConflictResolver classConflictResolver = null;
Ian Zernyd9bd0762023-03-24 16:46:18 +0100300 private CancelCompilationChecker cancelCompilationChecker = null;
Søren Gjessec4e5e932017-09-04 17:01:23 +0200301
Ian Zernye09adb72018-05-08 11:12:12 +0200302 abstract CompilationMode defaultCompilationMode();
303
Ian Zernyafb08e12018-01-08 14:22:58 +0100304 Builder(DiagnosticsHandler diagnosticsHandler) {
305 super(diagnosticsHandler);
Ian Zernye09adb72018-05-08 11:12:12 +0200306 mode = defaultCompilationMode();
Søren Gjessec4e5e932017-09-04 17:01:23 +0200307 }
308
309 // Internal constructor for testing.
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100310 Builder(AndroidApp app) {
311 super(AndroidApp.builder(app));
Ian Zernye09adb72018-05-08 11:12:12 +0200312 mode = defaultCompilationMode();
Søren Gjesse8fb83c82017-12-01 08:00:10 +0100313 }
314
Christoffer Quist Adamsen0eef4b02018-08-01 10:29:47 +0200315 // Internal constructor for testing.
316 Builder(AndroidApp app, DiagnosticsHandler diagnosticsHandler) {
317 super(AndroidApp.builder(app, new Reporter(diagnosticsHandler)));
318 mode = defaultCompilationMode();
319 }
320
Stephan Herhut7e3d2042017-10-18 14:12:23 +0200321 /**
322 * Get current compilation mode.
323 */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200324 public CompilationMode getMode() {
325 return mode;
326 }
327
Stephan Herhut7e3d2042017-10-18 14:12:23 +0200328 /**
329 * Set compilation mode.
330 */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200331 public B setMode(CompilationMode mode) {
332 assert mode != null;
333 this.mode = mode;
334 return self();
335 }
336
Stephan Herhut7e3d2042017-10-18 14:12:23 +0200337 /**
Ian Zerny113faac2017-12-14 12:58:23 +0100338 * Get the output path.
339 *
340 * @return Current output path, null if no output path-and-mode have been set.
341 * @see #setOutput(Path, OutputMode)
Stephan Herhut7e3d2042017-10-18 14:12:23 +0200342 */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200343 public Path getOutputPath() {
344 return outputPath;
345 }
346
Stephan Herhut7e3d2042017-10-18 14:12:23 +0200347 /**
348 * Get the output mode.
Ian Zerny113faac2017-12-14 12:58:23 +0100349 *
350 * @return Currently set output mode, null if no output path-and-mode have been set.
351 * @see #setOutput(Path, OutputMode)
Stephan Herhut7e3d2042017-10-18 14:12:23 +0200352 */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200353 public OutputMode getOutputMode() {
354 return outputMode;
355 }
356
Ian Zerny113faac2017-12-14 12:58:23 +0100357 /**
358 * Get the program consumer.
359 *
360 * @return The currently set program consumer, null if no program consumer or output
clementbera75174ac2019-09-04 09:14:44 +0200361 * path-and-mode is set, e.g., neither {@link #setProgramConsumer} nor {@link #setOutput}
362 * have been called.
Ian Zerny113faac2017-12-14 12:58:23 +0100363 */
364 public ProgramConsumer getProgramConsumer() {
365 return programConsumer;
366 }
367
368 /**
Morten Krogh-Jespersen946bea92021-03-18 20:29:42 +0100369 * Set an output destination to which proguard-map content should be written.
370 *
371 * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
372 * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
373 * #setProguardMapConsumer} will override the previous setting.
374 *
375 * @param proguardMapOutput File-system path to write output at.
376 */
377 B setProguardMapOutputPath(Path proguardMapOutput) {
378 assert proguardMapOutput != null;
379 return setProguardMapConsumer(new StringConsumer.FileConsumer(proguardMapOutput));
380 }
381
382 /**
383 * Set a consumer for receiving the proguard-map content.
384 *
385 * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
386 * override the previous setting.
387 *
388 * @param proguardMapConsumer Consumer to receive the content once produced.
389 */
390 B setProguardMapConsumer(StringConsumer proguardMapConsumer) {
391 this.proguardMapConsumer = proguardMapConsumer;
392 return self();
393 }
394
395 /**
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200396 * Set an output destination to which partition-map content should be written.
397 *
398 * <p>This is a short-hand for setting a {@link PartitionMapConsumer} using {@link
399 * #setPartitionMapConsumer}. Note that any subsequent call to this method or {@link
400 * #setPartitionMapConsumer} will override the previous setting.
401 *
402 * @param partitionMapOutput File-system path to write output at.
403 */
Morten Krogh-Jespersen8c36ac82023-04-25 09:25:32 +0200404 public B setPartitionMapOutputPath(Path partitionMapOutput) {
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200405 assert partitionMapOutput != null;
Morten Krogh-Jespersen58c98a92023-05-01 12:18:10 +0200406 return setPartitionMapConsumer(
407 PartitionMapZipContainer.createPartitionMapZipContainerConsumer(partitionMapOutput));
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200408 }
409
410 /**
411 * Set a consumer for receiving the partition map content.
412 *
413 * <p>Note that any subsequent call to this method or {@link #setPartitionMapOutputPath} will
414 * override the previous setting.
415 *
416 * @param partitionMapConsumer Consumer to receive the content once produced.
417 */
Morten Krogh-Jespersen8c36ac82023-04-25 09:25:32 +0200418 public B setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
Morten Krogh-Jespersen034a0df2023-04-24 15:22:10 +0200419 this.partitionMapConsumer = partitionMapConsumer;
420 return self();
421 }
422
423 /**
Mads Agerd9ae2a82018-11-29 13:01:55 +0100424 * Get the main dex list consumer that will receive the final complete main dex list.
425 */
426 public StringConsumer getMainDexListConsumer() {
427 return mainDexListConsumer;
428 }
429
430 /**
Alan Leung4b5db8e2019-07-23 13:53:10 -0700431 * Filter used to skip parsing of certain class in a dex file.
432 */
433 public BiPredicate<String, Long> getDexClassChecksumFilter() {
434 return dexClassChecksumFilter;
435 }
436
437 /**
Yohann Roussel2284bc82018-04-26 15:45:35 +0200438 * If set to true, legacy multidex partitioning will be optimized to reduce LinearAlloc usage
439 * during Dalvik DexOpt. Has no effect when compiling for a target with native multidex support
440 * or without main dex list specification.
441 */
442 public B setOptimizeMultidexForLinearAlloc(boolean optimizeMultidexForLinearAlloc) {
443 this.optimizeMultidexForLinearAlloc = optimizeMultidexForLinearAlloc;
444 return self();
445 }
446
447 /**
448 * If true, legacy multidex partitioning will be optimized to reduce LinearAlloc usage during
449 * Dalvik DexOpt.
450 */
451 protected boolean isOptimizeMultidexForLinearAlloc() {
452 return optimizeMultidexForLinearAlloc;
453 }
454
455 /**
Ian Zerny113faac2017-12-14 12:58:23 +0100456 * Set the program consumer.
457 *
458 * <p>Setting the program consumer will override any previous set consumer or any previous set
459 * output path & mode.
460 *
461 * @param programConsumer Program consumer to set as current. A null argument will clear the
462 * program consumer / output.
463 */
464 public B setProgramConsumer(ProgramConsumer programConsumer) {
465 // Setting an explicit program consumer resets any output-path/mode setup.
466 outputPath = null;
467 outputMode = null;
468 this.programConsumer = programConsumer;
469 return self();
470 }
471
472 /**
Mads Agerd9ae2a82018-11-29 13:01:55 +0100473 * Set an output destination to which main-dex-list content should be written.
474 *
475 * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
476 * #setMainDexListConsumer}. Note that any subsequent call to this method or {@link
477 * #setMainDexListConsumer} will override the previous setting.
478 *
479 * @param mainDexListOutputPath File-system path to write output at.
480 */
481 public B setMainDexListOutputPath(Path mainDexListOutputPath) {
482 mainDexListConsumer = new StringConsumer.FileConsumer(mainDexListOutputPath);
483 return self();
484 }
485
486 /**
487 * Set a consumer for receiving the main-dex-list content.
488 *
489 * <p>Note that any subsequent call to this method or {@link #setMainDexListOutputPath} will
490 * override the previous setting.
491 *
492 * @param mainDexListConsumer Consumer to receive the content once produced.
493 */
494 public B setMainDexListConsumer(StringConsumer mainDexListConsumer) {
495 this.mainDexListConsumer = mainDexListConsumer;
496 return self();
497 }
498
499 /**
Ian Zerny113faac2017-12-14 12:58:23 +0100500 * Set the output path-and-mode.
501 *
502 * <p>Setting the output path-and-mode will override any previous set consumer or any previous
503 * output path-and-mode, and implicitly sets the appropriate program consumer to write the
504 * output.
505 *
506 * @param outputPath Path to write the output to. Must be an archive or and existing directory.
507 * @param outputMode Mode in which to write the output.
508 */
509 public B setOutput(Path outputPath, OutputMode outputMode) {
Søren Gjesse4d015022018-09-14 13:26:57 +0200510 return setOutput(outputPath, outputMode, false);
511 }
512
513 // This is only public in R8Command.
514 protected B setOutput(Path outputPath, OutputMode outputMode, boolean includeDataResources) {
Ian Zerny113faac2017-12-14 12:58:23 +0100515 assert outputPath != null;
516 assert outputMode != null;
Ian Zerny113faac2017-12-14 12:58:23 +0100517 this.outputPath = outputPath;
518 this.outputMode = outputMode;
Søren Gjesse4d015022018-09-14 13:26:57 +0200519 programConsumer = createProgramOutputConsumer(outputPath, outputMode, includeDataResources);
Ian Zerny113faac2017-12-14 12:58:23 +0100520 return self();
521 }
522
Alan Leung4b5db8e2019-07-23 13:53:10 -0700523 /**
524 * Setting a dex class filter.
525 *
526 * A filter is a function that given a name of a class and a checksum can return false the user
527 * decides to skip parsing and ignore that class in the dex file.
528 */
529 public B setDexClassChecksumFilter(BiPredicate<String, Long> filter) {
530 assert filter != null;
531 this.dexClassChecksumFilter = filter;
532 return self();
533 }
534
Søren Gjesse7320ce52018-05-07 15:45:22 +0200535 protected InternalProgramOutputPathConsumer createProgramOutputConsumer(
Ian Zerny113faac2017-12-14 12:58:23 +0100536 Path path,
Søren Gjesse7320ce52018-05-07 15:45:22 +0200537 OutputMode mode,
538 boolean consumeDataResources) {
Ian Zernyef028f52018-01-08 14:23:17 +0100539 if (mode == OutputMode.DexIndexed) {
Ian Zerny113faac2017-12-14 12:58:23 +0100540 return FileUtils.isArchive(path)
Søren Gjesse7320ce52018-05-07 15:45:22 +0200541 ? new DexIndexedConsumer.ArchiveConsumer(path, consumeDataResources)
542 : new DexIndexedConsumer.DirectoryConsumer(path, consumeDataResources);
Ian Zerny113faac2017-12-14 12:58:23 +0100543 }
Alan Leungf21b09b2018-09-10 16:20:25 -0700544 if (mode == OutputMode.DexFilePerClass) {
545 if (FileUtils.isArchive(path)) {
546 return new DexFilePerClassFileConsumer.ArchiveConsumer(path, consumeDataResources) {
547 @Override
548 public boolean combineSyntheticClassesWithPrimaryClass() {
549 return false;
550 }
551 };
552 } else {
553 return new DexFilePerClassFileConsumer.DirectoryConsumer(path, consumeDataResources) {
554 @Override
555 public boolean combineSyntheticClassesWithPrimaryClass() {
556 return false;
557 }
558 };
559 }
560 }
Ian Zernyef028f52018-01-08 14:23:17 +0100561 if (mode == OutputMode.DexFilePerClassFile) {
Ian Zerny113faac2017-12-14 12:58:23 +0100562 return FileUtils.isArchive(path)
Søren Gjesse7320ce52018-05-07 15:45:22 +0200563 ? new DexFilePerClassFileConsumer.ArchiveConsumer(path, consumeDataResources)
564 : new DexFilePerClassFileConsumer.DirectoryConsumer(path, consumeDataResources);
Ian Zerny113faac2017-12-14 12:58:23 +0100565 }
Ian Zernyef028f52018-01-08 14:23:17 +0100566 if (mode == OutputMode.ClassFile) {
Ian Zerny113faac2017-12-14 12:58:23 +0100567 return FileUtils.isArchive(path)
Søren Gjesse7320ce52018-05-07 15:45:22 +0200568 ? new ClassFileConsumer.ArchiveConsumer(path, consumeDataResources)
569 : new ClassFileConsumer.DirectoryConsumer(path, consumeDataResources);
Ian Zerny113faac2017-12-14 12:58:23 +0100570 }
571 throw new Unreachable("Unexpected output mode: " + mode);
Ian Zerny7efd28d2017-12-12 09:17:42 +0100572 }
573
Ian Zernyafb08e12018-01-08 14:22:58 +0100574 /** Get the minimum API level (aka SDK version). */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200575 public int getMinApiLevel() {
Mathias Rav86d26022018-03-16 10:13:34 +0100576 return isMinApiLevelSet() ? minApiLevel : AndroidApiLevel.getDefault().getLevel();
577 }
578
579 boolean isMinApiLevelSet() {
580 return minApiLevel != 0;
Søren Gjessec4e5e932017-09-04 17:01:23 +0200581 }
582
Ian Zernyafb08e12018-01-08 14:22:58 +0100583 /** Set the minimum required API level (aka SDK version). */
Søren Gjessec4e5e932017-09-04 17:01:23 +0200584 public B setMinApiLevel(int minApiLevel) {
Mathias Rav86d26022018-03-16 10:13:34 +0100585 if (minApiLevel <= 0) {
586 getReporter().error("Invalid minApiLevel: " + minApiLevel);
587 } else {
588 this.minApiLevel = minApiLevel;
589 }
Søren Gjessec4e5e932017-09-04 17:01:23 +0200590 return self();
591 }
592
Ian Zernybaaad9f2018-01-09 07:45:24 +0100593 @Deprecated
Yohann Rousseld2580102017-10-09 15:17:14 +0200594 public B setEnableDesugaring(boolean enableDesugaring) {
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100595 this.desugarState = enableDesugaring ? DesugarState.ON : DesugarState.OFF;
Yohann Rousseld2580102017-10-09 15:17:14 +0200596 return self();
597 }
598
Ian Zernybaaad9f2018-01-09 07:45:24 +0100599 /**
600 * Force disable desugaring.
601 *
602 * <p>There are a few use cases where it makes sense to force disable desugaring, such as:
603 * <ul>
604 * <li>if all inputs are known to be at most Java 7; or
605 * <li>if a separate desugar tool has been used prior to compiling with D8.
606 * </ul>
607 *
608 * <p>Note that even for API 27, desugaring is still required for closures support on ART.
609 */
610 public B setDisableDesugaring(boolean disableDesugaring) {
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100611 this.desugarState = disableDesugaring ? DesugarState.OFF : DesugarState.ON;
Ian Zernybaaad9f2018-01-09 07:45:24 +0100612 return self();
613 }
614
615 /** Is desugaring forcefully disabled. */
616 public boolean getDisableDesugaring() {
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100617 return desugarState == DesugarState.OFF;
618 }
619
620 DesugarState getDesugaringState() {
621 return desugarState;
Mads Agerdbcc4ec2017-10-06 11:32:18 +0200622 }
623
Ian Zernyb23c47c2021-10-06 08:00:19 +0200624 /** Set a custom provider for defining the map id for the build. */
625 public B setMapIdProvider(MapIdProvider mapIdProvider) {
626 this.mapIdProvider = mapIdProvider;
627 return self();
628 }
629
630 public MapIdProvider getMapIdProvider() {
631 return mapIdProvider;
632 }
633
Ian Zerny1433d582021-10-12 09:44:48 +0200634 /** Set a custom provider for defining source-file attributes for classes. */
635 public B setSourceFileProvider(SourceFileProvider sourceFileProvider) {
636 this.sourceFileProvider = sourceFileProvider;
637 return self();
638 }
639
640 public SourceFileProvider getSourceFileProvider() {
641 return sourceFileProvider;
642 }
643
Søren Gjessebffd4ad2019-09-06 13:05:19 +0200644 @Deprecated
645 public B addSpecialLibraryConfiguration(String configuration) {
646 return addDesugaredLibraryConfiguration(configuration);
647 }
648
clementbera75174ac2019-09-04 09:14:44 +0200649 /** Desugared library configuration */
650 // Configuration "default" is for testing only and support will be dropped.
651 public B addDesugaredLibraryConfiguration(String configuration) {
Clément Béraddd19a12021-12-09 08:14:53 +0000652 this.desugaredLibrarySpecificationResources.add(
clementbera75174ac2019-09-04 09:14:44 +0200653 StringResource.fromString(configuration, Origin.unknown()));
Søren Gjesse95612222019-07-16 11:42:31 +0200654 return self();
655 }
656
clementbera75174ac2019-09-04 09:14:44 +0200657 /** Desugared library configuration */
658 public B addDesugaredLibraryConfiguration(StringResource configuration) {
Clément Béraddd19a12021-12-09 08:14:53 +0000659 this.desugaredLibrarySpecificationResources.add(configuration);
clementbera75174ac2019-09-04 09:14:44 +0200660 return self();
661 }
662
Clément Béra24cb20a2022-02-17 09:30:14 +0000663 DesugaredLibrarySpecification getDesugaredLibraryConfiguration(
clementbera79854ab2019-09-24 14:47:06 +0200664 DexItemFactory factory, boolean libraryCompilation) {
Clément Béraddd19a12021-12-09 08:14:53 +0000665 if (desugaredLibrarySpecificationResources.isEmpty()) {
Clément Béra752cac12022-02-23 13:38:58 +0000666 return HumanDesugaredLibrarySpecification.empty();
clementbera75174ac2019-09-04 09:14:44 +0200667 }
Clément Béraddd19a12021-12-09 08:14:53 +0000668 if (desugaredLibrarySpecificationResources.size() > 1) {
clementbera75174ac2019-09-04 09:14:44 +0200669 throw new CompilationError("Only one desugared library configuration is supported.");
670 }
Clément Béraddd19a12021-12-09 08:14:53 +0000671 StringResource desugaredLibrarySpecificationResource =
672 desugaredLibrarySpecificationResources.get(0);
Clément Béra24cb20a2022-02-17 09:30:14 +0000673 return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
674 desugaredLibrarySpecificationResource,
675 factory,
676 getReporter(),
677 libraryCompilation,
678 getMinApiLevel());
clementbera75174ac2019-09-04 09:14:44 +0200679 }
680
clementbera5dcde342019-09-04 14:56:30 +0200681 boolean hasDesugaredLibraryConfiguration() {
Clément Béraddd19a12021-12-09 08:14:53 +0000682 return !desugaredLibrarySpecificationResources.isEmpty();
Søren Gjessead54aa52019-07-16 15:30:01 +0200683 }
684
Alan Leung4b5db8e2019-07-23 13:53:10 -0700685 /** Encodes checksum for each class when generating dex files. */
686 public B setIncludeClassesChecksum(boolean enabled) {
687 this.includeClassesChecksum = enabled;
688 return self();
689 }
690
Søren Gjesse943389f2020-03-13 10:40:25 +0100691 /** Set the number of threads to use for the compilation */
692 B setThreadCount(int threadCount) {
693 if (threadCount <= 0) {
694 getReporter().error("Invalid threadCount: " + threadCount);
695 } else {
696 this.threadCount = threadCount;
697 }
698 return self();
699 }
700
701 int getThreadCount() {
702 return threadCount;
703 }
704
Alan Leung4b5db8e2019-07-23 13:53:10 -0700705 /** Encodes the checksums into the dex output. */
706 public boolean getIncludeClassesChecksum() {
707 return includeClassesChecksum;
708 }
709
Søren Gjesse99e8a742020-01-07 13:59:38 +0100710 List<AssertionsConfiguration> getAssertionsConfiguration() {
711 return assertionsConfiguration;
712 }
713
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100714 /** Configure compile time assertion enabling through a {@link AssertionsConfiguration}. */
715 public B addAssertionsConfiguration(
716 Function<AssertionsConfiguration.Builder, AssertionsConfiguration>
717 assertionsConfigurationGenerator) {
Søren Gjesse99e8a742020-01-07 13:59:38 +0100718 assertionsConfiguration.add(
719 assertionsConfigurationGenerator.apply(AssertionsConfiguration.builder(getReporter())));
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100720 return self();
721 }
722
Ian Zernybbd23922022-06-07 10:33:31 +0200723 /**
724 * Configure the present build as a "Android platform build".
725 *
726 * <p>A platform build, is a build where the runtime "bootclasspath" is known at compile time.
727 * In other words, the specified <i>min-api</i> is also known to be the <i>max-api</i>. In this
728 * mode the compiler will disable various features that provide support for newer runtimes as
729 * well as disable workarounds for older runtimes.
730 */
731 public B setAndroidPlatformBuild(boolean isAndroidPlatformBuild) {
732 this.isAndroidPlatformBuild = isAndroidPlatformBuild;
733 return self();
734 }
735
736 public boolean getAndroidPlatformBuild() {
737 return isAndroidPlatformBuild;
738 }
739
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200740 /**
741 * Add an ART profiles that should be rewritten to match the residual application. The ART
742 * profile is given to the compiler by the {@link ArtProfileProvider} and passed back to the
743 * {@link ArtProfileConsumer} at the end of compilation when the ART profile has been fully
744 * rewritten to match the residual application.
745 */
746 public B addArtProfileForRewriting(
747 ArtProfileProvider artProfileProvider, ArtProfileConsumer residualArtProfileProvider) {
748 artProfilesForRewriting.add(
749 new ArtProfileForRewriting(artProfileProvider, residualArtProfileProvider));
Christoffer Quist Adamsenc5a31ec2022-09-01 11:36:04 +0200750 return self();
751 }
752
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200753 List<ArtProfileForRewriting> getArtProfilesForRewriting() {
754 return artProfilesForRewriting;
Christoffer Quist Adamsenc5a31ec2022-09-01 11:36:04 +0200755 }
756
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200757 B addStartupProfileProviders(StartupProfileProvider... startupProfileProviders) {
758 return addStartupProfileProviders(Arrays.asList(startupProfileProviders));
759 }
760
761 B addStartupProfileProviders(Collection<StartupProfileProvider> startupProfileProviders) {
762 this.startupProfileProviders.addAll(startupProfileProviders);
763 return self();
764 }
765
766 List<StartupProfileProvider> getStartupProfileProviders() {
767 return startupProfileProviders;
768 }
769
Christoffer Quist Adamsen06268302022-06-28 12:35:16 +0200770 /**
Ian Zernyd9bd0762023-03-24 16:46:18 +0100771 * Set a cancellation checker.
772 *
773 * <p>The cancellation checker will be periodically called to check if the compilation should be
774 * cancelled before completion.
775 */
776 public B setCancelCompilationChecker(CancelCompilationChecker checker) {
777 this.cancelCompilationChecker = checker;
778 return self();
779 }
780
781 public CancelCompilationChecker getCancelCompilationChecker() {
782 return cancelCompilationChecker;
783 }
784
785 /**
Christoffer Quist Adamsen06268302022-06-28 12:35:16 +0200786 * Allow to skip to dump into file and dump into directory instruction, this is primarily used
787 * for chained compilation in L8 so there are no duplicated dumps.
788 */
789 B skipDump() {
790 dumpInputFlags = DumpInputFlags.noDump();
791 return self();
792 }
793
Søren Gjesse75a09792021-04-07 12:41:33 +0200794 B dumpInputToFile(Path file) {
795 dumpInputFlags = DumpInputFlags.dumpToFile(file);
796 return self();
797 }
798
799 B dumpInputToDirectory(Path directory) {
800 dumpInputFlags = DumpInputFlags.dumpToDirectory(directory);
801 return self();
802 }
803
804 DumpInputFlags getDumpInputFlags() {
805 return dumpInputFlags;
806 }
807
Benoit Lamarche2aae3202017-10-11 11:01:06 +0200808 @Override
Ian Zernyafb08e12018-01-08 14:22:58 +0100809 void validate() {
810 Reporter reporter = getReporter();
Ian Zernyd01e99e2018-01-04 09:38:36 +0100811 if (mode == null) {
812 reporter.error("Expected valid compilation mode, was null");
813 }
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100814 FileUtils.validateOutputFile(outputPath, reporter);
Ian Zernyef028f52018-01-08 14:23:17 +0100815 if (getProgramConsumer() == null) {
816 // This is never the case for a command-line parse, so we report using API references.
817 reporter.error("A ProgramConsumer or Output is required for compilation");
818 }
Ian Zernyd01e99e2018-01-04 09:38:36 +0100819 List<Class> programConsumerClasses = new ArrayList<>(3);
820 if (programConsumer instanceof DexIndexedConsumer) {
821 programConsumerClasses.add(DexIndexedConsumer.class);
822 }
823 if (programConsumer instanceof DexFilePerClassFileConsumer) {
824 programConsumerClasses.add(DexFilePerClassFileConsumer.class);
825 }
826 if (programConsumer instanceof ClassFileConsumer) {
827 programConsumerClasses.add(ClassFileConsumer.class);
828 }
829 if (programConsumerClasses.size() > 1) {
830 StringBuilder builder = new StringBuilder()
831 .append("Invalid program consumer.")
832 .append(" A program consumer can implement at most one consumer type but ")
833 .append(programConsumer.getClass().getName())
834 .append(" implements types:");
835 for (Class clazz : programConsumerClasses) {
836 builder.append(" ").append(clazz.getName());
837 }
838 reporter.error(builder.toString());
839 }
Søren Gjesse3ceb1b02020-01-13 16:07:10 +0100840 if (getMinApiLevel() > AndroidApiLevel.LATEST.getLevel()) {
Christoffer Quist Adamsen09063b42021-11-15 15:43:38 +0100841 if (getMinApiLevel() != AndroidApiLevel.ANDROID_PLATFORM.getLevel()) {
Søren Gjesse3ceb1b02020-01-13 16:07:10 +0100842 reporter.warning(
843 "An API level of "
844 + getMinApiLevel()
845 + " is not supported by this compiler. Please use an API level of "
846 + AndroidApiLevel.LATEST.getLevel()
847 + " or earlier");
848 }
849 }
Ian Zernya09cdc92022-08-29 14:31:26 +0200850 if (hasDesugaredLibraryConfiguration() && getAndroidPlatformBuild()) {
851 reporter.error("Android platform builds cannot use desugared library");
852 }
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100853 super.validate();
Søren Gjessec4e5e932017-09-04 17:01:23 +0200854 }
Ian Zerny8f3ba442020-03-11 16:32:27 +0100855
856 /**
857 * Add an inspection of the output program.
858 *
859 * <p>On a successful compilation the inspection is guaranteed to be called with inspectors that
860 * combined cover all of the output program. The inspections may be called multiple times with
861 * inspectors that have overlapping content (eg, classes synthesized based on multiple inputs
862 * can lead to this). Any overlapping content will be consistent, e.g., the inspection of type T
863 * will be the same (equality, not identify) as any other inspection of type T.
864 *
865 * <p>There is no guarantee of the order inspections are called or on which thread they are
866 * called.
867 *
868 * <p>The validity of an {@code Inspector} and all of its sub-inspectors, eg,
869 * {@MethodInspector}, is that of the callback. If any inspector object escapes the scope of the
870 * callback, the behavior of that inspector is undefined.
871 *
872 * @param inspection Inspection callback receiving inspectors denoting parts of the output.
873 */
Søren Gjesse9e1f8c52020-12-21 10:42:09 +0100874 public B addOutputInspection(Consumer<Inspector> inspection) {
Ian Zerny8f3ba442020-03-11 16:32:27 +0100875 outputInspections.add(inspection);
Søren Gjesse9e1f8c52020-12-21 10:42:09 +0100876 return self();
Ian Zerny8f3ba442020-03-11 16:32:27 +0100877 }
878
879 List<Consumer<Inspector>> getOutputInspections() {
880 return outputInspections;
881 }
Ian Zerny77440062022-08-26 13:49:08 +0200882
883 /**
884 * Set a conflict resolver to determine which class definition to use in case of duplicates.
885 *
886 * <p>If no resolver is set, the compiler will fail compilation in case of duplicates.
887 *
888 * @param resolver Resolver for choosing between duplicate classes.
889 */
890 public B setClassConflictResolver(ClassConflictResolver resolver) {
891 this.classConflictResolver = resolver;
892 return self();
893 }
894
895 ClassConflictResolver getClassConflictResolver() {
896 return classConflictResolver;
897 }
Søren Gjessec4e5e932017-09-04 17:01:23 +0200898 }
Søren Gjessec4e5e932017-09-04 17:01:23 +0200899}