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 |
7 import optparse | 8 import optparse |
8 import os | 9 import os |
9 import shutil | 10 import shutil |
10 import re | 11 import re |
11 import sys | 12 import sys |
12 import textwrap | 13 import textwrap |
13 | 14 |
14 from util import build_utils | 15 from util import build_utils |
15 from util import md5_check | 16 from util import md5_check |
16 | 17 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 return '\n'.join(map(ApplyColor, output.split('\n'))) | 54 return '\n'.join(map(ApplyColor, output.split('\n'))) |
54 | 55 |
55 | 56 |
56 ERRORPRONE_OPTIONS = [ | 57 ERRORPRONE_OPTIONS = [ |
57 # These crash on lots of targets. | 58 # These crash on lots of targets. |
58 '-Xep:ParameterPackage:OFF', | 59 '-Xep:ParameterPackage:OFF', |
59 '-Xep:OverridesGuiceInjectableMethod:OFF', | 60 '-Xep:OverridesGuiceInjectableMethod:OFF', |
60 '-Xep:OverridesJavaxInjectableMethod:OFF', | 61 '-Xep:OverridesJavaxInjectableMethod:OFF', |
61 ] | 62 ] |
62 | 63 |
| 64 def DoJavac( |
| 65 bootclasspath, classpath, classes_dir, chromium_code, |
| 66 use_errorprone_path, java_files): |
| 67 """Runs javac. |
63 | 68 |
64 def _FilterJavaFiles(paths, filters): | 69 Builds |java_files| with the provided |classpath| and puts the generated |
65 return [f for f in paths | 70 .class files into |classes_dir|. If |chromium_code| is true, extra lint |
66 if not filters or build_utils.MatchesGlob(f, filters)] | 71 checking will be enabled. |
| 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) |
67 | 124 |
68 | 125 |
69 _MAX_MANIFEST_LINE_LEN = 72 | 126 _MAX_MANIFEST_LINE_LEN = 72 |
70 | 127 |
71 | 128 |
72 def _CreateManifest(manifest_path, classpath, main_class=None, | 129 def CreateManifest(manifest_path, classpath, main_class=None, |
73 manifest_entries=None): | 130 manifest_entries=None): |
74 """Creates a manifest file with the given parameters. | 131 """Creates a manifest file with the given parameters. |
75 | 132 |
76 This generates a manifest file that compiles with the spec found at | 133 This generates a manifest file that compiles with the spec found at |
77 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifes
t | 134 http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifes
t |
78 | 135 |
79 Args: | 136 Args: |
80 manifest_path: The path to the manifest file that should be created. | 137 manifest_path: The path to the manifest file that should be created. |
81 classpath: The JAR files that should be listed on the manifest file's | 138 classpath: The JAR files that should be listed on the manifest file's |
82 classpath. | 139 classpath. |
83 main_class: If present, the class containing the main() function. | 140 main_class: If present, the class containing the main() function. |
(...skipping 18 matching lines...) Expand all Loading... |
102 wrapper = textwrap.TextWrapper(break_long_words=True, | 159 wrapper = textwrap.TextWrapper(break_long_words=True, |
103 drop_whitespace=False, | 160 drop_whitespace=False, |
104 subsequent_indent=' ', | 161 subsequent_indent=' ', |
105 width=_MAX_MANIFEST_LINE_LEN - 2) | 162 width=_MAX_MANIFEST_LINE_LEN - 2) |
106 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) | 163 output = '\r\n'.join(w for l in output for w in wrapper.wrap(l)) |
107 | 164 |
108 with open(manifest_path, 'w') as f: | 165 with open(manifest_path, 'w') as f: |
109 f.write(output) | 166 f.write(output) |
110 | 167 |
111 | 168 |
112 def _ParseOptions(argv): | 169 def main(argv): |
| 170 colorama.init() |
| 171 |
| 172 argv = build_utils.ExpandFileArgs(argv) |
| 173 |
113 parser = optparse.OptionParser() | 174 parser = optparse.OptionParser() |
114 build_utils.AddDepfileOption(parser) | 175 build_utils.AddDepfileOption(parser) |
115 | 176 |
116 parser.add_option( | 177 parser.add_option( |
117 '--src-gendirs', | 178 '--src-gendirs', |
118 help='Directories containing generated java files.') | 179 help='Directories containing generated java files.') |
119 parser.add_option( | 180 parser.add_option( |
120 '--java-srcjars', | 181 '--java-srcjars', |
121 action='append', | 182 action='append', |
122 default=[], | 183 default=[], |
123 help='List of srcjars to include in compilation.') | 184 help='List of srcjars to include in compilation.') |
124 parser.add_option( | 185 parser.add_option( |
125 '--bootclasspath', | 186 '--bootclasspath', |
126 action='append', | 187 action='append', |
127 default=[], | 188 default=[], |
128 help='Boot classpath for javac. If this is specified multiple times, ' | 189 help='Boot classpath for javac. If this is specified multiple times, ' |
129 'they will all be appended to construct the classpath.') | 190 'they will all be appended to construct the classpath.') |
130 parser.add_option( | 191 parser.add_option( |
131 '--classpath', | 192 '--classpath', |
132 action='append', | 193 action='append', |
133 help='Classpath for javac. If this is specified multiple times, they ' | 194 help='Classpath for javac. If this is specified multiple times, they ' |
134 'will all be appended to construct the classpath.') | 195 'will all be appended to construct the classpath.') |
135 parser.add_option( | 196 parser.add_option( |
136 '--javac-includes', | 197 '--javac-includes', |
137 default='', | |
138 help='A list of file patterns. If provided, only java files that match' | 198 help='A list of file patterns. If provided, only java files that match' |
139 'one of the patterns will be compiled.') | 199 'one of the patterns will be compiled.') |
140 parser.add_option( | 200 parser.add_option( |
141 '--jar-excluded-classes', | 201 '--jar-excluded-classes', |
142 default='', | 202 default='', |
143 help='List of .class file patterns to exclude from the jar.') | 203 help='List of .class file patterns to exclude from the jar.') |
144 | 204 |
145 parser.add_option( | 205 parser.add_option( |
146 '--chromium-code', | 206 '--chromium-code', |
147 type='int', | 207 type='int', |
148 help='Whether code being compiled should be built with stricter ' | 208 help='Whether code being compiled should be built with stricter ' |
149 'warnings for chromium code.') | 209 'warnings for chromium code.') |
150 | 210 |
151 parser.add_option( | 211 parser.add_option( |
152 '--use-errorprone-path', | 212 '--use-errorprone-path', |
153 help='Use the Errorprone compiler at this path.') | 213 help='Use the Errorprone compiler at this path.') |
154 | 214 |
| 215 parser.add_option( |
| 216 '--classes-dir', |
| 217 help='Directory for compiled .class files.') |
155 parser.add_option('--jar-path', help='Jar output path.') | 218 parser.add_option('--jar-path', help='Jar output path.') |
156 parser.add_option( | 219 parser.add_option( |
157 '--main-class', | 220 '--main-class', |
158 help='The class containing the main method.') | 221 help='The class containing the main method.') |
159 parser.add_option( | 222 parser.add_option( |
160 '--manifest-entry', | 223 '--manifest-entry', |
161 action='append', | 224 action='append', |
162 help='Key:value pairs to add to the .jar manifest.') | 225 help='Key:value pairs to add to the .jar manifest.') |
163 | 226 |
164 parser.add_option('--stamp', help='Path to touch on success.') | 227 parser.add_option('--stamp', help='Path to touch on success.') |
165 | 228 |
166 options, args = parser.parse_args(argv) | 229 options, args = parser.parse_args(argv) |
167 build_utils.CheckOptions(options, parser, required=('jar_path',)) | 230 |
| 231 if options.main_class and not options.jar_path: |
| 232 parser.error('--main-class requires --jar-path') |
168 | 233 |
169 bootclasspath = [] | 234 bootclasspath = [] |
170 for arg in options.bootclasspath: | 235 for arg in options.bootclasspath: |
171 bootclasspath += build_utils.ParseGypList(arg) | 236 bootclasspath += build_utils.ParseGypList(arg) |
172 options.bootclasspath = bootclasspath | |
173 | 237 |
174 classpath = [] | 238 classpath = [] |
175 for arg in options.classpath: | 239 for arg in options.classpath: |
176 classpath += build_utils.ParseGypList(arg) | 240 classpath += build_utils.ParseGypList(arg) |
177 options.classpath = classpath | |
178 | 241 |
179 java_srcjars = [] | 242 java_srcjars = [] |
180 for arg in options.java_srcjars: | 243 for arg in options.java_srcjars: |
181 java_srcjars += build_utils.ParseGypList(arg) | 244 java_srcjars += build_utils.ParseGypList(arg) |
182 options.java_srcjars = java_srcjars | |
183 | 245 |
| 246 java_files = args |
184 if options.src_gendirs: | 247 if options.src_gendirs: |
185 options.src_gendirs = build_utils.ParseGypList(options.src_gendirs) | 248 src_gendirs = build_utils.ParseGypList(options.src_gendirs) |
| 249 java_files += build_utils.FindInDirectories(src_gendirs, '*.java') |
186 | 250 |
187 options.javac_includes = build_utils.ParseGypList(options.javac_includes) | 251 input_files = bootclasspath + classpath + java_srcjars + java_files |
188 options.jar_excluded_classes = ( | 252 with build_utils.TempDir() as temp_dir: |
189 build_utils.ParseGypList(options.jar_excluded_classes)) | 253 classes_dir = os.path.join(temp_dir, 'classes') |
190 return options, args | 254 os.makedirs(classes_dir) |
| 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') |
191 | 261 |
| 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 |
192 | 271 |
193 def main(argv): | 272 if len(java_files) != 0: |
194 colorama.init() | 273 DoJavac( |
| 274 bootclasspath, |
| 275 classpath, |
| 276 classes_dir, |
| 277 options.chromium_code, |
| 278 options.use_errorprone_path, |
| 279 java_files) |
195 | 280 |
196 argv = build_utils.ExpandFileArgs(argv) | 281 if options.jar_path: |
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 | |
265 if options.main_class or options.manifest_entry: | 282 if options.main_class or options.manifest_entry: |
266 entries = [] | |
267 if options.manifest_entry: | 283 if options.manifest_entry: |
268 entries = [e.split(':') for e in options.manifest_entry] | 284 entries = map(lambda e: e.split(":"), options.manifest_entry) |
| 285 else: |
| 286 entries = [] |
269 manifest_file = os.path.join(temp_dir, 'manifest') | 287 manifest_file = os.path.join(temp_dir, 'manifest') |
270 _CreateManifest(manifest_file, options.classpath, options.main_class, | 288 CreateManifest(manifest_file, classpath, options.main_class, entries) |
271 entries) | |
272 else: | 289 else: |
273 manifest_file = None | 290 manifest_file = None |
274 jar.JarDirectory(classes_dir, | 291 jar.JarDirectory(classes_dir, |
275 options.jar_excluded_classes, | 292 build_utils.ParseGypList(options.jar_excluded_classes), |
276 options.jar_path, | 293 options.jar_path, |
277 manifest_file=manifest_file) | 294 manifest_file=manifest_file) |
278 | 295 |
279 if options.stamp: | 296 if options.classes_dir: |
280 build_utils.Touch(options.stamp) | 297 # Delete the old classes directory. This ensures that all .class files in |
| 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) |
281 | 304 |
282 if options.depfile: | 305 if options.depfile: |
283 build_utils.WriteDepfile(options.depfile, input_paths + python_deps) | 306 build_utils.WriteDepfile( |
| 307 options.depfile, |
| 308 input_files + build_utils.GetPythonDependencies()) |
284 | 309 |
285 | 310 if options.stamp: |
286 # List python deps in input_strings rather than input_paths since the contents | 311 build_utils.Touch(options.stamp) |
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 | |
295 | 312 |
296 | 313 |
297 if __name__ == '__main__': | 314 if __name__ == '__main__': |
298 sys.exit(main(sys.argv[1:])) | 315 sys.exit(main(sys.argv[1:])) |
299 | 316 |
300 | 317 |
OLD | NEW |