blob: 1b7ca86803b75f00ef1a77c229bc5a705bd3176e [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
import static com.android.tools.r8.utils.InternalOptions.DETERMINISTIC_DEBUGGING;
import static com.android.tools.r8.utils.MapConsumerUtils.wrapExistingMapConsumerIfNotNull;
import com.android.tools.r8.R8Command.Builder;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.dump.DumpOptions;
import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.inspector.Inspector;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import com.android.tools.r8.metadata.D8BuildMetadata;
import com.android.tools.r8.naming.MapConsumer;
import com.android.tools.r8.naming.ProguardMapStringConsumer;
import com.android.tools.r8.origin.ArchiveEntryOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.profile.art.ArtProfileForRewriting;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.shaking.ProguardConfigurationSource;
import com.android.tools.r8.shaking.ProguardConfigurationSourceFile;
import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
import com.android.tools.r8.startup.StartupProfileProvider;
import com.android.tools.r8.synthesis.GlobalSyntheticsResourceBytes;
import com.android.tools.r8.synthesis.GlobalSyntheticsResourceFile;
import com.android.tools.r8.synthesis.GlobalSyntheticsUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.DumpInputFlags;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalGlobalSyntheticsProgramProvider;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.android.tools.r8.utils.InternalOptions.MappingComposeOptions;
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
/**
* Immutable command structure for an invocation of the {@link D8} compiler.
*
* <p>To build a D8 command use the {@link D8Command.Builder} class. For example:
*
* <pre>
* D8Command command = D8Command.builder()
* .addProgramFiles(path1, path2)
* .setMode(CompilationMode.RELEASE)
* .setOutput(Paths.get("output.zip", OutputMode.DexIndexed))
* .build();
* </pre>
*/
@KeepForApi
public final class D8Command extends BaseCompilerCommand {
private static class DefaultD8DiagnosticsHandler implements DiagnosticsHandler {
@Override
public void error(Diagnostic error) {
if (error instanceof DexFileOverflowDiagnostic) {
DexFileOverflowDiagnostic overflowDiagnostic = (DexFileOverflowDiagnostic) error;
if (!overflowDiagnostic.hasMainDexSpecification()) {
DiagnosticsHandler.super.error(
new StringDiagnostic(
overflowDiagnostic.getDiagnosticMessage() + ". Try supplying a main-dex list"));
return;
}
}
DiagnosticsHandler.super.error(error);
}
}
/**
* Builder for constructing a D8Command.
*
* <p>A builder is obtained by calling {@link D8Command#builder}.
*/
@KeepForApi
public static class Builder extends BaseCompilerCommand.Builder<D8Command, Builder> {
private boolean intermediate = false;
private Path globalSyntheticsOutput = null;
private GlobalSyntheticsConsumer globalSyntheticsConsumer = null;
private final List<GlobalSyntheticsResourceProvider> globalSyntheticsResourceProviders =
new ArrayList<>();
private DesugarGraphConsumer desugarGraphConsumer = null;
private SyntheticInfoConsumer syntheticInfoConsumer = null;
private StringConsumer desugaredLibraryKeepRuleConsumer = null;
private String synthesizedClassPrefix = "";
private boolean enableMainDexListCheck = true;
private boolean minimalMainDex = false;
private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
private boolean enableMissingLibraryApiModeling = false;
private boolean enableRewritingOfArtProfilesIsNopCheck = false;
private Consumer<? super D8BuildMetadata> buildMetadataConsumer = null;
private Builder() {
this(new DefaultD8DiagnosticsHandler());
}
private Builder(DiagnosticsHandler diagnosticsHandler) {
super(diagnosticsHandler);
}
private Builder(AndroidApp app) {
super(app);
}
/**
* Add dex program-data.
*/
@Override
public Builder addDexProgramData(byte[] data, Origin origin) {
guard(() -> getAppBuilder().addDexProgramData(data, origin));
return self();
}
/**
* Add classpath file resources. These have @Override to ensure binary compatibility.
*/
@Override
public Builder addClasspathFiles(Path... files) {
return super.addClasspathFiles(files);
}
/**
* Add classpath file resources.
*/
@Override
public Builder addClasspathFiles(Collection<Path> files) {
return super.addClasspathFiles(files);
}
/**
* Add classfile resources provider for class-path resources.
*/
@Override
public Builder addClasspathResourceProvider(ClassFileResourceProvider provider) {
return super.addClasspathResourceProvider(provider);
}
/**
* Set input proguard map used for distribution of classes in multi-dex. Use {@link
* #setProguardMapInputFile}
*/
@Deprecated()
public Builder setProguardInputMapFile(Path proguardInputMap) {
getAppBuilder().setProguardMapInputData(proguardInputMap);
return self();
}
/** Set input proguard map used for distribution of classes in multi-dex. */
public Builder setProguardMapInputFile(Path proguardInputMap) {
getAppBuilder().setProguardMapInputData(proguardInputMap);
return self();
}
/**
* Set a consumer for receiving the proguard-map content.
*
* <p>Note that when a proguard-map consumer is specified for a release build, the compiler will
* optimize the line-number information and obtaining a source-level stacktrace will require the
* use of a retrace tool exactly as is needed for programs built by R8.
*
* <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
* override the previous setting.
*
* @param proguardMapConsumer Consumer to receive the content once produced.
*/
@Override
public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
return super.setProguardMapConsumer(proguardMapConsumer);
}
/**
* Set an output destination to which proguard-map content should be written.
*
* <p>Note that when a proguard-map output is specified for a release build, the compiler will
* optimize the line-number information and obtaining a source-level stacktrace will require the
* use of a retrace tool exactly as is needed for programs built by R8.
*
* <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
* #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
* #setProguardMapConsumer} will override the previous setting.
*
* @param proguardMapOutput File-system path to write output at.
*/
@Override
public Builder setProguardMapOutputPath(Path proguardMapOutput) {
return super.setProguardMapOutputPath(proguardMapOutput);
}
/**
* Set an output destination to which partition-map content should be written.
*
* <p>Note that when a proguard-map output is specified for a release build, the compiler will
* optimize the line-number information and obtaining a source-level stacktrace will require the
* use of a retrace tool exactly as is needed for programs built by R8.
*
* <p>This is a short-hand for setting a {@link PartitionMapConsumer} using {@link
* #setPartitionMapConsumer}. Note that any subsequent call to this method or {@link
* #setPartitionMapConsumer} will override the previous setting.
*
* @param partitionMapOutput File-system path to write output at.
*/
@Override
public Builder setPartitionMapOutputPath(Path partitionMapOutput) {
assert partitionMapOutput != null;
return super.setPartitionMapOutputPath(partitionMapOutput);
}
/**
* Set a consumer for receiving the partition map content.
*
* <p>Note that when a proguard-map output is specified for a release build, the compiler will
* optimize the line-number information and obtaining a source-level stacktrace will require the
* use of a retrace tool exactly as is needed for programs built by R8.
*
* <p>Note that any subsequent call to this method or {@link #setPartitionMapOutputPath} will
* override the previous setting.
*
* @param partitionMapConsumer Consumer to receive the content once produced.
*/
@Override
public Builder setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
assert partitionMapConsumer != null;
return super.setPartitionMapConsumer(partitionMapConsumer);
}
/**
* Indicate if compilation is to intermediate results, i.e., intended for later merging.
*
* <p>When compiling to intermediate mode, the compiler will avoid sharing of synthetic items,
* and instead annotate them as synthetics for possible later merging. For global synthetics,
* the compiler will emit these to a separate consumer (see {@code GlobalSyntheticsConsumer}
* with the expectation that a later build step will consume them again as part of a
* non-intermediate build (see {@code GlobalSyntheticsResourceProvider}. Synthetic items
* typically come from the desugaring of various language features, such as lambdas and default
* interface methods. Global synthetics are non-local in that many compilation units may
* reference the same synthetic. For example, desugaring records requires a global tag to
* distinguish the class of all records.
*
* <p>Intermediate mode is implied if compiling results to a "file-per-class-file".
*/
public Builder setIntermediate(boolean value) {
this.intermediate = value;
return self();
}
/**
* Set an output path for receiving the global synthetic content for the given compilation.
*
* <p>Note: this output is ignored if the compilation is not an "intermediate mode" compilation.
*
* <p>Note: setting this will clear out any consumer set by setGlobalSyntheticsConsumer.
*/
public Builder setGlobalSyntheticsOutput(Path globalSyntheticsOutput) {
this.globalSyntheticsConsumer = null;
this.globalSyntheticsOutput = globalSyntheticsOutput;
return self();
}
/**
* Set a consumer for receiving the global synthetic content for the given compilation.
*
* <p>Note: this consumer is ignored if the compilation is not an "intermediate mode"
* compilation.
*
* <p>Note: setting this will clear out any output path set by setGlobalSyntheticsOutput.
*/
public Builder setGlobalSyntheticsConsumer(GlobalSyntheticsConsumer globalSyntheticsConsumer) {
this.globalSyntheticsOutput = null;
this.globalSyntheticsConsumer = globalSyntheticsConsumer;
return self();
}
/** Add global synthetics resource providers. */
public Builder addGlobalSyntheticsResourceProviders(
GlobalSyntheticsResourceProvider... providers) {
return addGlobalSyntheticsResourceProviders(Arrays.asList(providers));
}
/** Add global synthetics resource providers. */
public Builder addGlobalSyntheticsResourceProviders(
Collection<GlobalSyntheticsResourceProvider> providers) {
providers.forEach(globalSyntheticsResourceProviders::add);
return self();
}
/** Add global synthetics resource files. */
public Builder addGlobalSyntheticsFiles(Path... files) {
return addGlobalSyntheticsFiles(Arrays.asList(files));
}
/** Add global synthetics resource files. */
public Builder addGlobalSyntheticsFiles(Collection<Path> files) {
for (Path file : files) {
addGlobalSyntheticsFileOrArchiveOfGlobalSynthetics(file);
}
return self();
}
private void addGlobalSyntheticsFileOrArchiveOfGlobalSynthetics(Path file) {
if (!FileUtils.isZipFile(file)) {
addGlobalSyntheticsResourceProviders(new GlobalSyntheticsResourceFile(file));
return;
}
PathOrigin origin = new PathOrigin(file);
try {
ZipUtils.iter(
file,
(entry, input) ->
addGlobalSyntheticsResourceProviders(
new GlobalSyntheticsResourceBytes(
new ArchiveEntryOrigin(entry.getName(), origin),
ByteStreams.toByteArray(input))));
} catch (IOException e) {
error(origin, e);
}
}
/**
* Set a consumer for receiving the keep rules to use when compiling the desugared library for
* the program being compiled in this compilation.
*
* @param keepRuleConsumer Consumer to receive the content once produced.
*/
public Builder setDesugaredLibraryKeepRuleConsumer(StringConsumer keepRuleConsumer) {
this.desugaredLibraryKeepRuleConsumer = keepRuleConsumer;
return self();
}
/**
* Get the consumer that will receive dependency information for desugaring.
*/
public DesugarGraphConsumer getDesugarGraphConsumer() {
return desugarGraphConsumer;
}
/**
* Set the consumer that will receive dependency information for desugaring.
*
* <p>Setting the consumer will clear any previously set consumer.
*/
public Builder setDesugarGraphConsumer(DesugarGraphConsumer desugarGraphConsumer) {
this.desugarGraphConsumer = desugarGraphConsumer;
return self();
}
/** Get the consumer that will receive information about compiler synthesized classes. */
public SyntheticInfoConsumer getSyntheticInfoConsumer() {
return syntheticInfoConsumer;
}
/**
* Set the consumer that will receive information about compiler synthesized classes.
*
* <p>Setting the consumer will clear any previously set consumer.
*/
public Builder setSyntheticInfoConsumer(SyntheticInfoConsumer syntheticInfoConsumer) {
this.syntheticInfoConsumer = syntheticInfoConsumer;
return self();
}
/**
* Add a collection of startup profile providers that should be used for distributing the
* program classes in dex.
*
* <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
* not support native multidex (API<=20).
*/
@Override
public Builder addStartupProfileProviders(StartupProfileProvider... startupProfileProviders) {
return super.addStartupProfileProviders(startupProfileProviders);
}
/**
* Add a collection of startup profile providers that should be used for distributing the
* program classes in dex.
*
* <p>NOTE: Startup profiles are ignored when compiling to class files or the min-API level does
* not support native multidex (API<=20).
*/
@Override
public Builder addStartupProfileProviders(
Collection<StartupProfileProvider> startupProfileProviders) {
return super.addStartupProfileProviders(startupProfileProviders);
}
@Override
Builder self() {
return this;
}
@Override
CompilationMode defaultCompilationMode() {
return CompilationMode.DEBUG;
}
Builder setSynthesizedClassesPrefix(String prefix) {
synthesizedClassPrefix = prefix;
return self();
}
@Deprecated
// Internal helper for supporting bazel integration.
Builder setEnableMainDexListCheck(boolean value) {
enableMainDexListCheck = value;
return self();
}
@Deprecated
// Internal helper for supporting bazel integration.
Builder setMinimalMainDex(boolean value) {
minimalMainDex = value;
return self();
}
/** Add proguard configuration files with rules for automatic main-dex-list calculation. */
public Builder addMainDexRulesFiles(Path... paths) {
return addMainDexRulesFiles(Arrays.asList(paths));
}
/** Add proguard configuration files with rules for automatic main-dex-list calculation. */
public Builder addMainDexRulesFiles(Collection<Path> paths) {
guard(() -> paths.forEach(p -> mainDexRules.add(new ProguardConfigurationSourceFile(p))));
return self();
}
/** Add proguard rules for automatic main-dex-list calculation. */
public Builder addMainDexRules(List<String> lines, Origin origin) {
guard(
() ->
mainDexRules.add(
new ProguardConfigurationSourceStrings(lines, Paths.get("."), origin)));
return self();
}
/**
* Enable experimental/pre-release support for modeling missing library APIs.
*
* <p>This allows enabling the feature while it is still default disabled by the compiler. Once
* the feature is default enabled, calling this method will have no affect.
*/
@Deprecated
public Builder setEnableExperimentalMissingLibraryApiModeling(boolean enable) {
this.enableMissingLibraryApiModeling = enable;
return self();
}
Builder setEnableRewritingOfArtProfilesIsNopCheck() {
enableRewritingOfArtProfilesIsNopCheck = true;
return self();
}
/**
* Set a consumer for receiving metadata about the current build intended for being stored in
* the app bundle.
*/
public Builder setBuildMetadataConsumer(
Consumer<? super D8BuildMetadata> buildMetadataConsumer) {
this.buildMetadataConsumer = buildMetadataConsumer;
return self();
}
@Override
void validate() {
if (isPrintHelp()) {
return;
}
Reporter reporter = getReporter();
if (getAppBuilder().hasMainDexList()) {
if (intermediate) {
reporter.error("Option --main-dex-list cannot be used with --intermediate");
}
if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) {
reporter.error("Option --main-dex-list cannot be used with --file-per-class");
}
}
if (!mainDexRules.isEmpty()) {
if (intermediate) {
reporter.error("Option --main-dex-rules cannot be used with --intermediate");
}
if (getProgramConsumer() instanceof DexFilePerClassFileConsumer) {
reporter.error("Option --main-dex-rules cannot be used with --file-per-class");
}
}
if (getMainDexListConsumer() != null
&& mainDexRules.isEmpty()
&& !getAppBuilder().hasMainDexList()) {
reporter.error(
"Option --main-dex-list-output requires --main-dex-rules and/or --main-dex-list");
}
if (getMinApiLevel() >= AndroidApiLevel.L_MR1.getLevel()) {
if (getMainDexListConsumer() != null || getAppBuilder().hasMainDexList()) {
reporter.error(
"D8 does not support main-dex inputs and outputs when compiling to API level "
+ AndroidApiLevel.L_MR1.getLevel()
+ " and above (min API level "
+ getMinApiLevel()
+ " was provided)");
}
}
if (hasDesugaredLibraryConfiguration() && getDisableDesugaring()) {
reporter.error("Using desugared library configuration requires desugaring to be enabled");
}
if (getProgramConsumer() instanceof ClassFileConsumer
&& getDisableDesugaring()
&& isMinApiLevelSet()) {
reporter.error("Compiling to CF with --min-api and --no-desugaring is not supported");
}
if (!getStartupProfileProviders().isEmpty()) {
if (intermediate) {
reporter.error("D8 startup layout is not supported in intermediate mode");
}
if (getMinApiLevel() < AndroidApiLevel.L.getLevel()) {
reporter.error(
"D8 startup layout requires native multi dex support (API level "
+ AndroidApiLevel.L.getLevel()
+ " and above, min API level "
+ getMinApiLevel()
+ " was provided)");
}
}
super.validate();
}
@Override
D8Command makeCommand() {
if (isPrintHelp() || isPrintVersion()) {
return new D8Command(isPrintHelp(), isPrintVersion());
}
final ProgramConsumer programConsumer = getProgramConsumer();
intermediate |= programConsumer instanceof DexFilePerClassFileConsumer;
DexItemFactory factory = new DexItemFactory();
DesugaredLibrarySpecification desugaredLibrarySpecification =
getDesugaredLibraryConfiguration(factory, false);
ImmutableList<ProguardConfigurationRule> mainDexKeepRules =
ProguardConfigurationParser.parse(mainDexRules, factory, getReporter());
if (!globalSyntheticsResourceProviders.isEmpty()) {
addProgramResourceProvider(
new InternalGlobalSyntheticsProgramProvider(globalSyntheticsResourceProviders));
}
// If compiling to CF with --no-desugaring then the target API is B for consistency with R8.
int minApiLevel =
programConsumer instanceof ClassFileConsumer && getDisableDesugaring()
? AndroidApiLevel.B.getLevel()
: getMinApiLevel();
GlobalSyntheticsConsumer globalConsumer =
GlobalSyntheticsUtils.determineGlobalSyntheticsConsumer(
intermediate, globalSyntheticsOutput, globalSyntheticsConsumer, programConsumer);
return new D8Command(
getAppBuilder().build(),
getMode(),
programConsumer,
getMainDexListConsumer(),
minApiLevel,
getReporter(),
getDesugaringState(),
intermediate,
globalConsumer,
isOptimizeMultidexForLinearAlloc(),
getIncludeClassesChecksum(),
getDexClassChecksumFilter(),
getDesugarGraphConsumer(),
getSyntheticInfoConsumer(),
desugaredLibraryKeepRuleConsumer,
desugaredLibrarySpecification,
getAssertionsConfiguration(),
getOutputInspections(),
synthesizedClassPrefix,
enableMainDexListCheck,
minimalMainDex,
mainDexKeepRules,
getThreadCount(),
getDumpInputFlags(),
getMapIdProvider(),
proguardMapConsumer,
partitionMapConsumer,
enableMissingLibraryApiModeling,
enableRewritingOfArtProfilesIsNopCheck,
buildMetadataConsumer,
getAndroidPlatformBuild(),
getArtProfilesForRewriting(),
getStartupProfileProviders(),
getClassConflictResolver(),
getCancelCompilationChecker(),
factory);
}
}
private final boolean intermediate;
private final GlobalSyntheticsConsumer globalSyntheticsConsumer;
private final SyntheticInfoConsumer syntheticInfoConsumer;
private final DesugarGraphConsumer desugarGraphConsumer;
private final StringConsumer desugaredLibraryKeepRuleConsumer;
private final DesugaredLibrarySpecification desugaredLibrarySpecification;
private final String synthesizedClassPrefix;
private final boolean enableMainDexListCheck;
private final boolean minimalMainDex;
private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
private final StringConsumer proguardMapConsumer;
private final PartitionMapConsumer partitionMapConsumer;
private final boolean enableMissingLibraryApiModeling;
private final boolean enableRewritingOfArtProfilesIsNopCheck;
private final DexItemFactory factory;
private final Consumer<? super D8BuildMetadata> buildMetadataConsumer;
public static Builder builder() {
return new Builder();
}
public static Builder builder(DiagnosticsHandler diagnosticsHandler) {
return new Builder(diagnosticsHandler);
}
// Internal builder to start from an existing AndroidApp.
static Builder builder(AndroidApp app) {
return new Builder(app);
}
/**
* Parse the D8 command-line.
*
* <p>Parsing will set the supplied options or their default value if they have any.
*
* @param args Command-line arguments array.
* @param origin Origin description of the command-line arguments.
* @return D8 command builder with state set up according to parsed command line.
*/
public static Builder parse(String[] args, Origin origin) {
return D8CommandParser.parse(args, origin);
}
/**
* Parse the D8 command-line.
*
* <p>Parsing will set the supplied options or their default value if they have any.
*
* @param args Command-line arguments array.
* @param origin Origin description of the command-line arguments.
* @param handler Custom defined diagnostics handler.
* @return D8 command builder with state set up according to parsed command line.
*/
public static Builder parse(String[] args, Origin origin, DiagnosticsHandler handler) {
return D8CommandParser.parse(args, origin, handler);
}
/** Get the help description for the D8 supported flags. */
public static List<ParseFlagInfo> getParseFlagsInformation() {
return D8CommandParser.getFlags();
}
private D8Command(
AndroidApp inputApp,
CompilationMode mode,
ProgramConsumer programConsumer,
StringConsumer mainDexListConsumer,
int minApiLevel,
Reporter diagnosticsHandler,
DesugarState enableDesugaring,
boolean intermediate,
GlobalSyntheticsConsumer globalSyntheticsConsumer,
boolean optimizeMultidexForLinearAlloc,
boolean encodeChecksum,
BiPredicate<String, Long> dexClassChecksumFilter,
DesugarGraphConsumer desugarGraphConsumer,
SyntheticInfoConsumer syntheticInfoConsumer,
StringConsumer desugaredLibraryKeepRuleConsumer,
DesugaredLibrarySpecification desugaredLibrarySpecification,
List<AssertionsConfiguration> assertionsConfiguration,
List<Consumer<Inspector>> outputInspections,
String synthesizedClassPrefix,
boolean enableMainDexListCheck,
boolean minimalMainDex,
ImmutableList<ProguardConfigurationRule> mainDexKeepRules,
int threadCount,
DumpInputFlags dumpInputFlags,
MapIdProvider mapIdProvider,
StringConsumer proguardMapConsumer,
PartitionMapConsumer partitionMapConsumer,
boolean enableMissingLibraryApiModeling,
boolean enableRewritingOfArtProfilesIsNopCheck,
Consumer<? super D8BuildMetadata> buildMetadataConsumer,
boolean isAndroidPlatformBuild,
List<ArtProfileForRewriting> artProfilesForRewriting,
List<StartupProfileProvider> startupProfileProviders,
ClassConflictResolver classConflictResolver,
CancelCompilationChecker cancelCompilationChecker,
DexItemFactory factory) {
super(
inputApp,
mode,
programConsumer,
mainDexListConsumer,
minApiLevel,
diagnosticsHandler,
enableDesugaring,
optimizeMultidexForLinearAlloc,
encodeChecksum,
dexClassChecksumFilter,
assertionsConfiguration,
outputInspections,
threadCount,
dumpInputFlags,
mapIdProvider,
null,
isAndroidPlatformBuild,
artProfilesForRewriting,
startupProfileProviders,
classConflictResolver,
cancelCompilationChecker);
this.intermediate = intermediate;
this.globalSyntheticsConsumer = globalSyntheticsConsumer;
this.syntheticInfoConsumer = syntheticInfoConsumer;
this.desugarGraphConsumer = desugarGraphConsumer;
this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
this.desugaredLibrarySpecification = desugaredLibrarySpecification;
this.synthesizedClassPrefix = synthesizedClassPrefix;
this.enableMainDexListCheck = enableMainDexListCheck;
this.minimalMainDex = minimalMainDex;
this.mainDexKeepRules = mainDexKeepRules;
this.proguardMapConsumer = proguardMapConsumer;
this.partitionMapConsumer = partitionMapConsumer;
this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
this.enableRewritingOfArtProfilesIsNopCheck = enableRewritingOfArtProfilesIsNopCheck;
this.factory = factory;
this.buildMetadataConsumer = buildMetadataConsumer;
}
private D8Command(boolean printHelp, boolean printVersion) {
super(printHelp, printVersion);
intermediate = false;
globalSyntheticsConsumer = null;
syntheticInfoConsumer = null;
desugarGraphConsumer = null;
desugaredLibraryKeepRuleConsumer = null;
desugaredLibrarySpecification = null;
synthesizedClassPrefix = null;
enableMainDexListCheck = true;
minimalMainDex = false;
mainDexKeepRules = null;
proguardMapConsumer = null;
partitionMapConsumer = null;
enableMissingLibraryApiModeling = false;
enableRewritingOfArtProfilesIsNopCheck = false;
factory = null;
buildMetadataConsumer = null;
}
@Override
InternalOptions getInternalOptions() {
InternalOptions internal = new InternalOptions(factory, getReporter());
assert !internal.debug;
internal.d8BuildMetadataConsumer = buildMetadataConsumer;
internal.debug = getMode() == CompilationMode.DEBUG;
internal.programConsumer = getProgramConsumer();
if (internal.isGeneratingClassFiles()) {
// Turn off switch optimizations when generating class files.
assert internal.enableSwitchRewriting;
internal.enableSwitchRewriting = false;
assert internal.enableStringSwitchConversion;
internal.enableStringSwitchConversion = false;
} else {
assert !internal.desugarSpecificOptions().allowAllDesugaredInput
|| getDesugarState() == DesugarState.OFF;
}
internal.mainDexListConsumer = getMainDexListConsumer();
internal.minimalMainDex = internal.debug || minimalMainDex;
internal.enableMainDexListCheck = enableMainDexListCheck;
internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
internal.intermediate = intermediate;
internal.retainCompileTimeAnnotations = intermediate;
internal.setGlobalSyntheticsConsumer(globalSyntheticsConsumer);
internal.setSyntheticInfoConsumer(syntheticInfoConsumer);
internal.desugarGraphConsumer = desugarGraphConsumer;
internal.mainDexKeepRules = mainDexKeepRules;
MapConsumer mapConsumer =
wrapExistingMapConsumerIfNotNull(
internal.mapConsumer, partitionMapConsumer, MapConsumerToPartitionMapConsumer::new);
internal.mapConsumer =
wrapExistingMapConsumerIfNotNull(
mapConsumer,
proguardMapConsumer,
nonNullStringConsumer ->
ProguardMapStringConsumer.builder().setStringConsumer(proguardMapConsumer).build());
internal.lineNumberOptimization =
!internal.debug && proguardMapConsumer != null
? LineNumberOptimization.ON
: LineNumberOptimization.OFF;
MappingComposeOptions mappingComposeOptions = internal.mappingComposeOptions();
mappingComposeOptions.enableExperimentalMappingComposition = true;
// Assert and fixup defaults.
assert !internal.isShrinking();
assert !internal.isMinifying();
assert !internal.passthroughDexCode;
internal.passthroughDexCode = true;
// Assert some of R8 optimizations are disabled.
assert !internal.inlinerOptions().enableInlining;
assert !internal.enableClassInlining;
assert !internal.enableEnumValueOptimization;
assert !internal.outline.enabled;
assert !internal.enableTreeShakingOfLibraryMethodOverrides;
internal.desugarState = getDesugarState();
internal.encodeChecksums = getIncludeClassesChecksum();
internal.dexClassChecksumFilter = getDexClassChecksumFilter();
internal.enableInheritanceClassInDexDistributor = isOptimizeMultidexForLinearAlloc();
internal.configureDesugaredLibrary(desugaredLibrarySpecification, synthesizedClassPrefix);
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
if (internal.isGeneratingClassFiles()
|| (System.getProperty("com.android.tools.r8.enableApiOutliningAndStubbing") == null
&& !enableMissingLibraryApiModeling)) {
internal.apiModelingOptions().disableApiCallerIdentification();
internal.apiModelingOptions().disableOutliningAndStubbing();
}
if (enableRewritingOfArtProfilesIsNopCheck) {
internal.getArtProfileOptions().setEnableNopCheckForTesting();
}
// Default is to remove all javac generated assertion code when generating dex.
assert internal.assertionsConfiguration == null;
internal.assertionsConfiguration =
new AssertionConfigurationWithDefault(
AssertionsConfiguration.builder(getReporter())
.setCompileTimeDisable()
.setScopeAll()
.build(),
getAssertionsConfiguration());
internal.outputInspections = InspectorImpl.wrapInspections(getOutputInspections());
if (!DETERMINISTIC_DEBUGGING) {
assert internal.threadCount == ThreadUtils.NOT_SPECIFIED;
internal.threadCount = getThreadCount();
}
// Disable global optimizations.
internal.disableGlobalOptimizations();
HorizontalClassMergerOptions horizontalClassMergerOptions =
internal.horizontalClassMergerOptions();
if (internal.isGeneratingDex()) {
horizontalClassMergerOptions.setRestrictToSynthetics();
} else {
assert internal.isGeneratingClassFiles();
horizontalClassMergerOptions.disable();
}
internal.configureAndroidPlatformBuild(getAndroidPlatformBuild());
internal.getArtProfileOptions().setArtProfilesForRewriting(getArtProfilesForRewriting());
if (!getStartupProfileProviders().isEmpty()) {
internal.getStartupOptions().setStartupProfileProviders(getStartupProfileProviders());
}
internal.programClassConflictResolver =
ProgramClassCollection.wrappedConflictResolver(
getClassConflictResolver(), internal.reporter);
internal.cancelCompilationChecker = getCancelCompilationChecker();
internal.tool = Tool.D8;
internal.setDumpInputFlags(getDumpInputFlags());
internal.dumpOptions = dumpOptions();
return internal;
}
private DumpOptions dumpOptions() {
DumpOptions.Builder builder = DumpOptions.builder(Tool.D8).readCurrentSystemProperties();
dumpBaseCommandOptions(builder);
return builder
.setIntermediate(intermediate)
.setDesugaredLibraryConfiguration(desugaredLibrarySpecification)
.setMainDexKeepRules(mainDexKeepRules)
.setEnableMissingLibraryApiModeling(enableMissingLibraryApiModeling)
.build();
}
}