| #!/usr/bin/env python |
| # Copyright (c) 2018, 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. |
| |
| ''' |
| Build r8lib.jar with both R8 and ProGuard and print a size comparison. |
| |
| By default, inlining is disabled in both R8 and ProGuard to make |
| method-by-method comparison much easier. Pass --inlining to enable inlining. |
| |
| By default, only shows methods where R8's DEX output is 5 or more instructions |
| larger than ProGuard+D8's output. Pass --threshold 0 to display all methods. |
| ''' |
| |
| import argparse |
| import build_r8lib |
| import os |
| import subprocess |
| import toolhelper |
| import utils |
| |
| |
| parser = argparse.ArgumentParser(description=__doc__.strip(), |
| formatter_class=argparse.RawTextHelpFormatter) |
| parser.add_argument('-t', '--tmpdir', |
| help='Store auxiliary files in given directory') |
| parser.add_argument('-i', '--inlining', action='store_true', |
| help='Enable inlining') |
| parser.add_argument('--threshold') |
| |
| R8_RELOCATIONS = [ |
| ('com.google.common', 'com.android.tools.r8.com.google.common'), |
| ('com.google.gson', 'com.android.tools.r8.com.google.gson'), |
| ('com.google.thirdparty', 'com.android.tools.r8.com.google.thirdparty'), |
| ('joptsimple', 'com.android.tools.r8.joptsimple'), |
| ('org.apache.commons', 'com.android.tools.r8.org.apache.commons'), |
| ('org.objectweb.asm', 'com.android.tools.r8.org.objectweb.asm'), |
| ('it.unimi.dsi.fastutil', 'com.android.tools.r8.it.unimi.dsi.fastutil'), |
| ] |
| |
| |
| def is_output_newer(input, output): |
| if not os.path.exists(output): |
| return False |
| return os.stat(input).st_mtime < os.stat(output).st_mtime |
| |
| |
| def check_call(args, **kwargs): |
| utils.PrintCmd(args) |
| return subprocess.check_call(args, **kwargs) |
| |
| |
| def main(tmpdir=None, inlining=True, |
| run_jarsizecompare=True, threshold=None): |
| if tmpdir is None: |
| with utils.TempDir() as tmpdir: |
| return main(tmpdir, inlining) |
| |
| inline_suffix = '-inline' if inlining else '-noinline' |
| |
| pg_config = utils.R8LIB_KEEP_RULES |
| r8lib_jar = os.path.join(utils.LIBS, 'r8lib%s.jar' % inline_suffix) |
| r8lib_map = os.path.join(utils.LIBS, 'r8lib%s-map.txt' % inline_suffix) |
| r8lib_args = None |
| if not inlining: |
| r8lib_args = ['-Dcom.android.tools.r8.disableinlining=1'] |
| pg_config = os.path.join(tmpdir, 'keep-noinline.txt') |
| with open(pg_config, 'w') as new_config: |
| with open(utils.R8LIB_KEEP_RULES) as old_config: |
| new_config.write(old_config.read().rstrip('\n') + |
| '\n-optimizations !method/inlining/*\n') |
| |
| if not is_output_newer(utils.R8_JAR, r8lib_jar): |
| r8lib_memory = os.path.join(tmpdir, 'r8lib%s-memory.txt' % inline_suffix) |
| build_r8lib.build_r8lib( |
| output_path=r8lib_jar, output_map=r8lib_map, |
| extra_args=r8lib_args, track_memory_file=r8lib_memory) |
| |
| pg_output = os.path.join(tmpdir, 'r8lib-pg%s.jar' % inline_suffix) |
| pg_memory = os.path.join(tmpdir, 'r8lib-pg%s-memory.txt' % inline_suffix) |
| pg_map = os.path.join(tmpdir, 'r8lib-pg%s-map.txt' % inline_suffix) |
| pg_args = ['tools/track_memory.sh', pg_memory, |
| 'third_party/proguard/proguard6.0.2/bin/proguard.sh', |
| '@' + pg_config, |
| '-lib', utils.RT_JAR, |
| '-injar', utils.R8_JAR, |
| '-printmapping', pg_map, |
| '-outjar', pg_output] |
| for library_name, relocated_package in R8_RELOCATIONS: |
| pg_args.extend(['-dontwarn', relocated_package + '.**', |
| '-dontnote', relocated_package + '.**']) |
| check_call(pg_args) |
| if threshold is None: |
| threshold = 5 |
| toolhelper.run('jarsizecompare', |
| ['--threshold', str(threshold), |
| '--lib', utils.RT_JAR, |
| '--input', 'input', utils.R8_JAR, |
| '--input', 'r8', r8lib_jar, r8lib_map, |
| '--input', 'pg', pg_output, pg_map]) |
| |
| |
| if __name__ == '__main__': |
| main(**vars(parser.parse_args())) |