Fail when compiling to native multidex with main-dex options.
Change-Id: Ic4418769c4d292e3b858efdfca13d1cf3ed52a6c
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index f0217b9..1004532 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
@@ -140,6 +141,14 @@
} else if (getMainDexListConsumer() != null) {
reporter.error("Option --main-dex-list-output require --main-dex-list");
}
+ if (getMinApiLevel() >= AndroidApiLevel.L.getLevel()) {
+ if (getMainDexListConsumer() != null || getAppBuilder().hasMainDexList()) {
+ reporter.error(
+ "D8 does not support main-dex inputs and outputs when compiling to API level "
+ + AndroidApiLevel.L.getLevel()
+ + " and above");
+ }
+ }
super.validate();
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 7e4974b..ae166d3 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -54,7 +54,6 @@
import com.android.tools.r8.shaking.TreePruner;
import com.android.tools.r8.shaking.VerticalClassMerger;
import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.ExceptionUtils;
@@ -244,12 +243,6 @@
System.setOut(new PrintStream(ByteStreams.nullOutputStream()));
}
try {
- AndroidApiLevel oLevel = AndroidApiLevel.O;
- if (options.minApiLevel >= oLevel.getLevel()
- && !options.mainDexKeepRules.isEmpty()) {
- throw new CompilationError("Automatic main dex list is not supported when compiling for "
- + oLevel.getName() + " and later (--min-api " + oLevel.getLevel() + ")");
- }
DexApplication application =
new ApplicationReader(inputApp, options, timing).read(executorService).toDirect();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index ff74d09..9f25fbc 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.shaking.ProguardConfigurationSourceBytes;
import com.android.tools.r8.shaking.ProguardConfigurationSourceFile;
import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
@@ -321,6 +322,17 @@
reporter.error(
"Option --main-dex-list-output require --main-dex-rules and/or --main-dex-list");
}
+ if (!(getProgramConsumer() instanceof ClassFileConsumer)
+ && getMinApiLevel() >= AndroidApiLevel.L.getLevel()) {
+ if (getMainDexListConsumer() != null
+ || !mainDexRules.isEmpty()
+ || getAppBuilder().hasMainDexList()) {
+ reporter.error(
+ "R8 does not support main-dex inputs and outputs when compiling to API level "
+ + AndroidApiLevel.L.getLevel()
+ + " and above");
+ }
+ }
for (Path file : programFiles) {
if (FileUtils.isDexFile(file)) {
reporter.error(new StringDiagnostic(
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index a478860..f6454f9 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -96,6 +96,7 @@
ExecutorService executorService,
ProgramClassConflictResolver resolver)
throws IOException, ExecutionException {
+ assert verifyMainDexOptionsCompatible(inputApp, options);
timing.begin("DexApplication.read");
final LazyLoadedDexApplication.Builder builder =
DexApplication.builder(itemFactory, timing, resolver);
@@ -123,7 +124,22 @@
return builder.build();
}
- private int verifyOrComputeMinApiLevel(int computedMinApiLevel, DexReader dexReader) {
+ private static boolean verifyMainDexOptionsCompatible(
+ AndroidApp inputApp, InternalOptions options) {
+ if (!options.isGeneratingDex()) {
+ return true;
+ }
+ AndroidApiLevel nativeMultiDex = AndroidApiLevel.L;
+ if (options.minApiLevel < nativeMultiDex.getLevel()) {
+ return true;
+ }
+ assert options.mainDexKeepRules.isEmpty();
+ assert options.mainDexListConsumer == null;
+ assert !inputApp.hasMainDexList();
+ return true;
+ }
+
+ private int validateOrComputeMinApiLevel(int computedMinApiLevel, DexReader dexReader) {
DexVersion version = DexVersion.getDexVersion(dexReader.getDexVersion());
if (options.minApiLevel == AndroidApiLevel.getDefault().getLevel()) {
computedMinApiLevel = Math
@@ -199,7 +215,7 @@
int computedMinApiLevel = options.minApiLevel;
for (ProgramResource input : dexSources) {
DexReader dexReader = new DexReader(input);
- computedMinApiLevel = verifyOrComputeMinApiLevel(computedMinApiLevel, dexReader);
+ computedMinApiLevel = validateOrComputeMinApiLevel(computedMinApiLevel, dexReader);
dexParsers.add(new DexParser(dexReader, classKind, itemFactory, options.reporter));
}
options.minApiLevel = computedMinApiLevel;
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index aed1231..6b51909 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ZipUtils;
@@ -251,6 +252,19 @@
}
@Test(expected = CompilationFailedException.class)
+ public void mainDexListWithNonLegacyMinApi() throws Throwable {
+ Path mainDexList = temp.newFile("main-dex-list.txt").toPath();
+ DiagnosticsChecker.checkErrorsContains(
+ "does not support main-dex",
+ (handler) ->
+ D8Command.builder(handler)
+ .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+ .setMinApiLevel(AndroidApiLevel.L.getLevel())
+ .addMainDexListFiles(mainDexList)
+ .build());
+ }
+
+ @Test(expected = CompilationFailedException.class)
public void invalidOutputFileTypeParse() throws Throwable {
Path invalidType = temp.getRoot().toPath().resolve("an-invalid-output-file-type.foobar");
parse("--output", invalidType.toString());
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 4356327..518d26f 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.ImmutableList;
@@ -227,6 +228,32 @@
parse("--main-dex-list-output", mainDexListOutput.toString());
}
+ @Test(expected = CompilationFailedException.class)
+ public void mainDexRulesWithNonLegacyMinApi() throws Throwable {
+ Path mainDexRules = temp.newFile("main-dex.rules").toPath();
+ DiagnosticsChecker.checkErrorsContains(
+ "does not support main-dex",
+ (handler) ->
+ R8Command.builder(handler)
+ .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+ .setMinApiLevel(AndroidApiLevel.L.getLevel())
+ .addMainDexRulesFiles(mainDexRules)
+ .build());
+ }
+
+ @Test(expected = CompilationFailedException.class)
+ public void mainDexListWithNonLegacyMinApi() throws Throwable {
+ Path mainDexList = temp.newFile("main-dex-list.txt").toPath();
+ DiagnosticsChecker.checkErrorsContains(
+ "does not support main-dex",
+ (handler) ->
+ R8Command.builder(handler)
+ .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+ .setMinApiLevel(AndroidApiLevel.L.getLevel())
+ .addMainDexListFiles(mainDexList)
+ .build());
+ }
+
@Test
public void existingOutputDirWithDexFiles() throws Throwable {
Path existingDir = temp.newFolder().toPath();
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
index 9d9f21d..48b23fe 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.common.collect.ImmutableList;
@@ -114,6 +115,7 @@
Path mainDexList = writeTextToTempFile(testClassMainDexName);
TestMainDexListConsumer consumer = new TestMainDexListConsumer();
testForD8()
+ .setMinApi(AndroidApiLevel.K)
.addProgramClasses(ImmutableList.of(TestClass.class, MyConsumer.class))
.addMainDexListFiles(ImmutableList.of(mainDexList))
.setMainDexListConsumer(consumer)
@@ -128,6 +130,7 @@
Path dexOutput = temp.getRoot().toPath().resolve("classes.zip");
// Build intermediate dex code first.
testForD8()
+ .setMinApi(AndroidApiLevel.K)
.addProgramClasses(ImmutableList.of(TestClass.class, MyConsumer.class))
.setIntermediate(true)
.setProgramConsumer(new ArchiveConsumer(dexOutput))
@@ -135,6 +138,7 @@
// Now test that when merging with a main dex list it is correctly updated.
TestMainDexListConsumer consumer = new TestMainDexListConsumer();
testForD8()
+ .setMinApi(AndroidApiLevel.K)
.addProgramFiles(dexOutput)
.addMainDexListFiles(ImmutableList.of(mainDexList))
.setMainDexListConsumer(consumer)
diff --git a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
index 01265bb..18ccf33 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
@@ -85,7 +85,7 @@
public void runTestWithR8(GraphConsumer consumer, String rule) throws Exception {
R8TestBuilder builder =
testForR8(Backend.DEX)
- .setMinApi(AndroidApiLevel.L)
+ .setMinApi(AndroidApiLevel.K)
.addProgramClasses(CLASSES)
.addMainDexRules(keepMainProguardConfiguration(HelloWorldMain.class))
.setMainDexKeptGraphConsumer(consumer);