blob: ee35e7f3c2595163edeff0f7c82fa41237de01d3 [file] [log] [blame]
Mads Ager418d1ca2017-05-22 09:35:49 +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
Morten Krogh-Jespersen4fa5d822020-03-25 19:28:09 +01006import static com.android.tools.r8.utils.InternalOptions.DETERMINISTIC_DEBUGGING;
7
Ian Zerny1fede152018-01-05 07:28:29 +01008import com.android.tools.r8.ProgramResource.Kind;
Clément Béra64a3c4c2020-11-10 08:16:17 +00009import com.android.tools.r8.dex.Marker.Tool;
Ian Zerny1c6f9542022-03-02 13:46:25 +010010import com.android.tools.r8.dump.DumpOptions;
Ian Zerny72475172018-09-18 05:52:00 +020011import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
Ian Zernybbb59cc2018-12-21 14:23:58 +010012import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
Rico Windb5bb3e92019-09-23 10:32:10 +020013import com.android.tools.r8.features.FeatureSplitConfiguration;
Mads Ager418d1ca2017-05-22 09:35:49 +020014import com.android.tools.r8.graph.DexItemFactory;
Ian Zerny8f3ba442020-03-11 16:32:27 +010015import com.android.tools.r8.inspector.Inspector;
16import com.android.tools.r8.inspector.internal.InspectorImpl;
Clément Béra24cb20a2022-02-17 09:30:14 +000017import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
Ian Zernyc1582852023-01-30 13:45:36 +010018import com.android.tools.r8.keepanno.asm.KeepEdgeReader;
19import com.android.tools.r8.keepanno.ast.KeepEdge;
20import com.android.tools.r8.keepanno.keeprules.KeepRuleExtractor;
Ian Zerny6ddf0e92021-11-18 11:29:33 +010021import com.android.tools.r8.naming.SourceFileRewriter;
Yohann Roussel73df5e62017-11-20 14:06:32 +010022import com.android.tools.r8.origin.Origin;
Yohann Roussel9a8d4372017-11-21 14:36:44 +010023import com.android.tools.r8.origin.PathOrigin;
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +020024import com.android.tools.r8.profile.art.ArtProfileForRewriting;
Ian Zerny140fad62023-01-27 10:33:19 +010025import com.android.tools.r8.shaking.FilteredClassPath;
Mads Ager418d1ca2017-05-22 09:35:49 +020026import com.android.tools.r8.shaking.ProguardConfiguration;
27import com.android.tools.r8.shaking.ProguardConfigurationParser;
Christoffer Quist Adamsen6e689542022-05-30 20:02:09 +020028import com.android.tools.r8.shaking.ProguardConfigurationParserOptions;
Yohann Rousself820a572017-05-31 20:25:51 +020029import com.android.tools.r8.shaking.ProguardConfigurationRule;
Søren Gjessea26ef842017-09-01 11:46:43 +020030import com.android.tools.r8.shaking.ProguardConfigurationSource;
Søren Gjesseb72b7432018-05-16 09:48:56 +020031import com.android.tools.r8.shaking.ProguardConfigurationSourceBytes;
Søren Gjessea26ef842017-09-01 11:46:43 +020032import com.android.tools.r8.shaking.ProguardConfigurationSourceFile;
33import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +020034import com.android.tools.r8.startup.StartupProfileProvider;
Ian Zerny1ca41482018-12-18 13:42:49 +000035import com.android.tools.r8.utils.AndroidApiLevel;
Mads Ager418d1ca2017-05-22 09:35:49 +020036import com.android.tools.r8.utils.AndroidApp;
Ian Zerny140fad62023-01-27 10:33:19 +010037import com.android.tools.r8.utils.ArchiveResourceProvider;
Søren Gjesse99e8a742020-01-07 13:59:38 +010038import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
Søren Gjesse75a09792021-04-07 12:41:33 +020039import com.android.tools.r8.utils.DumpInputFlags;
Søren Gjesseb72b7432018-05-16 09:48:56 +020040import com.android.tools.r8.utils.ExceptionDiagnostic;
Mads Ager418d1ca2017-05-22 09:35:49 +020041import com.android.tools.r8.utils.FileUtils;
42import com.android.tools.r8.utils.InternalOptions;
Søren Gjesse9a7876d2020-01-13 14:32:26 +010043import com.android.tools.r8.utils.InternalOptions.DesugarState;
Christoffer Quist Adamsen0cc904a2021-05-11 11:31:58 +020044import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
Tamas Kenez3b5829a2017-12-18 11:22:06 +010045import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
Ian Zerny77440062022-08-26 13:49:08 +020046import com.android.tools.r8.utils.ProgramClassCollection;
Yohann Roussel9a8d4372017-11-21 14:36:44 +010047import com.android.tools.r8.utils.Reporter;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +010048import com.android.tools.r8.utils.SemanticVersion;
Ian Zerny140fad62023-01-27 10:33:19 +010049import com.android.tools.r8.utils.SetUtils;
Yohann Roussel9a8d4372017-11-21 14:36:44 +010050import com.android.tools.r8.utils.StringDiagnostic;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +010051import com.android.tools.r8.utils.StringUtils;
Søren Gjesse943389f2020-03-13 10:40:25 +010052import com.android.tools.r8.utils.ThreadUtils;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +010053import com.google.common.base.Suppliers;
Mads Ager418d1ca2017-05-22 09:35:49 +020054import com.google.common.collect.ImmutableList;
Søren Gjesseb72b7432018-05-16 09:48:56 +020055import java.io.InputStream;
Mads Ager418d1ca2017-05-22 09:35:49 +020056import java.nio.file.Path;
57import java.nio.file.Paths;
Ian Zerny140fad62023-01-27 10:33:19 +010058import java.util.ArrayDeque;
Mads Ager418d1ca2017-05-22 09:35:49 +020059import java.util.ArrayList;
Ian Zerny99683a32021-01-12 19:11:56 +010060import java.util.Arrays;
Ian Zerny7d1591f2018-01-03 12:38:07 +010061import java.util.Collection;
Ian Zernyc1582852023-01-30 13:45:36 +010062import java.util.Collections;
Ian Zerny140fad62023-01-27 10:33:19 +010063import java.util.Deque;
Mads Ager418d1ca2017-05-22 09:35:49 +020064import java.util.List;
Clément Béra64a3c4c2020-11-10 08:16:17 +000065import java.util.Optional;
Ian Zerny140fad62023-01-27 10:33:19 +010066import java.util.Set;
Alan Leung4b5db8e2019-07-23 13:53:10 -070067import java.util.function.BiPredicate;
Jinseong Jeonbcbe4cb2017-08-15 21:29:20 -070068import java.util.function.Consumer;
Rico Wind25f6eab2019-09-06 11:06:11 +020069import java.util.function.Function;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +010070import java.util.function.Supplier;
Mads Ager418d1ca2017-05-22 09:35:49 +020071
Ian Zernyafb08e12018-01-08 14:22:58 +010072/**
Søren Gjesseb72b7432018-05-16 09:48:56 +020073 * Immutable command structure for an invocation of the {@link R8} compiler.
Ian Zernyafb08e12018-01-08 14:22:58 +010074 *
75 * <p>To build a R8 command use the {@link R8Command.Builder} class. For example:
76 *
77 * <pre>
78 * R8Command command = R8Command.builder()
79 * .addProgramFiles(path1, path2)
80 * .setMode(CompilationMode.RELEASE)
81 * .setOutput(Paths.get("output.zip", OutputMode.DexIndexed))
82 * .build();
83 * </pre>
84 */
Mathias Rav3fb4a3a2018-05-29 15:41:36 +020085@Keep
86public final class R8Command extends BaseCompilerCommand {
Mads Ager418d1ca2017-05-22 09:35:49 +020087
Ian Zernyafb08e12018-01-08 14:22:58 +010088 /**
89 * Builder for constructing a R8Command.
90 *
91 * <p>A builder is obtained by calling {@link R8Command#builder}.
92 */
Mathias Rav3fb4a3a2018-05-29 15:41:36 +020093 @Keep
Søren Gjessec4e5e932017-09-04 17:01:23 +020094 public static class Builder extends BaseCompilerCommand.Builder<R8Command, Builder> {
Mads Ager418d1ca2017-05-22 09:35:49 +020095
Morten Krogh-Jespersenff59ed32018-10-08 15:15:57 +020096 private static class DefaultR8DiagnosticsHandler implements DiagnosticsHandler {
Ian Zerny72475172018-09-18 05:52:00 +020097
98 @Override
99 public void error(Diagnostic error) {
100 if (error instanceof DexFileOverflowDiagnostic) {
101 DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error;
102 if (!overflowDiagnostic.hasMainDexSpecification()) {
Morten Krogh-Jespersenff59ed32018-10-08 15:15:57 +0200103 DiagnosticsHandler.super.error(
Ian Zerny72475172018-09-18 05:52:00 +0200104 new StringDiagnostic(
105 overflowDiagnostic.getDiagnosticMessage()
106 + ". Try supplying a main-dex list or main-dex rules"));
107 return;
108 }
109 }
Morten Krogh-Jespersenff59ed32018-10-08 15:15:57 +0200110 DiagnosticsHandler.super.error(error);
Ian Zerny72475172018-09-18 05:52:00 +0200111 }
112 }
113
Søren Gjessea26ef842017-09-01 11:46:43 +0200114 private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
Ian Zernyf8ca0352019-06-07 11:58:48 +0200115 private Consumer<ProguardConfiguration.Builder> proguardConfigurationConsumerForTesting = null;
Søren Gjesse430740d2019-01-10 16:49:42 +0100116 private Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer = null;
clementbera2cc55162019-08-19 12:19:46 +0200117 private StringConsumer desugaredLibraryKeepRuleConsumer = null;
Søren Gjessea26ef842017-09-01 11:46:43 +0200118 private final List<ProguardConfigurationSource> proguardConfigs = new ArrayList<>();
Ian Zernyafb08e12018-01-08 14:22:58 +0100119 private boolean disableTreeShaking = false;
120 private boolean disableMinification = false;
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +0200121 private boolean disableVerticalClassMerging = false;
Søren Gjesseff153482017-10-09 15:21:14 +0200122 private boolean forceProguardCompatibility = false;
Clément Béra64a3c4c2020-11-10 08:16:17 +0000123 private Optional<Boolean> includeDataResources = Optional.empty();
Ian Zernyf8ca0352019-06-07 11:58:48 +0200124 private StringConsumer proguardUsageConsumer = null;
125 private StringConsumer proguardSeedsConsumer = null;
126 private StringConsumer proguardConfigurationConsumer = null;
Ian Zerny6375a9e2018-12-14 13:52:48 +0100127 private GraphConsumer keptGraphConsumer = null;
128 private GraphConsumer mainDexKeptGraphConsumer = null;
Ian Zernyec9566d2022-03-02 13:41:14 +0100129 private InputDependencyGraphConsumer inputDependencyGraphConsumer = null;
Rico Wind25f6eab2019-09-06 11:06:11 +0200130 private final List<FeatureSplit> featureSplits = new ArrayList<>();
Clément Béra6cbeb552020-03-18 09:20:18 +0000131 private String synthesizedClassPrefix = "";
Ian Zerny9b307322022-05-09 14:57:57 +0200132 private boolean enableMissingLibraryApiModeling = false;
Ian Zernyc1582852023-01-30 13:45:36 +0100133 private boolean enableExperimentalKeepAnnotations = false;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100134 private SemanticVersion fakeCompilerVersion = null;
Ian Zernyafb08e12018-01-08 14:22:58 +0100135
Christoffer Quist Adamsen6e689542022-05-30 20:02:09 +0200136 private final ProguardConfigurationParserOptions.Builder parserOptionsBuilder =
137 ProguardConfigurationParserOptions.builder().readEnvironment();
Søren Gjessec641bcc2022-06-29 10:00:34 +0200138 private final boolean allowDexInArchive =
139 System.getProperty("com.android.tools.r8.allowDexInputToR8") != null;
Søren Gjessec9e940f2018-05-28 12:56:56 +0200140
Ian Zernye09adb72018-05-08 11:12:12 +0200141 // TODO(zerny): Consider refactoring CompatProguardCommandBuilder to avoid subclassing.
Ian Zerny72475172018-09-18 05:52:00 +0200142 Builder() {
143 this(new DefaultR8DiagnosticsHandler());
144 }
Mads Ager418d1ca2017-05-22 09:35:49 +0200145
Ian Zernye09adb72018-05-08 11:12:12 +0200146 Builder(DiagnosticsHandler diagnosticsHandler) {
Søren Gjessec25649a2018-02-01 12:41:28 +0100147 super(diagnosticsHandler);
Søren Gjessec641bcc2022-06-29 10:00:34 +0200148 setIgnoreDexInArchive(!allowDexInArchive);
Søren Gjesse8fb83c82017-12-01 08:00:10 +0100149 }
150
Mads Ager418d1ca2017-05-22 09:35:49 +0200151 private Builder(AndroidApp app) {
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100152 super(app);
Søren Gjessec641bcc2022-06-29 10:00:34 +0200153 setIgnoreDexInArchive(!allowDexInArchive);
Mads Ager418d1ca2017-05-22 09:35:49 +0200154 }
155
Christoffer Quist Adamsen0eef4b02018-08-01 10:29:47 +0200156 private Builder(AndroidApp app, DiagnosticsHandler diagnosticsHandler) {
157 super(app, diagnosticsHandler);
Søren Gjessec641bcc2022-06-29 10:00:34 +0200158 setIgnoreDexInArchive(!allowDexInArchive);
Christoffer Quist Adamsen0eef4b02018-08-01 10:29:47 +0200159 }
160
Ian Zernye09adb72018-05-08 11:12:12 +0200161 // Internal
162
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +0200163 void setDisableVerticalClassMerging(boolean disableVerticalClassMerging) {
164 this.disableVerticalClassMerging = disableVerticalClassMerging;
Christoffer Quist Adamsen3b237832018-08-15 16:56:11 +0200165 }
166
Mads Ager418d1ca2017-05-22 09:35:49 +0200167 @Override
168 Builder self() {
169 return this;
170 }
171
Ian Zernye09adb72018-05-08 11:12:12 +0200172 @Override
173 CompilationMode defaultCompilationMode() {
174 return CompilationMode.RELEASE;
175 }
176
Clément Béra6cbeb552020-03-18 09:20:18 +0000177 Builder setSynthesizedClassesPrefix(String prefix) {
178 synthesizedClassPrefix = prefix;
179 return self();
180 }
181
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100182 Builder setFakeCompilerVersion(SemanticVersion version) {
183 fakeCompilerVersion = version;
184 return self();
185 }
186
Stephan Herhut2ecfe142017-06-01 14:24:01 +0200187 /**
Ian Zernyafb08e12018-01-08 14:22:58 +0100188 * Disable tree shaking.
189 *
190 * <p>If true, tree shaking is completely disabled, otherwise tree shaking is configured by
191 * ProGuard configuration settings.
Stephan Herhut2ecfe142017-06-01 14:24:01 +0200192 */
Ian Zernyafb08e12018-01-08 14:22:58 +0100193 public Builder setDisableTreeShaking(boolean disableTreeShaking) {
194 this.disableTreeShaking = disableTreeShaking;
Jinseong Jeona4317e62017-07-31 22:50:07 -0700195 return self();
Mads Ager418d1ca2017-05-22 09:35:49 +0200196 }
197
Stephan Herhut2ecfe142017-06-01 14:24:01 +0200198 /**
Ian Zernyafb08e12018-01-08 14:22:58 +0100199 * Disable minification of names.
200 *
201 * <p>If true, minification of names is completely disabled, otherwise minification of names is
202 * configured by ProGuard configuration settings.
Tamas Kenez887d57f2017-08-22 17:07:25 +0200203 */
Ian Zernyafb08e12018-01-08 14:22:58 +0100204 public Builder setDisableMinification(boolean disableMinification) {
205 this.disableMinification = disableMinification;
Tamas Kenez887d57f2017-08-22 17:07:25 +0200206 return self();
207 }
208
Ian Zernyafb08e12018-01-08 14:22:58 +0100209 /** Add proguard configuration files with rules for automatic main-dex-list calculation. */
Søren Gjessea26ef842017-09-01 11:46:43 +0200210 public Builder addMainDexRulesFiles(Path... paths) {
Ian Zerny99683a32021-01-12 19:11:56 +0100211 return addMainDexRulesFiles(Arrays.asList(paths));
Yohann Rousself820a572017-05-31 20:25:51 +0200212 }
213
Ian Zernyafb08e12018-01-08 14:22:58 +0100214 /** Add proguard configuration files with rules for automatic main-dex-list calculation. */
Ian Zerny7d1591f2018-01-03 12:38:07 +0100215 public Builder addMainDexRulesFiles(Collection<Path> paths) {
Ian Zerny99683a32021-01-12 19:11:56 +0100216 guard(() -> paths.forEach(p -> mainDexRules.add(new ProguardConfigurationSourceFile(p))));
Søren Gjessea26ef842017-09-01 11:46:43 +0200217 return self();
218 }
219
Ian Zerny5b65b3f2017-12-22 13:37:45 +0100220 /** Add proguard rules for automatic main-dex-list calculation. */
Yohann Roussel73df5e62017-11-20 14:06:32 +0100221 public Builder addMainDexRules(List<String> lines, Origin origin) {
Ian Zerny99683a32021-01-12 19:11:56 +0100222 guard(
223 () ->
224 mainDexRules.add(
225 new ProguardConfigurationSourceStrings(lines, Paths.get("."), origin)));
Jinseong Jeona4317e62017-07-31 22:50:07 -0700226 return self();
Yohann Rousself820a572017-05-31 20:25:51 +0200227 }
228
Ian Zerny797abef2022-04-01 15:39:02 +0200229 /**
230 * Set Proguard compatibility mode.
231 *
232 * <p>If true, R8 will attempt to retain more compatibility with Proguard. Most notably, R8 will
233 * introduce rules for keeping more default constructors as well as various attributes. Note
234 * that setting R8 in compatibility mode will result in larger residual programs.
235 */
236 public Builder setProguardCompatibility(boolean value) {
237 this.forceProguardCompatibility = value;
238 return self();
239 }
240
241 /** Get the current value of Proguard compatibility mode. */
242 public boolean getProguardCompatibility() {
243 return forceProguardCompatibility;
244 }
245
Ian Zernyafb08e12018-01-08 14:22:58 +0100246 /** Add proguard configuration-file resources. */
Mads Ager418d1ca2017-05-22 09:35:49 +0200247 public Builder addProguardConfigurationFiles(Path... paths) {
Yohann Roussel11efcc02017-12-01 12:04:36 +0100248 guard(() -> {
249 for (Path path : paths) {
250 proguardConfigs.add(new ProguardConfigurationSourceFile(path));
251 }
252 });
Jinseong Jeona4317e62017-07-31 22:50:07 -0700253 return self();
Mads Ager418d1ca2017-05-22 09:35:49 +0200254 }
255
Ian Zernyafb08e12018-01-08 14:22:58 +0100256 /** Add proguard configuration-file resources. */
Mads Ager418d1ca2017-05-22 09:35:49 +0200257 public Builder addProguardConfigurationFiles(List<Path> paths) {
Yohann Roussel11efcc02017-12-01 12:04:36 +0100258 guard(() -> {
259 for (Path path : paths) {
260 proguardConfigs.add(new ProguardConfigurationSourceFile(path));
261 }
262 });
Søren Gjessea26ef842017-09-01 11:46:43 +0200263 return self();
264 }
265
Ian Zernyafb08e12018-01-08 14:22:58 +0100266 /** Add proguard configuration. */
Yohann Roussel73df5e62017-11-20 14:06:32 +0100267 public Builder addProguardConfiguration(List<String> lines, Origin origin) {
Yohann Roussel11efcc02017-12-01 12:04:36 +0100268 guard(() -> proguardConfigs.add(
269 new ProguardConfigurationSourceStrings(lines, Paths.get("."), origin)));
Jinseong Jeona4317e62017-07-31 22:50:07 -0700270 return self();
Mads Ager418d1ca2017-05-22 09:35:49 +0200271 }
272
Stephan Herhut2ecfe142017-06-01 14:24:01 +0200273 /**
Ian Zerny5b65b3f2017-12-22 13:37:45 +0100274 * Set an output destination to which proguard-map content should be written.
275 *
276 * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
277 * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
278 * #setProguardMapConsumer} will override the previous setting.
279 *
280 * @param proguardMapOutput File-system path to write output at.
Stephan Herhut2ecfe142017-06-01 14:24:01 +0200281 */
Morten Krogh-Jespersen946bea92021-03-18 20:29:42 +0100282 @Override
Ian Zernyafb08e12018-01-08 14:22:58 +0100283 public Builder setProguardMapOutputPath(Path proguardMapOutput) {
Morten Krogh-Jespersen946bea92021-03-18 20:29:42 +0100284 return super.setProguardMapOutputPath(proguardMapOutput);
Mads Ager418d1ca2017-05-22 09:35:49 +0200285 }
286
Ian Zerny5b65b3f2017-12-22 13:37:45 +0100287 /**
288 * Set a consumer for receiving the proguard-map content.
289 *
Ian Zernyafb08e12018-01-08 14:22:58 +0100290 * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
Ian Zerny5b65b3f2017-12-22 13:37:45 +0100291 * override the previous setting.
292 *
293 * @param proguardMapConsumer Consumer to receive the content once produced.
294 */
Morten Krogh-Jespersen946bea92021-03-18 20:29:42 +0100295 @Override
Ian Zerny5b65b3f2017-12-22 13:37:45 +0100296 public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
Morten Krogh-Jespersen946bea92021-03-18 20:29:42 +0100297 return super.setProguardMapConsumer(proguardMapConsumer);
Tamas Kenez9f855612017-09-20 18:09:03 +0200298 }
299
Søren Gjesse4d015022018-09-14 13:26:57 +0200300 /**
clementbera2cc55162019-08-19 12:19:46 +0200301 * Set a consumer for receiving the keep rules to use when compiling the desugared library for
302 * the program being compiled in this compilation.
303 *
304 * @param keepRuleConsumer Consumer to receive the content once produced.
305 */
306 public Builder setDesugaredLibraryKeepRuleConsumer(StringConsumer keepRuleConsumer) {
307 this.desugaredLibraryKeepRuleConsumer = keepRuleConsumer;
308 return self();
309 }
310
311 /**
Ian Zernyf8ca0352019-06-07 11:58:48 +0200312 * Set a consumer for receiving the proguard usage information.
313 *
314 * <p>Note that any subsequent calls to this method will replace the previous setting.
315 *
316 * @param proguardUsageConsumer Consumer to receive usage information.
317 */
318 public Builder setProguardUsageConsumer(StringConsumer proguardUsageConsumer) {
319 this.proguardUsageConsumer = proguardUsageConsumer;
320 return self();
321 }
322
323 /**
324 * Set a consumer for receiving the proguard seeds information.
325 *
326 * <p>Note that any subsequent calls to this method will replace the previous setting.
327 *
328 * @param proguardSeedsConsumer Consumer to receive seeds information.
Ian Zernyf8ca0352019-06-07 11:58:48 +0200329 */
330 public Builder setProguardSeedsConsumer(StringConsumer proguardSeedsConsumer) {
331 this.proguardSeedsConsumer = proguardSeedsConsumer;
332 return self();
333 }
334
335 /**
336 * Set a consumer for receiving the proguard configuration information.
337 *
338 * <p>Note that any subsequent calls to this method will replace the previous setting.
Ian Zernyf8ca0352019-06-07 11:58:48 +0200339 * @param proguardConfigurationConsumer
Ian Zernyf8ca0352019-06-07 11:58:48 +0200340 */
341 public Builder setProguardConfigurationConsumer(StringConsumer proguardConfigurationConsumer) {
342 this.proguardConfigurationConsumer = proguardConfigurationConsumer;
343 return self();
344 }
345
346 /**
Ian Zerny6375a9e2018-12-14 13:52:48 +0100347 * Set a consumer for receiving kept-graph events.
Ian Zerny6375a9e2018-12-14 13:52:48 +0100348 */
349 public Builder setKeptGraphConsumer(GraphConsumer graphConsumer) {
350 this.keptGraphConsumer = graphConsumer;
351 return self();
352 }
353
354 /**
355 * Set a consumer for receiving kept-graph events for the content of the main-dex output.
Ian Zerny6375a9e2018-12-14 13:52:48 +0100356 */
357 public Builder setMainDexKeptGraphConsumer(GraphConsumer graphConsumer) {
358 this.mainDexKeptGraphConsumer = graphConsumer;
359 return self();
360 }
361
362 /**
Ian Zernyec9566d2022-03-02 13:41:14 +0100363 * Set a consumer for receiving dependency edges for files referenced from inputs.
364 *
365 * <p>Note that these dependency edges are for files read when reading/parsing other input
366 * files, such as the proguard configuration files. For compilation dependencies for incremental
367 * desugaring see {@code setDesugarGraphConsumer}.
368 */
369 public Builder setInputDependencyGraphConsumer(
370 InputDependencyGraphConsumer inputDependencyGraphConsumer) {
371 this.inputDependencyGraphConsumer = inputDependencyGraphConsumer;
372 return self();
373 }
374
375 /**
Søren Gjesse4d015022018-09-14 13:26:57 +0200376 * Set the output path-and-mode.
377 *
378 * <p>Setting the output path-and-mode will override any previous set consumer or any previous
379 * output path-and-mode, and implicitly sets the appropriate program consumer to write the
380 * output.
381 *
382 * <p>By default data resources from the input will be included in the output. (see {@link
383 * #setOutput(Path, OutputMode, boolean) for details}
384 *
385 * @param outputPath Path to write the output to. Must be an archive or and existing directory.
386 * @param outputMode Mode in which to write the output.
387 */
388 @Override
389 public Builder setOutput(Path outputPath, OutputMode outputMode) {
390 setOutput(outputPath, outputMode, true);
391 return self();
392 }
393
394 /**
395 * Set the output path-and-mode and control if data resources are included.
396 *
397 * <p>In addition to setting the output path-and-mode (see {@link #setOutput(Path, OutputMode)})
398 * this can control if data resources should be included or not.
399 *
400 * <p>Data resources are non Java classfile items in the input.
401 *
402 * <p>If data resources are not included they are ignored in the input and will not produce
403 * anything in the output. If data resources are included they are processed according to the
404 * configuration and written to the output.
405 *
406 * @param outputPath Path to write the output to. Must be an archive or and existing directory.
407 * @param outputMode Mode in which to write the output.
408 * @param includeDataResources If data resources from the input should be included in the
409 * output.
410 */
411 @Override
412 public Builder setOutput(Path outputPath, OutputMode outputMode, boolean includeDataResources) {
Clément Béra64a3c4c2020-11-10 08:16:17 +0000413 this.includeDataResources = Optional.of(includeDataResources);
Søren Gjesse4d015022018-09-14 13:26:57 +0200414 return super.setOutput(outputPath, outputMode, includeDataResources);
415 }
416
Ian Zerny113faac2017-12-14 12:58:23 +0100417 @Override
Ian Zerny1fede152018-01-05 07:28:29 +0100418 public Builder addProgramResourceProvider(ProgramResourceProvider programProvider) {
419 return super.addProgramResourceProvider(
420 new EnsureNonDexProgramResourceProvider(programProvider));
421 }
422
Rico Wind25f6eab2019-09-06 11:06:11 +0200423 /**
424 * Add a {@link FeatureSplit} to the app. The {@link FeatureSplit} contains input and output
425 * providers, that enables us to generate dynamic apps with optional modules.
426 *
427 * @param featureSplitGenerator A function that uses the supplied {@link FeatureSplit.Builder}
428 * to generate a {@link FeatureSplit}.
429 */
430 public Builder addFeatureSplit(
431 Function<FeatureSplit.Builder, FeatureSplit> featureSplitGenerator) {
Rico Windb5bb3e92019-09-23 10:32:10 +0200432 FeatureSplit featureSplit = featureSplitGenerator.apply(FeatureSplit.builder(getReporter()));
433 featureSplits.add(featureSplit);
Rico Wind8b6d4aa2019-11-06 08:53:32 +0100434 for (ProgramResourceProvider programResourceProvider : featureSplit
435 .getProgramResourceProviders()) {
436 // Data resources are handled separately and passed directly to the feature split consumer.
437 ProgramResourceProvider providerWithoutDataResources = new ProgramResourceProvider() {
438 @Override
439 public Collection<ProgramResource> getProgramResources() throws ResourceException {
440 return programResourceProvider.getProgramResources();
441 }
442
443 @Override
444 public DataResourceProvider getDataResourceProvider() {
445 return null;
446 }
447 };
448 addProgramResourceProvider(providerWithoutDataResources);
449 }
Rico Wind25f6eab2019-09-06 11:06:11 +0200450 return self();
451 }
452
Ian Zerny9b307322022-05-09 14:57:57 +0200453 /**
454 * Enable experimental/pre-release support for modeling missing library APIs.
455 *
456 * <p>This allows enabling the feature while it is still default disabled by the compiler. Once
457 * the feature is default enabled, calling this method will have no affect.
458 */
459 @Deprecated
460 public Builder setEnableExperimentalMissingLibraryApiModeling(boolean enable) {
461 this.enableMissingLibraryApiModeling = enable;
462 return self();
463 }
464
Ian Zernyc1582852023-01-30 13:45:36 +0100465 @Deprecated
466 public Builder setEnableExperimentalKeepAnnotations(boolean enable) {
467 this.enableExperimentalKeepAnnotations = enable;
468 return self();
469 }
470
Søren Gjesse7320ce52018-05-07 15:45:22 +0200471 @Override
472 protected InternalProgramOutputPathConsumer createProgramOutputConsumer(
473 Path path,
474 OutputMode mode,
475 boolean consumeDataResources) {
Søren Gjesse4d015022018-09-14 13:26:57 +0200476 return super.createProgramOutputConsumer(path, mode, consumeDataResources);
Søren Gjesse7320ce52018-05-07 15:45:22 +0200477 }
478
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200479 /**
480 * Add a collection of startup profile providers that should be used for distributing the
481 * program classes in dex. The given startup profiles are also used to disallow optimizations
482 * across the startup and post-startup boundary.
483 *
484 * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
485 * not support native multidex (API<=20).
486 *
487 * <p>NOTE: This API is experimental and may be subject to changes.
488 */
489 @Override
490 public Builder addStartupProfileProviders(StartupProfileProvider... startupProfileProviders) {
491 return super.addStartupProfileProviders(startupProfileProviders);
492 }
493
494 /**
495 * Add a collection of startup profile providers that should be used for distributing the
496 * program classes in dex. The given startup profiles are also used to disallow optimizations
497 * across the startup and post-startup boundary.
498 *
499 * <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
500 * not support native multidex (API<=20).
501 *
502 * <p>NOTE: This API is experimental and may be subject to changes.
503 */
504 @Override
505 public Builder addStartupProfileProviders(
506 Collection<StartupProfileProvider> startupProfileProviders) {
507 return super.addStartupProfileProviders(startupProfileProviders);
508 }
509
Ian Zerny1fede152018-01-05 07:28:29 +0100510 @Override
Ian Zernyafb08e12018-01-08 14:22:58 +0100511 void validate() {
Rico Wind5a6662a2020-08-27 08:39:21 +0200512 if (isPrintHelp()) {
513 return;
514 }
Ian Zernyafb08e12018-01-08 14:22:58 +0100515 Reporter reporter = getReporter();
Ian Zerny113faac2017-12-14 12:58:23 +0100516 if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) {
517 reporter.error("R8 does not support compiling to a single DEX file per Java class file");
518 }
Mads Agerd9ae2a82018-11-29 13:01:55 +0100519 if (getMainDexListConsumer() != null
Ian Zerny1b958eb2017-12-19 10:35:33 +0100520 && mainDexRules.isEmpty()
521 && !getAppBuilder().hasMainDexList()) {
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100522 reporter.error(
Ian Zerny99683a32021-01-12 19:11:56 +0100523 "Option --main-dex-list-output requires --main-dex-rules and/or --main-dex-list");
Søren Gjessec801ecc2017-08-03 13:40:06 +0200524 }
Ian Zerny1ca41482018-12-18 13:42:49 +0000525 if (!(getProgramConsumer() instanceof ClassFileConsumer)
526 && getMinApiLevel() >= AndroidApiLevel.L.getLevel()) {
527 if (getMainDexListConsumer() != null
528 || !mainDexRules.isEmpty()
529 || getAppBuilder().hasMainDexList()) {
530 reporter.error(
531 "R8 does not support main-dex inputs and outputs when compiling to API level "
532 + AndroidApiLevel.L.getLevel()
533 + " and above");
534 }
535 }
Rico Wind25f6eab2019-09-06 11:06:11 +0200536 for (FeatureSplit featureSplit : featureSplits) {
537 assert featureSplit.getProgramConsumer() instanceof DexIndexedConsumer;
538 if (!(getProgramConsumer() instanceof DexIndexedConsumer)) {
539 reporter.error("R8 does not support class file output when using feature splits");
540 }
541 }
542
Ian Zerny1fede152018-01-05 07:28:29 +0100543 for (Path file : programFiles) {
544 if (FileUtils.isDexFile(file)) {
545 reporter.error(new StringDiagnostic(
546 "R8 does not support compiling DEX inputs", new PathOrigin(file)));
547 }
548 }
Mathias Rav86d26022018-03-16 10:13:34 +0100549 if (getProgramConsumer() instanceof ClassFileConsumer && isMinApiLevelSet()) {
550 reporter.error("R8 does not support --min-api when compiling to class files");
551 }
clementbera75174ac2019-09-04 09:14:44 +0200552 if (hasDesugaredLibraryConfiguration() && getDisableDesugaring()) {
553 reporter.error("Using desugared library configuration requires desugaring to be enabled");
Søren Gjessead54aa52019-07-16 15:30:01 +0200554 }
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100555 super.validate();
Søren Gjessec801ecc2017-08-03 13:40:06 +0200556 }
557
Mads Ager418d1ca2017-05-22 09:35:49 +0200558 @Override
Ian Zernyafb08e12018-01-08 14:22:58 +0100559 R8Command makeCommand() {
Ian Zernye09adb72018-05-08 11:12:12 +0200560 // If printing versions ignore everything else.
561 if (isPrintHelp() || isPrintVersion()) {
562 return new R8Command(isPrintHelp(), isPrintVersion());
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100563 }
Ian Zernye09adb72018-05-08 11:12:12 +0200564 return makeR8Command();
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100565 }
566
Ian Zernye09adb72018-05-08 11:12:12 +0200567 private R8Command makeR8Command() {
Ian Zernyafb08e12018-01-08 14:22:58 +0100568 Reporter reporter = getReporter();
Mads Ager418d1ca2017-05-22 09:35:49 +0200569 DexItemFactory factory = new DexItemFactory();
Ian Zerny99683a32021-01-12 19:11:56 +0100570 List<ProguardConfigurationRule> mainDexKeepRules =
571 ProguardConfigurationParser.parse(mainDexRules, factory, reporter);
Tamas Kenez56779222017-10-13 15:16:45 +0200572
Clément Béra24cb20a2022-02-17 09:30:14 +0000573 DesugaredLibrarySpecification desugaredLibrarySpecification =
clementbera79854ab2019-09-24 14:47:06 +0200574 getDesugaredLibraryConfiguration(factory, false);
clementbera75174ac2019-09-04 09:14:44 +0200575
Søren Gjesse91475052018-09-25 14:38:39 +0200576 ProguardConfigurationParser parser =
Ian Zernyec9566d2022-03-02 13:41:14 +0100577 new ProguardConfigurationParser(
Christoffer Quist Adamsen6e689542022-05-30 20:02:09 +0200578 factory, reporter, parserOptionsBuilder.build(), inputDependencyGraphConsumer);
Søren Gjesseb72b7432018-05-16 09:48:56 +0200579 if (!proguardConfigs.isEmpty()) {
Yohann Rousself17d02d2017-11-29 18:08:09 +0100580 parser.parse(proguardConfigs);
Mads Ager418d1ca2017-05-22 09:35:49 +0200581 }
Søren Gjesseb72b7432018-05-16 09:48:56 +0200582 ProguardConfiguration.Builder configurationBuilder = parser.getConfigurationBuilder();
583 configurationBuilder.setForceProguardCompatibility(forceProguardCompatibility);
Mads Ager418d1ca2017-05-22 09:35:49 +0200584
Ian Zernyf828e2a2021-10-11 13:45:39 +0200585 if (getMode() == CompilationMode.DEBUG) {
586 disableMinification = true;
587 configurationBuilder.disableOptimization();
588 }
589
Stephan Herhut1a9eee42018-01-31 10:51:10 +0100590 if (disableTreeShaking) {
591 configurationBuilder.disableShrinking();
592 }
593
594 if (disableMinification) {
595 configurationBuilder.disableObfuscation();
596 }
597
Ian Zerny140fad62023-01-27 10:33:19 +0100598 if (proguardConfigurationConsumerForTesting != null) {
599 proguardConfigurationConsumerForTesting.accept(configurationBuilder);
600 }
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100601
602 // Add embedded keep rules.
Ian Zerny140fad62023-01-27 10:33:19 +0100603 amendWithRulesAndProvidersForInjarsAndMetaInf(reporter, parser);
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100604
Ian Zernyc1582852023-01-30 13:45:36 +0100605 // Extract out rules for keep annotations and amend the configuration.
606 // TODO(b/248408342): Remove this and parse annotations as part of R8 root-set & enqueuer.
607 extractKeepAnnotationRules(parser);
Tamas Kenez56779222017-10-13 15:16:45 +0200608 ProguardConfiguration configuration = configurationBuilder.build();
Ian Zerny140fad62023-01-27 10:33:19 +0100609 getAppBuilder().addFilteredLibraryArchives(configuration.getLibraryjars());
Tamas Kenez56779222017-10-13 15:16:45 +0200610
Ian Zerny113faac2017-12-14 12:58:23 +0100611 assert getProgramConsumer() != null;
612
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100613 DesugarState desugaring =
614 (getProgramConsumer() instanceof ClassFileConsumer)
615 ? DesugarState.OFF
616 : getDesugaringState();
Mathias Rav1d6ef622018-02-27 11:57:36 +0100617
Rico Windb5bb3e92019-09-23 10:32:10 +0200618 FeatureSplitConfiguration featureSplitConfiguration =
Christoffer Quist Adamsenc94779d2020-09-10 08:20:41 +0200619 !featureSplits.isEmpty() ? new FeatureSplitConfiguration(featureSplits) : null;
Rico Windb5bb3e92019-09-23 10:32:10 +0200620
Ian Zernyb71106a2017-12-05 09:57:35 +0100621 R8Command command =
622 new R8Command(
623 getAppBuilder().build(),
Ian Zerny113faac2017-12-14 12:58:23 +0100624 getProgramConsumer(),
Ian Zernyb71106a2017-12-05 09:57:35 +0100625 mainDexKeepRules,
Mads Agerd9ae2a82018-11-29 13:01:55 +0100626 getMainDexListConsumer(),
Ian Zernyb71106a2017-12-05 09:57:35 +0100627 configuration,
628 getMode(),
629 getMinApiLevel(),
630 reporter,
Mathias Rav1d6ef622018-02-27 11:57:36 +0100631 desugaring,
Stephan Herhut1a9eee42018-01-31 10:51:10 +0100632 configuration.isShrinking(),
633 configuration.isObfuscating(),
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +0200634 disableVerticalClassMerging,
Ian Zernyb71106a2017-12-05 09:57:35 +0100635 forceProguardCompatibility,
Clément Béra64a3c4c2020-11-10 08:16:17 +0000636 includeDataResources,
Ian Zernyb71106a2017-12-05 09:57:35 +0100637 proguardMapConsumer,
Ian Zernyf8ca0352019-06-07 11:58:48 +0200638 proguardUsageConsumer,
639 proguardSeedsConsumer,
640 proguardConfigurationConsumer,
Ian Zerny6375a9e2018-12-14 13:52:48 +0100641 keptGraphConsumer,
642 mainDexKeptGraphConsumer,
Søren Gjesse430740d2019-01-10 16:49:42 +0100643 syntheticProguardRulesConsumer,
Søren Gjessead54aa52019-07-16 15:30:01 +0200644 isOptimizeMultidexForLinearAlloc(),
Alan Leung4b5db8e2019-07-23 13:53:10 -0700645 getIncludeClassesChecksum(),
clementbera2cc55162019-08-19 12:19:46 +0200646 getDexClassChecksumFilter(),
clementbera75174ac2019-09-04 09:14:44 +0200647 desugaredLibraryKeepRuleConsumer,
Clément Béraddd19a12021-12-09 08:14:53 +0000648 desugaredLibrarySpecification,
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100649 featureSplitConfiguration,
Ian Zerny8f3ba442020-03-11 16:32:27 +0100650 getAssertionsConfiguration(),
Søren Gjesse943389f2020-03-13 10:40:25 +0100651 getOutputInspections(),
Clément Béra6cbeb552020-03-18 09:20:18 +0000652 synthesizedClassPrefix,
Søren Gjesse75a09792021-04-07 12:41:33 +0200653 getThreadCount(),
Ian Zernyb23c47c2021-10-06 08:00:19 +0200654 getDumpInputFlags(),
Ian Zerny1433d582021-10-12 09:44:48 +0200655 getMapIdProvider(),
Ian Zerny9b307322022-05-09 14:57:57 +0200656 getSourceFileProvider(),
Ian Zernybbd23922022-06-07 10:33:31 +0200657 enableMissingLibraryApiModeling,
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200658 getAndroidPlatformBuild(),
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200659 getArtProfilesForRewriting(),
Ian Zerny77440062022-08-26 13:49:08 +0200660 getStartupProfileProviders(),
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100661 getClassConflictResolver(),
662 fakeCompilerVersion);
Ian Zernyec9566d2022-03-02 13:41:14 +0100663
664 if (inputDependencyGraphConsumer != null) {
665 inputDependencyGraphConsumer.finished();
666 }
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100667 return command;
Mads Ager418d1ca2017-05-22 09:35:49 +0200668 }
Ian Zerny4479c732018-01-04 14:04:56 +0100669
Ian Zerny140fad62023-01-27 10:33:19 +0100670 private void amendWithRulesAndProvidersForInjarsAndMetaInf(
671 Reporter reporter, ProguardConfigurationParser parser) {
672
Ian Zerny140fad62023-01-27 10:33:19 +0100673 // Since -injars can itself reference archives with rules and that in turn have -injars the
674 // completion of amending rules and providers must run in a fixed point. The fixed point is
675 // reached once the injars set is stable.
676 Set<FilteredClassPath> seenInjars = SetUtils.newIdentityHashSet();
677 Deque<ProgramResourceProvider> providers =
678 new ArrayDeque<>(getAppBuilder().getProgramResourceProviders());
679 while (true) {
680 for (FilteredClassPath injar : parser.getConfigurationBuilder().getInjars()) {
681 if (seenInjars.add(injar)) {
682 ArchiveResourceProvider provider = getAppBuilder().createAndAddProvider(injar);
Ian Zerny3fcd2bd2023-01-30 20:14:12 +0100683 if (provider != null) {
684 providers.add(provider);
685 }
Ian Zerny140fad62023-01-27 10:33:19 +0100686 }
687 }
688 if (providers.isEmpty()) {
689 return;
690 }
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100691
692 Supplier<SemanticVersion> semanticVersionSupplier =
693 Suppliers.memoize(
694 () -> {
695 SemanticVersion compilerVersion =
696 fakeCompilerVersion == null
697 ? SemanticVersion.create(
698 Version.getMajorVersion(),
699 Version.getMinorVersion(),
700 Version.getPatchVersion())
701 : fakeCompilerVersion;
702 if (compilerVersion.getMajor() < 0) {
Søren Gjesse6402f442023-02-14 12:44:53 +0100703 compilerVersion =
704 SemanticVersion.create(
705 Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100706 reporter.warning(
707 "Running R8 version "
708 + Version.getVersionString()
Søren Gjesse6402f442023-02-14 12:44:53 +0100709 + ", which cannot be represented as a semantic version. Using"
710 + " an artificial version newer than any known version for selecting"
711 + " Proguard configurations embedded under META-INF/. This means that"
712 + " all rules with a '-max-' qualifier will be excluded and all rules"
713 + " with a -min- qualifier will be included.");
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100714 }
715 return compilerVersion;
716 });
717
Ian Zerny140fad62023-01-27 10:33:19 +0100718 while (!providers.isEmpty()) {
719 DataResourceProvider dataResourceProvider = providers.pop().getDataResourceProvider();
720 if (dataResourceProvider != null) {
721 try {
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100722 ExtractEmbeddedRules embeddedProguardConfigurationVisitor =
723 new ExtractEmbeddedRules(reporter, semanticVersionSupplier);
Ian Zerny140fad62023-01-27 10:33:19 +0100724 dataResourceProvider.accept(embeddedProguardConfigurationVisitor);
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100725 embeddedProguardConfigurationVisitor.parseRelevantRules(parser);
Ian Zerny140fad62023-01-27 10:33:19 +0100726 } catch (ResourceException e) {
727 reporter.error(new ExceptionDiagnostic(e));
728 }
729 }
730 }
731 }
732 }
733
Ian Zernyc1582852023-01-30 13:45:36 +0100734 private void extractKeepAnnotationRules(ProguardConfigurationParser parser) {
735 if (!enableExperimentalKeepAnnotations) {
736 return;
737 }
738 try {
739 for (ProgramResourceProvider provider : getAppBuilder().getProgramResourceProviders()) {
740 for (ProgramResource resource : provider.getProgramResources()) {
741 if (resource.getKind() == Kind.CF) {
742 Set<KeepEdge> edges = KeepEdgeReader.readKeepEdges(resource.getBytes());
743 KeepRuleExtractor extractor =
744 new KeepRuleExtractor(
745 rule -> {
746 ProguardConfigurationSourceStrings source =
747 new ProguardConfigurationSourceStrings(
748 Collections.singletonList(rule), null, resource.getOrigin());
749 parser.parse(source);
750 });
751 edges.forEach(extractor::extract);
752 }
753 }
754 }
755 } catch (ResourceException e) {
756 throw getAppBuilder().getReporter().fatalError(new ExceptionDiagnostic(e));
757 }
758 }
759
Ian Zerny4479c732018-01-04 14:04:56 +0100760 // Internal for-testing method to add post-processors of the proguard configuration.
761 void addProguardConfigurationConsumerForTesting(Consumer<ProguardConfiguration.Builder> c) {
Ian Zernyf8ca0352019-06-07 11:58:48 +0200762 Consumer<ProguardConfiguration.Builder> oldConsumer = proguardConfigurationConsumerForTesting;
763 proguardConfigurationConsumerForTesting =
Ian Zerny4479c732018-01-04 14:04:56 +0100764 builder -> {
765 if (oldConsumer != null) {
766 oldConsumer.accept(builder);
767 }
768 c.accept(builder);
769 };
770 }
Søren Gjessec9e940f2018-05-28 12:56:56 +0200771
Søren Gjesse430740d2019-01-10 16:49:42 +0100772 void addSyntheticProguardRulesConsumerForTesting(
773 Consumer<List<ProguardConfigurationRule>> consumer) {
774 syntheticProguardRulesConsumer =
775 syntheticProguardRulesConsumer == null
776 ? consumer
777 : syntheticProguardRulesConsumer.andThen(consumer);
778
779 }
780
Christoffer Quist Adamsen62971ce2022-06-03 09:53:36 +0200781 void setEnableExperimentalCheckEnumUnboxed() {
782 parserOptionsBuilder.setEnableExperimentalCheckEnumUnboxed(true);
783 }
784
Christoffer Quist Adamsen067d98a2022-06-01 14:13:38 +0200785 void setEnableExperimentalConvertCheckNotNull() {
786 parserOptionsBuilder.setEnableExperimentalConvertCheckNotNull(true);
787 }
788
Christoffer Quist Adamsen6e689542022-05-30 20:02:09 +0200789 void setEnableExperimentalWhyAreYouNotInlining() {
790 parserOptionsBuilder.setEnableExperimentalWhyAreYouNotInlining(true);
791 }
792
Søren Gjessec08521d2018-07-05 16:08:02 +0200793 // Internal for-testing method to allow proguard options only available for testing.
Christoffer Quist Adamsen6e689542022-05-30 20:02:09 +0200794 void setEnableTestProguardOptions() {
795 parserOptionsBuilder.setEnableTestingOptions(true);
Søren Gjessec08521d2018-07-05 16:08:02 +0200796 }
Mads Ager418d1ca2017-05-22 09:35:49 +0200797 }
798
Ian Zerny1fede152018-01-05 07:28:29 +0100799 // Wrapper class to ensure that R8 does not allow DEX as program inputs.
800 private static class EnsureNonDexProgramResourceProvider implements ProgramResourceProvider {
801
802 final ProgramResourceProvider provider;
803
804 public EnsureNonDexProgramResourceProvider(ProgramResourceProvider provider) {
805 this.provider = provider;
806 }
807
808 @Override
809 public Collection<ProgramResource> getProgramResources() throws ResourceException {
810 Collection<ProgramResource> resources = provider.getProgramResources();
811 for (ProgramResource resource : resources) {
812 if (resource.getKind() == Kind.DEX) {
813 throw new ResourceException(resource.getOrigin(),
814 "R8 does not support compiling DEX inputs");
815 }
816 }
817 return resources;
818 }
Søren Gjesseb72b7432018-05-16 09:48:56 +0200819
820 @Override
821 public DataResourceProvider getDataResourceProvider() {
822 return provider.getDataResourceProvider();
823 }
Ian Zerny1fede152018-01-05 07:28:29 +0100824 }
825
Ian Zernyaefe7bc2022-05-04 11:28:19 +0200826 static String getUsageMessage() {
827 return R8CommandParser.getUsageMessage();
828 }
Mads Ager418d1ca2017-05-22 09:35:49 +0200829
Morten Krogh-Jespersen3ebe2162019-01-10 11:04:46 +0100830 private final List<ProguardConfigurationRule> mainDexKeepRules;
Mads Ager418d1ca2017-05-22 09:35:49 +0200831 private final ProguardConfiguration proguardConfiguration;
Ian Zernyafb08e12018-01-08 14:22:58 +0100832 private final boolean enableTreeShaking;
833 private final boolean enableMinification;
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +0200834 private final boolean disableVerticalClassMerging;
Søren Gjesseff153482017-10-09 15:21:14 +0200835 private final boolean forceProguardCompatibility;
Clément Béra64a3c4c2020-11-10 08:16:17 +0000836 private final Optional<Boolean> includeDataResources;
Ian Zerny3c34a7a2017-12-06 11:05:00 +0100837 private final StringConsumer proguardMapConsumer;
Ian Zernyf8ca0352019-06-07 11:58:48 +0200838 private final StringConsumer proguardUsageConsumer;
839 private final StringConsumer proguardSeedsConsumer;
840 private final StringConsumer proguardConfigurationConsumer;
Ian Zerny6375a9e2018-12-14 13:52:48 +0100841 private final GraphConsumer keptGraphConsumer;
842 private final GraphConsumer mainDexKeptGraphConsumer;
Søren Gjesse430740d2019-01-10 16:49:42 +0100843 private final Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer;
clementbera2cc55162019-08-19 12:19:46 +0200844 private final StringConsumer desugaredLibraryKeepRuleConsumer;
Clément Béra24cb20a2022-02-17 09:30:14 +0000845 private final DesugaredLibrarySpecification desugaredLibrarySpecification;
Rico Windb5bb3e92019-09-23 10:32:10 +0200846 private final FeatureSplitConfiguration featureSplitConfiguration;
Clément Béra6cbeb552020-03-18 09:20:18 +0000847 private final String synthesizedClassPrefix;
Ian Zerny9b307322022-05-09 14:57:57 +0200848 private final boolean enableMissingLibraryApiModeling;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100849 private final SemanticVersion fakeCompilerVersion;
Mads Ager418d1ca2017-05-22 09:35:49 +0200850
Ian Zernyafb08e12018-01-08 14:22:58 +0100851 /** Get a new {@link R8Command.Builder}. */
Mads Ager418d1ca2017-05-22 09:35:49 +0200852 public static Builder builder() {
853 return new Builder();
854 }
855
Ian Zernyafb08e12018-01-08 14:22:58 +0100856 /** Get a new {@link R8Command.Builder} using a custom defined diagnostics handler. */
Søren Gjesse8fb83c82017-12-01 08:00:10 +0100857 public static Builder builder(DiagnosticsHandler diagnosticsHandler) {
858 return new Builder(diagnosticsHandler);
859 }
860
Mads Ager418d1ca2017-05-22 09:35:49 +0200861 // Internal builder to start from an existing AndroidApp.
862 static Builder builder(AndroidApp app) {
863 return new Builder(app);
864 }
865
Christoffer Quist Adamsen0eef4b02018-08-01 10:29:47 +0200866 // Internal builder to start from an existing AndroidApp.
867 static Builder builder(AndroidApp app, DiagnosticsHandler diagnosticsHandler) {
868 return new Builder(app, diagnosticsHandler);
869 }
870
Ian Zerny113faac2017-12-14 12:58:23 +0100871 /**
872 * Parse the R8 command-line.
873 *
874 * Parsing will set the supplied options or their default value if they have any.
875 *
876 * @param args Command-line arguments array.
877 * @param origin Origin description of the command-line arguments.
878 * @return R8 command builder with state set up according to parsed command line.
879 */
880 public static Builder parse(String[] args, Origin origin) {
Mathias Rava2a64f12018-05-29 12:52:41 +0200881 return R8CommandParser.parse(args, origin);
Ian Zernybaaad9f2018-01-09 07:45:24 +0100882 }
883
884 /**
885 * Parse the R8 command-line.
886 *
887 * Parsing will set the supplied options or their default value if they have any.
888 *
889 * @param args Command-line arguments array.
890 * @param origin Origin description of the command-line arguments.
891 * @param handler Custom defined diagnostics handler.
892 * @return R8 command builder with state set up according to parsed command line.
893 */
894 public static Builder parse(String[] args, Origin origin, DiagnosticsHandler handler) {
Mathias Rava2a64f12018-05-29 12:52:41 +0200895 return R8CommandParser.parse(args, origin, handler);
Mads Ager418d1ca2017-05-22 09:35:49 +0200896 }
897
Ian Zernyaefe7bc2022-05-04 11:28:19 +0200898 /** Get the help description for the R8 supported flags. */
899 public static List<ParseFlagInfo> getParseFlagsInformation() {
900 return ImmutableList.copyOf(R8CommandParser.getFlags());
901 }
902
Ian Zernybaaad9f2018-01-09 07:45:24 +0100903 private R8Command(
Mads Ager418d1ca2017-05-22 09:35:49 +0200904 AndroidApp inputApp,
Ian Zerny7efd28d2017-12-12 09:17:42 +0100905 ProgramConsumer programConsumer,
Morten Krogh-Jespersen3ebe2162019-01-10 11:04:46 +0100906 List<ProguardConfigurationRule> mainDexKeepRules,
Ian Zerny7c5c4f72017-12-06 13:37:07 +0100907 StringConsumer mainDexListConsumer,
Mads Ager418d1ca2017-05-22 09:35:49 +0200908 ProguardConfiguration proguardConfiguration,
909 CompilationMode mode,
910 int minApiLevel,
Yohann Roussel9a8d4372017-11-21 14:36:44 +0100911 Reporter reporter,
Søren Gjesse9a7876d2020-01-13 14:32:26 +0100912 DesugarState enableDesugaring,
Ian Zernyafb08e12018-01-08 14:22:58 +0100913 boolean enableTreeShaking,
914 boolean enableMinification,
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +0200915 boolean disableVerticalClassMerging,
Søren Gjesseff153482017-10-09 15:21:14 +0200916 boolean forceProguardCompatibility,
Clément Béra64a3c4c2020-11-10 08:16:17 +0000917 Optional<Boolean> includeDataResources,
Ian Zerny3c34a7a2017-12-06 11:05:00 +0100918 StringConsumer proguardMapConsumer,
Ian Zernyf8ca0352019-06-07 11:58:48 +0200919 StringConsumer proguardUsageConsumer,
920 StringConsumer proguardSeedsConsumer,
921 StringConsumer proguardConfigurationConsumer,
Ian Zerny6375a9e2018-12-14 13:52:48 +0100922 GraphConsumer keptGraphConsumer,
923 GraphConsumer mainDexKeptGraphConsumer,
Søren Gjesse430740d2019-01-10 16:49:42 +0100924 Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer,
Søren Gjessead54aa52019-07-16 15:30:01 +0200925 boolean optimizeMultidexForLinearAlloc,
Alan Leung4b5db8e2019-07-23 13:53:10 -0700926 boolean encodeChecksum,
clementbera2cc55162019-08-19 12:19:46 +0200927 BiPredicate<String, Long> dexClassChecksumFilter,
clementbera75174ac2019-09-04 09:14:44 +0200928 StringConsumer desugaredLibraryKeepRuleConsumer,
Clément Béra24cb20a2022-02-17 09:30:14 +0000929 DesugaredLibrarySpecification desugaredLibrarySpecification,
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100930 FeatureSplitConfiguration featureSplitConfiguration,
Ian Zerny8f3ba442020-03-11 16:32:27 +0100931 List<AssertionsConfiguration> assertionsConfiguration,
Søren Gjesse943389f2020-03-13 10:40:25 +0100932 List<Consumer<Inspector>> outputInspections,
Clément Béra6cbeb552020-03-18 09:20:18 +0000933 String synthesizedClassPrefix,
Søren Gjesse75a09792021-04-07 12:41:33 +0200934 int threadCount,
Ian Zernyb23c47c2021-10-06 08:00:19 +0200935 DumpInputFlags dumpInputFlags,
Ian Zerny1433d582021-10-12 09:44:48 +0200936 MapIdProvider mapIdProvider,
Ian Zerny9b307322022-05-09 14:57:57 +0200937 SourceFileProvider sourceFileProvider,
Ian Zernybbd23922022-06-07 10:33:31 +0200938 boolean enableMissingLibraryApiModeling,
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200939 boolean isAndroidPlatformBuild,
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200940 List<ArtProfileForRewriting> artProfilesForRewriting,
Ian Zerny77440062022-08-26 13:49:08 +0200941 List<StartupProfileProvider> startupProfileProviders,
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100942 ClassConflictResolver classConflictResolver,
943 SemanticVersion fakeCompilerVersion) {
Søren Gjessecbeae782019-05-21 14:14:25 +0200944 super(
945 inputApp,
946 mode,
947 programConsumer,
948 mainDexListConsumer,
949 minApiLevel,
950 reporter,
951 enableDesugaring,
Søren Gjessead54aa52019-07-16 15:30:01 +0200952 optimizeMultidexForLinearAlloc,
Alan Leung4b5db8e2019-07-23 13:53:10 -0700953 encodeChecksum,
Søren Gjesse95fce5f2019-12-16 10:33:51 +0100954 dexClassChecksumFilter,
Ian Zerny8f3ba442020-03-11 16:32:27 +0100955 assertionsConfiguration,
Søren Gjesse943389f2020-03-13 10:40:25 +0100956 outputInspections,
Søren Gjesse75a09792021-04-07 12:41:33 +0200957 threadCount,
Ian Zernyb23c47c2021-10-06 08:00:19 +0200958 dumpInputFlags,
Ian Zerny1433d582021-10-12 09:44:48 +0200959 mapIdProvider,
Ian Zernybbd23922022-06-07 10:33:31 +0200960 sourceFileProvider,
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +0200961 isAndroidPlatformBuild,
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +0200962 artProfilesForRewriting,
Ian Zerny77440062022-08-26 13:49:08 +0200963 startupProfileProviders,
964 classConflictResolver);
Mads Ager418d1ca2017-05-22 09:35:49 +0200965 assert proguardConfiguration != null;
Yohann Rousself820a572017-05-31 20:25:51 +0200966 assert mainDexKeepRules != null;
967 this.mainDexKeepRules = mainDexKeepRules;
Mads Ager418d1ca2017-05-22 09:35:49 +0200968 this.proguardConfiguration = proguardConfiguration;
Ian Zernyafb08e12018-01-08 14:22:58 +0100969 this.enableTreeShaking = enableTreeShaking;
970 this.enableMinification = enableMinification;
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +0200971 this.disableVerticalClassMerging = disableVerticalClassMerging;
Søren Gjesseff153482017-10-09 15:21:14 +0200972 this.forceProguardCompatibility = forceProguardCompatibility;
Clément Béra64a3c4c2020-11-10 08:16:17 +0000973 this.includeDataResources = includeDataResources;
Ian Zernyb71106a2017-12-05 09:57:35 +0100974 this.proguardMapConsumer = proguardMapConsumer;
Ian Zernyf8ca0352019-06-07 11:58:48 +0200975 this.proguardUsageConsumer = proguardUsageConsumer;
976 this.proguardSeedsConsumer = proguardSeedsConsumer;
977 this.proguardConfigurationConsumer = proguardConfigurationConsumer;
Ian Zerny6375a9e2018-12-14 13:52:48 +0100978 this.keptGraphConsumer = keptGraphConsumer;
979 this.mainDexKeptGraphConsumer = mainDexKeptGraphConsumer;
Søren Gjesse430740d2019-01-10 16:49:42 +0100980 this.syntheticProguardRulesConsumer = syntheticProguardRulesConsumer;
clementbera2cc55162019-08-19 12:19:46 +0200981 this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
Clément Béraddd19a12021-12-09 08:14:53 +0000982 this.desugaredLibrarySpecification = desugaredLibrarySpecification;
Rico Windb5bb3e92019-09-23 10:32:10 +0200983 this.featureSplitConfiguration = featureSplitConfiguration;
Clément Béra6cbeb552020-03-18 09:20:18 +0000984 this.synthesizedClassPrefix = synthesizedClassPrefix;
Ian Zerny9b307322022-05-09 14:57:57 +0200985 this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +0100986 this.fakeCompilerVersion = fakeCompilerVersion;
Mads Ager418d1ca2017-05-22 09:35:49 +0200987 }
988
989 private R8Command(boolean printHelp, boolean printVersion) {
990 super(printHelp, printVersion);
Yohann Rousself820a572017-05-31 20:25:51 +0200991 mainDexKeepRules = ImmutableList.of();
Mads Ager418d1ca2017-05-22 09:35:49 +0200992 proguardConfiguration = null;
Ian Zernyafb08e12018-01-08 14:22:58 +0100993 enableTreeShaking = false;
994 enableMinification = false;
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +0200995 disableVerticalClassMerging = false;
Søren Gjesseff153482017-10-09 15:21:14 +0200996 forceProguardCompatibility = false;
Clément Béra64a3c4c2020-11-10 08:16:17 +0000997 includeDataResources = null;
Ian Zernyb71106a2017-12-05 09:57:35 +0100998 proguardMapConsumer = null;
Ian Zernyf8ca0352019-06-07 11:58:48 +0200999 proguardUsageConsumer = null;
1000 proguardSeedsConsumer = null;
1001 proguardConfigurationConsumer = null;
Ian Zerny6375a9e2018-12-14 13:52:48 +01001002 keptGraphConsumer = null;
1003 mainDexKeptGraphConsumer = null;
Søren Gjesse430740d2019-01-10 16:49:42 +01001004 syntheticProguardRulesConsumer = null;
clementbera2cc55162019-08-19 12:19:46 +02001005 desugaredLibraryKeepRuleConsumer = null;
Clément Béraddd19a12021-12-09 08:14:53 +00001006 desugaredLibrarySpecification = null;
Rico Windb5bb3e92019-09-23 10:32:10 +02001007 featureSplitConfiguration = null;
Clément Béra6cbeb552020-03-18 09:20:18 +00001008 synthesizedClassPrefix = null;
Ian Zerny9b307322022-05-09 14:57:57 +02001009 enableMissingLibraryApiModeling = false;
Søren Gjesse5de6d7d2023-02-10 12:37:19 +01001010 fakeCompilerVersion = null;
Mads Ager418d1ca2017-05-22 09:35:49 +02001011 }
Ian Zerny7efd28d2017-12-12 09:17:42 +01001012
Christoffer Quist Adamsencf197592021-12-02 16:03:30 +01001013 public DexItemFactory getDexItemFactory() {
1014 return proguardConfiguration.getDexItemFactory();
1015 }
1016
Ian Zernyafb08e12018-01-08 14:22:58 +01001017 /** Get the enable-tree-shaking state. */
1018 public boolean getEnableTreeShaking() {
1019 return enableTreeShaking;
Mads Ager418d1ca2017-05-22 09:35:49 +02001020 }
1021
Ian Zernyafb08e12018-01-08 14:22:58 +01001022 /** Get the enable-minification state. */
1023 public boolean getEnableMinification() {
1024 return enableMinification;
Mads Ager418d1ca2017-05-22 09:35:49 +02001025 }
1026
Ian Zerny797abef2022-04-01 15:39:02 +02001027 /** Get the Proguard compatibility state. */
1028 public boolean getProguardCompatibility() {
1029 return forceProguardCompatibility;
1030 }
1031
Stephan Herhut2ecfe142017-06-01 14:24:01 +02001032 @Override
Mads Ager418d1ca2017-05-22 09:35:49 +02001033 InternalOptions getInternalOptions() {
Ian Zernyf828e2a2021-10-11 13:45:39 +02001034 InternalOptions internal = new InternalOptions(getMode(), proguardConfiguration, getReporter());
Søren Gjesse5e984c02019-05-29 14:40:27 +02001035 assert !internal.testing.allowOutlinerInterfaceArrayArguments; // Only allow in tests.
Ian Zerny7efd28d2017-12-12 09:17:42 +01001036 internal.programConsumer = getProgramConsumer();
Christoffer Quist Adamsen9780d7a2021-11-15 11:14:34 +01001037 internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
Søren Gjesse9a7876d2020-01-13 14:32:26 +01001038 internal.desugarState = getDesugarState();
Jinseong Jeond42bc0b2019-04-03 10:10:28 -07001039 assert internal.isShrinking() == getEnableTreeShaking();
1040 assert internal.isMinifying() == getEnableMinification();
Søren Gjessefb882ae2017-05-29 09:17:46 +02001041 assert !internal.ignoreMissingClasses;
clementbera75174ac2019-09-04 09:14:44 +02001042 internal.ignoreMissingClasses =
1043 proguardConfiguration.isIgnoreWarnings()
clementbera75174ac2019-09-04 09:14:44 +02001044 || (forceProguardCompatibility
Ian Zernyf828e2a2021-10-11 13:45:39 +02001045 && !internal.isOptimizing()
clementbera75174ac2019-09-04 09:14:44 +02001046 && !internal.isShrinking()
1047 && !internal.isMinifying());
Søren Gjesse98428702017-10-26 12:27:38 +02001048
Søren Gjessefb882ae2017-05-29 09:17:46 +02001049 assert !internal.verbose;
Yohann Rousself820a572017-05-31 20:25:51 +02001050 internal.mainDexKeepRules = mainDexKeepRules;
Ian Zernyf828e2a2021-10-11 13:45:39 +02001051 internal.minimalMainDex = internal.debug;
Mads Agerd9ae2a82018-11-29 13:01:55 +01001052 internal.mainDexListConsumer = getMainDexListConsumer();
Tamas Kenez3b5829a2017-12-18 11:22:06 +01001053 internal.lineNumberOptimization =
Ian Zernyf828e2a2021-10-11 13:45:39 +02001054 (internal.isOptimizing() || internal.isMinifying())
Tamas Kenez87795822018-08-23 15:42:33 +02001055 ? LineNumberOptimization.ON
1056 : LineNumberOptimization.OFF;
Ian Zerny7c5c4f72017-12-06 13:37:07 +01001057
Christoffer Quist Adamsen0cc904a2021-05-11 11:31:58 +02001058 HorizontalClassMergerOptions horizontalClassMergerOptions =
1059 internal.horizontalClassMergerOptions();
Ian Zernyf828e2a2021-10-11 13:45:39 +02001060 assert internal.isOptimizing() || horizontalClassMergerOptions.isRestrictedToSynthetics();
Christoffer Quist Adamsen0cc904a2021-05-11 11:31:58 +02001061
Christoffer Quist Adamsen60a4ee72019-05-09 21:43:25 +02001062 assert !internal.enableTreeShakingOfLibraryMethodOverrides;
Ian Zernyf828e2a2021-10-11 13:45:39 +02001063 assert internal.enableVerticalClassMerging || !internal.isOptimizing();
Christoffer Quist Adamsen0cc904a2021-05-11 11:31:58 +02001064
Clément Béra9700fa02020-05-14 07:25:34 +00001065 if (!internal.isShrinking()) {
Christoffer Quist Adamsen64b7ae02020-10-25 07:47:59 +01001066 // If R8 is not shrinking, there is no point in running various optimizations since the
1067 // optimized classes will still remain in the program (the application size could increase).
Clément Béra9700fa02020-05-14 07:25:34 +00001068 internal.enableEnumUnboxing = false;
Christoffer Quist Adamsen64b7ae02020-10-25 07:47:59 +01001069 internal.enableVerticalClassMerging = false;
Clément Béra9700fa02020-05-14 07:25:34 +00001070 }
Ian Zernyb71106a2017-12-05 09:57:35 +01001071
1072 // Amend the proguard-map consumer with options from the proguard configuration.
Ian Zernyf8ca0352019-06-07 11:58:48 +02001073 internal.proguardMapConsumer =
1074 wrapStringConsumer(
1075 proguardMapConsumer,
1076 proguardConfiguration.isPrintMapping(),
1077 proguardConfiguration.getPrintMappingFile());
1078
1079 // Amend the usage information consumer with options from the proguard configuration.
1080 internal.usageInformationConsumer =
1081 wrapStringConsumer(
1082 proguardUsageConsumer,
1083 proguardConfiguration.isPrintUsage(),
1084 proguardConfiguration.getPrintUsageFile());
1085
1086 // Amend the pg-seeds consumer with options from the proguard configuration.
1087 internal.proguardSeedsConsumer =
1088 wrapStringConsumer(
1089 proguardSeedsConsumer,
1090 proguardConfiguration.isPrintSeeds(),
1091 proguardConfiguration.getSeedFile());
1092
1093 // Amend the configuration consumer with options from the proguard configuration.
1094 internal.configurationConsumer =
1095 wrapStringConsumer(
1096 proguardConfigurationConsumer,
1097 proguardConfiguration.isPrintConfiguration(),
1098 proguardConfiguration.getPrintConfigurationFile());
Ian Zernyb71106a2017-12-05 09:57:35 +01001099
Ian Zerny6375a9e2018-12-14 13:52:48 +01001100 // Set the kept-graph consumer if any. It will only be actively used if the enqueuer triggers.
1101 internal.keptGraphConsumer = keptGraphConsumer;
1102 internal.mainDexKeptGraphConsumer = mainDexKeptGraphConsumer;
1103
Søren Gjesse7320ce52018-05-07 15:45:22 +02001104 internal.dataResourceConsumer = internal.programConsumer.getDataResourceConsumer();
Søren Gjesseff153482017-10-09 15:21:14 +02001105
Rico Windb5bb3e92019-09-23 10:32:10 +02001106 internal.featureSplitConfiguration = featureSplitConfiguration;
1107
Søren Gjesse430740d2019-01-10 16:49:42 +01001108 internal.syntheticProguardRulesConsumer = syntheticProguardRulesConsumer;
1109
Ian Zerny8f3ba442020-03-11 16:32:27 +01001110 internal.outputInspections = InspectorImpl.wrapInspections(getOutputInspections());
1111
Ian Zerny9b307322022-05-09 14:57:57 +02001112 if (!enableMissingLibraryApiModeling) {
Morten Krogh-Jespersen7b02ca82022-09-05 15:27:50 +02001113 internal.apiModelingOptions().disableApiCallerIdentification();
1114 internal.apiModelingOptions().disableOutliningAndStubbing();
Ian Zerny9b307322022-05-09 14:57:57 +02001115 }
1116
Søren Gjesse99e8a742020-01-07 13:59:38 +01001117 // Default is to remove all javac generated assertion code when generating dex.
Søren Gjesseb9cb6ae2019-12-20 12:31:45 +01001118 assert internal.assertionsConfiguration == null;
Søren Gjessec393db52022-04-28 09:45:29 +02001119 AssertionsConfiguration.Builder builder = AssertionsConfiguration.builder(getReporter());
Søren Gjesseb9cb6ae2019-12-20 12:31:45 +01001120 internal.assertionsConfiguration =
Søren Gjesse99e8a742020-01-07 13:59:38 +01001121 new AssertionConfigurationWithDefault(
Søren Gjessec393db52022-04-28 09:45:29 +02001122 getProgramConsumer() instanceof ClassFileConsumer
1123 ? AssertionsConfiguration.Builder.passthroughAllAssertions(builder)
1124 : AssertionsConfiguration.Builder.compileTimeDisableAllAssertions(builder),
Søren Gjesse99e8a742020-01-07 13:59:38 +01001125 getAssertionsConfiguration());
Søren Gjessee37b6cf2018-07-12 11:35:54 +02001126
Christoffer Quist Adamsen904f23c2021-06-04 14:42:40 +02001127 // TODO(b/171552739): Enable class merging for CF. When compiling libraries, we need to be
1128 // careful when merging a public member 'm' from a class A into another class B, since B could
1129 // have a kept subclass, in which case 'm' would leak into the public API.
Ian Zerny6cb65a72019-10-30 13:30:55 +01001130 if (internal.isGeneratingClassFiles()) {
Christoffer Quist Adamsen0cc904a2021-05-11 11:31:58 +02001131 horizontalClassMergerOptions.disable();
Ian Zernye8616652022-06-15 09:48:18 +02001132 // R8 CF output does not support desugaring so disable it.
1133 internal.desugarState = DesugarState.OFF;
Ian Zerny6cb65a72019-10-30 13:30:55 +01001134 }
1135
Søren Gjesseff153482017-10-09 15:21:14 +02001136 // EXPERIMENTAL flags.
1137 assert !internal.forceProguardCompatibility;
1138 internal.forceProguardCompatibility = forceProguardCompatibility;
Christoffer Quist Adamsen5bbf7c82018-09-21 09:36:17 +02001139 if (disableVerticalClassMerging) {
1140 internal.enableVerticalClassMerging = false;
1141 }
Søren Gjesseff153482017-10-09 15:21:14 +02001142
Yohann Roussel2284bc82018-04-26 15:45:35 +02001143 internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
1144
Clément Béra30b0b052022-02-28 12:36:49 +00001145 internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification);
Clément Bérab2b85ea2022-08-23 12:56:56 +02001146 internal.synthesizedClassPrefix =
1147 synthesizedClassPrefix.isEmpty()
1148 ? System.getProperty("com.android.tools.r8.synthesizedClassPrefix", "")
1149 : synthesizedClassPrefix;
Clément Bérab55ec8f2022-08-31 12:22:14 +02001150 boolean l8Shrinking = !internal.synthesizedClassPrefix.isEmpty();
Clément Bérab2b85ea2022-08-23 12:56:56 +02001151 // TODO(b/214382176): Enable all the time.
Clément Béraeb77dd92022-04-21 08:38:52 +00001152 internal.loadAllClassDefinitions = l8Shrinking;
1153 if (l8Shrinking) {
Morten Krogh-Jespersen7b02ca82022-09-05 15:27:50 +02001154 internal.apiModelingOptions().disableStubbingOfClasses();
Clément Béraeb77dd92022-04-21 08:38:52 +00001155 }
clementbera2cc55162019-08-19 12:19:46 +02001156 internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
1157
Ian Zerny6ddf0e92021-11-18 11:29:33 +01001158 // Set up the map and source file providers.
1159 // Note that minify/optimize settings must be set on internal options before doing this.
1160 internal.mapIdProvider = getMapIdProvider();
1161 internal.sourceFileProvider =
1162 SourceFileRewriter.computeSourceFileProvider(
1163 getSourceFileProvider(), proguardConfiguration, internal);
1164
Ian Zernybbd23922022-06-07 10:33:31 +02001165 internal.configureAndroidPlatformBuild(getAndroidPlatformBuild());
1166
Christoffer Quist Adamsendafb0462022-09-01 12:37:09 +02001167 internal.getArtProfileOptions().setArtProfilesForRewriting(getArtProfilesForRewriting());
Christoffer Quist Adamsen4c6d15d2022-09-08 11:30:04 +02001168 if (!getStartupProfileProviders().isEmpty()) {
1169 internal.getStartupOptions().setStartupProfileProviders(getStartupProfileProviders());
1170 }
Christoffer Quist Adamsen4b3614b2022-08-23 11:14:25 +02001171
Ian Zerny77440062022-08-26 13:49:08 +02001172 internal.programClassConflictResolver =
1173 ProgramClassCollection.wrappedConflictResolver(
1174 getClassConflictResolver(), internal.reporter);
1175
Morten Krogh-Jespersen4fa5d822020-03-25 19:28:09 +01001176 if (!DETERMINISTIC_DEBUGGING) {
1177 assert internal.threadCount == ThreadUtils.NOT_SPECIFIED;
1178 internal.threadCount = getThreadCount();
1179 }
Søren Gjesse943389f2020-03-13 10:40:25 +01001180
Morten Krogh-Jespersen7d3f78b2023-01-31 13:25:58 +01001181 internal.tool = Tool.R8;
1182
Christoffer Quist Adamsen06268302022-06-28 12:35:16 +02001183 internal.setDumpInputFlags(getDumpInputFlags());
Clément Béra64a3c4c2020-11-10 08:16:17 +00001184 internal.dumpOptions = dumpOptions();
Clément Béraf4702462020-10-27 14:28:50 +00001185
Mads Ager418d1ca2017-05-22 09:35:49 +02001186 return internal;
1187 }
Ian Zernyf8ca0352019-06-07 11:58:48 +02001188
1189 private static StringConsumer wrapStringConsumer(
1190 StringConsumer optionConsumer, boolean optionsFlag, Path optionFile) {
1191 if (optionsFlag) {
1192 if (optionFile != null) {
1193 return new StringConsumer.FileConsumer(optionFile, optionConsumer);
1194 } else {
Søren Gjesse1af374d2019-09-06 10:44:54 +02001195 return new StandardOutConsumer(optionConsumer);
Ian Zernyf8ca0352019-06-07 11:58:48 +02001196 }
1197 }
1198 return optionConsumer;
1199 }
Søren Gjesse1af374d2019-09-06 10:44:54 +02001200
1201 private static class StandardOutConsumer extends StringConsumer.ForwardingConsumer {
1202
1203 public StandardOutConsumer(StringConsumer consumer) {
1204 super(consumer);
1205 }
1206
1207 @Override
1208 public void accept(String string, DiagnosticsHandler handler) {
1209 super.accept(string, handler);
1210 System.out.print(string);
1211 }
1212 }
Clément Béra64a3c4c2020-11-10 08:16:17 +00001213
1214 private DumpOptions dumpOptions() {
Ian Zerny1c6f9542022-03-02 13:46:25 +01001215 DumpOptions.Builder builder = DumpOptions.builder(Tool.R8).readCurrentSystemProperties();
Clément Béra64a3c4c2020-11-10 08:16:17 +00001216 dumpBaseCommandOptions(builder);
1217 return builder
1218 .setIncludeDataResources(includeDataResources)
1219 .setTreeShaking(getEnableTreeShaking())
1220 .setMinification(getEnableMinification())
1221 .setForceProguardCompatibility(forceProguardCompatibility)
1222 .setFeatureSplitConfiguration(featureSplitConfiguration)
1223 .setProguardConfiguration(proguardConfiguration)
Morten Krogh-Jespersendb5129f2021-03-01 16:04:46 +01001224 .setMainDexKeepRules(mainDexKeepRules)
Clément Béraddd19a12021-12-09 08:14:53 +00001225 .setDesugaredLibraryConfiguration(desugaredLibrarySpecification)
Ian Zernye72cb782022-06-07 12:47:56 +02001226 .setEnableMissingLibraryApiModeling(enableMissingLibraryApiModeling)
Clément Béra64a3c4c2020-11-10 08:16:17 +00001227 .build();
1228 }
Søren Gjesse5de6d7d2023-02-10 12:37:19 +01001229
1230 private static class ExtractEmbeddedRules implements DataResourceProvider.Visitor {
1231
1232 private final Supplier<SemanticVersion> compilerVersionSupplier;
1233 private final Reporter reporter;
1234 private final List<ProguardConfigurationSource> proguardSources = new ArrayList<>();
1235 private final List<ProguardConfigurationSource> r8Sources = new ArrayList<>();
1236 private SemanticVersion compilerVersion;
1237
1238 public ExtractEmbeddedRules(
1239 Reporter reporter, Supplier<SemanticVersion> compilerVersionSupplier) {
1240 this.compilerVersionSupplier = compilerVersionSupplier;
1241 this.reporter = reporter;
1242 }
1243
1244 @Override
1245 public void visit(DataDirectoryResource directory) {
1246 // Don't do anything.
1247 }
1248
1249 @Override
1250 public void visit(DataEntryResource resource) {
1251 if (relevantProguardResource(resource)) {
1252 assert !relevantR8Resource(resource);
1253 readProguardConfigurationSource(resource, proguardSources::add);
1254 } else if (relevantR8Resource(resource)) {
1255 assert !relevantProguardResource(resource);
1256 readProguardConfigurationSource(resource, r8Sources::add);
1257 }
1258 }
1259
1260 private void readProguardConfigurationSource(
1261 DataEntryResource resource, Consumer<ProguardConfigurationSource> consumer) {
1262 try (InputStream in = resource.getByteStream()) {
1263 consumer.accept(new ProguardConfigurationSourceBytes(in, resource.getOrigin()));
1264 } catch (ResourceException e) {
1265 reporter.error(
1266 new StringDiagnostic("Failed to open input: " + e.getMessage(), resource.getOrigin()));
1267 } catch (Exception e) {
1268 reporter.error(new ExceptionDiagnostic(e, resource.getOrigin()));
1269 }
1270 }
1271
1272 private boolean relevantProguardResource(DataEntryResource resource) {
1273 // Configurations in META-INF/com.android.tools/proguard/ are ignored.
1274 final String proguardPrefix = "META-INF/proguard";
1275 if (!resource.getName().startsWith(proguardPrefix)) {
1276 return false;
1277 }
1278 String withoutPrefix = resource.getName().substring(proguardPrefix.length());
1279 return withoutPrefix.startsWith("/");
1280 }
1281
1282 private boolean relevantR8Resource(DataEntryResource resource) {
1283 final String r8Prefix = "META-INF/com.android.tools/r8";
1284 if (!resource.getName().startsWith(r8Prefix)) {
1285 return false;
1286 }
1287 String withoutPrefix = resource.getName().substring(r8Prefix.length());
1288 if (withoutPrefix.startsWith("/")) {
1289 // Everything under META-INF/com.android.tools/r8/ is included (not version specific).
1290 return true;
1291 }
1292 // Expect one of the following patterns:
1293 // com.android.tools/r8-min-1.5.0/
1294 // com.android.tools/r8-max-1.5.99/
1295 // com.android.tools/r8-min-1.5.0-max-1.5.99/
1296 final String minPrefix = "-min-";
1297 final String maxPrefix = "-max-";
1298 if (!withoutPrefix.startsWith(minPrefix) && !withoutPrefix.startsWith(maxPrefix)) {
1299 return false;
1300 }
1301
1302 SemanticVersion from = SemanticVersion.min();
1303 SemanticVersion to = SemanticVersion.max();
1304
1305 if (withoutPrefix.startsWith(minPrefix)) {
1306 withoutPrefix = withoutPrefix.substring(minPrefix.length());
1307 int versionEnd = StringUtils.indexOf(withoutPrefix, '-', '/');
1308 if (versionEnd == -1) {
1309 return false;
1310 }
1311 try {
1312 from = SemanticVersion.parse(withoutPrefix.substring(0, versionEnd));
1313 } catch (IllegalArgumentException e) {
1314 return false;
1315 }
1316 withoutPrefix = withoutPrefix.substring(versionEnd);
1317 }
1318 if (withoutPrefix.startsWith(maxPrefix)) {
1319 withoutPrefix = withoutPrefix.substring(maxPrefix.length());
1320 int versionEnd = withoutPrefix.indexOf('/');
1321 if (versionEnd == -1) {
1322 return false;
1323 }
1324 try {
1325 to = SemanticVersion.parse(withoutPrefix.substring(0, versionEnd));
1326 } catch (IllegalArgumentException e) {
1327 return false;
1328 }
1329 }
1330 if (compilerVersion == null) {
1331 compilerVersion = compilerVersionSupplier.get();
1332 }
1333 return compilerVersion.isNewerOrEqual(from) && to.isNewerOrEqual(compilerVersion);
1334 }
1335
1336 private void parse(
1337 List<ProguardConfigurationSource> sources, ProguardConfigurationParser parser) {
1338 for (ProguardConfigurationSource source : sources) {
1339 try {
1340 parser.parse(source);
1341 } catch (Exception e) {
1342 reporter.error(new ExceptionDiagnostic(e, source.getOrigin()));
1343 }
1344 }
1345 }
1346
1347 void parseRelevantRules(ProguardConfigurationParser parser) {
1348 parse(!r8Sources.isEmpty() ? r8Sources : proguardSources, parser);
1349 }
1350 }
Mads Ager418d1ca2017-05-22 09:35:49 +02001351}