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

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

Issue 1373723003: Fix javac --incremental by using jmake for dependency analysis (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@aidl
Patch Set: review comments Created 5 years, 2 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 | « no previous file | build/android/gyp/util/md5_check.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
11 import sys 11 import sys
12 import textwrap 12 import textwrap
13 13
14 from util import build_utils 14 from util import build_utils
15 from util import md5_check
15 16
16 import jar 17 import jar
17 18
18 sys.path.append(build_utils.COLORAMA_ROOT) 19 sys.path.append(build_utils.COLORAMA_ROOT)
19 import colorama 20 import colorama
20 21
21 22
22 def ColorJavacOutput(output): 23 def ColorJavacOutput(output):
23 fileline_prefix = r'(?P<fileline>(?P<file>[-.\w/\\]+.java):(?P<line>[0-9]+):)' 24 fileline_prefix = r'(?P<fileline>(?P<file>[-.\w/\\]+.java):(?P<line>[0-9]+):)'
24 warning_re = re.compile( 25 warning_re = re.compile(
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 # 2. A single .java file results in multiple .class files when it contains 116 # 2. A single .java file results in multiple .class files when it contains
116 # nested classes. 117 # nested classes.
117 # Here's an example: 118 # Here's an example:
118 # source path: ../../base/android/java/src/org/chromium/Foo.java 119 # source path: ../../base/android/java/src/org/chromium/Foo.java
119 # jar paths: org/chromium/Foo.class, org/chromium/Foo$Inner.class 120 # 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 # 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 # off ".class" and "$*.class" and use a substring match against java_files.
122 def extract_predicate(path): 123 def extract_predicate(path):
123 if not path.endswith('.class'): 124 if not path.endswith('.class'):
124 return False 125 return False
125 path_without_suffix = re.sub(r'(?:\$[^/]+)?\.class$', '', path) 126 path_without_suffix = re.sub(r'(?:\$|\.)[^/]+class$', '', path)
126 return not any(path_without_suffix in p for p in java_files) 127 partial_java_path = path_without_suffix + '.java'
128 return not any(p.endswith(partial_java_path) for p in java_files)
127 129
128 build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate) 130 build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate)
131 for path in build_utils.FindInDirectory(dest_dir, '*.class'):
132 shutil.copystat(jar_path, path)
133
134
135 def _ConvertToJMakeArgs(javac_cmd, pdb_path):
136 new_args = ['bin/jmake', '-pdb', pdb_path]
137 if javac_cmd[0] != 'javac':
138 new_args.extend(('-jcexec', new_args[0]))
139 if md5_check.PRINT_EXPLANATIONS:
140 new_args.append('-Xtiming')
141
142 do_not_prefix = ('-classpath', '-bootclasspath')
Yaron 2015/10/01 17:21:20 make list?
143 skip_next = False
144 for arg in javac_cmd[1:]:
145 if not skip_next and arg not in do_not_prefix:
146 arg = '-C' + arg
147 new_args.append(arg)
148 skip_next = arg in do_not_prefix
149
150 return new_args
151
152
153 def _FilterJMakeOutput(stdout):
154 if md5_check.PRINT_EXPLANATIONS:
155 return stdout
156 return re.sub(r'\b(Jmake version|Writing project database).*?\n', '', stdout)
157
158
159 def _FixTempPathsInIncrementalMetadata(pdb_path, temp_dir):
160 # The .pdb records absolute paths. Fix up paths within /tmp (srcjars).
161 if os.path.exists(pdb_path):
162 # Although its a binary file, search/replace still seems to work fine.
163 with open(pdb_path) as fileobj:
164 pdb_data = fileobj.read()
165 with open(pdb_path, 'w') as fileobj:
166 fileobj.write(re.sub(r'/tmp/[^/]*', temp_dir, pdb_data))
129 167
130 168
131 def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs, 169 def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs,
132 runtime_classpath): 170 runtime_classpath):
133 with build_utils.TempDir() as temp_dir: 171 with build_utils.TempDir() as temp_dir:
134 srcjars = options.java_srcjars 172 srcjars = options.java_srcjars
135 # The .excluded.jar contains .class files excluded from the main jar. 173 # The .excluded.jar contains .class files excluded from the main jar.
136 # It is used for incremental compiles. 174 # It is used for incremental compiles.
137 excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar') 175 excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar')
138 176
139 classes_dir = os.path.join(temp_dir, 'classes') 177 classes_dir = os.path.join(temp_dir, 'classes')
140 os.makedirs(classes_dir) 178 os.makedirs(classes_dir)
141 179
142 changed_paths = None 180 changed_paths = None
181 # jmake can handle deleted files, but it's a rare case and it would
182 # complicate this script's logic.
143 if options.incremental and changes.AddedOrModifiedOnly(): 183 if options.incremental and changes.AddedOrModifiedOnly():
144 changed_paths = set(changes.IterChangedPaths()) 184 changed_paths = set(changes.IterChangedPaths())
145 # Do a full compile if classpath has changed. 185 # Do a full compile if classpath has changed.
186 # jmake doesn't seem to do this on its own... Might be that ijars mess up
187 # its change-detection logic.
146 if any(p in changed_paths for p in classpath_inputs): 188 if any(p in changed_paths for p in classpath_inputs):
147 changed_paths = None 189 changed_paths = None
148 else: 190
149 java_files = [p for p in java_files if p in changed_paths] 191 if options.incremental:
150 srcjars = [p for p in srcjars if p in changed_paths] 192 # jmake is a compiler wrapper that figures out the minimal set of .java
193 # files that need to be rebuilt given a set of .java files that have
194 # changed.
195 # jmake determines what files are stale based on timestamps between .java
196 # and .class files. Since we use .jars, .srcjars, and md5 checks,
197 # timestamp info isn't accurate for this purpose. Rather than use jmake's
198 # programatic interface (like we eventually should), we ensure that all
199 # .class files are newer than their .java files, and convey to jmake which
200 # sources are stale by having their .class files be missing entirely
201 # (by not extracting them).
202 pdb_path = options.jar_path + '.pdb'
203 javac_cmd = _ConvertToJMakeArgs(javac_cmd, pdb_path)
204 if srcjars:
205 _FixTempPathsInIncrementalMetadata(pdb_path, temp_dir)
151 206
152 if srcjars: 207 if srcjars:
153 java_dir = os.path.join(temp_dir, 'java') 208 java_dir = os.path.join(temp_dir, 'java')
154 os.makedirs(java_dir) 209 os.makedirs(java_dir)
155 for srcjar in options.java_srcjars: 210 for srcjar in options.java_srcjars:
156 extract_predicate = None
157 if changed_paths: 211 if changed_paths:
158 changed_subpaths = set(changes.IterChangedSubpaths(srcjar)) 212 changed_paths.update(changes.IterChangedSubpaths(srcjar))
159 extract_predicate = lambda p: p in changed_subpaths 213 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java')
160 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java',
161 predicate=extract_predicate)
162 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java') 214 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java')
163 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes)) 215 jar_srcs = _FilterJavaFiles(jar_srcs, options.javac_includes)
216 java_files.extend(jar_srcs)
217 if changed_paths:
218 # Set the mtime of all sources to 0 since we use the absense of .class
219 # files to tell jmake which files are stale.
220 for path in jar_srcs:
221 os.utime(path, (0, 0))
164 222
165 if java_files: 223 if java_files:
166 if changed_paths: 224 if changed_paths:
167 # When no files have been removed and the output jar already 225 changed_java_files = [p for p in java_files if p in changed_paths]
168 # exists, reuse .class files from the existing jar. 226 if os.path.exists(options.jar_path):
169 _ExtractClassFiles(options.jar_path, classes_dir, java_files) 227 _ExtractClassFiles(options.jar_path, classes_dir, changed_java_files)
170 _ExtractClassFiles(excluded_jar_path, classes_dir, java_files) 228 if os.path.exists(excluded_jar_path):
171 # Add the extracted files to the classpath. 229 _ExtractClassFiles(excluded_jar_path, classes_dir, changed_java_files)
230 # Add the extracted files to the classpath. This is required because
231 # when compiling only a subset of files, classes that haven't changed
232 # need to be findable.
172 classpath_idx = javac_cmd.index('-classpath') 233 classpath_idx = javac_cmd.index('-classpath')
173 javac_cmd[classpath_idx + 1] += ':' + classes_dir 234 javac_cmd[classpath_idx + 1] += ':' + classes_dir
174 235
175 # Don't include the output directory in the initial set of args since it 236 # 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). 237 # being in a temp dir makes it unstable (breaks md5 stamping).
177 cmd = javac_cmd + ['-d', classes_dir] + java_files 238 cmd = javac_cmd + ['-d', classes_dir] + java_files
178 239
179 build_utils.CheckOutput( 240 build_utils.CheckOutput(
180 cmd, 241 cmd,
181 print_stdout=options.chromium_code, 242 print_stdout=options.chromium_code,
243 stdout_filter=_FilterJMakeOutput,
182 stderr_filter=ColorJavacOutput) 244 stderr_filter=ColorJavacOutput)
183 245
184 if options.main_class or options.manifest_entry: 246 if options.main_class or options.manifest_entry:
185 entries = [] 247 entries = []
186 if options.manifest_entry: 248 if options.manifest_entry:
187 entries = [e.split(':') for e in options.manifest_entry] 249 entries = [e.split(':') for e in options.manifest_entry]
188 manifest_file = os.path.join(temp_dir, 'manifest') 250 manifest_file = os.path.join(temp_dir, 'manifest')
189 _CreateManifest(manifest_file, runtime_classpath, options.main_class, 251 _CreateManifest(manifest_file, runtime_classpath, options.main_class,
190 entries) 252 entries)
191 else: 253 else:
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 else: 416 else:
355 classpath_inputs.append(path) 417 classpath_inputs.append(path)
356 418
357 # Compute the list of paths that when changed, we need to rebuild. 419 # Compute the list of paths that when changed, we need to rebuild.
358 input_paths = classpath_inputs + options.java_srcjars + java_files 420 input_paths = classpath_inputs + options.java_srcjars + java_files
359 421
360 output_paths = [ 422 output_paths = [
361 options.jar_path, 423 options.jar_path,
362 options.jar_path.replace('.jar', '.excluded.jar'), 424 options.jar_path.replace('.jar', '.excluded.jar'),
363 ] 425 ]
426 if options.incremental:
427 output_paths.append(options.jar_path + '.pdb')
364 428
365 # An escape hatch to be able to check if incremental compiles are causing 429 # An escape hatch to be able to check if incremental compiles are causing
366 # problems. 430 # problems.
367 force = int(os.environ.get('DISABLE_INCREMENTAL_JAVAC', 0)) 431 force = int(os.environ.get('DISABLE_INCREMENTAL_JAVAC', 0))
368 432
369 # List python deps in input_strings rather than input_paths since the contents 433 # List python deps in input_strings rather than input_paths since the contents
370 # of them does not change what gets written to the depsfile. 434 # of them does not change what gets written to the depsfile.
371 build_utils.CallAndWriteDepfileIfStale( 435 build_utils.CallAndWriteDepfileIfStale(
372 lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files, 436 lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files,
373 classpath_inputs, runtime_classpath), 437 classpath_inputs, runtime_classpath),
374 options, 438 options,
375 input_paths=input_paths, 439 input_paths=input_paths,
376 input_strings=javac_cmd, 440 input_strings=javac_cmd,
377 output_paths=output_paths, 441 output_paths=output_paths,
378 force=force, 442 force=force,
379 pass_changes=True) 443 pass_changes=True)
380 444
381 445
382 if __name__ == '__main__': 446 if __name__ == '__main__':
383 sys.exit(main(sys.argv[1:])) 447 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | build/android/gyp/util/md5_check.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698