Merge commit '6d188632' into dev-release
diff --git a/src/main/java/com/android/tools/r8/D8Logger.java b/src/main/java/com/android/tools/r8/D8Logger.java
deleted file mode 100644
index 6c3fca0..0000000
--- a/src/main/java/com/android/tools/r8/D8Logger.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2017, 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 com.android.tools.r8.compatdx.CompatDx;
-import com.google.common.collect.ImmutableList;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.Arrays;
-
-public final class D8Logger {
-
-  private static final int STATUS_ERROR = 1;
-
-  private static final String USAGE_MESSAGE = String.join("\n", ImmutableList.of(
-      "Usage: java -jar d8logger.jar <compiler-options>",
-      " where <compiler-options> will be",
-      "",
-      " 1. forwarded to the 'd8' or 'compatdx' tool (depending on the presence of the '--dex'",
-      "    option), and also",
-      " 2. appended to the file in the environment variable 'D8LOGGER_OUTPUT'",
-      "",
-      " The options will be appended as a new line with TAB characters between the arguments."));
-
-  public static void main(String[] args) throws IOException {
-    if (args.length == 0) {
-      System.err.println(USAGE_MESSAGE);
-      System.exit(STATUS_ERROR);
-    }
-    String output = System.getenv("D8LOGGER_OUTPUT");
-    if (output == null) {
-      throw new IOException("D8Logger: D8LOGGER_OUTPUT environment variable must be set.");
-    }
-
-    if (output.length() > 0) {
-      String[] absArgs = Arrays.stream(args)
-          .map(s -> s.startsWith("-") ? s : Paths.get(s).toAbsolutePath().toString())
-          .toArray(String[]::new);
-      try (FileWriter fw = new FileWriter(output, true)) {
-        fw.write(String.join("\t", absArgs) + System.lineSeparator());
-      }
-    }
-
-    if (Arrays.stream(args).anyMatch(s -> s.equals("--dex"))) {
-      CompatDx.main(args);
-    } else {
-      D8.main(args);
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/SwissArmyKnife.java b/src/main/java/com/android/tools/r8/SwissArmyKnife.java
index 6bf5af9..f079277 100644
--- a/src/main/java/com/android/tools/r8/SwissArmyKnife.java
+++ b/src/main/java/com/android/tools/r8/SwissArmyKnife.java
@@ -4,9 +4,7 @@
 package com.android.tools.r8;
 
 import com.android.tools.r8.bisect.Bisect;
-import com.android.tools.r8.compatdx.CompatDx;
 import com.android.tools.r8.compatproguard.CompatProguard;
-import com.android.tools.r8.dexfilemerger.DexFileMerger;
 import com.android.tools.r8.dexsplitter.DexSplitter;
 import com.android.tools.r8.relocator.RelocatorCommandLine;
 import java.util.Arrays;
@@ -32,21 +30,12 @@
       case "bisect":
         Bisect.main(shift(args));
         break;
-      case "compatdx":
-        CompatDx.main(shift(args));
-        break;
       case "compatproguard":
         CompatProguard.main(shift(args));
         break;
       case "d8":
         D8.main(shift(args));
         break;
-      case "d8logger":
-        D8Logger.main(shift(args));
-        break;
-      case "dexfilemerger":
-        DexFileMerger.main(shift(args));
-        break;
       case "dexsegments":
         DexSegments.main(shift(args));
         break;
diff --git a/src/main/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilder.java b/src/main/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilder.java
deleted file mode 100644
index 69cbddb..0000000
--- a/src/main/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilder.java
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright (c) 2017, 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.compatdexbuilder;
-
-import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.CompatDxHelper;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.D8;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.origin.ArchiveEntryOrigin;
-import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.ThreadUtils;
-import com.google.common.io.ByteStreams;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.zip.CRC32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipOutputStream;
-
-public class CompatDexBuilder {
-
-  private static class DexConsumer extends DexIndexedConsumer.ForwardingConsumer {
-
-    byte[] bytes;
-
-    public DexConsumer() {
-      super(null);
-    }
-
-    @Override
-    public synchronized void accept(
-        int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) {
-      super.accept(fileIndex, data, descriptors, handler);
-      assert bytes == null;
-      bytes = data.copyByteData();
-    }
-
-    byte[] getBytes() {
-      return bytes;
-    }
-  }
-
-  private String input = null;
-  private String output = null;
-  private int numberOfThreads = 8;
-  private boolean noLocals = false;
-  private boolean backportStatics = false;
-
-  public static void main(String[] args)
-      throws IOException, InterruptedException, ExecutionException {
-    new CompatDexBuilder().run(args);
-  }
-
-  private void run(String[] args) throws IOException, InterruptedException, ExecutionException {
-    List<String> flags = new ArrayList<>();
-
-    for (String arg : args) {
-      if (arg.startsWith("@")) {
-        flags.addAll(Files.readAllLines(Paths.get(arg.substring(1))));
-      } else {
-        flags.add(arg);
-      }
-    }
-
-    for (int i = 0; i < flags.size(); i++) {
-      String flag = flags.get(i);
-      if (flag.startsWith("--positions=")) {
-        String positionsValue = flag.substring("--positions=".length());
-        if (positionsValue.startsWith("throwing") || positionsValue.startsWith("important")) {
-          noLocals = true;
-        }
-        continue;
-      }
-      if (flag.startsWith("--num-threads=")) {
-        numberOfThreads = Integer.parseInt(flag.substring("--num-threads=".length()));
-        continue;
-      }
-      switch (flag) {
-        case "--input_jar":
-          input = flags.get(++i);
-          break;
-        case "--output_zip":
-          output = flags.get(++i);
-          break;
-        case "--verify-dex-file":
-        case "--no-verify-dex-file":
-        case "--show_flags":
-        case "--no-optimize":
-        case "--nooptimize":
-        case "--help":
-          // Ignore
-          break;
-        case "--nolocals":
-          noLocals = true;
-          break;
-        case "--desugar-backport-statics":
-          backportStatics = true;
-          break;
-        default:
-          System.err.println("Unsupported option: " + flag);
-          System.exit(1);
-      }
-    }
-
-    if (input == null) {
-      System.err.println("No input jar specified");
-      System.exit(1);
-    }
-
-    if (output == null) {
-      System.err.println("No output jar specified");
-      System.exit(1);
-    }
-
-    ExecutorService executor = ThreadUtils.getExecutorService(numberOfThreads);
-    try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(Paths.get(output)))) {
-
-      List<ZipEntry> toDex = new ArrayList<>();
-
-      try (ZipFile zipFile = new ZipFile(input, StandardCharsets.UTF_8)) {
-        final Enumeration<? extends ZipEntry> entries = zipFile.entries();
-        while (entries.hasMoreElements()) {
-          ZipEntry entry = entries.nextElement();
-          if (!entry.getName().endsWith(".class")) {
-            try (InputStream stream = zipFile.getInputStream(entry)) {
-              addEntry(entry.getName(), stream, out);
-            }
-          } else {
-            toDex.add(entry);
-          }
-        }
-
-        List<Future<DexConsumer>> futures = new ArrayList<>(toDex.size());
-        for (int i = 0; i < toDex.size(); i++) {
-          ZipEntry classEntry = toDex.get(i);
-          futures.add(executor.submit(() -> dexEntry(zipFile, classEntry, executor)));
-        }
-        for (int i = 0; i < futures.size(); i++) {
-          ZipEntry entry = toDex.get(i);
-          DexConsumer consumer = futures.get(i).get();
-          addEntry(entry.getName() + ".dex", consumer.getBytes(), out);
-        }
-      }
-    } finally {
-      executor.shutdown();
-    }
-  }
-
-  private DexConsumer dexEntry(ZipFile zipFile, ZipEntry classEntry, ExecutorService executor)
-      throws IOException, CompilationFailedException {
-    DexConsumer consumer = new DexConsumer();
-    D8Command.Builder builder = D8Command.builder();
-    CompatDxHelper.ignoreDexInArchive(builder);
-    builder
-        .setProgramConsumer(consumer)
-        .setMode(noLocals ? CompilationMode.RELEASE : CompilationMode.DEBUG)
-        .setMinApiLevel(AndroidApiLevel.H_MR2.getLevel())
-        .setDisableDesugaring(true);
-    if (backportStatics) {
-      CompatDxHelper.enableDesugarBackportStatics(builder);
-    }
-    try (InputStream stream = zipFile.getInputStream(classEntry)) {
-      builder.addClassProgramData(
-          ByteStreams.toByteArray(stream),
-          new ArchiveEntryOrigin(
-              classEntry.getName(), new PathOrigin(Paths.get(zipFile.getName()))));
-    }
-    D8.run(builder.build(), executor);
-    return consumer;
-  }
-
-  private static void addEntry(String name, InputStream stream, ZipOutputStream out)
-      throws IOException {
-    addEntry(name, ByteStreams.toByteArray(stream), out);
-  }
-
-  private static void addEntry(String name, byte[] bytes, ZipOutputStream out) throws IOException {
-    ZipEntry zipEntry = new ZipEntry(name);
-    CRC32 crc32 = new CRC32();
-    crc32.update(bytes);
-    zipEntry.setSize(bytes.length);
-    zipEntry.setMethod(ZipEntry.STORED);
-    zipEntry.setCrc(crc32.getValue());
-    zipEntry.setTime(0);
-    out.putNextEntry(zipEntry);
-    out.write(bytes);
-    out.closeEntry();
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
deleted file mode 100644
index e98d5c0..0000000
--- a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
+++ /dev/null
@@ -1,626 +0,0 @@
-// Copyright (c) 2017, 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.compatdx;
-
-import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.CompatDxHelper;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.ProgramConsumer;
-import com.android.tools.r8.Version;
-import com.android.tools.r8.compatdx.CompatDx.DxCompatOptions.DxUsageMessage;
-import com.android.tools.r8.compatdx.CompatDx.DxCompatOptions.PositionInfo;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.logging.Log;
-import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
-import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.ThreadUtils;
-import com.android.tools.r8.utils.ZipUtils;
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.ByteStreams;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import joptsimple.OptionParser;
-import joptsimple.OptionSet;
-import joptsimple.OptionSpec;
-
-/**
- * Dx compatibility interface for d8.
- *
- * This should become a mostly drop-in replacement for uses of the DX dexer (eg, dx --dex ...).
- */
-public class CompatDx {
-
-  private static final String USAGE_HEADER = "Usage: compatdx [options] <input files>";
-
-  /**
-   * Compatibility options parsing for the DX --dex sub-command.
-   */
-  public static class DxCompatOptions {
-    // Final values after parsing.
-    // Note: These are ordered by their occurrence in "dx --help"
-    public final boolean help;
-    public final boolean version;
-    public final boolean debug;
-    public final boolean verbose;
-    public final PositionInfo positions;
-    public final boolean noLocals;
-    public final boolean noOptimize;
-    public final boolean statistics;
-    public final String optimizeList;
-    public final String noOptimizeList;
-    public final boolean noStrict;
-    public final boolean keepClasses;
-    public final String output;
-    public final String dumpTo;
-    public final int dumpWidth;
-    public final String dumpMethod;
-    public final boolean verboseDump;
-    public final boolean dump;
-    public final boolean noFiles;
-    public final boolean coreLibrary;
-    public final int numThreads;
-    public final boolean incremental;
-    public final boolean forceJumbo;
-    public final boolean noWarning;
-    public final boolean multiDex;
-    public final String mainDexList;
-    public final boolean minimalMainDex;
-    public final int minApiLevel;
-    public final boolean backportStatics;
-    public final String inputList;
-    public final ImmutableList<String> inputs;
-    // Undocumented option
-    public final int maxIndexNumber;
-
-    private static final String FILE_ARG = "file";
-    private static final String NUM_ARG = "number";
-    private static final String METHOD_ARG = "method";
-
-    public enum PositionInfo {
-      NONE, IMPORTANT, LINES, THROWING
-    }
-
-    // Exception thrown on invalid dx compat usage.
-    public static class DxUsageMessage extends Exception {
-      public final String message;
-
-      DxUsageMessage(String message) {
-        this.message = message;
-      }
-
-      void printHelpOn(PrintStream sink) throws IOException {
-        sink.println(message);
-      }
-    }
-
-    // Parsing specification.
-    private static class Spec {
-      final OptionParser parser;
-
-      // Note: These are ordered by their occurrence in "dx --help"
-      final OptionSpec<Void> debug;
-      final OptionSpec<Void> verbose;
-      final OptionSpec<String> positions;
-      final OptionSpec<Void> noLocals;
-      final OptionSpec<Void> noOptimize;
-      final OptionSpec<Void> statistics;
-      final OptionSpec<String> optimizeList;
-      final OptionSpec<String> noOptimizeList;
-      final OptionSpec<Void> noStrict;
-      final OptionSpec<Void> keepClasses;
-      final OptionSpec<String> output;
-      final OptionSpec<String> dumpTo;
-      final OptionSpec<Integer> dumpWidth;
-      final OptionSpec<String> dumpMethod;
-      final OptionSpec<Void> dump;
-      final OptionSpec<Void> verboseDump;
-      final OptionSpec<Void> noFiles;
-      final OptionSpec<Void> coreLibrary;
-      final OptionSpec<Integer> numThreads;
-      final OptionSpec<Void> incremental;
-      final OptionSpec<Void> forceJumbo;
-      final OptionSpec<Void> noWarning;
-      final OptionSpec<Void> multiDex;
-      final OptionSpec<String> mainDexList;
-      final OptionSpec<Void> minimalMainDex;
-      final OptionSpec<Integer> minApiLevel;
-      final OptionSpec<Void> backportStatics;
-      final OptionSpec<String> inputList;
-      final OptionSpec<String> inputs;
-      final OptionSpec<Void> version;
-      final OptionSpec<Void> help;
-      final OptionSpec<Integer> maxIndexNumber;
-
-      Spec() {
-        parser = new OptionParser();
-        parser.accepts("dex");
-        debug = parser.accepts("debug", "Print debug information");
-        verbose = parser.accepts("verbose", "Print verbose information");
-        positions = parser
-            .accepts("positions",
-                "What source-position information to keep. One of: none, lines, important")
-            .withOptionalArg()
-            .describedAs("keep")
-            .defaultsTo("lines");
-        noLocals = parser.accepts("no-locals", "Don't keep local variable information");
-        statistics = parser.accepts("statistics", "Print statistics information");
-        noOptimize = parser.accepts("no-optimize", "Don't optimize");
-        optimizeList = parser
-            .accepts("optimize-list", "File listing methods to optimize")
-            .withRequiredArg()
-            .describedAs(FILE_ARG);
-        noOptimizeList = parser
-            .accepts("no-optimize-list", "File listing methods not to optimize")
-            .withRequiredArg()
-            .describedAs(FILE_ARG);
-        noStrict = parser.accepts("no-strict", "Disable strict file/class name checks");
-        keepClasses = parser.accepts("keep-classes", "Keep input class files in in output jar");
-        output = parser
-            .accepts("output", "Output file or directory")
-            .withRequiredArg()
-            .describedAs(FILE_ARG);
-        dumpTo = parser
-            .accepts("dump-to", "File to dump information to")
-            .withRequiredArg()
-            .describedAs(FILE_ARG);
-        dumpWidth = parser
-            .accepts("dump-width", "Max width for columns in dump output")
-            .withRequiredArg()
-            .ofType(Integer.class)
-            .defaultsTo(0)
-            .describedAs(NUM_ARG);
-        dumpMethod = parser
-            .accepts("dump-method", "Method to dump information for")
-            .withRequiredArg()
-            .describedAs(METHOD_ARG);
-        dump = parser.accepts("dump", "Dump information");
-        verboseDump = parser.accepts("verbose-dump", "Dump verbose information");
-        noFiles = parser.accepts("no-files", "Don't fail if given no files");
-        coreLibrary = parser.accepts("core-library", "Construct a core library");
-        numThreads = parser
-            .accepts("num-threads", "Number of threads to run with")
-            .withRequiredArg()
-            .ofType(Integer.class)
-            .defaultsTo(1)
-            .describedAs(NUM_ARG);
-        incremental = parser.accepts("incremental", "Merge result with the output if it exists");
-        forceJumbo = parser.accepts("force-jumbo", "Force use of string-jumbo instructions");
-        noWarning = parser.accepts("no-warning", "Suppress warnings");
-        maxIndexNumber = parser.accepts("set-max-idx-number",
-            "Undocumented: Set maximal index number to use in a dex file.")
-            .withRequiredArg()
-            .ofType(Integer.class)
-            .defaultsTo(0)
-            .describedAs("Maximum index");
-        minimalMainDex = parser.accepts("minimal-main-dex", "Produce smallest possible main dex");
-        mainDexList = parser
-            .accepts("main-dex-list", "File listing classes that must be in the main dex file")
-            .withRequiredArg()
-            .describedAs(FILE_ARG);
-        multiDex =
-            parser
-                .accepts("multi-dex", "Allow generation of multi-dex")
-                .requiredIf(minimalMainDex, mainDexList, maxIndexNumber);
-        minApiLevel = parser
-            .accepts("min-sdk-version", "Minimum Android API level compatibility.")
-            .withRequiredArg().ofType(Integer.class);
-        backportStatics =
-            parser.accepts("desugar-backport-statics", "Backport additional Java 8 APIs");
-        inputList = parser
-            .accepts("input-list", "File listing input files")
-            .withRequiredArg()
-            .describedAs(FILE_ARG);
-        inputs = parser.nonOptions("Input files");
-        version = parser.accepts("version", "Print the version of this tool").forHelp();
-        help = parser.accepts("help", "Print this message").forHelp();
-      }
-    }
-
-    private DxCompatOptions(OptionSet options, Spec spec) {
-      help = options.has(spec.help);
-      version = options.has(spec.version);
-      debug = options.has(spec.debug);
-      verbose = options.has(spec.verbose);
-      if (options.has(spec.positions)) {
-        switch (options.valueOf(spec.positions)) {
-          case "none":
-            positions = PositionInfo.NONE;
-            break;
-          case "important":
-            positions = PositionInfo.IMPORTANT;
-            break;
-          case "lines":
-            positions = PositionInfo.LINES;
-            break;
-          case "throwing":
-            positions = PositionInfo.THROWING;
-            break;
-          default:
-            positions = PositionInfo.IMPORTANT;
-            break;
-        }
-      } else {
-        positions = PositionInfo.LINES;
-      }
-      noLocals = options.has(spec.noLocals);
-      noOptimize = options.has(spec.noOptimize);
-      statistics = options.has(spec.statistics);
-      optimizeList = options.valueOf(spec.optimizeList);
-      noOptimizeList = options.valueOf(spec.noOptimizeList);
-      noStrict = options.has(spec.noStrict);
-      keepClasses = options.has(spec.keepClasses);
-      output = options.valueOf(spec.output);
-      dumpTo = options.valueOf(spec.dumpTo);
-      dumpWidth = options.valueOf(spec.dumpWidth);
-      dumpMethod = options.valueOf(spec.dumpMethod);
-      dump = options.has(spec.dump);
-      verboseDump = options.has(spec.verboseDump);
-      noFiles = options.has(spec.noFiles);
-      coreLibrary = options.has(spec.coreLibrary);
-      numThreads = lastIntOf(options.valuesOf(spec.numThreads));
-      incremental = options.has(spec.incremental);
-      forceJumbo = options.has(spec.forceJumbo);
-      noWarning = options.has(spec.noWarning);
-      multiDex = options.has(spec.multiDex);
-      mainDexList = options.valueOf(spec.mainDexList);
-      minimalMainDex = options.has(spec.minimalMainDex);
-      if (options.has(spec.minApiLevel)) {
-        List<Integer> allMinApiLevels = options.valuesOf(spec.minApiLevel);
-        minApiLevel = allMinApiLevels.get(allMinApiLevels.size() - 1);
-      } else {
-        minApiLevel = AndroidApiLevel.getDefault().getLevel();
-      }
-      backportStatics = options.has(spec.backportStatics);
-      inputList = options.valueOf(spec.inputList);
-      inputs = ImmutableList.copyOf(options.valuesOf(spec.inputs));
-      maxIndexNumber = options.valueOf(spec.maxIndexNumber);
-    }
-
-    public static DxCompatOptions parse(String[] args) {
-      Spec spec = new Spec();
-      return new DxCompatOptions(spec.parser.parse(args), spec);
-    }
-
-    private static int lastIntOf(List<Integer> values) {
-      assert !values.isEmpty();
-      return values.get(values.size() - 1);
-    }
-  }
-
-  public static void main(String[] args) throws IOException {
-    try {
-      run(args);
-    } catch (DxUsageMessage e) {
-      System.err.println(USAGE_HEADER);
-      e.printHelpOn(System.err);
-      System.exit(1);
-    } catch (CompilationFailedException e) {
-      System.exit(1);
-    }
-  }
-
-  private static void run(String[] args)
-      throws DxUsageMessage, IOException, CompilationFailedException {
-    DxCompatOptions dexArgs = DxCompatOptions.parse(args);
-    if (dexArgs.help) {
-      printHelpOn(System.out);
-      return;
-    }
-    if (dexArgs.version) {
-      System.out.println("CompatDx " + Version.getVersionString());
-      return;
-    }
-    CompilationMode mode = CompilationMode.RELEASE;
-    Path output = null;
-    List<Path> inputs = new ArrayList<>();
-    boolean singleDexFile = !dexArgs.multiDex;
-    Path mainDexList = null;
-    int numberOfThreads = 1;
-
-    for (String path : dexArgs.inputs) {
-      processPath(new File(path), inputs);
-    }
-    if (inputs.isEmpty()) {
-      if (dexArgs.noFiles) {
-        return;
-      }
-      throw new DxUsageMessage("No input files specified");
-    }
-
-    if (!Log.ENABLED && dexArgs.debug) {
-      System.out.println("Warning: logging is not enabled for this build.");
-    }
-
-    if (dexArgs.dump && dexArgs.verbose) {
-      System.out.println("Warning: dump is not supported");
-    }
-
-    if (dexArgs.verboseDump) {
-      throw new Unimplemented("verbose dump file not yet supported");
-    }
-
-    if (dexArgs.dumpMethod != null) {
-      throw new Unimplemented("method-dump not yet supported");
-    }
-
-    if (dexArgs.output != null) {
-      output = Paths.get(dexArgs.output);
-      if (FileUtils.isDexFile(output)) {
-        if (!singleDexFile) {
-          throw new DxUsageMessage("Cannot output to a single dex-file when running with multidex");
-        }
-      } else if (!FileUtils.isArchive(output)
-          && (!output.toFile().exists() || !output.toFile().isDirectory())) {
-        throw new DxUsageMessage("Unsupported output file or output directory does not exist. "
-            + "Output must be a directory or a file of type dex, apk, jar or zip.");
-      }
-    }
-
-    if (dexArgs.dumpTo != null && dexArgs.verbose) {
-      System.out.println("dump-to file not yet supported");
-    }
-
-    if (dexArgs.positions == PositionInfo.NONE && dexArgs.verbose) {
-      System.out.println("Warning: no support for positions none.");
-    }
-
-    if (dexArgs.positions == PositionInfo.LINES && !dexArgs.noLocals) {
-      mode = CompilationMode.DEBUG;
-    }
-
-    if (dexArgs.incremental) {
-      throw new Unimplemented("incremental merge not supported yet");
-    }
-
-    if (dexArgs.forceJumbo && dexArgs.verbose) {
-      System.out.println(
-          "Warning: no support for forcing jumbo-strings.\n"
-              + "Strings will only use jumbo-string indexing if necessary.\n"
-              + "Make sure that any dex merger subsequently used "
-              + "supports correct handling of jumbo-strings (eg, D8/R8 does).");
-    }
-
-    if (dexArgs.noOptimize && dexArgs.verbose) {
-      System.out.println("Warning: no support for not optimizing");
-    }
-
-    if (dexArgs.optimizeList != null) {
-      throw new Unimplemented("no support for optimize-method list");
-    }
-
-    if (dexArgs.noOptimizeList != null) {
-      throw new Unimplemented("no support for dont-optimize-method list");
-    }
-
-    if (dexArgs.statistics && dexArgs.verbose) {
-      System.out.println("Warning: no support for printing statistics");
-    }
-
-    if (dexArgs.numThreads > 1) {
-      numberOfThreads = dexArgs.numThreads;
-    }
-
-    if (dexArgs.mainDexList != null) {
-      mainDexList = Paths.get(dexArgs.mainDexList);
-    }
-
-    if (dexArgs.noStrict) {
-      if (dexArgs.verbose) {
-        System.out.println("Warning: conservative main-dex list not yet supported");
-      }
-    } else {
-      if (dexArgs.verbose) {
-        System.out.println("Warning: strict name checking not yet supported");
-      }
-    }
-
-    if (dexArgs.minimalMainDex && dexArgs.verbose) {
-      System.out.println("Warning: minimal main-dex support is not yet supported");
-    }
-
-    if (dexArgs.maxIndexNumber != 0 && dexArgs.verbose) {
-      System.out.println("Warning: internal maximum-index setting is not supported");
-    }
-
-    if (numberOfThreads < 1) {
-      throw new DxUsageMessage("Invalid numThreads value of " + numberOfThreads);
-    }
-    ExecutorService executor = ThreadUtils.getExecutorService(numberOfThreads);
-
-    try {
-      D8Command.Builder builder = D8Command.builder();
-      CompatDxHelper.ignoreDexInArchive(builder);
-      builder
-          .addProgramFiles(inputs)
-          .setProgramConsumer(createConsumer(inputs, output, singleDexFile, dexArgs.keepClasses))
-          .setMode(mode)
-          .setDisableDesugaring(true) // DX does not desugar.
-          .setMinApiLevel(dexArgs.minApiLevel);
-      if (mainDexList != null) {
-        builder.addMainDexListFiles(mainDexList);
-      }
-      if (dexArgs.backportStatics) {
-        CompatDxHelper.enableDesugarBackportStatics(builder);
-      }
-      CompatDxHelper.run(builder.build(), dexArgs.minimalMainDex);
-    } finally {
-      executor.shutdown();
-    }
-  }
-
-  private static ProgramConsumer createConsumer(
-      List<Path> inputs, Path output, boolean singleDexFile, boolean keepClasses)
-      throws DxUsageMessage {
-    if (output == null) {
-      return DexIndexedConsumer.emptyConsumer();
-    }
-    if (singleDexFile) {
-      return new SingleDexFileConsumer(
-          FileUtils.isDexFile(output)
-              ? new NamedDexFileConsumer(output)
-              : createDexConsumer(output, inputs, keepClasses));
-    }
-    return createDexConsumer(output, inputs, keepClasses);
-  }
-
-  private static DexIndexedConsumer createDexConsumer(
-      Path output, List<Path> inputs, boolean keepClasses)
-      throws DxUsageMessage {
-    if (keepClasses) {
-      if (!FileUtils.isArchive(output)) {
-        throw new DxCompatOptions.DxUsageMessage(
-            "Output must be an archive when --keep-classes is set.");
-      }
-      return new DexKeepClassesConsumer(output, inputs);
-    }
-    return FileUtils.isArchive(output)
-        ? new DexIndexedConsumer.ArchiveConsumer(output)
-        : new DexIndexedConsumer.DirectoryConsumer(output);
-  }
-
-  private static class SingleDexFileConsumer extends DexIndexedConsumer.ForwardingConsumer {
-
-    private byte[] bytes = null;
-
-    public SingleDexFileConsumer(DexIndexedConsumer consumer) {
-      super(consumer);
-    }
-
-    @Override
-    public void accept(
-        int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) {
-      if (fileIndex > 0) {
-        throw new CompilationError(
-            "Compilation result could not fit into a single dex file. "
-                + "Reduce the input-program size or run with --multi-dex enabled");
-      }
-      assert bytes == null;
-      // Store a copy of the bytes as we may not assume the backing is valid after accept returns.
-      bytes = data.copyByteData();
-    }
-
-    @Override
-    public void finished(DiagnosticsHandler handler) {
-      if (bytes != null) {
-        super.accept(0, ByteDataView.of(bytes), null, handler);
-      }
-      super.finished(handler);
-    }
-  }
-
-  private static class NamedDexFileConsumer extends DexIndexedConsumer.ForwardingConsumer {
-    private final Path output;
-
-    public NamedDexFileConsumer(Path output) {
-      super(null);
-      this.output = output;
-    }
-
-    @Override
-    public void accept(
-        int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) {
-      StandardOpenOption[] options = {
-        StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING
-      };
-      try (OutputStream stream = new BufferedOutputStream(Files.newOutputStream(output, options))) {
-        stream.write(data.getBuffer(), data.getOffset(), data.getLength());
-      } catch (IOException e) {
-        handler.error(new ExceptionDiagnostic(e, new PathOrigin(output)));
-      }
-    }
-  }
-
-  private static class DexKeepClassesConsumer extends DexIndexedConsumer.ArchiveConsumer {
-
-    private final List<Path> inputs;
-
-    public DexKeepClassesConsumer(Path archive, List<Path> inputs) {
-      super(archive);
-      this.inputs = inputs;
-    }
-
-    @Override
-    public void finished(DiagnosticsHandler handler) {
-      try {
-        writeZipWithClasses(handler);
-      } catch (IOException e) {
-        handler.error(new ExceptionDiagnostic(e, getOrigin()));
-      }
-      super.finished(handler);
-    }
-
-    private void writeZipWithClasses(DiagnosticsHandler handler) throws IOException {
-      // For each input archive file, add all class files within.
-      for (Path input : inputs) {
-        if (FileUtils.isArchive(input)) {
-          try (ZipFile zipFile = FileUtils.createZipFile(input.toFile(), StandardCharsets.UTF_8)) {
-            final Enumeration<? extends ZipEntry> entries = zipFile.entries();
-            while (entries.hasMoreElements()) {
-              ZipEntry entry = entries.nextElement();
-              if (ZipUtils.isClassFile(entry.getName())) {
-                try (InputStream entryStream = zipFile.getInputStream(entry)) {
-                  byte[] bytes = ByteStreams.toByteArray(entryStream);
-                  outputBuilder.addFile(entry.getName(), ByteDataView.of(bytes), handler);
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  static void printHelpOn(PrintStream sink) throws IOException {
-    sink.println(USAGE_HEADER);
-    new DxCompatOptions.Spec().parser.printHelpOn(sink);
-  }
-
-  private static void processPath(File file, List<Path> files) {
-    if (!file.exists()) {
-      throw new CompilationError("File does not exist: " + file);
-    }
-    if (file.isDirectory()) {
-      processDirectory(file, files);
-      return;
-    }
-    Path path = file.toPath();
-    if (FileUtils.isZipFile(path) || FileUtils.isJarFile(path) || FileUtils.isClassFile(path)) {
-      files.add(path);
-      return;
-    }
-    if (FileUtils.isApkFile(path)) {
-      throw new Unimplemented("apk files not yet supported");
-    }
-  }
-
-  private static void processDirectory(File directory, List<Path> files) {
-    assert directory.exists();
-    for (File file : directory.listFiles()) {
-      processPath(file, files);
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/dexfilemerger/DexFileMerger.java b/src/main/java/com/android/tools/r8/dexfilemerger/DexFileMerger.java
deleted file mode 100644
index 7cbf816..0000000
--- a/src/main/java/com/android/tools/r8/dexfilemerger/DexFileMerger.java
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright (c) 2017, 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.dexfilemerger;
-
-import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.DexFileMergerHelper;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.utils.ExceptionDiagnostic;
-import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.OptionsParsing;
-import com.android.tools.r8.utils.OptionsParsing.ParseContext;
-import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.ZipUtils;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-
-public class DexFileMerger {
-  /** File name prefix of a {@code .dex} file automatically loaded in an archive. */
-  private static final String DEX_PREFIX = "classes";
-
-  private static final String DEFAULT_OUTPUT_ARCHIVE_FILENAME = "classes.dex.jar";
-
-  private static final boolean PRINT_ARGS = false;
-
-  /** Strategies for outputting multiple {@code .dex} files supported by {@link DexFileMerger}. */
-  private enum MultidexStrategy {
-    /** Create exactly one .dex file. The operation will fail if .dex limits are exceeded. */
-    OFF,
-    /** Create exactly one &lt;prefixN&gt;.dex file with N taken from the (single) input archive. */
-    GIVEN_SHARD,
-    /**
-     * Assemble .dex files similar to {@link com.android.dx.command.dexer.Main dx}, with all but one
-     * file as large as possible.
-     */
-    MINIMAL,
-    /**
-     * Allow some leeway and sometimes use additional .dex files to speed up processing. This option
-     * exists to give flexibility but it often (or always) may be identical to {@link #MINIMAL}.
-     */
-    BEST_EFFORT;
-
-    public boolean isMultidexAllowed() {
-      switch (this) {
-        case OFF:
-        case GIVEN_SHARD:
-          return false;
-        case MINIMAL:
-        case BEST_EFFORT:
-          return true;
-      }
-      throw new AssertionError("Unknown: " + this);
-    }
-
-    public static MultidexStrategy parse(String value) {
-      switch (value) {
-        case "off":
-          return OFF;
-        case "given_shard":
-          return GIVEN_SHARD;
-        case "minimal":
-          return MINIMAL;
-        case "best_effort":
-          return BEST_EFFORT;
-        default:
-          throw new RuntimeException(
-              "Multidex argument must be either 'off', 'given_shard', 'minimal' or 'best_effort'.");
-      }
-    }
-  }
-
-  private static class Options {
-    List<String> inputArchives = new ArrayList<>();
-    String outputArchive = DEFAULT_OUTPUT_ARCHIVE_FILENAME;
-    MultidexStrategy multidexMode = MultidexStrategy.OFF;
-    String mainDexListFile = null;
-    boolean minimalMainDex = false;
-    boolean verbose = false;
-    String dexPrefix = DEX_PREFIX;
-  }
-
-
-  private static Options parseArguments(String[] args) throws IOException {
-    // We may have a single argument which is a parameter file path, prefixed with '@'.
-    if (args.length == 1 && args[0].startsWith("@")) {
-      // TODO(tamaskenez) Implement more sophisticated processing
-      // which is aligned with Blaze's
-      // com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor
-      Path paramsFile = Paths.get(args[0].substring(1));
-      List<String> argsList = new ArrayList<>();
-      for (String s : Files.readAllLines(paramsFile)) {
-        s = s.trim();
-        if (s.isEmpty()) {
-          continue;
-        }
-        // Trim optional enclosing single quotes. Unescaping omitted for now.
-        if (s.length() >= 2 && s.startsWith("'") && s.endsWith("'")) {
-          s = s.substring(1, s.length() - 1);
-        }
-        argsList.add(s);
-      }
-      args = argsList.toArray(new String[argsList.size()]);
-    }
-
-    Options options = new Options();
-    ParseContext context = new ParseContext(args);
-    List<String> strings;
-    String string;
-    Boolean b;
-    while (context.head() != null) {
-      if (context.head().startsWith("@")) {
-        throw new RuntimeException("A params file must be the only argument: " + context.head());
-      }
-      strings = OptionsParsing.tryParseMulti(context, "--input");
-      if (strings != null) {
-        options.inputArchives.addAll(strings);
-        continue;
-      }
-      string = OptionsParsing.tryParseSingle(context, "--output", "-o");
-      if (string != null) {
-        options.outputArchive = string;
-        continue;
-      }
-      string = OptionsParsing.tryParseSingle(context, "--multidex", null);
-      if (string != null) {
-        options.multidexMode = MultidexStrategy.parse(string);
-        continue;
-      }
-      string = OptionsParsing.tryParseSingle(context, "--main-dex-list", null);
-      if (string != null) {
-        options.mainDexListFile = string;
-        continue;
-      }
-      b = OptionsParsing.tryParseBoolean(context, "--minimal-main-dex");
-      if (b != null) {
-        options.minimalMainDex = b;
-        continue;
-      }
-      b = OptionsParsing.tryParseBoolean(context, "--verbose");
-      if (b != null) {
-        options.verbose = b;
-        continue;
-      }
-      string = OptionsParsing.tryParseSingle(context, "--max-bytes-wasted-per-file", null);
-      if (string != null) {
-        System.err.println("Warning: '--max-bytes-wasted-per-file' is ignored.");
-        continue;
-      }
-      string = OptionsParsing.tryParseSingle(context, "--set-max-idx-number", null);
-      if (string != null) {
-        System.err.println("Warning: The '--set-max-idx-number' option is ignored.");
-        continue;
-      }
-      b = OptionsParsing.tryParseBoolean(context, "--forceJumbo");
-      if (b != null) {
-        System.err.println(
-            "Warning: '--forceJumbo' can be safely omitted. Strings will only use "
-                + "jumbo-string indexing if necessary.");
-        continue;
-      }
-      string = OptionsParsing.tryParseSingle(context, "--dex_prefix", null);
-      if (string != null) {
-        options.dexPrefix = string;
-        continue;
-      }
-      throw new RuntimeException(String.format("Unknown options: '%s'.", context.head()));
-    }
-    return options;
-  }
-
-  /**
-   * Implements a DexIndexedConsumer writing into a ZipStream with support for custom dex file name
-   * prefix, reindexing a single dex output file to a nonzero index and reporting if any data has
-   * been written.
-   */
-  private static class ArchiveConsumer implements DexIndexedConsumer {
-    private final Path path;
-    private final String prefix;
-    private final Integer singleFixedFileIndex;
-    private final Origin origin;
-    private ZipOutputStream stream = null;
-
-    private int highestIndexWritten = -1;
-    private final Map<Integer, Runnable> writers = new TreeMap<>();
-    private boolean hasWrittenSomething = false;
-
-    /** If singleFixedFileIndex is not null then we expect only one output dex file */
-    private ArchiveConsumer(Path path, String prefix, Integer singleFixedFileIndex) {
-      this.path = path;
-      this.prefix = prefix;
-      this.singleFixedFileIndex = singleFixedFileIndex;
-      this.origin = new PathOrigin(path);
-    }
-
-    private boolean hasWrittenSomething() {
-      return hasWrittenSomething;
-    }
-
-    private String getDexFileName(int fileIndex) {
-      if (singleFixedFileIndex != null) {
-        fileIndex = singleFixedFileIndex;
-      }
-      return prefix + (fileIndex == 0 ? "" : (fileIndex + 1)) + FileUtils.DEX_EXTENSION;
-    }
-
-    @Override
-    public synchronized void accept(
-        int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) {
-      if (singleFixedFileIndex != null && fileIndex != 0) {
-        handler.error(new StringDiagnostic("Result does not fit into a single dex file."));
-        return;
-      }
-      // Make a copy of the actual bytes as they will possibly be accessed later by the runner.
-      final byte[] bytes = data.copyByteData();
-      writers.put(fileIndex, () -> writeEntry(fileIndex, bytes, descriptors, handler));
-
-      while (writers.containsKey(highestIndexWritten + 1)) {
-        ++highestIndexWritten;
-        writers.get(highestIndexWritten).run();
-        writers.remove(highestIndexWritten);
-      }
-    }
-
-    /** Get or open the zip output stream. */
-    private synchronized ZipOutputStream getStream(DiagnosticsHandler handler) {
-      if (stream == null) {
-        try {
-          stream =
-              new ZipOutputStream(
-                  Files.newOutputStream(
-                      path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING));
-        } catch (IOException e) {
-          handler.error(new ExceptionDiagnostic(e, origin));
-        }
-      }
-      return stream;
-    }
-
-    private void writeEntry(
-        int fileIndex, byte[] data, Set<String> descriptors, DiagnosticsHandler handler) {
-      try {
-        ZipUtils.writeToZipStream(
-            getStream(handler),
-            getDexFileName(fileIndex),
-            ByteDataView.of(data),
-            ZipEntry.DEFLATED);
-        hasWrittenSomething = true;
-      } catch (IOException e) {
-        handler.error(new ExceptionDiagnostic(e, origin));
-      }
-    }
-
-    @Override
-    public void finished(DiagnosticsHandler handler) {
-      if (!writers.isEmpty()) {
-        handler.error(
-            new StringDiagnostic(
-                "Failed to write zip, for a multidex output some of the classes.dex files were"
-                    + " not produced."));
-      }
-      try {
-        if (stream != null) {
-          stream.close();
-          stream = null;
-        }
-      } catch (IOException e) {
-        handler.error(new ExceptionDiagnostic(e, origin));
-      }
-    }
-  }
-
-  private static int parseFileIndexFromShardFilename(String inputArchive) {
-    Pattern namingPattern = Pattern.compile("([0-9]+)\\..*");
-    String name = new File(inputArchive).getName();
-    Matcher matcher = namingPattern.matcher(name);
-    if (!matcher.matches()) {
-      throw new RuntimeException(
-          String.format(
-              "Expect input named <N>.xxx.zip for --multidex=given_shard but got %s.", name));
-    }
-    int shard = Integer.parseInt(matcher.group(1));
-    if (shard <= 0) {
-      throw new RuntimeException(
-          String.format("Expect positive N in input named <N>.xxx.zip but got %d.", shard));
-    }
-    return shard;
-  }
-
-  public static void run(String[] args) throws CompilationFailedException, IOException {
-    Options options = parseArguments(args);
-
-    if (options.inputArchives.isEmpty()) {
-      throw new RuntimeException("Need at least one --input");
-    }
-
-    if (options.mainDexListFile != null && options.inputArchives.size() != 1) {
-      throw new RuntimeException(
-          "--main-dex-list only supported with exactly one --input, use DexFileSplitter for more");
-    }
-
-    if (!options.multidexMode.isMultidexAllowed()) {
-      if (options.mainDexListFile != null) {
-        throw new RuntimeException(
-            "--main-dex-list is only supported with multidex enabled, but mode is: "
-                + options.multidexMode.toString());
-      }
-      if (options.minimalMainDex) {
-        throw new RuntimeException(
-            "--minimal-main-dex is only supported with multidex enabled, but mode is: "
-                + options.multidexMode.toString());
-      }
-    }
-
-    D8Command.Builder builder = D8Command.builder();
-
-    Map<String, Integer> inputOrdering = new HashMap<>(options.inputArchives.size());
-    int sequenceNumber = 0;
-    for (String s : options.inputArchives) {
-      builder.addProgramFiles(Paths.get(s));
-      inputOrdering.put(s, sequenceNumber++);
-    }
-
-    // Determine enabling multidexing and file indexing.
-    Integer singleFixedFileIndex = null;
-    switch (options.multidexMode) {
-      case OFF:
-        singleFixedFileIndex = 0;
-        break;
-      case GIVEN_SHARD:
-        if (options.inputArchives.size() != 1) {
-          throw new RuntimeException("'--multidex=given_shard' requires exactly one --input.");
-        }
-        singleFixedFileIndex = parseFileIndexFromShardFilename(options.inputArchives.get(0)) - 1;
-        break;
-      case MINIMAL:
-      case BEST_EFFORT:
-        // Nothing to do.
-        break;
-      default:
-        throw new Unreachable("Unexpected enum: " + options.multidexMode);
-    }
-
-    if (options.mainDexListFile != null) {
-      builder.addMainDexListFiles(Paths.get(options.mainDexListFile));
-    }
-
-    ArchiveConsumer consumer =
-        new ArchiveConsumer(
-            Paths.get(options.outputArchive), options.dexPrefix, singleFixedFileIndex);
-    builder.setProgramConsumer(consumer);
-
-    DexFileMergerHelper.run(builder.build(), options.minimalMainDex, inputOrdering);
-
-    // If input was empty we still need to write out an empty zip.
-    if (!consumer.hasWrittenSomething()) {
-      File f = new File(options.outputArchive);
-      ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f));
-      out.close();
-    }
-  }
-
-  public static void main(String[] args) {
-    try {
-      if (PRINT_ARGS) {
-        printArgs(args);
-      }
-      run(args);
-    } catch (CompilationFailedException | IOException e) {
-      System.err.println("Merge failed: " + e.getMessage());
-      System.exit(1);
-    }
-  }
-
-  private static void printArgs(String[] args) {
-    System.err.print("r8.DexFileMerger");
-    for (String s : args) {
-      System.err.printf(" %s", s);
-    }
-    System.err.println("");
-  }
-}
diff --git a/src/main/keep.txt b/src/main/keep.txt
index 2450f6b..7791d4e 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -8,8 +8,6 @@
 -keep public class com.android.tools.r8.D8 { public static void main(java.lang.String[]); }
 -keep public class com.android.tools.r8.R8 { public static void main(java.lang.String[]); }
 -keep public class com.android.tools.r8.ExtractMarker { public static void main(java.lang.String[]); }
--keep public class com.android.tools.r8.compatdexbuilder.CompatDexBuilder { public static void main(java.lang.String[]); }
--keep public class com.android.tools.r8.dexfilemerger.DexFileMerger { public static void main(java.lang.String[]); }
 -keep public class com.android.tools.r8.dexsplitter.DexSplitter { public static void main(java.lang.String[]); }
 
 -keep public class com.android.tools.r8.Version { public static java.lang.String getVersionString(); }
@@ -25,6 +23,3 @@
 
 # Compatibility command line program used by the Android Platform build.
 -keep public class com.android.tools.r8.compatproguard.CompatProguard { public static void main(java.lang.String[]); }
-
-# Compatibility command line program used by in google3.
--keep public class com.android.tools.r8.compatdx.CompatDx { public static void main(java.lang.String[]); }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilderTests.java b/src/test/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilderTests.java
deleted file mode 100644
index 341fb67..0000000
--- a/src/test/java/com/android/tools/r8/compatdexbuilder/CompatDexBuilderTests.java
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2017, 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.compatdexbuilder;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-public class CompatDexBuilderTests {
-
-  @Rule public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
-  @Test
-  public void compileManyClasses() throws IOException, InterruptedException, ExecutionException {
-    final String SUBDIR = "naming001";
-    final String INPUT_JAR = ToolHelper.TESTS_BUILD_DIR + "examples/" + SUBDIR + ".jar";
-    final List<String> CLASS_NAMES =
-        ImmutableList.of(
-            "A",
-            "B",
-            "C",
-            "D",
-            "E",
-            "F",
-            "G",
-            "H",
-            "I",
-            "J",
-            "K",
-            "L",
-            "Reflect2$A",
-            "Reflect2$B",
-            "Reflect2",
-            "Reflect");
-
-    // Run CompatDexBuilder on naming001.jar
-    Path outputZip = temp.getRoot().toPath().resolve("out.zip");
-    CompatDexBuilder.main(
-        new String[] {"--input_jar", INPUT_JAR, "--output_zip", outputZip.toString()});
-    assertTrue(outputZip.toFile().exists());
-
-    // Verify if all the classes have their corresponding ".class.dex" files in the zip.
-    Set<String> expectedNames = new HashSet<>();
-    for (String className : CLASS_NAMES) {
-      expectedNames.add(SUBDIR + "/" + className + ".class.dex");
-    }
-    try (ZipFile zipFile = new ZipFile(outputZip.toFile(), StandardCharsets.UTF_8)) {
-      for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
-        ZipEntry ze = e.nextElement();
-        expectedNames.remove(ze.getName());
-      }
-    }
-    assertTrue(expectedNames.isEmpty());
-  }
-
-  @Test
-  public void compileTwoClassesAndRun()
-      throws IOException, InterruptedException, ExecutionException, CompilationFailedException {
-    // Run CompatDexBuilder on dexMergeSample.jar
-    final String INPUT_JAR = ToolHelper.EXAMPLES_BUILD_DIR + "dexmergesample.jar";
-    Path outputZip = temp.getRoot().toPath().resolve("out.zip");
-    CompatDexBuilder.main(
-        new String[] {"--input_jar", INPUT_JAR, "--output_zip", outputZip.toString()});
-
-    // Merge zip content into a single dex file.
-    Path d8OutDir = temp.newFolder().toPath();
-    D8.run(
-        D8Command.builder()
-            .setOutput(d8OutDir, OutputMode.DexIndexed)
-            .addProgramFiles(outputZip)
-            .build());
-
-    // Validate by running methods of Class1 and Class2
-    for (String className : new String[] {"Class1", "Class2"}) {
-      ArtCommandBuilder artCommandBuilder = new ArtCommandBuilder();
-      artCommandBuilder.appendClasspath(d8OutDir.resolve("classes.dex").toString());
-      artCommandBuilder.setMainClass("dexmergesample." + className);
-      String out = ToolHelper.runArt(artCommandBuilder);
-      assertEquals(out, className + "\n");
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java b/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java
deleted file mode 100644
index 4ec0131..0000000
--- a/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) 2017, 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.compatdx;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.StringUtils.BraceType;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import java.io.IOException;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-public class CompatDxTests {
-  private static final int MAX_METHOD_COUNT = Constants.U16BIT_MAX;
-
-  private static final String EXAMPLE_JAR_FILE1 = ToolHelper.EXAMPLES_BUILD_DIR + "arithmetic.jar";
-  private static final String EXAMPLE_JAR_FILE2 = ToolHelper.EXAMPLES_BUILD_DIR + "barray.jar";
-
-  private static final String NO_LOCALS = "--no-locals";
-  private static final String NO_POSITIONS = "--positions=none";
-  private static final String MULTIDEX = "--multi-dex";
-  private static final String NUM_THREADS_5 = "--num-threads=5";
-
-  @Rule
-  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
-  @Test
-  public void noFilesTest() throws IOException {
-    runDexer("--no-files");
-  }
-
-  @Test
-  public void noOutputTest() throws IOException {
-    runDexerWithoutOutput(NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void singleJarInputFile() throws IOException {
-    runDexer(NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void multipleJarInputFiles() throws IOException {
-    runDexer(NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1, EXAMPLE_JAR_FILE2);
-  }
-
-  @Test
-  public void outputZipFile() throws IOException {
-    runDexerWithOutput("foo.dex.zip", NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void useMultipleThreads() throws IOException {
-    runDexer(NUM_THREADS_5, NO_POSITIONS, NO_LOCALS, EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void withPositions() throws IOException {
-    runDexer(NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void withLocals() throws IOException {
-    runDexer(NO_POSITIONS, MULTIDEX, EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void withoutMultidex() throws IOException {
-    runDexer(NO_POSITIONS, NO_LOCALS, EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void writeToNamedDexFile() throws IOException {
-    runDexerWithOutput("named-output.dex", EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void keepClassesSingleDexTest() throws IOException {
-    runDexerWithOutput("out.zip", "--keep-classes", EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void keepClassesMultiDexTest() throws IOException {
-    runDexerWithOutput("out.zip", "--keep-classes", "--multi-dex", EXAMPLE_JAR_FILE1);
-  }
-
-  @Test
-  public void ignoreDexInArchiveTest() throws IOException {
-    // Create a JAR with both a .class and a .dex file (the .dex file is just empty).
-    Path jarWithClassesAndDex = temp.newFile("test.jar").toPath();
-    Files.copy(Paths.get(EXAMPLE_JAR_FILE1), jarWithClassesAndDex,
-        StandardCopyOption.REPLACE_EXISTING);
-    URI uri = URI.create("jar:" + jarWithClassesAndDex.toUri());
-    FileSystem fileSystem = FileSystems.newFileSystem(uri, ImmutableMap.of("create", "true"));
-    Path dexFile = fileSystem.getPath("classes.dex");
-    Files.newOutputStream(dexFile, StandardOpenOption.CREATE).close();
-    fileSystem.close();
-
-    // Only test this with CompatDx, as dx does not like the empty .dex file.
-    List<String> d8Args =ImmutableList.of(
-        "--output=" + temp.newFolder("out").toString(), jarWithClassesAndDex.toString());
-    CompatDx.main(d8Args.toArray(StringUtils.EMPTY_ARRAY));
-  }
-
-  private void runDexer(String... args) throws IOException {
-    runDexerWithOutput("", args);
-  }
-
-  private void runDexerWithoutOutput(String... args) throws IOException {
-    runDexerWithOutput(null, args);
-  }
-
-  private Path getOutputD8() {
-    return temp.getRoot().toPath().resolve("d8-out");
-  }
-
-  private Path getOutputDX() {
-    return temp.getRoot().toPath().resolve("dx-out");
-  }
-
-  private void runDexerWithOutput(String out, String... args) throws IOException {
-    Path d8Out = null;
-    Path dxOut = null;
-    if (out != null) {
-      Path baseD8 = getOutputD8();
-      Path baseDX = getOutputDX();
-      Files.createDirectory(baseD8);
-      Files.createDirectory(baseDX);
-      d8Out = baseD8.resolve(out);
-      dxOut = baseDX.resolve(out);
-      assertNotEquals(d8Out, dxOut);
-    }
-
-    List<String> d8Args = new ArrayList<>(args.length + 2);
-    d8Args.add("--dex");
-    if (d8Out != null) {
-      d8Args.add("--output=" + d8Out);
-    }
-    Collections.addAll(d8Args, args);
-    System.out.println("running: d8 " + StringUtils.join(d8Args, " "));
-    CompatDx.main(d8Args.toArray(StringUtils.EMPTY_ARRAY));
-
-    List<String> dxArgs = new ArrayList<>(args.length + 2);
-    if (dxOut != null) {
-      dxArgs.add("--output=" + dxOut);
-    }
-    Collections.addAll(dxArgs, args);
-    System.out.println("running: dx " + StringUtils.join(dxArgs, " "));
-    ProcessResult result = ToolHelper.runDX(dxArgs.toArray(StringUtils.EMPTY_ARRAY));
-    assertEquals(result.stderr, 0, result.exitCode);
-
-    if (out == null) {
-      // Can't check output if explicitly not writing any.
-      return;
-    }
-
-    List<Path> d8Files = Files.list(Files.isDirectory(d8Out) ? d8Out : d8Out.getParent())
-        .sorted().collect(Collectors.toList());
-    List<Path> dxFiles = Files.list(Files.isDirectory(dxOut) ? dxOut : dxOut.getParent())
-        .sorted().collect(Collectors.toList());
-    assertEquals("Out file names differ",
-        StringUtils.join(dxFiles, "\n", BraceType.NONE, (file) ->
-            file.getFileName().toString()),
-        StringUtils.join(d8Files, "\n", BraceType.NONE, (file) ->
-            file.getFileName().toString()));
-
-    for (int i = 0; i < d8Files.size(); i++) {
-      if (FileUtils.isArchive(d8Files.get(i))) {
-        compareArchiveFiles(d8Files.get(i), dxFiles.get(i));
-      }
-    }
-  }
-
-  private void compareArchiveFiles(Path d8File, Path dxFile) throws IOException {
-    ZipFile d8Zip = new ZipFile(d8File.toFile(), StandardCharsets.UTF_8);
-    ZipFile dxZip = new ZipFile(dxFile.toFile(), StandardCharsets.UTF_8);
-    // TODO(zerny): This should test resource containment too once supported.
-    Set<String> d8Content = d8Zip.stream().map(ZipEntry::getName).collect(Collectors.toSet());
-    Set<String> dxContent = dxZip.stream().map(ZipEntry::getName).collect(Collectors.toSet());
-    for (String entry : d8Content) {
-      assertTrue("Expected dx output to contain " + entry, dxContent.contains(entry));
-    }
-    for (String entry : dxContent) {
-      Path path = Paths.get(entry);
-      if (FileUtils.isDexFile(path) || FileUtils.isClassFile(path)) {
-        assertTrue("Expected d8 output to contain " + entry, d8Content.contains(entry));
-      }
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/dexfilemerger/DexFileMergerTests.java b/src/test/java/com/android/tools/r8/dexfilemerger/DexFileMergerTests.java
deleted file mode 100644
index 91364d4..0000000
--- a/src/test/java/com/android/tools/r8/dexfilemerger/DexFileMergerTests.java
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2017, 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.dexfilemerger;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.DexFileMergerHelper;
-import com.android.tools.r8.ExtractMarker;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.ResourceException;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.dex.Marker;
-import com.android.tools.r8.maindexlist.MainDexListTests;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.AndroidApp;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Collection;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-
-public class DexFileMergerTests extends TestBase {
-
-  private static final String CLASS_DIR = ToolHelper.EXAMPLES_BUILD_DIR + "classes/dexmergesample";
-  private static final String CLASS1_CLASS = CLASS_DIR + "/Class1.class";
-  private static final String CLASS2_CLASS = CLASS_DIR + "/Class2.class";
-  private static final int MAX_METHOD_COUNT = Constants.U16BIT_MAX;
-
-  private Path createMergerInputWithTwoClasses(OutputMode outputMode, boolean addMarker)
-      throws CompilationFailedException, IOException {
-    // Compile Class1 and Class2
-    Path mergerInputZip = temp.newFolder().toPath().resolve("merger-input.zip");
-    D8Command command =
-        D8Command.builder()
-            .setOutput(mergerInputZip, outputMode)
-            .addProgramFiles(Paths.get(CLASS1_CLASS))
-            .addProgramFiles(Paths.get(CLASS2_CLASS))
-            .build();
-
-    DexFileMergerHelper.runD8ForTesting(command, !addMarker);
-
-    return mergerInputZip;
-  }
-
-  private void testMarker(boolean addMarkerToInput)
-      throws CompilationFailedException, IOException, ResourceException, ExecutionException {
-    Path mergerInputZip = createMergerInputWithTwoClasses(OutputMode.DexIndexed, addMarkerToInput);
-    int expectedNumberOfMarkers = addMarkerToInput ? 1 : 0;
-
-    Collection<Marker> inputMarkers = ExtractMarker.extractMarkerFromDexFile(mergerInputZip);
-    assertEquals(expectedNumberOfMarkers, inputMarkers.size());
-
-    // Test that the DexFileMerger preserves markers.
-    Path mergerOutputZip = temp.getRoot().toPath().resolve("merger-out.zip");
-    DexFileMerger.main(
-        new String[] {
-          "--input", mergerInputZip.toString(), "--output", mergerOutputZip.toString()
-        });
-    Collection<Marker> outputMarkers = ExtractMarker.extractMarkerFromDexFile(mergerOutputZip);
-    assertEquals(expectedNumberOfMarkers, outputMarkers.size());
-
-    // Test that D8 when used for merging preserves markers.
-    D8.main(new String[] { mergerInputZip.toString(), "--output", mergerOutputZip.toString() });
-    Collection<Marker> d8OutputMarkers = ExtractMarker.extractMarkerFromDexFile((mergerOutputZip));
-    assertEquals(expectedNumberOfMarkers, d8OutputMarkers.size());
-  }
-
-  @Test
-  public void testMarkerPreserved()
-      throws CompilationFailedException, IOException, ResourceException, ExecutionException {
-    testMarker(true);
-  }
-
-  @Test
-  public void testMarkerNotAdded()
-      throws CompilationFailedException, IOException, ResourceException, ExecutionException {
-    testMarker(false);
-  }
-
-  @Test
-  public void mergeTwoFiles() throws CompilationFailedException, IOException {
-    Path mergerInputZip = createMergerInputWithTwoClasses(OutputMode.DexFilePerClassFile, false);
-
-    Path mergerOutputZip = temp.getRoot().toPath().resolve("merger-out.zip");
-    DexFileMerger.main(
-        new String[] {
-          "--input", mergerInputZip.toString(), "--output", mergerOutputZip.toString()
-        });
-
-    // Test by running methods of Class1 and Class2
-    for (String className : new String[] {"Class1", "Class2"}) {
-      ArtCommandBuilder builder = new ArtCommandBuilder();
-      builder.appendClasspath(mergerOutputZip.toString());
-      builder.setMainClass("dexmergesample." + className);
-      String out = ToolHelper.runArt(builder);
-      assertEquals(out, className + "\n");
-    }
-  }
-
-  private void generateClassesAndTest(int extraMethodCount, int programResourcesSize)
-      throws IOException, ExecutionException, CompilationFailedException {
-    AndroidApp generatedApp =
-        MainDexListTests.generateApplication(
-            ImmutableList.of("A", "B"),
-            AndroidApiLevel.N.getLevel(),
-            MAX_METHOD_COUNT / 2 + 1 + extraMethodCount);
-    Path appDir = temp.newFolder().toPath().resolve("merger-input.zip");
-    assertEquals(programResourcesSize, generatedApp.getDexProgramResourcesForTesting().size());
-    generatedApp.write(appDir, OutputMode.DexIndexed);
-
-    Path outZip = temp.getRoot().toPath().resolve("out.zip");
-    DexFileMerger.run(
-        new String[] {
-          "--input", appDir.toString(), "--output", outZip.toString(), "--multidex=off"
-        });
-  }
-
-  @Test
-  public void failIfTooBig() throws IOException, ExecutionException {
-    // Generates an application with two classes, each with the number of methods just enough not to
-    // fit into a single dex file.
-    try {
-      generateClassesAndTest(1, 2);
-      fail("Expect to fail");
-    } catch (CompilationFailedException e) {
-      assertThat(e.getCause().getMessage(), containsString("does not fit into a single dex file"));
-    }
-  }
-
-  @Test
-  public void failIfTooBigControl()
-      throws IOException, ExecutionException, CompilationFailedException {
-    // Control test for failIfTooBig to make sure we don't fail with less methods.
-    generateClassesAndTest(0, 1);
-  }
-}