Add --build-metadata-output option to D8/R8 CLI
Bug: b/290648731
Change-Id: Ia1de5da083720b61f62dba64f082f0530306fdab
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
index 48f5c36..8359c03 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommandParser.java
@@ -21,6 +21,7 @@
C extends BaseCompilerCommand, B extends BaseCompilerCommand.Builder<C, B>> {
protected static final String ART_PROFILE_FLAG = "--art-profile";
+ protected static final String BUILD_METADATA_OUTPUT_FLAG = "--build-metadata-output";
protected static final String MIN_API_FLAG = "--min-api";
protected static final String STARTUP_PROFILE_FLAG = "--startup-profile";
protected static final String THREAD_COUNT_FLAG = "--thread-count";
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index a16189b..f7daa25 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.profile.art.ArtProfileProviderUtils;
import com.android.tools.r8.profile.startup.StartupProfileProviderUtils;
import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.FlagFile;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
@@ -18,6 +19,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
@@ -45,7 +47,8 @@
"--desugared-lib-pg-conf-output",
THREAD_COUNT_FLAG,
ART_PROFILE_FLAG,
- STARTUP_PROFILE_FLAG);
+ STARTUP_PROFILE_FLAG,
+ BUILD_METADATA_OUTPUT_FLAG);
// Note: this must be a subset of OPTIONS_WITH_ONE_PARAMETER.
private static final Set<String> OPTIONS_WITH_TWO_PARAMETERS = ImmutableSet.of(ART_PROFILE_FLAG);
@@ -213,6 +216,7 @@
}
private D8Command.Builder parse(String[] args, Origin origin, D8Command.Builder builder) {
+ Path buildMetadataOutputPath = null;
CompilationMode compilationMode = null;
Path outputPath = null;
Path globalsOutputPath = null;
@@ -360,6 +364,19 @@
Path startupProfilePath = Paths.get(nextArg);
builder.addStartupProfileProviders(
StartupProfileProviderUtils.createFromHumanReadableArtProfile(startupProfilePath));
+ } else if (arg.equals(BUILD_METADATA_OUTPUT_FLAG)) {
+ if (buildMetadataOutputPath != null) {
+ builder.error(
+ new StringDiagnostic(
+ "Cannot output build metadata to both '"
+ + buildMetadataOutputPath
+ + "' and '"
+ + nextArg
+ + "'",
+ origin));
+ continue;
+ }
+ buildMetadataOutputPath = Paths.get(nextArg);
} else if (arg.startsWith("--")) {
if (tryParseAssertionArgument(builder, arg, origin)) {
continue;
@@ -384,6 +401,17 @@
if (!classpathBuilder.isEmpty()) {
builder.addClasspathResourceProvider(classpathBuilder.build());
}
+ if (buildMetadataOutputPath != null) {
+ final Path finalBuildMetadataOutputPath = buildMetadataOutputPath;
+ builder.setBuildMetadataConsumer(
+ buildMetadata -> {
+ try {
+ FileUtils.writeTextFile(finalBuildMetadataOutputPath, buildMetadata.toJson());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
if (compilationMode != null) {
builder.setMode(compilationMode);
}
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java
index 898f4eb..9765bfe 100644
--- a/src/main/java/com/android/tools/r8/R8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.profile.art.ArtProfileProviderUtils;
import com.android.tools.r8.profile.startup.StartupProfileProviderUtils;
import com.android.tools.r8.utils.ArchiveResourceProvider;
+import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.FlagFile;
import com.android.tools.r8.utils.MapIdTemplateProvider;
import com.android.tools.r8.utils.SourceFileTemplateProvider;
@@ -22,6 +23,8 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -59,7 +62,8 @@
"--source-file-template",
ART_PROFILE_FLAG,
STARTUP_PROFILE_FLAG,
- THREAD_COUNT_FLAG);
+ THREAD_COUNT_FLAG,
+ BUILD_METADATA_OUTPUT_FLAG);
// Note: this must be a subset of OPTIONS_WITH_ONE_PARAMETER.
private static final Set<String> OPTIONS_WITH_TWO_PARAMETERS =
@@ -208,6 +212,7 @@
private void parse(
String[] args, Origin argsOrigin, R8Command.Builder builder, ParseState state) {
+ Path buildMetadataOutputPath = null;
String[] expandedArgs = FlagFile.expandFlagFiles(args, builder::error);
FeatureSplitConfigCollector featureSplitConfigCollector = new FeatureSplitConfigCollector();
for (int i = 0; i < expandedArgs.length; i++) {
@@ -359,6 +364,19 @@
Path startupProfilePath = Paths.get(nextArg);
builder.addStartupProfileProviders(
StartupProfileProviderUtils.createFromHumanReadableArtProfile(startupProfilePath));
+ } else if (arg.equals(BUILD_METADATA_OUTPUT_FLAG)) {
+ if (buildMetadataOutputPath != null) {
+ builder.error(
+ new StringDiagnostic(
+ "Cannot output build metadata to both '"
+ + buildMetadataOutputPath
+ + "' and '"
+ + nextArg
+ + "'",
+ argsOrigin));
+ continue;
+ }
+ buildMetadataOutputPath = Paths.get(nextArg);
} else if (arg.startsWith("--")) {
if (tryParseAssertionArgument(builder, arg, argsOrigin)) {
continue;
@@ -382,6 +400,17 @@
}
addFeatureSplitConfigs(
builder, featureSplitConfigCollector.getConfigs(), state.includeDataResources);
+ if (buildMetadataOutputPath != null) {
+ final Path finalBuildMetadataOutputPath = buildMetadataOutputPath;
+ builder.setBuildMetadataConsumer(
+ buildMetadata -> {
+ try {
+ FileUtils.writeTextFile(finalBuildMetadataOutputPath, buildMetadata.toJson());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
}
private void addFeatureSplitConfigs(
diff --git a/src/test/java/com/android/tools/r8/metadata/D8BuildMetadataTest.java b/src/test/java/com/android/tools/r8/metadata/D8BuildMetadataTest.java
index cdcdbfb..b2e0a3a 100644
--- a/src/test/java/com/android/tools/r8/metadata/D8BuildMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/metadata/D8BuildMetadataTest.java
@@ -10,6 +10,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -17,6 +19,9 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.Version;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.origin.EmbeddedOrigin;
+import com.android.tools.r8.utils.FileUtils;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@@ -38,7 +43,7 @@
}
@Test
- public void test() throws Exception {
+ public void testApi() throws Exception {
D8BuildMetadata buildMetadata =
testForD8(parameters.getBackend())
.addInnerClasses(getClass())
@@ -51,6 +56,32 @@
.setMinApi(parameters)
.compile()
.getBuildMetadata();
+ inspect(buildMetadata);
+ }
+
+ @Test
+ public void testCli() throws Exception {
+ Path buildMetadataOutputPath = temp.newFile("d8.txt").toPath();
+ String[] args =
+ new String[] {
+ "--build-metadata-output",
+ buildMetadataOutputPath.toString(),
+ "--desugared-lib",
+ LibraryDesugaringSpecification.JDK11.getSpecification().toString(),
+ "--lib",
+ ToolHelper.getMostRecentAndroidJar().toString(),
+ "--min-api",
+ Integer.toString(parameters.getApiLevel().getLevel()),
+ "--release",
+ ToolHelper.getClassFileForTestClass(Main.class).toString()
+ };
+ D8.run(D8Command.parse(args, EmbeddedOrigin.INSTANCE).build());
+ D8BuildMetadata buildMetadata =
+ D8BuildMetadata.fromJson(FileUtils.readTextFile(buildMetadataOutputPath));
+ inspect(buildMetadata);
+ }
+
+ private void inspect(D8BuildMetadata buildMetadata) {
String json = buildMetadata.toJson();
System.out.println(json);
// Inspecting the exact contents is not important here, but it *is* important to test that the