blob: 45a62ef04af70ec64cc06d835afefe5d948878a6 [file] [log] [blame]
// Copyright (c) 2018, 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.dexsplitter;
import com.android.tools.r8.CompilationException;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.DexSplitterHelper;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.utils.FeatureClassMapping;
import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
import com.android.tools.r8.utils.OptionsParsing;
import com.android.tools.r8.utils.OptionsParsing.ParseContext;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class DexSplitter {
private static final String DEFAULT_OUTPUT_ARCHIVE_FILENAME = "split";
private static final boolean PRINT_ARGS = false;
public static class Options {
List<String> inputArchives = new ArrayList<>();
List<String> featureJars = new ArrayList<>();
String splitBaseName = DEFAULT_OUTPUT_ARCHIVE_FILENAME;
String featureSplitMapping;
String proguardMap;
}
private static Options parseArguments(String[] args) throws IOException {
Options options = new Options();
ParseContext context = new ParseContext(args);
while (context.head() != null) {
List<String> input = OptionsParsing.tryParseMulti(context, "--input");
if (input != null) {
options.inputArchives.addAll(input);
continue;
}
List<String> featureJars = OptionsParsing.tryParseMulti(context, "--feature-jar");
if (featureJars != null) {
options.featureJars.addAll(featureJars);
continue;
}
String output = OptionsParsing.tryParseSingle(context, "--output", "-o");
if (output != null) {
options.splitBaseName = output;
continue;
}
String proguardMap = OptionsParsing.tryParseSingle(context, "--proguard-map", null);
if (proguardMap != null) {
options.proguardMap = proguardMap;
continue;
}
String featureSplit = OptionsParsing.tryParseSingle(context, "--feature-splits", null);
if (featureSplit != null) {
options.featureSplitMapping = featureSplit;
continue;
}
throw new RuntimeException(String.format("Unknown options: '%s'.", context.head()));
}
return options;
}
private static FeatureClassMapping createFeatureClassMapping(Options options)
throws IOException, FeatureMappingException, ResourceException {
if (options.featureSplitMapping != null) {
return FeatureClassMapping.fromSpecification(Paths.get(options.featureSplitMapping));
}
assert !options.featureJars.isEmpty();
return FeatureClassMapping.fromJarFiles(options.featureJars);
}
private static void run(String[] args)
throws CompilationFailedException, IOException, CompilationException, ExecutionException,
ResourceException, FeatureMappingException {
Options options = parseArguments(args);
run(options);
}
public static void run(Options options)
throws IOException, FeatureMappingException, ResourceException, CompilationException,
ExecutionException, CompilationFailedException {
if (options.inputArchives.isEmpty()) {
throw new RuntimeException("Need at least one --input");
}
if (options.featureSplitMapping == null && options.featureJars.isEmpty()) {
throw new RuntimeException("You must supply a feature split mapping or feature jars");
}
if (options.featureSplitMapping != null && !options.featureJars.isEmpty()) {
throw new RuntimeException("You can't supply both a feature split mapping and feature jars");
}
D8Command.Builder builder = D8Command.builder();
for (String s : options.inputArchives) {
builder.addProgramFiles(Paths.get(s));
}
// We set the actual consumer on the ApplicationWriter when we have calculated the distribution
// since we don't yet know the distribution.
builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
FeatureClassMapping featureClassMapping = createFeatureClassMapping(options);
DexSplitterHelper.run(
builder.build(), featureClassMapping, options.splitBaseName, options.proguardMap);
}
public static void main(String[] args) {
try {
if (PRINT_ARGS) {
printArgs(args);
}
run(args);
} catch (CompilationFailedException
| IOException
| CompilationException
| ExecutionException
| ResourceException
| FeatureMappingException e) {
System.err.println("Splitting failed: " + e.getMessage());
System.exit(1);
}
}
private static void printArgs(String[] args) {
System.err.printf("r8.DexSplitter");
for (String s : args) {
System.err.printf(" %s", s);
}
System.err.println("");
}
}