1418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file 2418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// for details. All rights reserved. Use of this source code is governed by a 3418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// BSD-style license that can be found in the LICENSE file. 4418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpackage com.android.tools.r8; 5418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 6418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.graph.DexItemFactory; 7418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.shaking.ProguardConfiguration; 8418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.shaking.ProguardConfigurationParser; 9f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Rousselimport com.android.tools.r8.shaking.ProguardConfigurationRule; 10418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.shaking.ProguardRuleParserException; 11418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.AndroidApp; 12418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.FileUtils; 13418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.InternalOptions; 14f19dfabc704b3975d66019c0817d65fc48921284Denis Vnukovimport com.android.tools.r8.utils.OutputMode; 15418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.google.common.collect.ImmutableList; 16418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.io.IOException; 17418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Path; 18418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Paths; 19418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.ArrayList; 20418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Collections; 21418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.List; 22418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Optional; 23418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 24418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpublic class R8Command extends BaseCommand { 25418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 26418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public static class Builder extends BaseCommand.Builder<R8Command, Builder> { 27418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 28f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel private final List<Path> mainDexRules = new ArrayList<>(); 29854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse private boolean minimalMainDex = false; 30418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private final List<Path> proguardConfigFiles = new ArrayList<>(); 31418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private Optional<Boolean> treeShaking = Optional.empty(); 32418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private Optional<Boolean> minification = Optional.empty(); 33418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private boolean ignoreMissingClasses = false; 34418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 35418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private Builder() { 36418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager super(CompilationMode.RELEASE); 37418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 38418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 39418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private Builder(AndroidApp app) { 40418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager super(app, CompilationMode.RELEASE); 41418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 42418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 43418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager @Override 44418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager Builder self() { 45418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 46418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 47418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 482ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 492ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Enable/disable tree shaking. This overrides any settings in proguard configuration files. 502ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 51418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public Builder setTreeShaking(boolean useTreeShaking) { 52418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager treeShaking = Optional.of(useTreeShaking); 53418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 54418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 55418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 562ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 572ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Enable/disable minification. This overrides any settings in proguard configuration files. 582ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 59418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public Builder setMinification(boolean useMinification) { 60418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager minification = Optional.of(useMinification); 61418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 62418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 63418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 642ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 652ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Add proguard configuration file resources for automatic main dex list calculation. 662ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 67f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel public Builder addMainDexRules(Path... paths) { 68f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel Collections.addAll(mainDexRules, paths); 69f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel return this; 70f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel } 71f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel 722ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 732ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Add proguard configuration file resources for automatic main dex list calculation. 742ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 75f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel public Builder addMainDexRules(List<Path> paths) { 76f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel mainDexRules.addAll(paths); 77f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel return this; 78f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel } 79f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel 802ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 81854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse * Request minimal main dex generated when main dex rules are used. 82854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse * 83854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse * The main purpose of this is to verify that the main dex rules are sufficient 84854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse * for running on a platform without native multi dex support. 85854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse */ 86854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse public Builder setMinimalMainDex(boolean value) { 87854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse minimalMainDex = value; 88854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse return this; 89854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse } 90854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse /** 912ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Add proguard configuration file resources. 922ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 93418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public Builder addProguardConfigurationFiles(Path... paths) { 94418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager Collections.addAll(proguardConfigFiles, paths); 95418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 96418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 97418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 982ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 992ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Add proguard configuration file resources. 1002ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 101418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public Builder addProguardConfigurationFiles(List<Path> paths) { 102418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager proguardConfigFiles.addAll(paths); 103418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 104418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 105418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 1062ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 1072ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Set a proguard mapping file resource. 1082ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 109418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public Builder setProguardMapFile(Path path) { 110418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager getAppBuilder().setProguardMapFile(path); 111418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 112418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 113418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 1142ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut /** 1152ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut * Set a package distribution file resource. 1162ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut */ 117418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public Builder setPackageDistributionFile(Path path) { 118418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager getAppBuilder().setPackageDistributionFile(path); 119418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 120418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 121418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 122418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager /** 123418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager * Deprecated flag to avoid failing if classes are missing during compilation. 124418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager * 125418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager * <p>TODO: Make compilation safely assume this flag to be true and remove the flag. 126418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager */ 127418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager Builder setIgnoreMissingClasses(boolean ignoreMissingClasses) { 128418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.ignoreMissingClasses = ignoreMissingClasses; 129418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return this; 130418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 131418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 132418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager @Override 133418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public R8Command build() throws CompilationException, IOException { 134418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // If printing versions ignore everything else. 135418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (isPrintHelp() || isPrintVersion()) { 136418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return new R8Command(isPrintHelp(), isPrintVersion()); 137418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 138418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 13978be58456a12d4a51ad5fb0c19c292c01746f97bYohann Roussel validate(); 140418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager DexItemFactory factory = new DexItemFactory(); 141f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel ImmutableList<ProguardConfigurationRule> mainDexKeepRules; 142f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel if (this.mainDexRules.isEmpty()) { 143f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel mainDexKeepRules = ImmutableList.of(); 144f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel } else { 145f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel ProguardConfigurationParser parser = new ProguardConfigurationParser(factory); 146f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel try { 147f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel parser.parse(mainDexRules); 148f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel } catch (ProguardRuleParserException e) { 149f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel throw new CompilationException(e.getMessage(), e.getCause()); 150f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel } 151f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel mainDexKeepRules = parser.getConfig().getRules(); 152f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel } 153418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ProguardConfiguration configuration; 154418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (proguardConfigFiles.isEmpty()) { 155418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager configuration = ProguardConfiguration.defaultConfiguration(factory); 156418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else { 157418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ProguardConfigurationParser parser = new ProguardConfigurationParser(factory); 158418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager try { 159418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager parser.parse(proguardConfigFiles); 160418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } catch (ProguardRuleParserException e) { 161418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throw new CompilationException(e.getMessage(), e.getCause()); 162418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 163418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager configuration = parser.getConfig(); 1648842c41758db478ebc54437f583367750cd18378Alan Leung addProgramFiles(configuration.getInjars(), false); 165418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager addLibraryFiles(configuration.getLibraryjars()); 166418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 167418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 168418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager boolean useTreeShaking = treeShaking.orElse(configuration.isShrinking()); 169418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager boolean useMinification = minification.orElse(configuration.isObfuscating()); 170418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 171418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return new R8Command( 172418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager getAppBuilder().build(), 173418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager getOutputPath(), 174f19dfabc704b3975d66019c0817d65fc48921284Denis Vnukov getOutputMode(), 175f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel mainDexKeepRules, 176854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse minimalMainDex, 177418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager configuration, 178418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager getMode(), 179418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager getMinApiLevel(), 180418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager useTreeShaking, 181418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager useMinification, 182341bbdae4c7b6fe0f5dd95c7158488af6768e7baIan Zerny ignoreMissingClasses); 183418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 184418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 185418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 186418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // Internal state to verify parsing properties not enforced by the builder. 187418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private static class ParseState { 1882ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut 189418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager CompilationMode mode = null; 190418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 191418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 192418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager static final String USAGE_MESSAGE = String.join("\n", ImmutableList.of( 193418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "Usage: r8 [options] <input-files>", 194418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager " where <input-files> are any combination of dex, class, zip, jar, or apk files", 195418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager " and options are:", 196877c186b70e433f6b4b85a6f16d7dbcb1f9c2f0fIan Zerny " --release # Compile without debugging information (default).", 197877c186b70e433f6b4b85a6f16d7dbcb1f9c2f0fIan Zerny " --debug # Compile with debugging information.", 198f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --output <file> # Output result in <file>.", 199341bbdae4c7b6fe0f5dd95c7158488af6768e7baIan Zerny " # <file> must be an existing directory or a zip file.", 200f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --lib <file> # Add <file> as a library resource.", 201877c186b70e433f6b4b85a6f16d7dbcb1f9c2f0fIan Zerny " --min-api # Minimum Android API level compatibility.", 202f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --pg-conf <file> # Proguard configuration <file> (implies tree shaking/minification).", 203f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --pg-map <file> # Proguard map <file>.", 204f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --no-tree-shaking # Force disable tree shaking of unreachable classes.", 205f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --no-minification # Force disable minification of names.", 206f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --multidex-rules <file> # Enable automatic classes partitioning for legacy multidex.", 207f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " # <file> is a Proguard configuration file (with only keep rules).", 208f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --version # Print the version of r8.", 209f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel " --help # Print this message.")); 210418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 211f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules; 212854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse private final boolean minimalMainDex; 213418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private final ProguardConfiguration proguardConfiguration; 214418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private final boolean useTreeShaking; 215418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private final boolean useMinification; 216418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private final boolean ignoreMissingClasses; 217418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 218418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public static Builder builder() { 219418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return new Builder(); 220418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 221418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 222418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // Internal builder to start from an existing AndroidApp. 223418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager static Builder builder(AndroidApp app) { 224418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return new Builder(app); 225418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 226418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 227418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public static Builder parse(String[] args) throws CompilationException, IOException { 228418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager Builder builder = builder(); 229418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager parse(args, builder, new ParseState()); 230418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return builder; 231418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 232418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 233418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private static ParseState parse(String[] args, Builder builder, ParseState state) 234418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throws CompilationException, IOException { 235418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager for (int i = 0; i < args.length; i++) { 236b28d1cc2188a131786ec148631d13f4ce0e59f1dSøren Gjesse String arg = args[i].trim(); 237b28d1cc2188a131786ec148631d13f4ce0e59f1dSøren Gjesse if (arg.length() == 0) { 238b28d1cc2188a131786ec148631d13f4ce0e59f1dSøren Gjesse continue; 239b28d1cc2188a131786ec148631d13f4ce0e59f1dSøren Gjesse } else if (arg.equals("--help")) { 240418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setPrintHelp(true); 241418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--version")) { 242418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setPrintVersion(true); 243418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--debug")) { 244418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (state.mode == CompilationMode.RELEASE) { 245418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throw new CompilationException("Cannot compile in both --debug and --release mode."); 246418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 247418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager state.mode = CompilationMode.DEBUG; 248418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setMode(state.mode); 249418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--release")) { 250418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (state.mode == CompilationMode.DEBUG) { 251418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throw new CompilationException("Cannot compile in both --debug and --release mode."); 252418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 253418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager state.mode = CompilationMode.RELEASE; 254418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setMode(state.mode); 255418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--output")) { 256418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager String outputPath = args[++i]; 257418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (builder.getOutputPath() != null) { 258418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throw new CompilationException( 259418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "Cannot output both to '" 260418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager + builder.getOutputPath().toString() 261418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager + "' and '" 262418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager + outputPath 263418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager + "'"); 264418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 265418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setOutputPath(Paths.get(outputPath)); 266418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--lib")) { 267418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.addLibraryFiles(Paths.get(args[++i])); 268877c186b70e433f6b4b85a6f16d7dbcb1f9c2f0fIan Zerny } else if (arg.equals("--min-api")) { 269418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setMinApiLevel(Integer.valueOf(args[++i])); 270418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--no-tree-shaking")) { 271418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setTreeShaking(false); 272418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--no-minification")) { 273418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setMinification(false); 274f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel } else if (arg.equals("--multidex-rules")) { 275f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel builder.addMainDexRules(Paths.get(args[++i])); 276854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse } else if (arg.equals("--minimal-maindex")) { 277854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse builder.setMinimalMainDex(true); 278418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--pg-conf")) { 279418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.addProguardConfigurationFiles(Paths.get(args[++i])); 280418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--pg-map")) { 281418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setProguardMapFile(Paths.get(args[++i])); 282418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.equals("--ignore-missing-classes")) { 283418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.setIgnoreMissingClasses(true); 284418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else if (arg.startsWith("@")) { 285418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // TODO(zerny): Replace this with pipe reading. 286418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager String argsFile = arg.substring(1); 287418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager try { 288418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager List<String> linesInFile = FileUtils.readTextFile(Paths.get(argsFile)); 289418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager List<String> argsInFile = new ArrayList<>(); 290418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager for (String line : linesInFile) { 291418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager for (String word : line.split("\\s")) { 292418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager String trimmed = word.trim(); 293418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (!trimmed.isEmpty()) { 294418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager argsInFile.add(trimmed); 295418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 296418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 297418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 298418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // TODO(zerny): We need to define what CWD should be for files referenced in an args file. 299418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager state = parse(argsInFile.toArray(new String[argsInFile.size()]), builder, state); 300418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } catch (IOException | CompilationException e) { 301418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throw new CompilationException( 302418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager "Failed to read arguments from file " + argsFile + ": " + e.getMessage()); 303418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 304418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } else { 305418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (arg.startsWith("--")) { 306418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager throw new CompilationException("Unknown option: " + arg); 307418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 308418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager builder.addProgramFiles(Paths.get(arg)); 309418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 310418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 311418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return state; 312418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 313418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 314418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private R8Command( 315418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager AndroidApp inputApp, 316418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager Path outputPath, 317f19dfabc704b3975d66019c0817d65fc48921284Denis Vnukov OutputMode outputMode, 318f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel ImmutableList<ProguardConfigurationRule> mainDexKeepRules, 319854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse boolean minimalMainDex, 320418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ProguardConfiguration proguardConfiguration, 321418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager CompilationMode mode, 322418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager int minApiLevel, 323418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager boolean useTreeShaking, 324418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager boolean useMinification, 325341bbdae4c7b6fe0f5dd95c7158488af6768e7baIan Zerny boolean ignoreMissingClasses) { 326341bbdae4c7b6fe0f5dd95c7158488af6768e7baIan Zerny super(inputApp, outputPath, outputMode, mode, minApiLevel); 327418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager assert proguardConfiguration != null; 328f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel assert mainDexKeepRules != null; 329f19dfabc704b3975d66019c0817d65fc48921284Denis Vnukov assert getOutputMode() == OutputMode.Indexed : "Only regular mode is supported in R8"; 330f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel this.mainDexKeepRules = mainDexKeepRules; 331854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse this.minimalMainDex = minimalMainDex; 332418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.proguardConfiguration = proguardConfiguration; 333418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.useTreeShaking = useTreeShaking; 334418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.useMinification = useMinification; 335418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager this.ignoreMissingClasses = ignoreMissingClasses; 336418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 337418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 338418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager private R8Command(boolean printHelp, boolean printVersion) { 339418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager super(printHelp, printVersion); 340f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel mainDexKeepRules = ImmutableList.of(); 341854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse minimalMainDex = false; 342418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager proguardConfiguration = null; 343418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager useTreeShaking = false; 344418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager useMinification = false; 345418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager ignoreMissingClasses = false; 346418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 347418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 348418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public boolean useTreeShaking() { 349418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return useTreeShaking; 350418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 351418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 352418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager public boolean useMinification() { 353418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return useMinification; 354418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 355418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 3562ecfe14809f915219856ef7387f04f2721fdccfcStephan Herhut @Override 357418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager InternalOptions getInternalOptions() { 358418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager InternalOptions internal = new InternalOptions(proguardConfiguration.getDexItemFactory()); 359fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert !internal.debug; 360418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.debug = getMode() == CompilationMode.DEBUG; 361418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.minApiLevel = getMinApiLevel(); 362fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert !internal.skipMinification; 363418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.skipMinification = !useMinification(); 364fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert internal.useTreeShaking; 365418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.useTreeShaking = useTreeShaking(); 36689379978605ff75677cb5a25cca79728b7d98b14Jinseong Jeon assert !internal.printUsage; 36789379978605ff75677cb5a25cca79728b7d98b14Jinseong Jeon internal.printUsage = proguardConfiguration.isPrintUsage(); 36889379978605ff75677cb5a25cca79728b7d98b14Jinseong Jeon internal.printUsageFile = proguardConfiguration.getPrintUsageFile(); 369fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert !internal.ignoreMissingClasses; 370418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.ignoreMissingClasses = ignoreMissingClasses; 371418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager 372418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager // TODO(zerny): Consider which other proguard options should be given flags. 373fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert internal.packagePrefix.length() == 0; 374418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.packagePrefix = proguardConfiguration.getPackagePrefix(); 375fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert internal.allowAccessModification; 376418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.allowAccessModification = proguardConfiguration.getAllowAccessModification(); 377418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager for (String pattern : proguardConfiguration.getAttributesRemovalPatterns()) { 378418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.attributeRemoval.applyPattern(pattern); 379418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 380418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (proguardConfiguration.isIgnoreWarnings()) { 381418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.ignoreMissingClasses = true; 382418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 383fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert internal.seedsFile == null; 384418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (proguardConfiguration.getSeedFile() != null) { 385418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.seedsFile = proguardConfiguration.getSeedFile(); 386418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 387fb882ae717d46db2b8d3685bd74c4beb6df39801Søren Gjesse assert !internal.verbose; 388418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (proguardConfiguration.isVerbose()) { 389418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.verbose = true; 390418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 391418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager if (!proguardConfiguration.isObfuscating()) { 392418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.skipMinification = true; 393418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 394418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.printSeeds |= proguardConfiguration.getPrintSeeds(); 395418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.printMapping |= proguardConfiguration.isPrintingMapping(); 396418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.printMappingFile = proguardConfiguration.getPrintMappingOutput(); 397418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.classObfuscationDictionary = proguardConfiguration.getClassObfuscationDictionary(); 398418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.obfuscationDictionary = proguardConfiguration.getObfuscationDictionary(); 399f820a57655a3b5712825de91bf9d95b9d88e84bfYohann Roussel internal.mainDexKeepRules = mainDexKeepRules; 400854a7d4617a50c95bdbd7efc266c7ba6335b8d0cSøren Gjesse internal.minimalMainDex = minimalMainDex; 401418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.keepRules = proguardConfiguration.getRules(); 402418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager internal.dontWarnPatterns = proguardConfiguration.getDontWarnPatterns(); 403f19dfabc704b3975d66019c0817d65fc48921284Denis Vnukov internal.outputMode = getOutputMode(); 404522bb04a225c6dd2585fcc60b5babb97bcc267b7Ian Zerny if (internal.debug) { 405522bb04a225c6dd2585fcc60b5babb97bcc267b7Ian Zerny // TODO(zerny): Should we support removeSwitchMaps in debug mode? b/62936642 406522bb04a225c6dd2585fcc60b5babb97bcc267b7Ian Zerny internal.removeSwitchMaps = false; 407522bb04a225c6dd2585fcc60b5babb97bcc267b7Ian Zerny // TODO(zerny): Should we support inlining in debug mode? b/62937285 408522bb04a225c6dd2585fcc60b5babb97bcc267b7Ian Zerny internal.inlineAccessors = false; 409522bb04a225c6dd2585fcc60b5babb97bcc267b7Ian Zerny } 410418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager return internal; 411418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager } 412418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager} 413