blob: 29fed2c2ee22e53a7f891b09b0823d8aef0c4b7a [file] [log] [blame]
Ian Zerny5ffa58f2020-02-26 08:37:14 +01001#!/usr/bin/env python
2# Copyright (c) 2020, 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
Ian Zerny77bdf5f2020-07-08 11:46:24 +02006import archive
Ian Zerny5ffa58f2020-02-26 08:37:14 +01007import argparse
Ian Zerny77bdf5f2020-07-08 11:46:24 +02008import jdk
Ian Zerny5ffa58f2020-02-26 08:37:14 +01009import os
Ian Zerny77bdf5f2020-07-08 11:46:24 +020010import retrace
Ian Zerny5ffa58f2020-02-26 08:37:14 +010011import subprocess
12import sys
13import zipfile
14
Ian Zerny5ffa58f2020-02-26 08:37:14 +010015import utils
16
17
18def make_parser():
19 parser = argparse.ArgumentParser(description = 'Compile a dump artifact.')
20 parser.add_argument(
21 '-d',
22 '--dump',
Christoffer Quist Adamsend84a6f02020-05-16 12:29:35 +020023 help='Dump file or directory to compile',
Ian Zerny5ffa58f2020-02-26 08:37:14 +010024 default=None)
25 parser.add_argument(
Rico Wind9ed87b92020-03-06 12:37:18 +010026 '--temp',
27 help='Temp directory to extract the dump to, allows you to rerun the command'
28 ' more easily in the terminal with changes',
29 default=None)
30 parser.add_argument(
Ian Zerny5ffa58f2020-02-26 08:37:14 +010031 '-c',
32 '--compiler',
Rico Windf73f18d2020-03-03 09:28:54 +010033 help='Compiler to use',
Ian Zerny5ffa58f2020-02-26 08:37:14 +010034 default=None)
35 parser.add_argument(
36 '-v',
37 '--version',
38 help='Compiler version to use (default read from dump version file).'
39 'Valid arguments are:'
40 ' "master" to run from your own tree,'
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +010041 ' "source" to run from build classes directly,'
Ian Zerny5ffa58f2020-02-26 08:37:14 +010042 ' "X.Y.Z" to run a specific version, or'
43 ' <hash> to run that hash from master.',
44 default=None)
45 parser.add_argument(
Morten Krogh-Jespersend8bceb52020-03-06 12:56:48 +010046 '--r8-jar',
47 help='Path to an R8 jar.',
48 default=None)
49 parser.add_argument(
Morten Krogh-Jespersen9206a662020-11-23 08:47:06 +010050 '-override',
51 help='Do not override any extracted dump in temp-dir',
52 default=False,
53 action='store_true')
54 parser.add_argument(
Ian Zerny5ffa58f2020-02-26 08:37:14 +010055 '--nolib',
56 help='Use the non-lib distribution (default uses the lib distribution)',
57 default=False,
58 action='store_true')
59 parser.add_argument(
Rico Wind28653642020-03-31 13:59:07 +020060 '--printtimes',
61 help='Print timing information from r8',
62 default=False,
63 action='store_true')
64 parser.add_argument(
Ian Zerny5ffa58f2020-02-26 08:37:14 +010065 '--ea',
66 help='Enable Java assertions when running the compiler (default disabled)',
67 default=False,
68 action='store_true')
69 parser.add_argument(
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010070 '--classfile',
71 help='Run with classfile output',
72 default=False,
73 action='store_true')
74 parser.add_argument(
Ian Zerny5ffa58f2020-02-26 08:37:14 +010075 '--debug-agent',
76 help='Enable Java debug agent and suspend compilation (default disabled)',
77 default=False,
78 action='store_true')
Ian Zerny77bdf5f2020-07-08 11:46:24 +020079 parser.add_argument(
80 '--xmx',
81 help='Set JVM max heap size (-Xmx)',
82 default=None)
83 parser.add_argument(
84 '--threads',
85 help='Set the number of threads to use',
86 default=None)
87 parser.add_argument(
88 '--min-api',
89 help='Set min-api (default read from dump properties file)',
90 default=None)
Søren Gjesse7360f2b2020-08-10 09:13:35 +020091 parser.add_argument(
Clément Béradaae4ca2020-10-27 14:26:41 +000092 '--desugared-lib',
93 help='Set desugared-library (default set from dump)',
94 default=None)
95 parser.add_argument(
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +010096 '--disable-desugared-lib',
97 help='Disable desugared-libary if it will be set from dump',
98 default=False,
99 action='store_true'
100 )
101 parser.add_argument(
Søren Gjesse7360f2b2020-08-10 09:13:35 +0200102 '--loop',
103 help='Run the compilation in a loop',
104 default=False,
105 action='store_true')
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100106 return parser
107
108def error(msg):
109 print msg
110 sys.exit(1)
111
112class Dump(object):
113
114 def __init__(self, directory):
115 self.directory = directory
116
117 def if_exists(self, name):
118 f = os.path.join(self.directory, name)
119 if os.path.exists(f):
120 return f
121 return None
122
123 def program_jar(self):
124 return self.if_exists('program.jar')
125
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200126 def feature_jars(self):
127 feature_jars = []
128 i = 1
129 while True:
130 feature_jar = self.if_exists('feature-%s.jar' % i)
131 if feature_jar:
132 feature_jars.append(feature_jar)
133 i = i + 1
134 else:
135 return feature_jars
136
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100137 def library_jar(self):
138 return self.if_exists('library.jar')
139
140 def classpath_jar(self):
141 return self.if_exists('classpath.jar')
142
Clément Béradaae4ca2020-10-27 14:26:41 +0000143 def desugared_library_json(self):
144 return self.if_exists('desugared-library.json')
145
Clément Béra64a3c4c2020-11-10 08:16:17 +0000146 def proguard_input_map(self):
147 if self.if_exists('proguard_input.config'):
148 print "Unimplemented: proguard_input configuration."
149
150 def main_dex_resource(self):
151 if self.if_exists('main-dex-list.txt'):
152 print "Unimplemented: main-dex-list."
153
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200154 def build_properties_file(self):
155 return self.if_exists('build.properties')
156
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100157 def config_file(self):
158 return self.if_exists('proguard.config')
159
160 def version_file(self):
161 return self.if_exists('r8-version')
162
163 def version(self):
164 f = self.version_file()
165 if f:
166 return open(f).read().split(' ')[0]
167 return None
168
169def read_dump(args, temp):
170 if args.dump is None:
Christoffer Quist Adamsend84a6f02020-05-16 12:29:35 +0200171 error("A dump file or directory must be specified")
172 if os.path.isdir(args.dump):
173 return Dump(args.dump)
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200174 dump_file = zipfile.ZipFile(os.path.abspath(args.dump), 'r')
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100175 with utils.ChangedWorkingDirectory(temp):
Morten Krogh-Jespersen9206a662020-11-23 08:47:06 +0100176 if args.override or not os.path.isfile(
Morten Krogh-Jespersenc2af7692020-12-17 16:30:41 +0100177 os.path.join(temp, 'r8-version')):
Morten Krogh-Jespersen9206a662020-11-23 08:47:06 +0100178 print("Extracting into: %s" % temp)
179 dump_file.extractall()
Morten Krogh-Jespersenc2af7692020-12-17 16:30:41 +0100180 if not os.path.isfile(os.path.join(temp, 'r8-version')):
Morten Krogh-Jespersen9206a662020-11-23 08:47:06 +0100181 error("Did not extract into %s. Either the zip file is invalid or the "
182 "dump is missing files" % temp)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100183 return Dump(temp)
184
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200185def determine_build_properties(args, dump):
186 build_properties = {}
187 build_properties_file = dump.build_properties_file()
188 if build_properties_file:
189 with open(build_properties_file) as f:
190 build_properties_contents = f.readlines()
191 for line in build_properties_contents:
192 stripped = line.strip()
193 if stripped:
194 pair = stripped.split('=')
195 build_properties[pair[0]] = pair[1]
196 return build_properties
197
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100198def determine_version(args, dump):
199 if args.version is None:
200 return dump.version()
201 return args.version
202
203def determine_compiler(args, dump):
Rico Windf73f18d2020-03-03 09:28:54 +0100204 compilers = ['d8', 'r8', 'r8full']
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100205 if args.compiler not in compilers:
Rico Windf73f18d2020-03-03 09:28:54 +0100206 error("Unable to determine a compiler to use. Specified %s,"
207 " Valid options: %s" % (args.compiler, ', '.join(compilers)))
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100208 return args.compiler
209
210def determine_output(args, temp):
211 return os.path.join(temp, 'out.jar')
212
Ian Zerny77bdf5f2020-07-08 11:46:24 +0200213def determine_min_api(args, build_properties):
214 if args.min_api:
215 return args.min_api
216 if 'min-api' in build_properties:
217 return build_properties.get('min-api')
218 return None
219
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200220def determine_feature_output(feature_jar, temp):
221 return os.path.join(temp, os.path.basename(feature_jar)[:-4] + ".out.jar")
222
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100223def determine_program_jar(args, dump):
224 if hasattr(args, 'program_jar') and args.program_jar:
225 return args.program_jar
226 return dump.program_jar()
227
228def determine_class_file(args, build_properties):
229 if args.classfile:
230 return args.classfile
231 if 'classfile' in build_properties:
232 return True
233 return None
234
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100235def download_distribution(args, version, temp):
236 if version == 'master':
237 return utils.R8_JAR if args.nolib else utils.R8LIB_JAR
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100238 if version == 'source':
239 return '%s:%s' % (utils.BUILD_JAVA_MAIN_DIR, utils.ALL_DEPS_JAR)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100240 name = 'r8.jar' if args.nolib else 'r8lib.jar'
241 source = archive.GetUploadDestination(version, name, is_hash(version))
242 dest = os.path.join(temp, 'r8.jar')
243 utils.download_file_from_cloud_storage(source, dest)
244 return dest
245
246def prepare_wrapper(dist, temp):
247 wrapper_file = os.path.join(
248 utils.REPO_ROOT,
249 'src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java')
Ian Zerny268c9632020-11-13 11:36:35 +0100250 cmd = [
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100251 jdk.GetJavacExecutable(),
252 wrapper_file,
253 '-d', temp,
254 '-cp', dist,
Ian Zerny268c9632020-11-13 11:36:35 +0100255 ]
256 utils.PrintCmd(cmd)
257 subprocess.check_output(cmd)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100258 return temp
259
260def is_hash(version):
261 return len(version) == 40
262
Søren Gjesse7360f2b2020-08-10 09:13:35 +0200263def run1(out, args, otherargs):
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100264 with utils.TempDir() as temp:
Søren Gjesse7360f2b2020-08-10 09:13:35 +0200265 if out:
266 temp = out
Rico Wind9ed87b92020-03-06 12:37:18 +0100267 if not os.path.exists(temp):
268 os.makedirs(temp)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100269 dump = read_dump(args, temp)
Ian Zerny46bc4cf2020-08-03 15:58:27 +0200270 if not dump.program_jar():
271 error("Cannot compile dump with no program classes")
272 if not dump.library_jar():
273 print "WARNING: Unexpected lack of library classes in dump"
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200274 build_properties = determine_build_properties(args, dump)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100275 version = determine_version(args, dump)
276 compiler = determine_compiler(args, dump)
277 out = determine_output(args, temp)
Ian Zerny77bdf5f2020-07-08 11:46:24 +0200278 min_api = determine_min_api(args, build_properties)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100279 classfile = determine_class_file(args, build_properties)
Morten Krogh-Jespersend8bceb52020-03-06 12:56:48 +0100280 jar = args.r8_jar if args.r8_jar else download_distribution(args, version, temp)
Ian Zerny268c9632020-11-13 11:36:35 +0100281 if ':' not in jar and not os.path.exists(jar):
282 error("Distribution does not exist: " + jar)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100283 wrapper_dir = prepare_wrapper(jar, temp)
284 cmd = [jdk.GetJavaExecutable()]
285 if args.debug_agent:
286 if not args.nolib:
287 print "WARNING: Running debugging agent on r8lib is questionable..."
288 cmd.append(
289 '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005')
Ian Zerny77bdf5f2020-07-08 11:46:24 +0200290 if args.xmx:
291 cmd.append('-Xmx' + args.xmx)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100292 if args.ea:
293 cmd.append('-ea')
Rico Wind28653642020-03-31 13:59:07 +0200294 if args.printtimes:
295 cmd.append('-Dcom.android.tools.r8.printtimes=1')
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +0100296 if hasattr(args, 'properties'):
297 cmd.extend(args.properties);
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100298 cmd.extend(['-cp', '%s:%s' % (wrapper_dir, jar)])
299 if compiler == 'd8':
300 cmd.append('com.android.tools.r8.D8')
301 if compiler.startswith('r8'):
302 cmd.append('com.android.tools.r8.utils.CompileDumpCompatR8')
303 if compiler == 'r8':
304 cmd.append('--compat')
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100305 # For recompilation of dumps run_on_app_dumps pass in a program jar.
306 cmd.append(determine_program_jar(args, dump))
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100307 cmd.extend(['--output', out])
Christoffer Quist Adamsenfcfc63a2020-05-15 19:04:24 +0200308 for feature_jar in dump.feature_jars():
309 cmd.extend(['--feature-jar', feature_jar,
310 determine_feature_output(feature_jar, temp)])
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100311 if dump.library_jar():
312 cmd.extend(['--lib', dump.library_jar()])
313 if dump.classpath_jar():
314 cmd.extend(['--classpath', dump.classpath_jar()])
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +0100315 if dump.desugared_library_json() and not args.disable_desugared_lib:
Clément Béradaae4ca2020-10-27 14:26:41 +0000316 cmd.extend(['--desugared-lib', dump.desugared_library_json()])
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100317 if compiler != 'd8' and dump.config_file():
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100318 if hasattr(args, 'config_file_consumer') and args.config_file_consumer:
319 args.config_file_consumer(dump.config_file())
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100320 cmd.extend(['--pg-conf', dump.config_file()])
Ian Zerny588120b2020-04-03 13:08:03 +0200321 if compiler != 'd8':
322 cmd.extend(['--pg-map-output', '%s.map' % out])
Ian Zerny77bdf5f2020-07-08 11:46:24 +0200323 if min_api:
324 cmd.extend(['--min-api', min_api])
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100325 if classfile:
326 cmd.extend(['--classfile'])
Ian Zerny77bdf5f2020-07-08 11:46:24 +0200327 if args.threads:
328 cmd.extend(['--threads', args.threads])
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100329 cmd.extend(otherargs)
330 utils.PrintCmd(cmd)
331 try:
332 print subprocess.check_output(cmd, stderr=subprocess.STDOUT)
333 return 0
334 except subprocess.CalledProcessError, e:
335 print e.output
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100336 if not args.nolib and version != 'source':
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100337 stacktrace = os.path.join(temp, 'stacktrace')
338 open(stacktrace, 'w+').write(e.output)
339 local_map = utils.R8LIB_MAP if version == 'master' else None
340 hash_or_version = None if version == 'master' else version
341 print "=" * 80
342 print " RETRACED OUTPUT"
343 print "=" * 80
Morten Krogh-Jespersen64c52722020-10-27 08:33:42 +0100344 retrace.run(
345 local_map, hash_or_version, stacktrace, is_hash(version), no_r8lib=False)
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100346 return 1
347
Søren Gjesse7360f2b2020-08-10 09:13:35 +0200348def run(args, otherargs):
349 if (args.loop):
350 count = 1
351 while True:
352 print('Iteration {:03d}'.format(count))
353 out = args.temp
354 if out:
355 out = os.path.join(out, '{:03d}'.format(count))
356 run1(out, args, otherargs)
357 count += 1
358 else:
359 run1(args.temp, args, otherargs)
360
Ian Zerny5ffa58f2020-02-26 08:37:14 +0100361if __name__ == '__main__':
362 (args, otherargs) = make_parser().parse_known_args(sys.argv[1:])
363 sys.exit(run(args, otherargs))