Merge "Revert "Enforce class access flags to be valid.""
diff --git a/build.gradle b/build.gradle
index d93cbf1..c351aca 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,23 +16,23 @@
'-XepDisableAllChecks',
// D8 want to use reference equality, thus disable the checker explicitly
'-Xep:ReferenceEquality:OFF',
- '-Xep:ClassCanBeStatic:WARN',
- '-Xep:OperatorPrecedence:WARN',
- '-Xep:RemoveUnusedImports:WARN',
- '-Xep:MissingOverride:WARN',
- '-Xep:OvershadowingSubclassFields:WARN',
- '-Xep:IntLongMath:WARN',
- '-Xep:EqualsHashCode:WARN',
- '-Xep:InconsistentOverloads:WARN',
- '-Xep:ArrayHashCode:WARN',
- '-Xep:EqualsIncompatibleType:WARN',
- '-Xep:NonOverridingEquals:WARN',
- '-Xep:FallThrough:WARN',
- '-Xep:MissingCasesInEnumSwitch:WARN',
- '-Xep:MissingDefault:WARN',
- '-Xep:MultipleTopLevelClasses:WARN',
- '-Xep:NarrowingCompoundAssignment:WARN',
- '-Xep:BoxedPrimitiveConstructor:WARN']
+ '-Xep:ClassCanBeStatic:ERROR',
+ '-Xep:OperatorPrecedence:ERROR',
+ '-Xep:RemoveUnusedImports:ERROR',
+ '-Xep:MissingOverride:ERROR',
+ '-Xep:OvershadowingSubclassFields:ERROR',
+ '-Xep:IntLongMath:ERROR',
+ '-Xep:EqualsHashCode:ERROR',
+ '-Xep:InconsistentOverloads:ERROR',
+ '-Xep:ArrayHashCode:ERROR',
+ '-Xep:EqualsIncompatibleType:ERROR',
+ '-Xep:NonOverridingEquals:ERROR',
+ '-Xep:FallThrough:ERROR',
+ '-Xep:MissingCasesInEnumSwitch:ERROR',
+ '-Xep:MissingDefault:ERROR',
+ '-Xep:MultipleTopLevelClasses:ERROR',
+ '-Xep:NarrowingCompoundAssignment:ERROR',
+ '-Xep:BoxedPrimitiveConstructor:ERROR']
apply from: 'copyAdditionalJctfCommonFiles.gradle'
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index a32aa20..24dfb07 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -12,137 +12,40 @@
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.ExecutionException;
public class ExtractMarker {
- private static class Command {
- public static class Builder {
- private boolean printHelp = false;
- private boolean verbose;
- private boolean summary;
- private List<Path> programFiles = new ArrayList<>();
+ public static Marker extractMarkerFromDexFile(Path file) throws IOException, ExecutionException {
+ AndroidApp.Builder appBuilder = AndroidApp.builder();
+ appBuilder.setVdexAllowed();
+ appBuilder.addProgramFiles(FilteredClassPath.unfiltered(file));
+ return extractMarker(appBuilder.build());
+ }
- public Builder setPrintHelp(boolean printHelp) {
- this.printHelp = printHelp;
- return this;
- }
+ public static Marker extractMarkerFromDexProgramData(byte[] data)
+ throws IOException, ExecutionException {
+ AndroidApp app = AndroidApp.fromDexProgramData(data);
+ return extractMarker(app);
+ }
- public boolean isPrintHelp() {
- return printHelp;
- }
-
- public Builder setVerbose(boolean verbose) {
- this.verbose = verbose;
- return this;
- }
-
- public Builder setSummary(boolean summary) {
- this.summary = summary;
- return this;
- }
-
- public Builder addProgramFile(Path programFile) {
- programFiles.add(programFile);
- return this;
- }
-
- public ExtractMarker.Command build() throws CompilationException, IOException {
- // If printing versions ignore everything else.
- if (isPrintHelp()) {
- return new ExtractMarker.Command(isPrintHelp());
- }
- return new ExtractMarker.Command(verbose, summary, programFiles);
- }
- }
-
- static final String USAGE_MESSAGE = String.join("\n", ImmutableList.of(
- "Usage: extractmarker [options] <input-files>",
- " where <input-files> are dex or vdex files",
- " --verbose # More verbose output.",
- " --summary # Print summary at the end.",
- " --help # Print this message."));
-
- public static ExtractMarker.Command.Builder builder() {
- return new Builder();
- }
-
- public static ExtractMarker.Command.Builder parse(String[] args)
- throws CompilationException, IOException {
- ExtractMarker.Command.Builder builder = builder();
- parse(args, builder);
- return builder;
- }
-
- private static void parse(String[] args, ExtractMarker.Command.Builder builder)
- throws CompilationException, IOException {
- for (int i = 0; i < args.length; i++) {
- String arg = args[i].trim();
- if (arg.length() == 0) {
- continue;
- } else if (arg.equals("--verbose")) {
- builder.setVerbose(true);
- } else if (arg.equals("--summary")) {
- builder.setSummary(true);
- } else if (arg.equals("--help")) {
- builder.setPrintHelp(true);
- } else {
- if (arg.startsWith("--")) {
- throw new CompilationException("Unknown option: " + arg);
- }
- builder.addProgramFile(Paths.get(arg));
- }
- }
- }
-
- private final boolean printHelp;
- private final boolean verbose;
- private final boolean summary;
- private final List<Path> programFiles;
-
- private Command(boolean verbose, boolean summary, List<Path> programFiles) {
- this.printHelp = false;
- this.verbose = verbose;
- this.summary = summary;
- this.programFiles = programFiles;
- }
-
- private Command(boolean printHelp) {
- this.printHelp = printHelp;
- this.verbose = false;
- this.summary = false;
- programFiles = ImmutableList.of();
- }
-
- public boolean isPrintHelp() {
- return printHelp;
- }
-
- public List<Path> getProgramFiles() {
- return programFiles;
- }
-
- public boolean getVerbose() {
- return verbose;
- }
-
- public boolean getSummary() {
- return summary;
- }
+ private static Marker extractMarker(AndroidApp app) throws IOException, ExecutionException {
+ InternalOptions options = new InternalOptions();
+ options.skipReadingDexCode = true;
+ options.minApiLevel = AndroidApiLevel.P.getLevel();
+ DexApplication dexApp =
+ new ApplicationReader(app, options, new Timing("ExtractMarker")).read();
+ return dexApp.dexItemFactory.extractMarker();
}
public static void main(String[] args)
throws IOException, CompilationException, ExecutionException {
- ExtractMarker.Command.Builder builder = ExtractMarker.Command.parse(args);
- ExtractMarker.Command command = builder.build();
+ ExtractMarkerCommand.Builder builder = ExtractMarkerCommand.parse(args);
+ ExtractMarkerCommand command = builder.build();
if (command.isPrintHelp()) {
- System.out.println(ExtractMarker.Command.USAGE_MESSAGE);
+ System.out.println(ExtractMarkerCommand.USAGE_MESSAGE);
return;
}
@@ -153,26 +56,17 @@
int otherCount = 0;
for (Path programFile : command.getProgramFiles()) {
try {
- InternalOptions options = new InternalOptions();
- options.skipReadingDexCode = true;
- options.minApiLevel = AndroidApiLevel.P.getLevel();
- AndroidApp.Builder appBuilder = AndroidApp.builder();
- appBuilder.setVdexAllowed();
- appBuilder.addProgramFiles(FilteredClassPath.unfiltered(programFile));
- DexApplication dexApp =
- new ApplicationReader(appBuilder.build(), options, new Timing("ExtractMarker"))
- .read();
- Marker readMarker = dexApp.dexItemFactory.extractMarker();
if (command.getVerbose()) {
System.out.print(programFile);
System.out.print(": ");
}
- if (readMarker == null) {
+ Marker marker = extractMarkerFromDexFile(programFile);
+ if (marker == null) {
System.out.println("D8/R8 marker not found.");
otherCount++;
} else {
- System.out.println(readMarker.toString());
- if (readMarker.isD8()) {
+ System.out.println(marker.toString());
+ if (marker.isD8()) {
d8Count++;
} else {
r8Count++;
diff --git a/src/main/java/com/android/tools/r8/ExtractMarkerCommand.java b/src/main/java/com/android/tools/r8/ExtractMarkerCommand.java
new file mode 100644
index 0000000..729b50a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ExtractMarkerCommand.java
@@ -0,0 +1,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;
+
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+class ExtractMarkerCommand {
+
+ public static class Builder {
+ private boolean printHelp = false;
+ private boolean verbose;
+ private boolean summary;
+ private List<Path> programFiles = new ArrayList<>();
+
+ public Builder setPrintHelp(boolean printHelp) {
+ this.printHelp = printHelp;
+ return this;
+ }
+
+ public boolean isPrintHelp() {
+ return printHelp;
+ }
+
+ public Builder setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ return this;
+ }
+
+ public Builder setSummary(boolean summary) {
+ this.summary = summary;
+ return this;
+ }
+
+ public Builder addProgramFile(Path programFile) {
+ programFiles.add(programFile);
+ return this;
+ }
+
+ public ExtractMarkerCommand build() throws CompilationException, IOException {
+ // If printing versions ignore everything else.
+ if (isPrintHelp()) {
+ return new ExtractMarkerCommand(isPrintHelp());
+ }
+ return new ExtractMarkerCommand(verbose, summary, programFiles);
+ }
+ }
+
+ static final String USAGE_MESSAGE = String.join("\n", ImmutableList.of(
+ "Usage: extractmarker [options] <input-files>",
+ " where <input-files> are dex or vdex files",
+ " --verbose # More verbose output.",
+ " --summary # Print summary at the end.",
+ " --help # Print this message."));
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Builder parse(String[] args)
+ throws CompilationException, IOException {
+ Builder builder = builder();
+ parse(args, builder);
+ return builder;
+ }
+
+ private static void parse(String[] args, Builder builder)
+ throws CompilationException, IOException {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i].trim();
+ if (arg.length() == 0) {
+ continue;
+ } else if (arg.equals("--verbose")) {
+ builder.setVerbose(true);
+ } else if (arg.equals("--summary")) {
+ builder.setSummary(true);
+ } else if (arg.equals("--help")) {
+ builder.setPrintHelp(true);
+ } else {
+ if (arg.startsWith("--")) {
+ throw new CompilationException("Unknown option: " + arg);
+ }
+ builder.addProgramFile(Paths.get(arg));
+ }
+ }
+ }
+
+ private final boolean printHelp;
+ private final boolean verbose;
+ private final boolean summary;
+ private final List<Path> programFiles;
+
+ private ExtractMarkerCommand(boolean verbose, boolean summary, List<Path> programFiles) {
+ this.printHelp = false;
+ this.verbose = verbose;
+ this.summary = summary;
+ this.programFiles = programFiles;
+ }
+
+ private ExtractMarkerCommand(boolean printHelp) {
+ this.printHelp = printHelp;
+ this.verbose = false;
+ this.summary = false;
+ programFiles = ImmutableList.of();
+ }
+
+ public boolean isPrintHelp() {
+ return printHelp;
+ }
+
+ public List<Path> getProgramFiles() {
+ return programFiles;
+ }
+
+ public boolean getVerbose() {
+ return verbose;
+ }
+
+ public boolean getSummary() {
+ return summary;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 44e1bf4..4368013 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -8,6 +8,8 @@
public final class Version {
+ // This field is accessed from release scripts using simple pattern matching.
+ // Therefore, changing this field could break our release scripts.
public static final String LABEL = "v0.2.0-dev";
private Version() {
diff --git a/src/main/java/com/android/tools/r8/dex/Marker.java b/src/main/java/com/android/tools/r8/dex/Marker.java
index 463d484..e1f3316 100644
--- a/src/main/java/com/android/tools/r8/dex/Marker.java
+++ b/src/main/java/com/android/tools/r8/dex/Marker.java
@@ -51,6 +51,10 @@
return tool == Tool.R8;
}
+ public String getVersion() {
+ return (String) content.get("version");
+ }
+
public Marker put(String key, int value) {
// value is converted to Long ensuring equals works with the parsed json string.
return internalPut(key, Long.valueOf(value));
diff --git a/src/test/java/com/android/tools/r8/ExtractMarkerTest.java b/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
new file mode 100644
index 0000000..fd1bfcb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ExtractMarkerTest.java
@@ -0,0 +1,31 @@
+// 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.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.utils.CompilationFailedException;
+import com.google.common.io.ByteStreams;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+
+public class ExtractMarkerTest {
+
+ @Test
+ public void extractMarkerTest()
+ throws CompilationFailedException, IOException, ExecutionException {
+ String classFile = ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
+ D8Command command = D8Command.builder()
+ .addProgramFiles(Paths.get(classFile))
+ .build();
+ D8Output output = D8.run(command);
+ byte[] data = ByteStreams.toByteArray(output.getDexResources().get(0).getStream());
+ Marker marker = ExtractMarker.extractMarkerFromDexProgramData(data);
+ assert marker != null;
+ assert marker.getTool() == Tool.D8;
+ assert marker.getVersion().equals(Version.LABEL);
+ }
+}
diff --git a/tools/archive.py b/tools/archive.py
index 20d057c..8e7436b 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -65,10 +65,15 @@
def Main():
if not 'BUILDBOT_BUILDERNAME' in os.environ:
raise Exception('You are not a bot, don\'t archive builds')
+ # Create maven release first which uses a build that exclude dependencies.
+ create_maven_release.main(["--out", utils.LIBS])
+
+ # Generate and copy the build that exclude dependencies.
+ gradle.RunGradleExcludeDeps([utils.R8])
+ shutil.copyfile(utils.R8_JAR, utils.R8_EXCLUDE_DEPS_JAR)
+
# Ensure all archived artifacts has been built before archiving.
gradle.RunGradle([utils.D8, utils.R8, utils.COMPATDX, utils.COMPATPROGUARD])
- create_maven_release.main(['--jar', utils.R8_JAR, "--out", utils.LIBS])
-
version = GetVersion()
is_master = IsMaster(version)
if is_master:
@@ -86,6 +91,7 @@
for file in [utils.D8_JAR,
utils.R8_JAR,
+ utils.R8_EXCLUDE_DEPS_JAR,
utils.COMPATDX_JAR,
utils.COMPATPROGUARD_JAR,
utils.MAVEN_ZIP]:
diff --git a/tools/create_maven_release.py b/tools/create_maven_release.py
index 85b558a..cc045a2 100755
--- a/tools/create_maven_release.py
+++ b/tools/create_maven_release.py
@@ -3,8 +3,9 @@
# 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.
-import hashlib
import argparse
+import gradle
+import hashlib
from os import makedirs
from os.path import join
from shutil import copyfile, make_archive, rmtree
@@ -14,13 +15,13 @@
import tempfile
import utils
-LICENSETEMPLATE = Template(
+DEPENDENCYTEMPLATE = Template(
"""
- <license>
- <name>$name</name>
- <url>$url</url>
- <distribution>repo</distribution>
- </license>""")
+ <dependency>
+ <groupId>$group</groupId>
+ <artifactId>$artifact</artifactId>
+ <version>$version</version>
+ </dependency>""")
POMTEMPLATE = Template(
"""<project
@@ -42,8 +43,10 @@
<name>BSD-3-Clause</name>
<url>https://opensource.org/licenses/BSD-3-Clause</url>
<distribution>repo</distribution>
- </license>$library_licenses
+ </license>
</licenses>
+ <dependencies>$dependencies
+ </dependencies>
<developers>
<developer>
<name>The Android Open Source Project</name>
@@ -62,19 +65,19 @@
def parse_options(argv):
result = argparse.ArgumentParser()
- result.add_argument('--jar', help='jar file to package')
result.add_argument('--out', help='directory in which to put the output zip file')
return result.parse_args(argv)
-def determine_version(jar):
- cmd = []
- cmd.append('java')
- cmd.extend(['-jar', jar]);
- cmd.append('--version')
- output = subprocess.check_output(cmd)
- version_string = output.split()[1]
- assert version_string.startswith("v")
- return version_string[1:]
+def determine_version():
+ version_file = join(
+ utils.SRC_ROOT, 'com', 'android', 'tools', 'r8', 'Version.java')
+ with open(version_file, 'r') as file:
+ for line in file:
+ if 'final String LABEL ' in line:
+ result = line[line.find('"v') + 2:]
+ result = result[:result.find('"')]
+ return result
+ raise Exception('Unable to determine version.')
def generate_library_licenses():
license_prefix = 'license: '
@@ -103,9 +106,76 @@
result += LICENSETEMPLATE.substitute(name=name, url=url)
return result
+
+# Generate the dependencies block for the pom file.
+#
+# We ask gradle to list all dependencies. In that output
+# we locate the runtimeClasspath block for 'main' which
+# looks something like:
+#
+# runtimeClasspath - Runtime classpath of source set 'main'.
+# +--- net.sf.jopt-simple:jopt-simple:4.6
+# +--- com.googlecode.json-simple:json-simple:1.1
+# +--- com.google.guava:guava:23.0
+# +--- it.unimi.dsi:fastutil:7.2.0
+# +--- org.ow2.asm:asm:6.0
+# +--- org.ow2.asm:asm-commons:6.0
+# | \--- org.ow2.asm:asm-tree:6.0
+# | \--- org.ow2.asm:asm:6.0
+# +--- org.ow2.asm:asm-tree:6.0 (*)
+# +--- org.ow2.asm:asm-analysis:6.0
+# | \--- org.ow2.asm:asm-tree:6.0 (*)
+# \--- org.ow2.asm:asm-util:6.0
+# \--- org.ow2.asm:asm-tree:6.0 (*)
+#
+# We filter out the repeats that are marked by '(*)'.
+#
+# For each remaining line, we remove the junk at the start
+# in chunks. As an example:
+#
+# ' | \--- org.ow2.asm:asm-tree:6.0 ' --strip-->
+# '| \--- org.ow2.asm:asm-tree:6.0' -->
+# '\--- org.ow2.asm:asm-tree:6.0' -->
+# 'org.ow2.asm:asm-tree:6.0'
+#
+# The end result is the dependency we are looking for:
+#
+# groupId: org.ow2.asm
+# artifact: asm-tree
+# version: 6.0
+def generate_dependencies():
+ dependencies = gradle.RunGradleGetOutput(['dependencies'])
+ dependency_lines = []
+ collect = False
+ for line in dependencies.splitlines():
+ if 'runtimeClasspath' in line and "'main'" in line:
+ collect = True
+ continue
+ if collect:
+ if not len(line) == 0:
+ if not '(*)' in line:
+ trimmed = line.strip()
+ while trimmed.find(' ') != -1:
+ trimmed = trimmed[trimmed.find(' ') + 1:].strip()
+ if not trimmed in dependency_lines:
+ dependency_lines.append(trimmed)
+ else:
+ break
+ result = ''
+ for dep in dependency_lines:
+ components = dep.split(':')
+ assert len(components) == 3
+ group = components[0]
+ artifact = components[1]
+ version = components[2]
+ result += DEPENDENCYTEMPLATE.substitute(
+ group=group, artifact=artifact, version=version)
+ return result
+
def write_pom_file(version, pom_file):
- library_licenses = generate_library_licenses()
- version_pom = POMTEMPLATE.substitute(version=version, library_licenses=library_licenses)
+ dependencies = generate_dependencies()
+ version_pom = POMTEMPLATE.substitute(
+ version=version, dependencies=dependencies)
with open(pom_file, 'w') as file:
file.write(version_pom)
@@ -131,13 +201,14 @@
def main(argv):
options = parse_options(argv)
- jar = options.jar
outdir = options.out
- if jar == None or outdir == None:
- print 'Need to supply --jar and --out.'
+ if outdir == None:
+ print 'Need to supply output dir with --out.'
exit(1)
+ # Build the R8 no deps artifact.
+ gradle.RunGradleExcludeDeps([utils.R8])
# Create directory structure for this version.
- version = determine_version(jar)
+ version = determine_version()
with utils.TempDir() as tmp_dir:
version_dir = join(
tmp_dir, 'com', 'google', 'android', 'tools', 'r8', version, 'r8')
@@ -147,7 +218,7 @@
write_pom_file(version, pom_file)
# Copy the jar to the output.
target_jar = join(version_dir, 'r8-' + version + '.jar')
- copyfile(jar, target_jar)
+ copyfile(utils.R8_JAR, target_jar)
# Create check sums.
write_md5_for(target_jar)
write_md5_for(pom_file)
diff --git a/tools/gradle.py b/tools/gradle.py
index 275c270..df80cc9 100755
--- a/tools/gradle.py
+++ b/tools/gradle.py
@@ -54,9 +54,12 @@
else:
print 'gradle.py: Shadow library present'
-def RunGradle(args, throw_on_failure=True):
+def EnsureDeps():
EnsureGradle()
EnsureShadow()
+
+def RunGradle(args, throw_on_failure=True):
+ EnsureDeps()
cmd = [GRADLE]
cmd.extend(args)
utils.PrintCmd(cmd)
@@ -66,6 +69,19 @@
raise
return return_value
+def RunGradleExcludeDeps(args, throw_on_failure=True):
+ EnsureDeps()
+ args.append('-Pexclude_deps')
+ RunGradle(args, throw_on_failure)
+
+def RunGradleGetOutput(args):
+ EnsureDeps()
+ cmd = [GRADLE]
+ cmd.extend(args)
+ utils.PrintCmd(cmd)
+ with utils.ChangedWorkingDirectory(utils.REPO_ROOT):
+ return subprocess.check_output(cmd)
+
def Main():
RunGradle(sys.argv[1:])
diff --git a/tools/utils.py b/tools/utils.py
index 40a62b8..cf01d3b 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -20,6 +20,7 @@
DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')
LIBS = os.path.join(REPO_ROOT, 'build', 'libs')
MAVEN_ZIP = os.path.join(LIBS, 'r8.zip')
+SRC_ROOT = os.path.join(REPO_ROOT, 'src', 'main', 'java')
D8 = 'd8'
R8 = 'r8'
@@ -28,6 +29,7 @@
D8_JAR = os.path.join(LIBS, 'd8.jar')
R8_JAR = os.path.join(LIBS, 'r8.jar')
+R8_EXCLUDE_DEPS_JAR = os.path.join(LIBS, 'r8-exclude-deps.jar')
COMPATDX_JAR = os.path.join(LIBS, 'compatdx.jar')
COMPATPROGUARD_JAR = os.path.join(LIBS, 'compatproguard.jar')