Merge "Add option --main-dex-list to D8 command line"
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java
index ec4f527..5eb67c4 100644
--- a/src/main/java/com/android/tools/r8/BaseCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCommand.java
@@ -248,6 +248,10 @@
}
protected void validate() throws CompilationException {
+ if (app.hasMainDexList() && outputMode == OutputMode.FilePerClass) {
+ throw new CompilationException(
+ "Option --main-dex-list cannot be used with --file-per-class");
+ }
FileUtils.validateOutputFile(outputPath);
}
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 6ac5f1e..b856556 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -71,6 +71,14 @@
return this;
}
+ protected void validate() throws CompilationException {
+ super.validate();
+ if (getAppBuilder().hasMainDexList() && intermediate) {
+ throw new CompilationException(
+ "Option --main-dex-list cannot be used with --intermediate");
+ }
+ }
+
/**
* Build the final D8Command.
*/
@@ -95,17 +103,19 @@
"Usage: d8 [options] <input-files>",
" where <input-files> are any combination of dex, class, zip, jar, or apk files",
" and options are:",
- " --debug # Compile with debugging information (default).",
- " --release # Compile without debugging information.",
- " --output <file> # Output result in <outfile>.",
- " # <file> must be an existing directory or a zip file.",
- " --lib <file> # Add <file> as a library resource.",
- " --classpath <file> # Add <file> as a classpath resource.",
- " --min-api # Minimum Android API level compatibility",
- " --intermediate # Compile an intermediate result intended for later merging.",
- " --file-per-class # Produce a separate dex file per class",
- " --version # Print the version of d8.",
- " --help # Print this message."));
+ " --debug # Compile with debugging information (default).",
+ " --release # Compile without debugging information.",
+ " --output <file> # Output result in <outfile>.",
+ " # <file> must be an existing directory or a zip file.",
+ " --lib <file> # Add <file> as a library resource.",
+ " --classpath <file> # Add <file> as a classpath resource.",
+ " --min-api # Minimum Android API level compatibility",
+ " --intermediate # Compile an intermediate result intended for later",
+ " # merging.",
+ " --file-per-class # Produce a separate dex file per class",
+ " --main-dex-list <file> # List of classes to place in the primary dex file.",
+ " --version # Print the version of d8.",
+ " --help # Print this message."));
private boolean intermediate = false;
@@ -121,6 +131,7 @@
public static Builder parse(String[] args) throws CompilationException, IOException {
CompilationMode modeSet = null;
Path outputPath = null;
+ String mainDexList = null;
Builder builder = builder();
try {
for (int i = 0; i < args.length; i++) {
@@ -156,6 +167,12 @@
builder.addLibraryFiles(Paths.get(args[++i]));
} else if (arg.equals("--classpath")) {
builder.addClasspathFiles(Paths.get(args[++i]));
+ } else if (arg.equals("--main-dex-list")) {
+ if (mainDexList != null) {
+ throw new CompilationException("Only one --main-dex-list supported");
+ }
+ mainDexList = args[++i];
+ builder.setMainDexListFile(Paths.get(mainDexList));
} else if (arg.equals("--min-api")) {
builder.setMinApiLevel(Integer.valueOf(args[++i]));
} else if (arg.equals("--intermediate")) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 3b88ba8..c2a3245 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -129,6 +129,14 @@
return self();
}
+ protected void validate() throws CompilationException {
+ super.validate();
+ if (minimalMainDex && mainDexRules.isEmpty()) {
+ throw new CompilationException(
+ "Option --minimal-main-dex require --main-dex-rules");
+ }
+ }
+
@Override
public R8Command build() throws CompilationException, IOException {
// If printing versions ignore everything else.
@@ -193,20 +201,23 @@
"Usage: r8 [options] <input-files>",
" where <input-files> are any combination of dex, class, zip, jar, or apk files",
" and options are:",
- " --release # Compile without debugging information (default).",
- " --debug # Compile with debugging information.",
- " --output <file> # Output result in <file>.",
- " # <file> must be an existing directory or a zip file.",
- " --lib <file> # Add <file> as a library resource.",
- " --min-api # Minimum Android API level compatibility.",
- " --pg-conf <file> # Proguard configuration <file> (implies tree shaking/minification).",
- " --pg-map <file> # Proguard map <file>.",
- " --no-tree-shaking # Force disable tree shaking of unreachable classes.",
- " --no-minification # Force disable minification of names.",
- " --multidex-rules <file> # Enable automatic classes partitioning for legacy multidex.",
- " # <file> is a Proguard configuration file (with only keep rules).",
- " --version # Print the version of r8.",
- " --help # Print this message."));
+ " --release # Compile without debugging information (default).",
+ " --debug # Compile with debugging information.",
+ " --output <file> # Output result in <file>.",
+ " # <file> must be an existing directory or a zip file.",
+ " --lib <file> # Add <file> as a library resource.",
+ " --min-api # Minimum Android API level compatibility.",
+ " --pg-conf <file> # Proguard configuration <file> (implies tree",
+ " # shaking/minification).",
+ " --pg-map <file> # Proguard map <file>.",
+ " --no-tree-shaking # Force disable tree shaking of unreachable classes.",
+ " --no-minification # Force disable minification of names.",
+ " --main-dex-rules <file> # Proguard keep rules for classes to place in the",
+ " # primary dex file.",
+ " --minimal-main-dex # Only place classes specified by --main-dex-rules",
+ " # in the primary dex file.",
+ " --version # Print the version of r8.",
+ " --help # Print this message."));
private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
private final boolean minimalMainDex;
@@ -271,9 +282,9 @@
builder.setTreeShaking(false);
} else if (arg.equals("--no-minification")) {
builder.setMinification(false);
- } else if (arg.equals("--multidex-rules")) {
+ } else if (arg.equals("--main-dex-rules")) {
builder.addMainDexRules(Paths.get(args[++i]));
- } else if (arg.equals("--minimal-maindex")) {
+ } else if (arg.equals("--minimal-main-dex")) {
builder.setMinimalMainDex(true);
} else if (arg.equals("--pg-conf")) {
builder.addProguardConfigurationFiles(Paths.get(args[++i]));
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index e767030..19d5153 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -579,6 +579,10 @@
return this;
}
+ public boolean hasMainDexList() {
+ return mainDexList != null;
+ }
+
/**
* Set the main-dex list data.
*/
diff --git a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
index 6f45137..ed146b72 100644
--- a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java
@@ -156,6 +156,37 @@
}
@Test
+ public void mainDexList() throws Throwable {
+ Path mailDexList = temp.getRoot().toPath().resolve("main-dex-list.txt");
+ D8Command command = parse("--main-dex-list", mailDexList.toString());
+ assertTrue(ToolHelper.getApp(command).hasMainDexList());
+ }
+
+ @Test
+ public void multipleMainDexList() throws Throwable {
+ thrown.expect(CompilationException.class);
+ Path mailDexList1 = temp.getRoot().toPath().resolve("main-dex-list-1.txt");
+ Path mailDexList2 = temp.getRoot().toPath().resolve("main-dex-list-2.txt");
+ parse("--main-dex-list", mailDexList1.toString(), "--main-dex-list", mailDexList2.toString());
+ }
+
+ @Test
+ public void mainDexListWithFilePerClass() throws Throwable {
+ thrown.expect(CompilationException.class);
+ Path mailDexList = temp.getRoot().toPath().resolve("main-dex-list.txt");
+ D8Command command = parse("--main-dex-list", mailDexList.toString(), "--file-per-class");
+ assertTrue(ToolHelper.getApp(command).hasMainDexList());
+ }
+
+ @Test
+ public void mainDexListWithIntermediate() throws Throwable {
+ thrown.expect(CompilationException.class);
+ Path mailDexList = temp.getRoot().toPath().resolve("main-dex-list.txt");
+ D8Command command = parse("--main-dex-list", mailDexList.toString(), "--intermediate");
+ assertTrue(ToolHelper.getApp(command).hasMainDexList());
+ }
+
+ @Test
public void invalidOutputFileTypeParse() throws Throwable {
thrown.expect(CompilationException.class);
Path invalidType = temp.getRoot().toPath().resolve("an-invalid-output-file-type.foobar");
diff --git a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
index 0c737b9..27f0367 100644
--- a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java
@@ -89,6 +89,24 @@
}
@Test
+ public void mainDexRules() throws Throwable {
+ Path mailDexRules = temp.newFile("main-dex.rules").toPath();
+ parse("--main-dex-rules", mailDexRules.toString());
+ }
+
+ @Test
+ public void minimalMainDex() throws Throwable {
+ thrown.expect(CompilationException.class);
+ parse("--minimal-main-dex");
+ }
+
+ @Test
+ public void mainDexRulesWithMinimalMainDex() throws Throwable {
+ Path mailDexRules = temp.newFile("main-dex.rules").toPath();
+ parse("--main-dex-rules", mailDexRules.toString(), "--minimal-main-dex");
+ }
+
+ @Test
public void existingOutputDirWithDexFiles() throws Throwable {
Path existingDir = temp.newFolder().toPath();
List<Path> classesFiles = ImmutableList.of(
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 1dabbd3..ee8981b 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -158,9 +158,9 @@
app_provided_pg_conf = True
if options.k:
args.extend(['--pg-conf', options.k])
- if 'multidexrules' in values:
- for rules in values['multidexrules']:
- args.extend(['--multidex-rules', rules])
+ if 'maindexrules' in values:
+ for rules in values['maindexrules']:
+ args.extend(['--main-dex-rules', rules])
if not options.no_libraries and 'libraries' in values:
for lib in values['libraries']:
diff --git a/tools/youtube_data.py b/tools/youtube_data.py
index a3d3791..114e6c7 100644
--- a/tools/youtube_data.py
+++ b/tools/youtube_data.py
@@ -77,7 +77,7 @@
'pgconf': [
'%s_proguard.config' % V12_22_PREFIX,
'%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
- 'multidexrules' : [
+ 'maindexrules' : [
os.path.join(V12_22_BASE, 'mainDexClasses.rules'),
os.path.join(V12_22_BASE, 'main-dex-classes-release.cfg'),
os.path.join(V12_22_BASE, 'main_dex_YouTubeRelease_proguard.cfg')],