blob: 76d7d56f944a211ff2cbdaa2c35c90c6c9d7a31a [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 com.android.tools.r8.graph.DexItemFactory;
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.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class GenerateMainDexListCommand extends BaseCommand {
private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
private final Path mainDexListOutput;
private final DexItemFactory factory;
/**
* Get the output path for the main-dex list. Null if not set.
*/
public Path getMainDexListOutputPath() {
return mainDexListOutput;
}
public static class Builder extends BaseCommand.Builder<GenerateMainDexListCommand, Builder> {
private final DexItemFactory factory = new DexItemFactory();
private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
private Path mainDexListOutput = null;
@Override
GenerateMainDexListCommand.Builder self() {
return this;
}
/**
* Add proguard configuration file resources for automatic main dex list calculation.
*/
public GenerateMainDexListCommand.Builder addMainDexRulesFiles(Path... paths) {
for (Path path : paths) {
mainDexRules.add(new ProguardConfigurationSourceFile(path));
}
return self();
}
/**
* Add proguard configuration file resources for automatic main dex list calculation.
*/
public GenerateMainDexListCommand.Builder addMainDexRulesFiles(List<Path> paths) {
for (Path path : paths) {
mainDexRules.add(new ProguardConfigurationSourceFile(path));
}
return self();
}
/**
* Add proguard configuration for automatic main dex list calculation.
*/
public GenerateMainDexListCommand.Builder addMainDexRules(List<String> lines) {
mainDexRules.add(new ProguardConfigurationSourceStrings(lines));
return self();
}
/**
* Get the output path for the main-dex list. Null if not set.
*/
public Path getMainDexListOutputPath() {
return mainDexListOutput;
}
/**
* Set the output file for the main-dex list.
*
* If the file exists it will be overwritten.
*/
public GenerateMainDexListCommand.Builder setMainDexListOutputPath(Path mainDexListOutputPath) {
mainDexListOutput = mainDexListOutputPath;
return self();
}
@Override
public GenerateMainDexListCommand build() throws CompilationException, IOException {
// If printing versions ignore everything else.
if (isPrintHelp() || isPrintVersion()) {
return new GenerateMainDexListCommand(isPrintHelp(), isPrintVersion());
}
validate();
ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
if (this.mainDexRules.isEmpty()) {
mainDexKeepRules = ImmutableList.of();
} else {
ProguardConfigurationParser parser = new ProguardConfigurationParser(factory);
try {
parser.parse(mainDexRules);
} catch (ProguardRuleParserException e) {
throw new CompilationException(e.getMessage(), e.getCause());
}
mainDexKeepRules = parser.getConfig().getRules();
}
return new GenerateMainDexListCommand(
factory,
getAppBuilder().build(),
mainDexKeepRules,
mainDexListOutput);
}
}
static final String USAGE_MESSAGE = String.join("\n", ImmutableList.of(
"Usage: maindex [options] <input-files>",
" where <input-files> are JAR files",
" and options are:",
" --main-dex-rules <file> # Proguard keep rules for classes to place in the",
" # primary dex file.",
" --main-dex-list <file> # List of classes to place in the primary dex file.",
" --main-dex-list-output <file> # Output the full main-dex list in <file>.",
" --version # Print the version.",
" --help # Print this message."));
public static GenerateMainDexListCommand.Builder builder() {
return new GenerateMainDexListCommand.Builder();
}
public static GenerateMainDexListCommand.Builder parse(String[] args)
throws CompilationException, IOException {
GenerateMainDexListCommand.Builder builder = builder();
parse(args, builder);
return builder;
}
private static void parse(String[] args, GenerateMainDexListCommand.Builder builder)
throws CompilationException, IOException {
for (int i = 0; i < args.length; i++) {
String arg = args[i].trim();
if (arg.length() == 0) {
continue;
} else if (arg.equals("--help")) {
builder.setPrintHelp(true);
} else if (arg.equals("--version")) {
builder.setPrintVersion(true);
} else if (arg.equals("--main-dex-rules")) {
builder.addMainDexRulesFiles(Paths.get(args[++i]));
} else if (arg.equals("--main-dex-list")) {
builder.addMainDexListFiles(Paths.get(args[++i]));
} else if (arg.equals("--main-dex-list-output")) {
builder.setMainDexListOutputPath(Paths.get(args[++i]));
} else {
if (arg.startsWith("--")) {
throw new CompilationException("Unknown option: " + arg);
}
builder.addProgramFiles(Paths.get(arg));
}
}
}
private GenerateMainDexListCommand(
DexItemFactory factory,
AndroidApp inputApp,
ImmutableList<ProguardConfigurationRule> mainDexKeepRules,
Path mainDexListOutput) {
super(inputApp);
this.factory = factory;
this.mainDexKeepRules = mainDexKeepRules;
this.mainDexListOutput = mainDexListOutput;
}
private GenerateMainDexListCommand(boolean printHelp, boolean printVersion) {
super(printHelp, printVersion);
this.factory = new DexItemFactory();
this.mainDexKeepRules = ImmutableList.of();
this.mainDexListOutput = null;
}
@Override
InternalOptions getInternalOptions() {
InternalOptions internal = new InternalOptions(factory);
internal.mainDexKeepRules = mainDexKeepRules;
if (mainDexListOutput != null) {
internal.printMainDexListFile = mainDexListOutput;
}
internal.minimalMainDex = internal.debug;
internal.removeSwitchMaps = false;
internal.inlineAccessors = false;
return internal;
}
}