|  | #!/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())) |