1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tools.r8wrappers; 17 18 import com.android.tools.r8.ArchiveProgramResourceProvider; 19 import com.android.tools.r8.CompilationFailedException; 20 import com.android.tools.r8.D8; 21 import com.android.tools.r8.D8Command; 22 import com.android.tools.r8.ParseFlagInfo; 23 import com.android.tools.r8.ParseFlagPrinter; 24 import com.android.tools.r8.Version; 25 import com.android.tools.r8.origin.Origin; 26 import com.android.tools.r8wrappers.utils.WrapperDiagnosticsHandler; 27 import com.android.tools.r8wrappers.utils.WrapperFlag; 28 import java.nio.file.Files; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.List; 34 35 public class D8Wrapper { 36 37 private static final String WRAPPER_STRING = "d8-aosp-wrapper"; 38 39 private static final Origin CLI_ORIGIN = 40 new Origin(Origin.root()) { 41 @Override 42 public String part() { 43 return WRAPPER_STRING; 44 } 45 }; 46 47 private static final String NO_DEX_FLAG = "--no-dex-input-jar"; 48 private static final String INFO_FLAG = "--info"; getAdditionalFlagsInfo()49 private static List<ParseFlagInfo> getAdditionalFlagsInfo() { 50 return Arrays.asList( 51 new WrapperFlag(NO_DEX_FLAG, "Input archive with potential all dex code ignored."), 52 new WrapperFlag(INFO_FLAG, "Print the info-level log messages from the compiler.")); 53 } 54 getUsageMessage()55 private static String getUsageMessage() { 56 StringBuilder builder = 57 appendLines( 58 new StringBuilder(), 59 "Usage: d8 [options] [@<argfile>] <input-files>", 60 " where <input-files> are any combination of dex, class, zip, jar or apk files", 61 " and each <argfile> is a file containing additional arguments (one per line)", 62 " and options are:"); 63 new ParseFlagPrinter() 64 .addFlags(D8Command.getParseFlagsInformation()) 65 .addFlags(getAdditionalFlagsInfo()) 66 .setIndent(2) 67 .appendLinesToBuilder(builder); 68 return builder.toString(); 69 } 70 appendLines(StringBuilder builder, String... lines)71 private static StringBuilder appendLines(StringBuilder builder, String... lines) { 72 for (String line : lines) { 73 builder.append(line).append(System.lineSeparator()); 74 } 75 return builder; 76 } 77 main(String[] args)78 public static void main(String[] args) throws CompilationFailedException { 79 D8Wrapper wrapper = new D8Wrapper(); 80 String[] remainingArgs = wrapper.parseWrapperArguments(args); 81 D8Command.Builder builder = D8Command.parse( 82 remainingArgs, CLI_ORIGIN, wrapper.diagnosticsHandler); 83 if (builder.isPrintHelp()) { 84 System.out.println(getUsageMessage()); 85 return; 86 } 87 if (builder.isPrintVersion()) { 88 System.out.println("D8(" + WRAPPER_STRING + ") " + Version.getVersionString()); 89 return; 90 } 91 wrapper.applyWrapperArguments(builder); 92 R8Wrapper.applyCommonCompilerArguments(builder); 93 D8.run(builder.build()); 94 } 95 96 private WrapperDiagnosticsHandler diagnosticsHandler = new WrapperDiagnosticsHandler(); 97 private boolean printInfoDiagnostics = false; 98 private List<Path> noDexArchives = new ArrayList<>(); 99 parseWrapperArguments(String[] args)100 private String[] parseWrapperArguments(String[] args) { 101 List<String> remainingArgs = new ArrayList<>(); 102 for (int i = 0; i < args.length; i++) { 103 String arg = args[i]; 104 switch (arg) { 105 case INFO_FLAG: 106 { 107 printInfoDiagnostics = true; 108 break; 109 } 110 case NO_DEX_FLAG: 111 { 112 if (++i >= args.length) { 113 throw new RuntimeException("Missing argument to " + NO_DEX_FLAG); 114 } 115 Path path = Paths.get(args[i]); 116 if (!Files.isRegularFile(path)) { 117 throw new RuntimeException("Unexpected argument to " + NO_DEX_FLAG + ". Expected an archive"); 118 } 119 noDexArchives.add(path); 120 break; 121 } 122 default: 123 { 124 remainingArgs.add(arg); 125 break; 126 } 127 } 128 } 129 return remainingArgs.toArray(new String[0]); 130 } 131 applyWrapperArguments(D8Command.Builder builder)132 private void applyWrapperArguments(D8Command.Builder builder) { 133 diagnosticsHandler.setWarnOnUnsupportedMainDexList(true); 134 diagnosticsHandler.setPrintInfoDiagnostics(printInfoDiagnostics); 135 for (Path path : noDexArchives) { 136 builder.addProgramResourceProvider( 137 ArchiveProgramResourceProvider.fromArchive( 138 path, 139 ArchiveProgramResourceProvider::includeClassFileEntries)); 140 } 141 } 142 } 143