blob: abda4937f6e6f5cc419300c340fc683799d3161b [file] [log] [blame]
Ian Zerny37097652019-04-11 13:13:27 +02001#!/usr/bin/env python
2# Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6# Run R8 on a simple Hello World program
7# Report Golem-compatible RunTimeRaw values:
8#
9# <NAME>-Total(RunTimeRaw): <time> ms
10#
11# where <NAME> is Hello{,Dex}{,Large}{,NoOpt}
12
13import argparse
14import os
15import subprocess
16import sys
17import time
18import zipfile
19
20import golem
21import jdk
22import utils
23
24HELLO_JAR = os.path.join(utils.BUILD, 'test', 'examples', 'hello.jar')
25
26EXTRA_INPUTS = [
27 os.path.join(utils.THIRD_PARTY, 'sample_libraries', lib) for lib in [
28 'animal-sniffer-annotations-1.17.jar',
29 'annotations-13.0.jar',
30 'checker-compat-qual-2.5.2.jar',
31 'collections-28.0.0.jar',
32 'common-1.1.1.jar',
33 'commons-collections4-4.3.jar',
34 'commons-compress-1.18.jar',
35 'commons-lang3-3.8.1.jar',
36 'commons-math3-3.6.1.jar',
37 'constraint-layout-solver-1.1.3.jar',
38 'converter-gson-2.5.0.jar',
39 'dagger-2.22.1.jar',
40 'error_prone_annotations-2.2.0.jar',
41 'failureaccess-1.0.1.jar',
42 'gson-2.8.2.jar',
43 'guava-27.1-android.jar',
44 'j2objc-annotations-1.1.jar',
45 'javax.inject-1.jar',
46 'jsr305-3.0.2.jar',
47 'kotlin-stdlib-1.3.21.jar',
48 'kotlin-stdlib-common-1.3.21.jar',
49 'kotlin-stdlib-jdk7-1.3.21.jar',
50 'listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar',
51 'okhttp-3.14.0.jar',
52 'okio-1.17.2.jar',
53 'play-services-ads-17.2.0-javadoc.jar',
54 'play-services-ads-base-17.2.0-javadoc.jar',
55 'play-services-ads-lite-17.2.0-javadoc.jar',
56 'play-services-analytics-16.0.8-javadoc.jar',
57 'play-services-analytics-impl-16.0.8-javadoc.jar',
58 'play-services-base-16.1.0-javadoc.jar',
59 'play-services-basement-16.2.0-javadoc.jar',
60 'play-services-cast-16.1.2-javadoc.jar',
61 'play-services-drive-16.1.0-javadoc.jar',
62 'play-services-fitness-16.0.1-javadoc.jar',
63 'play-services-games-17.0.0-javadoc.jar',
64 'play-services-gass-17.2.0-javadoc.jar',
65 'play-services-gcm-16.1.0-javadoc.jar',
66 'play-services-iid-16.0.1-javadoc.jar',
67 'play-services-measurement-16.4.0-javadoc.jar',
68 'play-services-measurement-api-16.4.0-javadoc.jar',
69 'play-services-measurement-base-16.4.0-javadoc.jar',
70 'play-services-measurement-impl-16.4.0-javadoc.jar',
71 'play-services-measurement-sdk-16.4.0-javadoc.jar',
72 'play-services-measurement-sdk-api-16.4.0-javadoc.jar',
73 'play-services-tagmanager-v4-impl-16.0.8-javadoc.jar',
74 'play-services-vision-17.0.2-javadoc.jar',
75 'play-services-vision-common-17.0.2-javadoc.jar',
76 'protobuf-lite-3.0.1.jar',
77 'reactive-streams-1.0.2.jar',
78 'retrofit-2.5.0.jar',
79 'rxjava-2.2.8.jar',
80 'support-annotations-28.0.0.jar',
81 ]
82]
83
84EXTRA_KEEP_RULES = ['-dontwarn java.lang.ClassValue']
85
86def parse_arguments():
87 parser = argparse.ArgumentParser(
88 description = 'Compile a hello world example program')
89 parser.add_argument('--tool',
90 choices = ['d8', 'r8', 'pg'],
91 required = True,
92 help = 'Compiler tool to use.')
93 parser.add_argument('--output-mode',
94 choices = ['dex', 'cf'],
95 required = True,
96 help = 'Output mode to compile to.')
97 parser.add_argument('--golem',
98 help = 'Running on golem, link in third_party resources.',
99 default = False,
100 action = 'store_true')
101 parser.add_argument('--large',
102 help = 'Add many additional program inputs.',
103 default = False,
104 action = 'store_true')
105 parser.add_argument('--noopt',
106 help = 'Disable most optimizations/processing.',
107 default = False,
108 action = 'store_true')
109 parser.add_argument('--print-memoryuse',
110 help = 'Prints the line \'<NAME>-Total(MemoryUse):'
111 ' <mem>\' at the end where <mem> is the peak'
112 ' peak resident set size (VmHWM) in bytes.',
113 default = False,
114 action = 'store_true')
115 parser.add_argument('--output',
116 help = 'Output directory to keep the generated files')
117 return parser.parse_args()
118
119def GetConfRules(extra, noopt):
120 rules = ['-keep class hello.Hello { void main(java.lang.String[]); }']
121 if len(extra) > 0:
122 rules.extend(EXTRA_KEEP_RULES)
123 if noopt:
124 rules.extend([
125 '-dontoptimize',
126 '-dontshrink',
127 '-dontobfuscate',
128 '-keepattributes *',
129 ])
130 return rules
131
132def GetCompilerPrefix(tool, mode, output, input, lib, extra, noopt):
133 return [
134 jdk.GetJavaExecutable(),
135 '-jar', utils.R8_JAR if tool == 'r8' else utils.D8_JAR,
136 '--output', output,
137 '--lib', lib,
138 '--debug' if noopt else '--release',
139 input,
140 ] + ([] if mode == 'cf' else ['--min-api', '21']) + extra
141
142def Compile(tool, output_mode, lib, extra, output_dir, noopt, temp_dir):
143 output = os.path.join(output_dir, 'out.zip')
144 if tool == 'd8':
145 if output_mode != 'dex':
146 raise ValueError('Invalid output mode for D8')
Ian Zerny92545362019-05-06 10:46:55 +0200147 classpath = []
148 for cp_entry in extra:
149 classpath.extend(['--classpath', cp_entry])
Ian Zerny37097652019-04-11 13:13:27 +0200150 return [
Ian Zerny92545362019-05-06 10:46:55 +0200151 GetCompilerPrefix(
152 tool, output_mode, output, HELLO_JAR, lib, classpath, noopt)
Ian Zerny37097652019-04-11 13:13:27 +0200153 ]
154 # The compilation is either R8 or PG.
155 # Write keep rules to a temporary file.
156 rules = GetConfRules(extra, noopt)
157 rules_file = os.path.join(temp_dir, 'rules.conf')
158 open(rules_file, 'w').write('\n'.join(rules))
159 if tool == 'r8':
160 cmd = GetCompilerPrefix(
161 tool, output_mode, output, HELLO_JAR, lib, extra, noopt)
162 cmd.extend(['--pg-conf', rules_file])
163 if output_mode == 'cf':
164 cmd.append('--classfile')
165 return [cmd]
166 if tool == 'pg':
167 # Build PG invokation with additional rules to silence warnings.
168 pg_out = output if output_mode == 'cf' \
169 else os.path.join(output_dir, 'pgout.zip')
170 cmds = [[
171 jdk.GetJavaExecutable(),
172 '-jar', utils.PROGUARD_JAR,
173 '-injars', ':'.join([HELLO_JAR] + extra),
174 '-libraryjars', lib,
175 '-outjars', pg_out,
176 '-dontwarn **',
177 '@' + rules_file
178 ]]
179 if output_mode == 'dex':
180 cmds.append(
181 GetCompilerPrefix('d8', 'dex', output, pg_out, lib, [], noopt))
182 return cmds
183 raise ValueError('Unknown tool: ' + tool)
184
185def ProcessInput(input, tmp_dir):
186 if not input.endswith('.aar'):
187 return input
188 out_dir = os.path.join(tmp_dir, input)
189 os.makedirs(out_dir)
190 zip = zipfile.ZipFile(input, 'r')
191 zip.extractall(out_dir)
192 zip.close()
193 return os.path.join(out_dir, 'classes.jar')
194
195def Main():
196 args = parse_arguments()
197 if args.golem:
198 golem.link_third_party()
199 utils.check_java_version()
200
201 with utils.TempDir() as temp_dir:
202 cmd_prefix = []
203 output_dir = args.output if args.output else temp_dir
204 temp_dir = os.path.join(args.output, 'tmp') if args.output else temp_dir
205
206 track_memory_file = None
207 if args.print_memoryuse:
208 track_memory_file = os.path.join(output_dir, utils.MEMORY_USE_TMP_FILE)
209 cmd_prefix.extend(['tools/track_memory.sh', track_memory_file])
210
Ian Zerny08ad2c32019-04-11 13:30:32 +0200211 name = 'CompileHelloExample'
Ian Zerny37097652019-04-11 13:13:27 +0200212
213 tool = args.tool
214 output_mode = args.output_mode
215 lib = None
216 if output_mode == 'dex':
217 name += 'Dex'
218 lib = utils.get_android_jar(28)
219 else:
220 lib = utils.RT_JAR
221
222 extra = []
223 if args.large:
224 name += 'Large'
225 extra = EXTRA_INPUTS
226
227 if args.noopt:
228 name += 'NoOpt'
229
230 cmds = Compile(
231 tool,
232 output_mode,
233 lib,
234 extra,
235 output_dir,
236 args.noopt,
237 temp_dir,
238 )
239
240 t0 = time.time()
241 for cmd in cmds:
242 fullcmd = cmd_prefix + cmd
243 utils.PrintCmd(fullcmd)
Ian Zerny678683a2019-05-07 11:28:23 +0200244 subprocess.check_output(fullcmd)
Ian Zerny37097652019-04-11 13:13:27 +0200245 dt = time.time() - t0
246
247 if args.print_memoryuse:
248 print('{}(MemoryUse): {}'
249 .format(name, utils.grep_memoryuse(track_memory_file)))
250
251 print('{}(RunTimeRaw): {} ms'
252 .format(name, 1000.0 * dt))
253
254if __name__ == '__main__':
255 sys.exit(Main())