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

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

Issue 1373443004: Improve javac.py --incremental logic by having it recompile more files (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 wrapper = textwrap.TextWrapper(break_long_words=True, 102 wrapper = textwrap.TextWrapper(break_long_words=True,
102 drop_whitespace=False, 103 drop_whitespace=False,
103 subsequent_indent=' ', 104 subsequent_indent=' ',
104 width=_MAX_MANIFEST_LINE_LEN - 2) 105 width=_MAX_MANIFEST_LINE_LEN - 2)
105 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) 106 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l))
106 107
107 with open(manifest_path, 'w') as f: 108 with open(manifest_path, 'w') as f:
108 f.write(output) 109 f.write(output)
109 110
110 111
112 def _DetermineFilesToRecompile(java_files, changed_paths):
113 # Calculate the set of files that must be recompiled as those within
114 # |changed_paths| as well as those that contain a reference to a class within
115 # |changed_paths|.
116 # This approach only mostly works. It's possible for a constant to be inlined
117 # across multiple files like so:
118 # class A { static final int foo = 1; }
119 # class B { static final int bar = A.foo; }
120 # class C { static final int baz = B.bar; }
121 # In this case, when A changes, A and B will be recompiled, but C will not.
122 changed_java_files = [p for p in java_files if p in changed_paths]
123 java_files_to_recompile = list(changed_java_files)
124
125 changed_class_names = []
126 for path in java_files_to_recompile:
127 class_name, _ = os.path.splitext(os.path.basename(path))
128 changed_class_names.append(class_name)
129
130 class_name_pattern = re.compile(r'\b(?:%s)\b' % '|'.join(changed_class_names))
Yaron 2015/09/25 18:34:09 I'm having trouble thinking this through but make
agrieve 2015/09/25 18:49:44 You can't reference an inner class without typing
131 for path in java_files:
132 if path in changed_paths:
133 continue
134 with open(path, 'rb') as fileobj:
135 data = fileobj.read()
136 if class_name_pattern.search(data):
137 java_files_to_recompile.append(path)
138 return java_files_to_recompile
139
140
111 def _ExtractClassFiles(jar_path, dest_dir, java_files): 141 def _ExtractClassFiles(jar_path, dest_dir, java_files):
112 """Extracts all .class files not corresponding to |java_files|.""" 142 """Extracts all .class files not corresponding to |java_files|."""
113 # Two challenges exist here: 143 # Two challenges exist here:
114 # 1. |java_files| have prefixes that are not represented in the the jar paths. 144 # 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 145 # 2. A single .java file results in multiple .class files when it contains
116 # nested classes. 146 # nested classes.
117 # Here's an example: 147 # Here's an example:
118 # source path: ../../base/android/java/src/org/chromium/Foo.java 148 # source path: ../../base/android/java/src/org/chromium/Foo.java
119 # jar paths: org/chromium/Foo.class, org/chromium/Foo$Inner.class 149 # 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 150 # 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. 151 # off ".class" and "$*.class" and use a substring match against java_files.
122 def extract_predicate(path): 152 def extract_predicate(path):
123 if not path.endswith('.class'): 153 if not path.endswith('.class'):
124 return False 154 return False
125 path_without_suffix = re.sub(r'(?:\$[^/]+)?\.class$', '', path) 155 path_without_suffix = re.sub(r'(?:\$|\.)[^/]+class$', '', path)
126 return not any(path_without_suffix in p for p in java_files) 156 partial_java_path = path_without_suffix + '.java'
157 ret = not any(p.endswith(partial_java_path) for p in java_files)
158 return ret
Yaron 2015/09/25 18:34:09 merge with line above
agrieve 2015/09/25 18:49:44 Done.
127 159
128 build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate) 160 build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate)
129 161
130 162
131 def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs, 163 def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs,
132 runtime_classpath): 164 runtime_classpath):
133 with build_utils.TempDir() as temp_dir: 165 with build_utils.TempDir() as temp_dir:
134 srcjars = options.java_srcjars 166 srcjars = options.java_srcjars
135 # The .excluded.jar contains .class files excluded from the main jar. 167 # The .excluded.jar contains .class files excluded from the main jar.
136 # It is used for incremental compiles. 168 # It is used for incremental compiles.
137 excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar') 169 excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar')
138 170
139 classes_dir = os.path.join(temp_dir, 'classes') 171 classes_dir = os.path.join(temp_dir, 'classes')
140 os.makedirs(classes_dir) 172 os.makedirs(classes_dir)
141 173
142 changed_paths = None 174 changed_paths = None
143 if options.incremental and changes.AddedOrModifiedOnly(): 175 if options.incremental and changes.AddedOrModifiedOnly():
144 changed_paths = set(changes.IterChangedPaths()) 176 changed_paths = set(changes.IterChangedPaths())
145 # Do a full compile if classpath has changed. 177 # Do a full compile if classpath has changed.
146 if any(p in changed_paths for p in classpath_inputs): 178 if any(p in changed_paths for p in classpath_inputs):
147 changed_paths = None 179 changed_paths = None
148 else: 180 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] 181 srcjars = [p for p in srcjars if p in changed_paths]
151 182
152 if srcjars: 183 if srcjars:
153 java_dir = os.path.join(temp_dir, 'java') 184 java_dir = os.path.join(temp_dir, 'java')
154 os.makedirs(java_dir) 185 os.makedirs(java_dir)
155 for srcjar in options.java_srcjars: 186 for srcjar in options.java_srcjars:
156 extract_predicate = None
157 if changed_paths: 187 if changed_paths:
158 changed_subpaths = set(changes.IterChangedSubpaths(srcjar)) 188 changed_paths.update(changes.IterChangedSubpaths(srcjar))
159 extract_predicate = lambda p: p in changed_subpaths 189 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') 190 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java')
163 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes)) 191 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes))
164 192
193 if changed_paths:
194 java_files = _DetermineFilesToRecompile(java_files, changed_paths)
195 if md5_check.PRINT_EXPLANATIONS:
196 print 'Files to recompile:'
197 print ' ' + '\n '.join(java_files)
198
165 if java_files: 199 if java_files:
166 if changed_paths: 200 if changed_paths:
167 # When no files have been removed and the output jar already 201 # When no files have been removed and the output jar already
168 # exists, reuse .class files from the existing jar. 202 # exists, reuse .class files from the existing jar.
169 _ExtractClassFiles(options.jar_path, classes_dir, java_files) 203 _ExtractClassFiles(options.jar_path, classes_dir, java_files)
170 _ExtractClassFiles(excluded_jar_path, classes_dir, java_files) 204 _ExtractClassFiles(excluded_jar_path, classes_dir, java_files)
171 # Add the extracted files to the classpath. 205 # Add the extracted files to the classpath.
172 classpath_idx = javac_cmd.index('-classpath') 206 classpath_idx = javac_cmd.index('-classpath')
173 javac_cmd[classpath_idx + 1] += ':' + classes_dir 207 javac_cmd[classpath_idx + 1] += ':' + classes_dir
174 208
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 options, 405 options,
372 input_paths=input_paths, 406 input_paths=input_paths,
373 input_strings=javac_cmd, 407 input_strings=javac_cmd,
374 output_paths=output_paths, 408 output_paths=output_paths,
375 force=force, 409 force=force,
376 pass_changes=True) 410 pass_changes=True)
377 411
378 412
379 if __name__ == '__main__': 413 if __name__ == '__main__':
380 sys.exit(main(sys.argv[1:])) 414 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