aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
blob: a6b45ae17b9e6de20fd57fe9e327a7243380961d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 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.compatproguard;

import com.android.tools.r8.CompilationException;
import com.android.tools.r8.R8;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.Version;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.utils.AndroidApp;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;

/**
 * Proguard + dx compatibility interface for r8.
 *
 * This should become a mostly drop-in replacement for uses of Proguard followed by dx for
 * use with the Android Platform build.
 *
 * It accepts all Proguard flags supported by r8, except -outjars.
 *
 * It accepts a few dx flags which are known to be used in the Android Platform build.
 *
 * The flag -outjars does not make sense as r8 (like Proguard + dx) produces Dex output.
 * For output use --output as for R8 proper.
 */
public class CompatProguard {
  public static class CompatProguardOptions {
    public final String output;
    public final int minApi;
    public final boolean forceProguardCompatibility;
    public final boolean ignoreMissingClasses;
    public final boolean multiDex;
    public final List<String> proguardConfig;

    CompatProguardOptions(List<String> proguardConfig, String output, int minApi,
        boolean multiDex, boolean forceProguardCompatibility, boolean ignoreMissingClasses) {
      this.output = output;
      this.minApi = minApi;
      this.forceProguardCompatibility = forceProguardCompatibility;
      this.ignoreMissingClasses = ignoreMissingClasses;
      this.multiDex = multiDex;
      this.proguardConfig = proguardConfig;
    }

    public static CompatProguardOptions parse(String[] args) throws CompilationException {
      String output = null;
      int minApi = 1;
      boolean forceProguardCompatibility = false;
      boolean ignoreMissingClasses = false;
      boolean multiDex = false;
      boolean coreLibrary = false;

      ImmutableList.Builder<String> builder = ImmutableList.builder();
      if (args.length > 0) {
        StringBuilder currentLine = new StringBuilder(args[0]);
        for (int i = 1; i < args.length; i++) {
          String arg = args[i];
          if (arg.charAt(0) == '-') {
            if (arg.equals("--min-api")) {
              minApi = Integer.valueOf(args[++i]);
            } else if (arg.equals("--force-proguard-compatibility")) {
              forceProguardCompatibility = true;
            } else if (arg.equals("--ignore-missing-classes")) {
              ignoreMissingClasses = true;
            } else if (arg.equals("--output")) {
              output = args[++i];
            } else if (arg.equals("--multi-dex")) {
              multiDex = true;
            } else if (arg.equals("--core-library")) {
              coreLibrary = true;
            } else if (arg.equals("-outjars")) {
              throw new CompilationException(
                  "Proguard argument -outjar is not supported. Use R8 compatible --output flag");
            } else {
              builder.add(currentLine.toString());
              currentLine = new StringBuilder(arg);
            }
          } else {
            currentLine.append(' ').append(arg);
          }
        }
        builder.add(currentLine.toString());
      }
      return new CompatProguardOptions(builder.build(), output, minApi, multiDex,
          forceProguardCompatibility, ignoreMissingClasses);
    }
  }

  private static void run(String[] args) throws IOException, CompilationException {
    if (args.length == 0) {
      Version.printToolVersion("CompatProguard");
      return;
    }
    System.out.println("CompatProguard " + String.join(" ", args));
    // Run R8 passing all the options from the command line as a Proguard configuration.
    CompatProguardOptions options = CompatProguardOptions.parse(args);
    R8Command.Builder builder =
        new CompatProguardCommandBuilder(
            options.forceProguardCompatibility, options.ignoreMissingClasses);
    builder.setOutputPath(Paths.get(options.output))
        .addProguardConfiguration(options.proguardConfig)
        .setMinApiLevel(options.minApi);
    AndroidApp result = R8.runInternal(builder.build());

    if (!options.multiDex) {
      if (result.getDexProgramResources().size() > 1) {
        throw new CompilationError(
            "Compilation result could not fit into a single dex file. "
                + "Reduce the input-program size or run with --multi-dex enabled");
      }
    }
  }

  public static void main(String[] args) throws IOException {
    try {
      run(args);
    } catch (CompilationException e) {
      System.err.println(e.getMessage());
      System.exit(1);
    }
  }
}