| // 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; | |
| import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException; | |
| import com.android.tools.r8.dex.ApplicationReader; | |
| import com.android.tools.r8.graph.AppInfoWithClassHierarchy; | |
| import com.android.tools.r8.graph.AppServices; | |
| import com.android.tools.r8.graph.AppView; | |
| import com.android.tools.r8.graph.DirectMappedDexApplication; | |
| import com.android.tools.r8.graph.SubtypingInfo; | |
| import com.android.tools.r8.shaking.AppInfoWithLiveness; | |
| import com.android.tools.r8.shaking.Enqueuer; | |
| import com.android.tools.r8.shaking.EnqueuerFactory; | |
| import com.android.tools.r8.shaking.EnqueuerResult; | |
| import com.android.tools.r8.shaking.RootSetUtils.RootSet; | |
| import com.android.tools.r8.shaking.RootSetUtils.RootSetBuilder; | |
| import com.android.tools.r8.utils.ExceptionUtils; | |
| import com.android.tools.r8.utils.InternalOptions; | |
| import com.android.tools.r8.utils.StringUtils; | |
| import com.android.tools.r8.utils.ThreadUtils; | |
| import com.android.tools.r8.utils.Timing; | |
| import java.io.IOException; | |
| import java.nio.file.Path; | |
| import java.nio.file.Paths; | |
| import java.util.Set; | |
| import java.util.concurrent.ExecutionException; | |
| import java.util.concurrent.ExecutorService; | |
| /** | |
| * PrintSeeds prints the classes, interfaces, methods and fields selected by a given ProGuard | |
| * configuration <pg-conf.txt> when compiling a given program <r8.jar> alongside a given | |
| * library <rt.jar>. | |
| * | |
| * <p>The output format is identical to what is printed when {@code -printseeds} is specified in | |
| * <pg-conf.txt>, but running PrintSeeds can be faster than running R8 with {@code | |
| * -printseeds}. See also the {@link PrintUses} program in R8. | |
| */ | |
| public class PrintSeeds { | |
| private static final String USAGE = | |
| StringUtils.joinLines( | |
| "Arguments: <rt.jar> <r8.jar> <pg-conf.txt>", | |
| "", | |
| "PrintSeeds prints the classes, interfaces, methods and fields selected by", | |
| "<pg-conf.txt> when compiling <r8.jar> alongside <rt.jar>.", | |
| "", | |
| "The output format is identical to what is printed when -printseeds is specified in", | |
| "<pg-conf.txt>, but running PrintSeeds can be faster than running R8 with", | |
| "-printseeds. See also the " + PrintUses.class.getSimpleName() + " program in R8."); | |
| public static void main(String[] args) throws Exception { | |
| if (args.length != 3) { | |
| throw new RuntimeException(StringUtils.joinLines("Invalid invocation.", USAGE)); | |
| } | |
| Path rtJar = Paths.get(args[0]); | |
| Path r8Jar = Paths.get(args[1]); | |
| Path pgConf = Paths.get(args[2]); | |
| R8Command command = | |
| R8Command.builder() | |
| .addLibraryFiles(rtJar) | |
| .addProgramFiles(r8Jar) | |
| .addProguardConfigurationFiles(pgConf) | |
| .setProgramConsumer(ClassFileConsumer.emptyConsumer()) | |
| .build(); | |
| Set<String> descriptors = new ArchiveClassFileProvider(r8Jar).getClassDescriptors(); | |
| InternalOptions options = command.getInternalOptions(); | |
| ExecutorService executorService = ThreadUtils.getExecutorService(options); | |
| ExceptionUtils.withR8CompilationHandler( | |
| command.getReporter(), | |
| () -> { | |
| try { | |
| run(command, descriptors, options, executorService); | |
| } finally { | |
| executorService.shutdown(); | |
| } | |
| }); | |
| } | |
| private static void run( | |
| R8Command command, Set<String> descriptors, InternalOptions options, ExecutorService executor) | |
| throws IOException { | |
| assert !options.forceProguardCompatibility; | |
| Timing timing = new Timing("PrintSeeds"); | |
| try { | |
| DirectMappedDexApplication application = | |
| new ApplicationReader(command.getInputApp(), options, timing).read(executor).toDirect(); | |
| AppView<AppInfoWithClassHierarchy> appView = AppView.createForR8(application); | |
| appView.setAppServices(AppServices.builder(appView).build()); | |
| SubtypingInfo subtypingInfo = new SubtypingInfo(appView); | |
| RootSet rootSet = | |
| RootSet.builder(appView, subtypingInfo, options.getProguardConfiguration().getRules()) | |
| .build(executor); | |
| Enqueuer enqueuer = | |
| EnqueuerFactory.createForInitialTreeShaking(appView, executor, subtypingInfo); | |
| EnqueuerResult enqueuerResult = enqueuer.traceApplication(rootSet, executor, timing); | |
| AppInfoWithLiveness appInfo = enqueuerResult.getAppInfo(); | |
| RootSetBuilder.writeSeeds( | |
| appInfo, System.out, type -> descriptors.contains(type.toDescriptorString())); | |
| } catch (ExecutionException e) { | |
| throw unwrapExecutionException(e); | |
| } | |
| } | |
| } |