Add direct CLI options for dump to file and directory
For some build system integrations setting the JVM system
properties is not easily available having a command line option
can be convenient.
The two command line options are not advertised in the help,
but just silently there.
Change-Id: Ie1aa70c50654abf72584de591faec16d96931fea
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 555713b..69c1ec8 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -12,6 +12,7 @@
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.DumpInputFlags;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.Reporter;
@@ -47,7 +48,8 @@
private final BiPredicate<String, Long> dexClassChecksumFilter;
private final List<AssertionsConfiguration> assertionsConfiguration;
private final List<Consumer<Inspector>> outputInspections;
- private int threadCount;
+ private final int threadCount;
+ private final DumpInputFlags dumpInputFlags;
BaseCompilerCommand(boolean printHelp, boolean printVersion) {
super(printHelp, printVersion);
@@ -63,6 +65,7 @@
assertionsConfiguration = new ArrayList<>();
outputInspections = null;
threadCount = ThreadUtils.NOT_SPECIFIED;
+ dumpInputFlags = DumpInputFlags.noDump();
}
BaseCompilerCommand(
@@ -78,7 +81,8 @@
BiPredicate<String, Long> dexClassChecksumFilter,
List<AssertionsConfiguration> assertionsConfiguration,
List<Consumer<Inspector>> outputInspections,
- int threadCount) {
+ int threadCount,
+ DumpInputFlags dumpInputFlags) {
super(app);
assert minApiLevel > 0;
assert mode != null;
@@ -94,6 +98,7 @@
this.assertionsConfiguration = assertionsConfiguration;
this.outputInspections = outputInspections;
this.threadCount = threadCount;
+ this.dumpInputFlags = dumpInputFlags;
}
/**
@@ -174,6 +179,10 @@
return threadCount;
}
+ DumpInputFlags getDumpInputFlags() {
+ return dumpInputFlags;
+ }
+
Reporter getReporter() {
return reporter;
}
@@ -207,6 +216,7 @@
private List<AssertionsConfiguration> assertionsConfiguration = new ArrayList<>();
private List<Consumer<Inspector>> outputInspections = new ArrayList<>();
protected StringConsumer proguardMapConsumer = null;
+ private DumpInputFlags dumpInputFlags = DumpInputFlags.noDump();
abstract CompilationMode defaultCompilationMode();
@@ -583,6 +593,20 @@
return self();
}
+ B dumpInputToFile(Path file) {
+ dumpInputFlags = DumpInputFlags.dumpToFile(file);
+ return self();
+ }
+
+ B dumpInputToDirectory(Path directory) {
+ dumpInputFlags = DumpInputFlags.dumpToDirectory(directory);
+ return self();
+ }
+
+ DumpInputFlags getDumpInputFlags() {
+ return dumpInputFlags;
+ }
+
@Override
void validate() {
Reporter reporter = getReporter();
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
index ca4e9e4..1316be8 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
@@ -21,6 +21,8 @@
protected static final String MIN_API_FLAG = "--min-api";
protected static final String THREAD_COUNT_FLAG = "--thread-count";
protected static final String MAP_DIAGNOSTICS = "--map-diagnostics";
+ protected static final String DUMP_INPUT_TO_FILE = "--dumpinputtofile";
+ protected static final String DUMP_INPUT_TO_DIRECTORY = "--dumpinputtodirectory";
static final Iterable<String> ASSERTIONS_USAGE_MESSAGE =
Arrays.asList(
@@ -211,6 +213,23 @@
return 2;
}
+ int tryParseDump(B builder, String arg, String[] args, int argsIndex, Origin origin) {
+ if (!arg.equals(DUMP_INPUT_TO_FILE) && !arg.equals(DUMP_INPUT_TO_DIRECTORY)) {
+ return -1;
+ }
+ if (args.length <= argsIndex + 1) {
+ builder.error(new StringDiagnostic("Missing argument(s) for " + arg + ".", origin));
+ return args.length - argsIndex;
+ }
+ if (arg.equals(DUMP_INPUT_TO_FILE)) {
+ builder.dumpInputToFile(Paths.get(args[argsIndex + 1]));
+ } else {
+ assert arg.equals(DUMP_INPUT_TO_DIRECTORY);
+ builder.dumpInputToDirectory(Paths.get(args[argsIndex + 1]));
+ }
+ return 1;
+ }
+
/**
* This method must match the lookup in
* {@link com.android.tools.r8.JdkClassFileProvider#fromJdkHome}.
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 7e20368..7dbcb32 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -21,6 +21,7 @@
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.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
@@ -317,6 +318,7 @@
minimalMainDex,
mainDexKeepRules,
getThreadCount(),
+ getDumpInputFlags(),
factory);
}
}
@@ -397,6 +399,7 @@
boolean minimalMainDex,
ImmutableList<ProguardConfigurationRule> mainDexKeepRules,
int threadCount,
+ DumpInputFlags dumpInputFlags,
DexItemFactory factory) {
super(
inputApp,
@@ -411,7 +414,8 @@
dexClassChecksumFilter,
assertionsConfiguration,
outputInspections,
- threadCount);
+ threadCount,
+ dumpInputFlags);
this.intermediate = intermediate;
this.desugarGraphConsumer = desugarGraphConsumer;
this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
@@ -502,10 +506,7 @@
internal.threadCount = getThreadCount();
}
- if (skipDump) {
- internal.dumpInputToDirectory = null;
- internal.dumpInputToFile = null;
- }
+ internal.setDumpInputFlags(getDumpInputFlags(), skipDump);
internal.dumpOptions = dumpOptions();
return internal;
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index 8f90ade..9e729e0 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -290,6 +290,11 @@
i += argsConsumed;
continue;
}
+ argsConsumed = tryParseDump(builder, arg, expandedArgs, i, origin);
+ if (argsConsumed >= 0) {
+ i += argsConsumed;
+ continue;
+ }
builder.error(new StringDiagnostic("Unknown option: " + arg, origin));
} else if (arg.startsWith("@")) {
builder.error(new StringDiagnostic("Recursive @argfiles are not supported: ", origin));
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 1fc7689..27108a1 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.origin.Origin;
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.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.Pair;
@@ -95,6 +96,7 @@
List<AssertionsConfiguration> assertionsConfiguration,
List<Consumer<Inspector>> outputInspections,
int threadCount,
+ DumpInputFlags dumpInputFlags,
DexItemFactory factory) {
super(
inputApp,
@@ -109,7 +111,8 @@
dexClassChecksumFilter,
assertionsConfiguration,
outputInspections,
- threadCount);
+ threadCount,
+ dumpInputFlags);
this.d8Command = d8Command;
this.r8Command = r8Command;
this.libraryConfiguration = libraryConfiguration;
@@ -196,6 +199,8 @@
assert internal.threadCount == ThreadUtils.NOT_SPECIFIED;
internal.threadCount = getThreadCount();
}
+
+ internal.setDumpInputFlags(getDumpInputFlags(), false);
internal.dumpOptions = dumpOptions();
return internal;
@@ -395,6 +400,7 @@
getAssertionsConfiguration(),
getOutputInspections(),
getThreadCount(),
+ getDumpInputFlags(),
factory);
}
}
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java
index 402e59a..4224ad8 100644
--- a/src/main/java/com/android/tools/r8/L8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -176,6 +176,11 @@
i += argsConsumed;
continue;
}
+ argsConsumed = tryParseDump(builder, arg, expandedArgs, i, origin);
+ if (argsConsumed >= 0) {
+ i += argsConsumed;
+ continue;
+ }
builder.error(new StringDiagnostic("Unknown option: " + arg, origin));
} else {
builder.addProgramFiles(Paths.get(arg));
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 2b3f988..e3de56c 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -27,6 +27,7 @@
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.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -585,7 +586,8 @@
getOutputInspections(),
synthesizedClassPrefix,
skipDump,
- getThreadCount());
+ getThreadCount(),
+ getDumpInputFlags());
return command;
}
@@ -750,7 +752,8 @@
List<Consumer<Inspector>> outputInspections,
String synthesizedClassPrefix,
boolean skipDump,
- int threadCount) {
+ int threadCount,
+ DumpInputFlags dumpInputFlags) {
super(
inputApp,
mode,
@@ -764,7 +767,8 @@
dexClassChecksumFilter,
assertionsConfiguration,
outputInspections,
- threadCount);
+ threadCount,
+ dumpInputFlags);
assert proguardConfiguration != null;
assert mainDexKeepRules != null;
this.mainDexKeepRules = mainDexKeepRules;
@@ -956,10 +960,7 @@
internal.threadCount = getThreadCount();
}
- if (skipDump) {
- internal.dumpInputToDirectory = null;
- internal.dumpInputToFile = null;
- }
+ internal.setDumpInputFlags(getDumpInputFlags(), skipDump);
internal.dumpOptions = dumpOptions();
return internal;
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java
index 277bec8..ab664c3 100644
--- a/src/main/java/com/android/tools/r8/R8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -271,6 +271,11 @@
i += argsConsumed;
continue;
}
+ argsConsumed = tryParseDump(builder, arg, expandedArgs, i, argsOrigin);
+ if (argsConsumed >= 0) {
+ i += argsConsumed;
+ continue;
+ }
builder.error(new StringDiagnostic("Unknown option: " + arg, argsOrigin));
} else if (arg.startsWith("@")) {
builder.error(new StringDiagnostic("Recursive @argfiles are not supported: ", argsOrigin));
diff --git a/src/main/java/com/android/tools/r8/utils/DumpInputFlags.java b/src/main/java/com/android/tools/r8/utils/DumpInputFlags.java
new file mode 100644
index 0000000..d37de80
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/DumpInputFlags.java
@@ -0,0 +1,55 @@
+// Copyright (c) 2021, 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.utils;
+
+import java.nio.file.Path;
+
+public abstract class DumpInputFlags {
+
+ public static DumpInputFlags noDump() {
+ return new DumpInputFlags() {
+ @Override
+ Path getDumpInputToFile() {
+ return null;
+ }
+
+ @Override
+ Path getDumpInputToDirectory() {
+ return null;
+ }
+ };
+ }
+
+ public static DumpInputFlags dumpToFile(Path file) {
+ return new DumpInputFlags() {
+ @Override
+ Path getDumpInputToFile() {
+ return file;
+ }
+
+ @Override
+ Path getDumpInputToDirectory() {
+ return null;
+ }
+ };
+ }
+
+ public static DumpInputFlags dumpToDirectory(Path file) {
+ return new DumpInputFlags() {
+ @Override
+ Path getDumpInputToFile() {
+ return null;
+ }
+
+ @Override
+ Path getDumpInputToDirectory() {
+ return file;
+ }
+ };
+ }
+
+ abstract Path getDumpInputToFile();
+
+ abstract Path getDumpInputToDirectory();
+}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index ee29d30..79e63c0 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
-
import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.DataResourceConsumer;
@@ -391,6 +390,21 @@
return marker;
}
+ public void setDumpInputFlags(DumpInputFlags dumpInputFlags, boolean skipDump) {
+ if (skipDump) {
+ dumpInputToDirectory = null;
+ dumpInputToFile = null;
+ return;
+ }
+
+ if (dumpInputFlags.getDumpInputToFile() != null) {
+ dumpInputToFile = dumpInputFlags.getDumpInputToFile().toString();
+ }
+ if (dumpInputFlags.getDumpInputToDirectory() != null) {
+ dumpInputToDirectory = dumpInputFlags.getDumpInputToDirectory().toString();
+ }
+ }
+
public boolean hasConsumer() {
return programConsumer != null;
}
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
index 10b8afe..ca3e2f0 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
@@ -59,6 +59,9 @@
// Allow test proguard options
private boolean allowTestProguardOptions = false;
+ private String dumpInputToFile = null;
+ private String dumpInputToDirectory = null;
+
private boolean addR8ExternalDeps = false;
private List<String> jvmFlags = new ArrayList<>();
@@ -95,6 +98,16 @@
return self();
}
+ public ExternalR8TestBuilder dumpInputToFile(String arg) {
+ dumpInputToFile = arg;
+ return self();
+ }
+
+ public ExternalR8TestBuilder dumpInputToDirectory(String arg) {
+ dumpInputToDirectory = arg;
+ return self();
+ }
+
@Override
ExternalR8TestCompileResult internalCompile(
Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
@@ -155,6 +168,14 @@
command.add(libJar.toAbsolutePath().toString());
}
}
+ if (dumpInputToFile != null) {
+ command.add("--dumpinputtofile");
+ command.add(dumpInputToFile);
+ }
+ if (dumpInputToDirectory != null) {
+ command.add("--dumpinputtodirectory");
+ command.add(dumpInputToDirectory);
+ }
command.addAll(programJars.stream().map(Path::toString).collect(Collectors.toList()));
ProcessBuilder processBuilder = new ProcessBuilder(command);
diff --git a/src/test/java/com/android/tools/r8/dump/DumpInputsTest.java b/src/test/java/com/android/tools/r8/dump/DumpInputsTest.java
index 008846d..5437118 100644
--- a/src/test/java/com/android/tools/r8/dump/DumpInputsTest.java
+++ b/src/test/java/com/android/tools/r8/dump/DumpInputsTest.java
@@ -40,7 +40,7 @@
}
@Test
- public void testDumpToFile() throws Exception {
+ public void testDumpToFileSystemProperty() throws Exception {
Path dump = temp.newFolder().toPath().resolve("dump.zip");
try {
testForExternalR8(parameters.getBackend(), parameters.getRuntime())
@@ -55,7 +55,22 @@
}
@Test
- public void testDumpToDirectory() throws Exception {
+ public void testDumpToFileCLI() throws Exception {
+ Path dump = temp.newFolder().toPath().resolve("dump.zip");
+ try {
+ testForExternalR8(parameters.getBackend(), parameters.getRuntime())
+ .dumpInputToFile(dump.toString())
+ .addProgramClasses(TestClass.class)
+ .compile();
+ } catch (AssertionError e) {
+ verifyDump(dump, false, true);
+ return;
+ }
+ fail("Expected external compilation to exit");
+ }
+
+ @Test
+ public void testDumpToDirectorySystemProperty() throws Exception {
Path dumpDir = temp.newFolder().toPath();
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class)
@@ -69,17 +84,19 @@
.assertAllInfoMessagesMatch(containsString("Dumped compilation inputs to:"))
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("Hello, world");
- assertTrue(Files.isDirectory(dumpDir));
- List<Path> paths = Files.walk(dumpDir, 1).collect(Collectors.toList());
- boolean hasVerified = false;
- for (Path path : paths) {
- if (!path.equals(dumpDir)) {
- // The non-external run here results in assert code calling application read.
- verifyDump(path, false, false);
- hasVerified = true;
- }
- }
- assertTrue(hasVerified);
+
+ verifyDumpDirectory(dumpDir, false, false);
+ }
+
+ @Test
+ public void testDumpToDirectoryCLI() throws Exception {
+ Path dumpDir = temp.newFolder().toPath();
+ testForExternalR8(parameters.getBackend(), parameters.getRuntime())
+ .dumpInputToDirectory(dumpDir.toString())
+ .addProgramClasses(TestClass.class)
+ .compile();
+
+ verifyDumpDirectory(dumpDir, false, false);
}
private void verifyDump(Path dumpFile, boolean hasClasspath, boolean hasProguardConfig)
@@ -105,6 +122,21 @@
DescriptorUtils.javaTypeToDescriptor(TestClass.class.getTypeName()))));
}
+ private void verifyDumpDirectory(Path dumpDir, boolean hasClasspath, boolean hasProguardConfig)
+ throws IOException {
+ assertTrue(Files.isDirectory(dumpDir));
+ List<Path> paths = Files.walk(dumpDir, 1).collect(Collectors.toList());
+ boolean hasVerified = false;
+ for (Path path : paths) {
+ if (!path.equals(dumpDir)) {
+ // The non-external run here results in assert code calling application read.
+ verifyDump(path, hasClasspath, hasProguardConfig);
+ hasVerified = true;
+ }
+ }
+ assertTrue(hasVerified);
+ }
+
static class TestClass {
public static void main(String[] args) {
System.out.println("Hello, world");