| OLD | NEW |
| 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 fnmatch | |
| 8 import optparse | 7 import optparse |
| 9 import os | 8 import os |
| 10 import shutil | 9 import shutil |
| 11 import re | 10 import re |
| 12 import sys | 11 import sys |
| 13 import textwrap | 12 import textwrap |
| 14 | 13 |
| 15 from util import build_utils | 14 from util import build_utils |
| 16 from util import md5_check | 15 from util import md5_check |
| 17 | 16 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 return '\n'.join(map(ApplyColor, output.split('\n'))) | 53 return '\n'.join(map(ApplyColor, output.split('\n'))) |
| 55 | 54 |
| 56 | 55 |
| 57 ERRORPRONE_OPTIONS = [ | 56 ERRORPRONE_OPTIONS = [ |
| 58 # These crash on lots of targets. | 57 # These crash on lots of targets. |
| 59 '-Xep:ParameterPackage:OFF', | 58 '-Xep:ParameterPackage:OFF', |
| 60 '-Xep:OverridesGuiceInjectableMethod:OFF', | 59 '-Xep:OverridesGuiceInjectableMethod:OFF', |
| 61 '-Xep:OverridesJavaxInjectableMethod:OFF', | 60 '-Xep:OverridesJavaxInjectableMethod:OFF', |
| 62 ] | 61 ] |
| 63 | 62 |
| 64 def DoJavac( | |
| 65 bootclasspath, classpath, classes_dir, chromium_code, | |
| 66 use_errorprone_path, java_files): | |
| 67 """Runs javac. | |
| 68 | 63 |
| 69 Builds |java_files| with the provided |classpath| and puts the generated | 64 def _FilterJavaFiles(paths, filters): |
| 70 .class files into |classes_dir|. If |chromium_code| is true, extra lint | 65 return [f for f in paths |
| 71 checking will be enabled. | 66 if not filters or build_utils.MatchesGlob(f, filters)] |
| 72 """ | |
| 73 | |
| 74 jar_inputs = [] | |
| 75 for path in classpath: | |
| 76 if os.path.exists(path + '.TOC'): | |
| 77 jar_inputs.append(path + '.TOC') | |
| 78 else: | |
| 79 jar_inputs.append(path) | |
| 80 | |
| 81 javac_args = [ | |
| 82 '-g', | |
| 83 # Chromium only allows UTF8 source files. Being explicit avoids | |
| 84 # javac pulling a default encoding from the user's environment. | |
| 85 '-encoding', 'UTF-8', | |
| 86 '-classpath', ':'.join(classpath), | |
| 87 '-d', classes_dir] | |
| 88 | |
| 89 if bootclasspath: | |
| 90 javac_args.extend([ | |
| 91 '-bootclasspath', ':'.join(bootclasspath), | |
| 92 '-source', '1.7', | |
| 93 '-target', '1.7', | |
| 94 ]) | |
| 95 | |
| 96 if chromium_code: | |
| 97 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed. | |
| 98 javac_args.extend(['-Xlint:unchecked']) | |
| 99 else: | |
| 100 # XDignore.symbol.file makes javac compile against rt.jar instead of | |
| 101 # ct.sym. This means that using a java internal package/class will not | |
| 102 # trigger a compile warning or error. | |
| 103 javac_args.extend(['-XDignore.symbol.file']) | |
| 104 | |
| 105 if use_errorprone_path: | |
| 106 javac_cmd = [use_errorprone_path] + ERRORPRONE_OPTIONS | |
| 107 else: | |
| 108 javac_cmd = ['javac'] | |
| 109 | |
| 110 javac_cmd = javac_cmd + javac_args + java_files | |
| 111 | |
| 112 def Compile(): | |
| 113 build_utils.CheckOutput( | |
| 114 javac_cmd, | |
| 115 print_stdout=chromium_code, | |
| 116 stderr_filter=ColorJavacOutput) | |
| 117 | |
| 118 record_path = os.path.join(classes_dir, 'javac.md5.stamp') | |
| 119 md5_check.CallAndRecordIfStale( | |
| 120 Compile, | |
| 121 record_path=record_path, | |
| 122 input_paths=java_files + jar_inputs, | |
| 123 input_strings=javac_cmd) | |
| 124 | 67 |
| 125 | 68 |
| 126 _MAX_MANIFEST_LINE_LEN = 72 | 69 _MAX_MANIFEST_LINE_LEN = 72 |
| 127 | 70 |
| 128 | 71 |
| 129 def CreateManifest(manifest_path, classpath, main_class=None, | 72 def _CreateManifest(manifest_path, classpath, main_class=None, |
| 130 manifest_entries=None): | 73 manifest_entries=None): |
| 131 """Creates a manifest file with the given parameters. | 74 """Creates a manifest file with the given parameters. |
| 132 | 75 |
| 133 This generates a manifest file that compiles with the spec found at | 76 This generates a manifest file that compiles with the spec found at |
| 134 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifes
t | 77 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifes
t |
| 135 | 78 |
| 136 Args: | 79 Args: |
| 137 manifest_path: The path to the manifest file that should be created. | 80 manifest_path: The path to the manifest file that should be created. |
| 138 classpath: The JAR files that should be listed on the manifest file's | 81 classpath: The JAR files that should be listed on the manifest file's |
| 139 classpath. | 82 classpath. |
| 140 main_class: If present, the class containing the main() function. | 83 main_class: If present, the class containing the main() function. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 159 wrapper = textwrap.TextWrapper(break_long_words=True, | 102 wrapper = textwrap.TextWrapper(break_long_words=True, |
| 160 drop_whitespace=False, | 103 drop_whitespace=False, |
| 161 subsequent_indent=' ', | 104 subsequent_indent=' ', |
| 162 width=_MAX_MANIFEST_LINE_LEN - 2) | 105 width=_MAX_MANIFEST_LINE_LEN - 2) |
| 163 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)) |
| 164 | 107 |
| 165 with open(manifest_path, 'w') as f: | 108 with open(manifest_path, 'w') as f: |
| 166 f.write(output) | 109 f.write(output) |
| 167 | 110 |
| 168 | 111 |
| 169 def main(argv): | 112 def _ParseOptions(argv): |
| 170 colorama.init() | |
| 171 | |
| 172 argv = build_utils.ExpandFileArgs(argv) | |
| 173 | |
| 174 parser = optparse.OptionParser() | 113 parser = optparse.OptionParser() |
| 175 build_utils.AddDepfileOption(parser) | 114 build_utils.AddDepfileOption(parser) |
| 176 | 115 |
| 177 parser.add_option( | 116 parser.add_option( |
| 178 '--src-gendirs', | 117 '--src-gendirs', |
| 179 help='Directories containing generated java files.') | 118 help='Directories containing generated java files.') |
| 180 parser.add_option( | 119 parser.add_option( |
| 181 '--java-srcjars', | 120 '--java-srcjars', |
| 182 action='append', | 121 action='append', |
| 183 default=[], | 122 default=[], |
| 184 help='List of srcjars to include in compilation.') | 123 help='List of srcjars to include in compilation.') |
| 185 parser.add_option( | 124 parser.add_option( |
| 186 '--bootclasspath', | 125 '--bootclasspath', |
| 187 action='append', | 126 action='append', |
| 188 default=[], | 127 default=[], |
| 189 help='Boot classpath for javac. If this is specified multiple times, ' | 128 help='Boot classpath for javac. If this is specified multiple times, ' |
| 190 'they will all be appended to construct the classpath.') | 129 'they will all be appended to construct the classpath.') |
| 191 parser.add_option( | 130 parser.add_option( |
| 192 '--classpath', | 131 '--classpath', |
| 193 action='append', | 132 action='append', |
| 194 help='Classpath for javac. If this is specified multiple times, they ' | 133 help='Classpath for javac. If this is specified multiple times, they ' |
| 195 'will all be appended to construct the classpath.') | 134 'will all be appended to construct the classpath.') |
| 196 parser.add_option( | 135 parser.add_option( |
| 197 '--javac-includes', | 136 '--javac-includes', |
| 137 default='', |
| 198 help='A list of file patterns. If provided, only java files that match' | 138 help='A list of file patterns. If provided, only java files that match' |
| 199 'one of the patterns will be compiled.') | 139 'one of the patterns will be compiled.') |
| 200 parser.add_option( | 140 parser.add_option( |
| 201 '--jar-excluded-classes', | 141 '--jar-excluded-classes', |
| 202 default='', | 142 default='', |
| 203 help='List of .class file patterns to exclude from the jar.') | 143 help='List of .class file patterns to exclude from the jar.') |
| 204 | 144 |
| 205 parser.add_option( | 145 parser.add_option( |
| 206 '--chromium-code', | 146 '--chromium-code', |
| 207 type='int', | 147 type='int', |
| 208 help='Whether code being compiled should be built with stricter ' | 148 help='Whether code being compiled should be built with stricter ' |
| 209 'warnings for chromium code.') | 149 'warnings for chromium code.') |
| 210 | 150 |
| 211 parser.add_option( | 151 parser.add_option( |
| 212 '--use-errorprone-path', | 152 '--use-errorprone-path', |
| 213 help='Use the Errorprone compiler at this path.') | 153 help='Use the Errorprone compiler at this path.') |
| 214 | 154 |
| 215 parser.add_option( | |
| 216 '--classes-dir', | |
| 217 help='Directory for compiled .class files.') | |
| 218 parser.add_option('--jar-path', help='Jar output path.') | 155 parser.add_option('--jar-path', help='Jar output path.') |
| 219 parser.add_option( | 156 parser.add_option( |
| 220 '--main-class', | 157 '--main-class', |
| 221 help='The class containing the main method.') | 158 help='The class containing the main method.') |
| 222 parser.add_option( | 159 parser.add_option( |
| 223 '--manifest-entry', | 160 '--manifest-entry', |
| 224 action='append', | 161 action='append', |
| 225 help='Key:value pairs to add to the .jar manifest.') | 162 help='Key:value pairs to add to the .jar manifest.') |
| 226 | 163 |
| 227 parser.add_option('--stamp', help='Path to touch on success.') | 164 parser.add_option('--stamp', help='Path to touch on success.') |
| 228 | 165 |
| 229 options, args = parser.parse_args(argv) | 166 options, args = parser.parse_args(argv) |
| 230 | 167 build_utils.CheckOptions(options, parser, required=('jar_path',)) |
| 231 if options.main_class and not options.jar_path: | |
| 232 parser.error('--main-class requires --jar-path') | |
| 233 | 168 |
| 234 bootclasspath = [] | 169 bootclasspath = [] |
| 235 for arg in options.bootclasspath: | 170 for arg in options.bootclasspath: |
| 236 bootclasspath += build_utils.ParseGypList(arg) | 171 bootclasspath += build_utils.ParseGypList(arg) |
| 172 options.bootclasspath = bootclasspath |
| 237 | 173 |
| 238 classpath = [] | 174 classpath = [] |
| 239 for arg in options.classpath: | 175 for arg in options.classpath: |
| 240 classpath += build_utils.ParseGypList(arg) | 176 classpath += build_utils.ParseGypList(arg) |
| 177 options.classpath = classpath |
| 241 | 178 |
| 242 java_srcjars = [] | 179 java_srcjars = [] |
| 243 for arg in options.java_srcjars: | 180 for arg in options.java_srcjars: |
| 244 java_srcjars += build_utils.ParseGypList(arg) | 181 java_srcjars += build_utils.ParseGypList(arg) |
| 182 options.java_srcjars = java_srcjars |
| 245 | 183 |
| 246 java_files = args | |
| 247 if options.src_gendirs: | 184 if options.src_gendirs: |
| 248 src_gendirs = build_utils.ParseGypList(options.src_gendirs) | 185 options.src_gendirs = build_utils.ParseGypList(options.src_gendirs) |
| 249 java_files += build_utils.FindInDirectories(src_gendirs, '*.java') | |
| 250 | 186 |
| 251 input_files = bootclasspath + classpath + java_srcjars + java_files | 187 options.javac_includes = build_utils.ParseGypList(options.javac_includes) |
| 252 with build_utils.TempDir() as temp_dir: | 188 options.jar_excluded_classes = ( |
| 253 classes_dir = os.path.join(temp_dir, 'classes') | 189 build_utils.ParseGypList(options.jar_excluded_classes)) |
| 254 os.makedirs(classes_dir) | 190 return options, args |
| 255 if java_srcjars: | |
| 256 java_dir = os.path.join(temp_dir, 'java') | |
| 257 os.makedirs(java_dir) | |
| 258 for srcjar in java_srcjars: | |
| 259 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java') | |
| 260 java_files += build_utils.FindInDirectory(java_dir, '*.java') | |
| 261 | 191 |
| 262 if options.javac_includes: | |
| 263 javac_includes = build_utils.ParseGypList(options.javac_includes) | |
| 264 filtered_java_files = [] | |
| 265 for f in java_files: | |
| 266 for include in javac_includes: | |
| 267 if fnmatch.fnmatch(f, include): | |
| 268 filtered_java_files.append(f) | |
| 269 break | |
| 270 java_files = filtered_java_files | |
| 271 | 192 |
| 272 if len(java_files) != 0: | 193 def main(argv): |
| 273 DoJavac( | 194 colorama.init() |
| 274 bootclasspath, | |
| 275 classpath, | |
| 276 classes_dir, | |
| 277 options.chromium_code, | |
| 278 options.use_errorprone_path, | |
| 279 java_files) | |
| 280 | 195 |
| 281 if options.jar_path: | 196 argv = build_utils.ExpandFileArgs(argv) |
| 197 options, java_files = _ParseOptions(argv) |
| 198 |
| 199 if options.src_gendirs: |
| 200 java_files += build_utils.FindInDirectories(options.src_gendirs, '*.java') |
| 201 |
| 202 java_files = _FilterJavaFiles(java_files, options.javac_includes) |
| 203 |
| 204 javac_args = [ |
| 205 '-g', |
| 206 # Chromium only allows UTF8 source files. Being explicit avoids |
| 207 # javac pulling a default encoding from the user's environment. |
| 208 '-encoding', 'UTF-8', |
| 209 '-classpath', ':'.join(options.classpath), |
| 210 ] |
| 211 |
| 212 if options.bootclasspath: |
| 213 javac_args.extend([ |
| 214 '-bootclasspath', ':'.join(options.bootclasspath), |
| 215 '-source', '1.7', |
| 216 '-target', '1.7', |
| 217 ]) |
| 218 |
| 219 if options.chromium_code: |
| 220 # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed. |
| 221 javac_args.extend(['-Xlint:unchecked']) |
| 222 else: |
| 223 # XDignore.symbol.file makes javac compile against rt.jar instead of |
| 224 # ct.sym. This means that using a java internal package/class will not |
| 225 # trigger a compile warning or error. |
| 226 javac_args.extend(['-XDignore.symbol.file']) |
| 227 |
| 228 javac_cmd = ['javac'] |
| 229 if options.use_errorprone_path: |
| 230 javac_cmd = [options.use_errorprone_path] + ERRORPRONE_OPTIONS |
| 231 |
| 232 # Compute the list of paths that when changed, we need to rebuild. |
| 233 input_paths = options.bootclasspath + options.java_srcjars + java_files |
| 234 for path in options.classpath: |
| 235 if os.path.exists(path + '.TOC'): |
| 236 input_paths.append(path + '.TOC') |
| 237 else: |
| 238 input_paths.append(path) |
| 239 python_deps = build_utils.GetPythonDependencies() |
| 240 |
| 241 def OnStaleMd5(): |
| 242 with build_utils.TempDir() as temp_dir: |
| 243 if options.java_srcjars: |
| 244 java_dir = os.path.join(temp_dir, 'java') |
| 245 os.makedirs(java_dir) |
| 246 for srcjar in options.java_srcjars: |
| 247 build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java') |
| 248 jar_srcs = build_utils.FindInDirectory(java_dir, '*.java') |
| 249 java_files.extend(_FilterJavaFiles(jar_srcs, options.javac_includes)) |
| 250 |
| 251 if not java_files: |
| 252 return |
| 253 |
| 254 classes_dir = os.path.join(temp_dir, 'classes') |
| 255 os.makedirs(classes_dir) |
| 256 # Don't include the output directory in the initial set of args since it |
| 257 # being in a temp dir makes it unstable (breaks md5 stamping). |
| 258 cmd = javac_cmd + javac_args + ['-d', classes_dir] + java_files |
| 259 |
| 260 build_utils.CheckOutput( |
| 261 cmd, |
| 262 print_stdout=options.chromium_code, |
| 263 stderr_filter=ColorJavacOutput) |
| 264 |
| 282 if options.main_class or options.manifest_entry: | 265 if options.main_class or options.manifest_entry: |
| 266 entries = [] |
| 283 if options.manifest_entry: | 267 if options.manifest_entry: |
| 284 entries = map(lambda e: e.split(":"), options.manifest_entry) | 268 entries = [e.split(':') for e in options.manifest_entry] |
| 285 else: | |
| 286 entries = [] | |
| 287 manifest_file = os.path.join(temp_dir, 'manifest') | 269 manifest_file = os.path.join(temp_dir, 'manifest') |
| 288 CreateManifest(manifest_file, classpath, options.main_class, entries) | 270 _CreateManifest(manifest_file, options.classpath, options.main_class, |
| 271 entries) |
| 289 else: | 272 else: |
| 290 manifest_file = None | 273 manifest_file = None |
| 291 jar.JarDirectory(classes_dir, | 274 jar.JarDirectory(classes_dir, |
| 292 build_utils.ParseGypList(options.jar_excluded_classes), | 275 options.jar_excluded_classes, |
| 293 options.jar_path, | 276 options.jar_path, |
| 294 manifest_file=manifest_file) | 277 manifest_file=manifest_file) |
| 295 | 278 |
| 296 if options.classes_dir: | 279 if options.stamp: |
| 297 # Delete the old classes directory. This ensures that all .class files in | 280 build_utils.Touch(options.stamp) |
| 298 # the output are actually from the input .java files. For example, if a | |
| 299 # .java file is deleted or an inner class is removed, the classes | |
| 300 # directory should not contain the corresponding old .class file after | |
| 301 # running this action. | |
| 302 build_utils.DeleteDirectory(options.classes_dir) | |
| 303 shutil.copytree(classes_dir, options.classes_dir) | |
| 304 | 281 |
| 305 if options.depfile: | 282 if options.depfile: |
| 306 build_utils.WriteDepfile( | 283 build_utils.WriteDepfile(options.depfile, input_paths + python_deps) |
| 307 options.depfile, | |
| 308 input_files + build_utils.GetPythonDependencies()) | |
| 309 | 284 |
| 310 if options.stamp: | 285 |
| 311 build_utils.Touch(options.stamp) | 286 # List python deps in input_strings rather than input_paths since the contents |
| 287 # of them does not change what gets written to the depsfile. |
| 288 md5_check.CallAndRecordIfStale( |
| 289 OnStaleMd5, |
| 290 record_path=options.jar_path + '.javac.md5.stamp', |
| 291 input_paths=input_paths, |
| 292 input_strings=javac_cmd + javac_args + python_deps, |
| 293 force=not os.path.exists(options.jar_path)) |
| 294 |
| 312 | 295 |
| 313 | 296 |
| 314 if __name__ == '__main__': | 297 if __name__ == '__main__': |
| 315 sys.exit(main(sys.argv[1:])) | 298 sys.exit(main(sys.argv[1:])) |
| 316 | 299 |
| 317 | 300 |
| OLD | NEW |