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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/android/gyp/javac.py
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index c95dc98eaa7c670703a79303ea22b11eaae8b524..728c49d5eef513191a56f85993dbf368898ffbfe 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -108,6 +108,102 @@ def _CreateManifest(manifest_path, classpath, main_class=None,
f.write(output)
+def _ExtractClassFiles(jar_path, dest_dir, java_files):
+ """Extracts all .class files not corresponding to |java_files|."""
+ # Two challenges exist here:
+ # 1. |java_files| have prefixes that are not represented in the the jar paths.
+ # 2. A single .java file results in multiple .class files when it contains
+ # nested classes.
+ # Here's an example:
+ # source path: ../../base/android/java/src/org/chromium/Foo.java
+ # jar paths: org/chromium/Foo.class, org/chromium/Foo$Inner.class
+ # To extract only .class files not related to the given .java files, we strip
+ # off ".class" and "$*.class" and use a substring match against java_files.
+ def extract_predicate(path):
+ if not path.endswith('.class'):
+ return False
+ path_without_suffix = re.sub(r'(?:\$[^/]+)?\.class$', '', path)
+ return not any(path_without_suffix in p for p in java_files)
+
+ build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate)
+
+
+def _OnStaleMd5(changes, options, javac_cmd, java_files, classpath_inputs,
+ runtime_classpath):
+ with build_utils.TempDir() as temp_dir:
+ srcjars = options.java_srcjars
+ # The .excluded.jar contains .class files excluded from the main jar.
+ # It is used for incremental compiles.
+ excluded_jar_path = options.jar_path.replace('.jar', '.excluded.jar')
+
+ classes_dir = os.path.join(temp_dir, 'classes')
+ os.makedirs(classes_dir)
+
+ changed_paths = None
+ if options.incremental and changes.AddedOrModifiedOnly():
+ changed_paths = set(changes.IterChangedPaths())
+ # Do a full compile if classpath has changed.
+ if any(p in changed_paths for p in classpath_inputs):
+ changed_paths = None
+ else:
+ java_files = [p for p in java_files if p in changed_paths]
+ srcjars = [p for p in srcjars if p in changed_paths]
+
+ if srcjars:
+ java_dir = os.path.join(temp_dir, 'java')
+ os.makedirs(java_dir)
+ for srcjar in options.java_srcjars:
+ extract_predicate = None
+ if changed_paths:
+ changed_subpaths = set(changes.IterChangedSubpaths(srcjar))
+ extract_predicate = lambda p: p in changed_subpaths
+ build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java',
+ predicate=extract_predicate)
+ jar_srcs = build_utils.FindInDirectory(java_dir, '*.java')
+ java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes))
+
+ if java_files:
+ if changed_paths:
+ # When no files have been removed and the output jar already
+ # exists, reuse .class files from the existing jar.
+ _ExtractClassFiles(options.jar_path, classes_dir, java_files)
+ _ExtractClassFiles(excluded_jar_path, classes_dir, java_files)
+ # Add the extracted files to the classpath.
+ classpath_idx = javac_cmd.index('-classpath')
+ javac_cmd[classpath_idx + 1] += ':' + classes_dir
+
+ # Don't include the output directory in the initial set of args since it
+ # being in a temp dir makes it unstable (breaks md5 stamping).
+ cmd = javac_cmd + ['-d', classes_dir] + java_files
+
+ build_utils.CheckOutput(
+ cmd,
+ print_stdout=options.chromium_code,
+ stderr_filter=ColorJavacOutput)
+
+ if options.main_class or options.manifest_entry:
+ entries = []
+ if options.manifest_entry:
+ entries = [e.split(':') for e in options.manifest_entry]
+ manifest_file = os.path.join(temp_dir, 'manifest')
+ _CreateManifest(manifest_file, runtime_classpath, options.main_class,
+ entries)
+ else:
+ manifest_file = None
+
+ glob = options.jar_excluded_classes
+ inclusion_predicate = lambda f: not build_utils.MatchesGlob(f, glob)
+ exclusion_predicate = lambda f: not inclusion_predicate(f)
+
+ jar.JarDirectory(classes_dir,
+ options.jar_path,
+ manifest_file=manifest_file,
+ predicate=inclusion_predicate)
+ jar.JarDirectory(classes_dir,
+ excluded_jar_path,
+ predicate=exclusion_predicate)
+
+
def _ParseOptions(argv):
parser = optparse.OptionParser()
build_utils.AddDepfileOption(parser)
@@ -136,6 +232,11 @@ def _ParseOptions(argv):
action='store_true',
help='Whether to use interface jars (.interface.jar) when compiling')
parser.add_option(
+ '--incremental',
+ action='store_true',
+ help='Whether to re-use .class files rather than recompiling them '
+ '(when possible).')
+ parser.add_option(
'--javac-includes',
default='',
help='A list of file patterns. If provided, only java files that match'
@@ -239,62 +340,40 @@ def main(argv):
# trigger a compile warning or error.
javac_cmd.extend(['-XDignore.symbol.file'])
- # Compute the list of paths that when changed, we need to rebuild.
- input_paths = options.bootclasspath + options.java_srcjars + java_files
+ classpath_inputs = options.bootclasspath
# TODO(agrieve): Remove this .TOC heuristic once GYP is no more.
- if not options.use_ijars:
+ if options.use_ijars:
+ classpath_inputs.extend(compile_classpath)
+ else:
for path in compile_classpath:
if os.path.exists(path + '.TOC'):
- input_paths.append(path + '.TOC')
- else:
- input_paths.append(path)
-
- def on_stale_md5():
- with build_utils.TempDir() as temp_dir:
- if options.java_srcjars:
- java_dir = os.path.join(temp_dir, 'java')
- os.makedirs(java_dir)
- for srcjar in options.java_srcjars:
- build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java')
- jar_srcs = build_utils.FindInDirectory(java_dir, '*.java')
- java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes))
-
- classes_dir = os.path.join(temp_dir, 'classes')
- os.makedirs(classes_dir)
-
- if java_files:
- # Don't include the output directory in the initial set of args since it
- # being in a temp dir makes it unstable (breaks md5 stamping).
- cmd = javac_cmd + ['-d', classes_dir] + java_files
-
- build_utils.CheckOutput(
- cmd,
- print_stdout=options.chromium_code,
- stderr_filter=ColorJavacOutput)
-
- if options.main_class or options.manifest_entry:
- entries = []
- if options.manifest_entry:
- entries = [e.split(':') for e in options.manifest_entry]
- manifest_file = os.path.join(temp_dir, 'manifest')
- _CreateManifest(manifest_file, runtime_classpath, options.main_class,
- entries)
+ classpath_inputs.append(path + '.TOC')
else:
- manifest_file = None
- jar.JarDirectory(classes_dir,
- options.jar_excluded_classes,
- options.jar_path,
- manifest_file=manifest_file)
+ classpath_inputs.append(path)
+
+ # Compute the list of paths that when changed, we need to rebuild.
+ input_paths = classpath_inputs + options.java_srcjars + java_files
+
+ output_paths = [
+ options.jar_path,
+ options.jar_path.replace('.jar', '.excluded.jar'),
+ ]
+ # An escape hatch to be able to check if incremental compiles are causing
+ # problems.
+ force = int(os.environ.get('DISABLE_INCREMENTAL_JAVAC', 0))
# List python deps in input_strings rather than input_paths since the contents
# of them does not change what gets written to the depsfile.
build_utils.CallAndWriteDepfileIfStale(
- on_stale_md5,
+ lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files,
+ classpath_inputs, runtime_classpath),
options,
input_paths=input_paths,
input_strings=javac_cmd,
- output_paths=[options.jar_path])
+ output_paths=output_paths,
+ force=force,
+ pass_changes=True)
if __name__ == '__main__':
« 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