Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Side by Side Diff: build/android/gyp/javac.py

Issue 1361733002: Make javac invocations incremental when possible (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@apkbuilder
Patch Set: add flag and disable by default Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/android/gyp/jar.py ('k') | build/android/gyp/util/build_utils.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2013 The Chromium Authors. All rights reserved. 3 # Copyright 2013 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 import optparse 7 import optparse
8 import os 8 import os
9 import shutil 9 import shutil
10 import re 10 import re
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 wrapper = textwrap.TextWrapper(break_long_words=True, 101 wrapper = textwrap.TextWrapper(break_long_words=True,
102 drop_whitespace=False, 102 drop_whitespace=False,
103 subsequent_indent=' ', 103 subsequent_indent=' ',
104 width=_MAX_MANIFEST_LINE_LEN - 2) 104 width=_MAX_MANIFEST_LINE_LEN - 2)
105 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) 105 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l))
106 106
107 with open(manifest_path, 'w') as f: 107 with open(manifest_path, 'w') as f:
108 f.write(output) 108 f.write(output)
109 109
110 110
111 def _ExtractClassFiles(jar_path, dest_dir, java_files):
112 """Extracts all .class files not corresponding to |java_files|."""
113 # Two challenges exist here:
114 # 1. |java_files| have prefixes that are not represented in the the jar paths.
115 # 2. A single .java file results in multiple .class files when it contains
116 # nested classes.
117 # Here's an example:
118 # source path: ../../base/android/java/src/org/chromium/Foo.java
119 # jar paths: org/chromium/Foo.class, org/chromium/Foo$Inner.class
120 # To extract only .class files not related to the given .java files, we strip
121 # off ".class" and "$*.class" and use a substring match against java_files.
122 def extract_predicate(path):
123 if not path.endswith('.class'):
124 return False
125 path_without_suffix = re.sub(r'(?:\$[^/]+)?\.class$', '', path)
126 return not any(path_without_suffix in p for p in java_files)
127
128 build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate)
129
130
131 def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs,
132 runtime_classpath):
133 with build_utils.TempDir() as temp_dir:
134 srcjars = options.java_srcjars
135 # The .excluded.jar contains .class files excluded from the main jar.
136 # It is used for incremental compiles.
137 excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar')
138
139 classes_dir = os.path.join(temp_dir, 'classes')
140 os.makedirs(classes_dir)
141
142 changed_paths = None
143 if options.incremental and changes.AddedOrModifiedOnly():
144 changed_paths = set(changes.IterChangedPaths())
145 # Do a full compile if classpath has changed.
146 if any(p in changed_paths for p in classpath_inputs):
147 changed_paths = None
148 else:
149 java_files = [p for p in java_files if p in changed_paths]
150 srcjars = [p for p in srcjars if p in changed_paths]
151
152 if srcjars:
153 java_dir = os.path.join(temp_dir, 'java')
154 os.makedirs(java_dir)
155 for srcjar in options.java_srcjars:
156 extract_predicate = None
157 if changed_paths:
158 changed_subpaths = set(changes.IterChangedSubpaths(srcjar))
159 extract_predicate = lambda p: p in changed_subpaths
160 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java',
161 predicate=extract_predicate)
162 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java')
163 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes))
164
165 if java_files:
166 if changed_paths:
167 # When no files have been removed and the output jar already
168 # exists, reuse .class files from the existing jar.
169 _ExtractClassFiles(options.jar_path, classes_dir, java_files)
170 _ExtractClassFiles(excluded_jar_path, classes_dir, java_files)
171 # Add the extracted files to the classpath.
172 classpath_idx = javac_cmd.index('-classpath')
173 javac_cmd[classpath_idx + 1] += ':' + classes_dir
174
175 # Don't include the output directory in the initial set of args since it
176 # being in a temp dir makes it unstable (breaks md5 stamping).
177 cmd = javac_cmd + ['-d', classes_dir] + java_files
178
179 build_utils.CheckOutput(
180 cmd,
181 print_stdout=options.chromium_code,
182 stderr_filter=ColorJavacOutput)
183
184 if options.main_class or options.manifest_entry:
185 entries = []
186 if options.manifest_entry:
187 entries = [e.split(':') for e in options.manifest_entry]
188 manifest_file = os.path.join(temp_dir, 'manifest')
189 _CreateManifest(manifest_file, runtime_classpath, options.main_class,
190 entries)
191 else:
192 manifest_file = None
193
194 glob = options.jar_excluded_classes
195 inclusion_predicate = lambda f: not build_utils.MatchesGlob(f, glob)
196 exclusion_predicate = lambda f: not inclusion_predicate(f)
197
198 jar.JarDirectory(classes_dir,
199 options.jar_path,
200 manifest_file=manifest_file,
201 predicate=inclusion_predicate)
202 jar.JarDirectory(classes_dir,
203 excluded_jar_path,
204 predicate=exclusion_predicate)
205
206
111 def _ParseOptions(argv): 207 def _ParseOptions(argv):
112 parser = optparse.OptionParser() 208 parser = optparse.OptionParser()
113 build_utils.AddDepfileOption(parser) 209 build_utils.AddDepfileOption(parser)
114 210
115 parser.add_option( 211 parser.add_option(
116 '--src-gendirs', 212 '--src-gendirs',
117 help='Directories containing generated java files.') 213 help='Directories containing generated java files.')
118 parser.add_option( 214 parser.add_option(
119 '--java-srcjars', 215 '--java-srcjars',
120 action='append', 216 action='append',
121 default=[], 217 default=[],
122 help='List of srcjars to include in compilation.') 218 help='List of srcjars to include in compilation.')
123 parser.add_option( 219 parser.add_option(
124 '--bootclasspath', 220 '--bootclasspath',
125 action='append', 221 action='append',
126 default=[], 222 default=[],
127 help='Boot classpath for javac. If this is specified multiple times, ' 223 help='Boot classpath for javac. If this is specified multiple times, '
128 'they will all be appended to construct the classpath.') 224 'they will all be appended to construct the classpath.')
129 parser.add_option( 225 parser.add_option(
130 '--classpath', 226 '--classpath',
131 action='append', 227 action='append',
132 help='Classpath for javac. If this is specified multiple times, they ' 228 help='Classpath for javac. If this is specified multiple times, they '
133 'will all be appended to construct the classpath.') 229 'will all be appended to construct the classpath.')
134 parser.add_option( 230 parser.add_option(
135 '--use-ijars', 231 '--use-ijars',
136 action='store_true', 232 action='store_true',
137 help='Whether to use interface jars (.interface.jar) when compiling') 233 help='Whether to use interface jars (.interface.jar) when compiling')
138 parser.add_option( 234 parser.add_option(
235 '--incremental',
236 action='store_true',
237 help='Whether to re-use .class files rather than recompiling them '
238 '(when possible).')
239 parser.add_option(
139 '--javac-includes', 240 '--javac-includes',
140 default='', 241 default='',
141 help='A list of file patterns. If provided, only java files that match' 242 help='A list of file patterns. If provided, only java files that match'
142 'one of the patterns will be compiled.') 243 'one of the patterns will be compiled.')
143 parser.add_option( 244 parser.add_option(
144 '--jar-excluded-classes', 245 '--jar-excluded-classes',
145 default='', 246 default='',
146 help='List of .class file patterns to exclude from the jar.') 247 help='List of .class file patterns to exclude from the jar.')
147 248
148 parser.add_option( 249 parser.add_option(
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 333
233 if options.chromium_code: 334 if options.chromium_code:
234 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed. 335 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed.
235 javac_cmd.extend(['-Xlint:unchecked']) 336 javac_cmd.extend(['-Xlint:unchecked'])
236 else: 337 else:
237 # XDignore.symbol.file makes javac compile against rt.jar instead of 338 # XDignore.symbol.file makes javac compile against rt.jar instead of
238 # ct.sym. This means that using a java internal package/class will not 339 # ct.sym. This means that using a java internal package/class will not
239 # trigger a compile warning or error. 340 # trigger a compile warning or error.
240 javac_cmd.extend(['-XDignore.symbol.file']) 341 javac_cmd.extend(['-XDignore.symbol.file'])
241 342
242 # Compute the list of paths that when changed, we need to rebuild. 343 classpath_inputs = options.bootclasspath
243 input_paths = options.bootclasspath + options.java_srcjars + java_files
244 # TODO(agrieve): Remove this .TOC heuristic once GYP is no more. 344 # TODO(agrieve): Remove this .TOC heuristic once GYP is no more.
245 if not options.use_ijars: 345 if options.use_ijars:
346 classpath_inputs.extend(compile_classpath)
347 else:
246 for path in compile_classpath: 348 for path in compile_classpath:
247 if os.path.exists(path + '.TOC'): 349 if os.path.exists(path + '.TOC'):
248 input_paths.append(path + '.TOC') 350 classpath_inputs.append(path + '.TOC')
249 else: 351 else:
250 input_paths.append(path) 352 classpath_inputs.append(path)
251 353
252 def on_stale_md5(): 354 # Compute the list of paths that when changed, we need to rebuild.
253 with build_utils.TempDir() as temp_dir: 355 input_paths = classpath_inputs + options.java_srcjars + java_files
254 if options.java_srcjars:
255 java_dir = os.path.join(temp_dir, 'java')
256 os.makedirs(java_dir)
257 for srcjar in options.java_srcjars:
258 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java')
259 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java')
260 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes))
261 356
262 classes_dir = os.path.join(temp_dir, 'classes') 357 output_paths = [
263 os.makedirs(classes_dir) 358 options.jar_path,
359 options.jar_path.replace('.jar', '.excluded.jar'),
360 ]
264 361
265 if java_files: 362 # An escape hatch to be able to check if incremental compiles are causing
266 # Don't include the output directory in the initial set of args since it 363 # problems.
267 # being in a temp dir makes it unstable (breaks md5 stamping). 364 force = int(os.environ.get('DISABLE_INCREMENTAL_JAVAC', 0))
268 cmd = javac_cmd + ['-d', classes_dir] + java_files
269
270 build_utils.CheckOutput(
271 cmd,
272 print_stdout=options.chromium_code,
273 stderr_filter=ColorJavacOutput)
274
275 if options.main_class or options.manifest_entry:
276 entries = []
277 if options.manifest_entry:
278 entries = [e.split(':') for e in options.manifest_entry]
279 manifest_file = os.path.join(temp_dir, 'manifest')
280 _CreateManifest(manifest_file, runtime_classpath, options.main_class,
281 entries)
282 else:
283 manifest_file = None
284 jar.JarDirectory(classes_dir,
285 options.jar_excluded_classes,
286 options.jar_path,
287 manifest_file=manifest_file)
288
289 365
290 # List python deps in input_strings rather than input_paths since the contents 366 # List python deps in input_strings rather than input_paths since the contents
291 # of them does not change what gets written to the depsfile. 367 # of them does not change what gets written to the depsfile.
292 build_utils.CallAndWriteDepfileIfStale( 368 build_utils.CallAndWriteDepfileIfStale(
293 on_stale_md5, 369 lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files,
370 classpath_inputs, runtime_classpath),
294 options, 371 options,
295 input_paths=input_paths, 372 input_paths=input_paths,
296 input_strings=javac_cmd, 373 input_strings=javac_cmd,
297 output_paths=[options.jar_path]) 374 output_paths=output_paths,
375 force=force,
376 pass_changes=True)
298 377
299 378
300 if __name__ == '__main__': 379 if __name__ == '__main__':
301 sys.exit(main(sys.argv[1:])) 380 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « build/android/gyp/jar.py ('k') | build/android/gyp/util/build_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698