1#!/usr/bin/env python3 2# 3# Copyright 2013 The Chromium Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7import collections 8import functools 9import itertools 10import logging 11import argparse 12import os 13import pathlib 14import re 15import shlex 16import shutil 17import sys 18import time 19import zipfile 20 21import javac_output_processor 22from util import build_utils 23from util import md5_check 24from util import jar_info_utils 25from util import server_utils 26import action_helpers # build_utils adds //build to sys.path. 27import zip_helpers 28 29_JAVAC_EXTRACTOR = os.path.join(build_utils.DIR_SOURCE_ROOT, 'third_party', 30 'android_prebuilts', 'build_tools', 'common', 31 'framework', 'javac_extractor.jar') 32 33 34def ProcessJavacOutput(output, target_name): 35 # These warnings cannot be suppressed even for third party code. Deprecation 36 # warnings especially do not help since we must support older android version. 37 deprecated_re = re.compile(r'Note: .* uses? or overrides? a deprecated API') 38 unchecked_re = re.compile( 39 r'(Note: .* uses? unchecked or unsafe operations.)$') 40 recompile_re = re.compile(r'(Note: Recompile with -Xlint:.* for details.)$') 41 42 def ApplyFilters(line): 43 return not (deprecated_re.match(line) or unchecked_re.match(line) 44 or recompile_re.match(line)) 45 46 output = build_utils.FilterReflectiveAccessJavaWarnings(output) 47 48 # Warning currently cannot be silenced via javac flag. 49 if 'Unsafe is internal proprietary API' in output: 50 # Example: 51 # HiddenApiBypass.java:69: warning: Unsafe is internal proprietary API and 52 # may be removed in a future release 53 # import sun.misc.Unsafe; 54 # ^ 55 output = re.sub(r'.*?Unsafe is internal proprietary API[\s\S]*?\^\n', '', 56 output) 57 output = re.sub(r'\d+ warnings\n', '', output) 58 59 lines = (l for l in output.split('\n') if ApplyFilters(l)) 60 61 output_processor = javac_output_processor.JavacOutputProcessor(target_name) 62 lines = output_processor.Process(lines) 63 64 return '\n'.join(lines) 65 66 67def CreateJarFile(jar_path, 68 classes_dir, 69 services_map=None, 70 additional_jar_files=None, 71 extra_classes_jar=None): 72 """Zips files from compilation into a single jar.""" 73 logging.info('Start creating jar file: %s', jar_path) 74 with action_helpers.atomic_output(jar_path) as f: 75 with zipfile.ZipFile(f.name, 'w') as z: 76 zip_helpers.zip_directory(z, classes_dir) 77 if services_map: 78 for service_class, impl_classes in sorted(services_map.items()): 79 zip_path = 'META-INF/services/' + service_class 80 data = ''.join(f'{x}\n' for x in sorted(impl_classes)) 81 zip_helpers.add_to_zip_hermetic(z, zip_path, data=data) 82 83 if additional_jar_files: 84 for src_path, zip_path in additional_jar_files: 85 zip_helpers.add_to_zip_hermetic(z, zip_path, src_path=src_path) 86 if extra_classes_jar: 87 path_transform = lambda p: p if p.endswith('.class') else None 88 zip_helpers.merge_zips(z, [extra_classes_jar], 89 path_transform=path_transform) 90 logging.info('Completed jar file: %s', jar_path) 91 92 93# Java lines end in semicolon, whereas Kotlin lines do not. 94_PACKAGE_RE = re.compile(r'^package\s+(.*?)(;|\s*$)', flags=re.MULTILINE) 95 96_SERVICE_IMPL_RE = re.compile( 97 r'^([\t ]*)@ServiceImpl\(\s*(.+?)\.class\)(.*?)\sclass\s+(\w+)', 98 flags=re.MULTILINE | re.DOTALL) 99 100# Finds all top-level classes (by looking for those that are not indented). 101_TOP_LEVEL_CLASSES_RE = re.compile( 102 # Start of line, or after /* package */ 103 r'^(?:/\*.*\*/\s*)?' 104 # Annotations 105 r'(?:@\w+(?:\(.*\))\s+)*' 106 r'(?:(?:public|protected|private)\s+)?' 107 r'(?:(?:static|abstract|final|sealed)\s+)*' 108 r'(?:class|@?interface|enum|record)\s+' 109 r'(\w+?)\b[^"]*?$', 110 flags=re.MULTILINE) 111 112 113def ParseJavaSource(data, services_map, path=None): 114 """This should support both Java and Kotlin files.""" 115 package_name = '' 116 if m := _PACKAGE_RE.search(data): 117 package_name = m.group(1) 118 119 class_names = _TOP_LEVEL_CLASSES_RE.findall(data) 120 121 # Very rare, so worth an upfront check. 122 if '@ServiceImpl' in data: 123 for indent, service_class, modifiers, impl_class in ( 124 _SERVICE_IMPL_RE.findall(data)): 125 if 'public' not in modifiers: 126 raise Exception(f'@ServiceImpl can be used only on public classes ' 127 f'(when parsing {path})') 128 # Assume indent means nested class that is one level deep. 129 if indent: 130 impl_class = f'{class_names[0]}${impl_class}' 131 else: 132 assert class_names[0] == impl_class 133 134 # Parse imports to resolve the class. 135 dot_idx = service_class.find('.') 136 # Handle @ServiceImpl(OuterClass.InnerClass.class) 137 outer_class = service_class if dot_idx == -1 else service_class[:dot_idx] 138 139 if m := re.search(r'^import\s+([\w\.]*\.' + outer_class + r')[;\s]', 140 data, 141 flags=re.MULTILINE): 142 service_class = m.group(1) + service_class[len(outer_class):] 143 else: 144 service_class = f'{package_name}.{service_class}' 145 146 # Convert OuterClass.InnerClass -> OuterClass$InnerClass. 147 for m in list(re.finditer(r'\.[A-Z]', service_class))[1:]: 148 idx = m.start() 149 service_class = service_class[:idx] + '$' + service_class[idx + 1:] 150 151 services_map[service_class].append(f'{package_name}.{impl_class}') 152 153 return package_name, class_names 154 155 156class _MetadataParser: 157 158 def __init__(self, chromium_code, exclude_globs, include_globs): 159 self._chromium_code = chromium_code 160 self._exclude_globs = exclude_globs 161 self._include_globs = include_globs 162 # Map of .java path -> .srcjar/nested/path.java. 163 self._srcjar_files = {} 164 # Map of @ServiceImpl class -> impl class 165 self.services_map = collections.defaultdict(list) 166 167 def AddSrcJarSources(self, srcjar_path, extracted_paths, parent_dir): 168 for path in extracted_paths: 169 # We want the path inside the srcjar so the viewer can have a tree 170 # structure. 171 self._srcjar_files[path] = '{}/{}'.format( 172 srcjar_path, os.path.relpath(path, parent_dir)) 173 174 def _CheckPathMatchesClassName(self, source_file, package_name, class_name): 175 if source_file.endswith('.java'): 176 parts = package_name.split('.') + [class_name + '.java'] 177 else: 178 parts = package_name.split('.') + [class_name + '.kt'] 179 expected_suffix = os.path.sep.join(parts) 180 if not source_file.endswith(expected_suffix): 181 raise Exception(('Source package+class name do not match its path.\n' 182 'Actual path: %s\nExpected path: %s') % 183 (source_file, expected_suffix)) 184 185 def _ProcessInfo(self, java_file, package_name, class_names, source): 186 for class_name in class_names: 187 yield '{}.{}'.format(package_name, class_name) 188 # Skip aidl srcjars since they don't indent code correctly. 189 if '_aidl.srcjar' in source: 190 continue 191 assert not self._chromium_code or len(class_names) == 1, ( 192 'Chromium java files must only have one class: {} found: {}'.format( 193 source, class_names)) 194 if self._chromium_code: 195 # This check is not necessary but nice to check this somewhere. 196 self._CheckPathMatchesClassName(java_file, package_name, class_names[0]) 197 198 def _ShouldIncludeInJarInfo(self, fully_qualified_name): 199 name_as_class_glob = fully_qualified_name.replace('.', '/') + '.class' 200 if self._include_globs and not build_utils.MatchesGlob( 201 name_as_class_glob, self._include_globs): 202 return False 203 return not build_utils.MatchesGlob(name_as_class_glob, self._exclude_globs) 204 205 def ParseAndWriteInfoFile(self, output_path, java_files, kt_files=None): 206 """Writes a .jar.info file. 207 208 Maps fully qualified names for classes to either the java file that they 209 are defined in or the path of the srcjar that they came from. 210 """ 211 logging.info('Collecting info file entries') 212 entries = {} 213 for path in itertools.chain(java_files, kt_files or []): 214 data = pathlib.Path(path).read_text() 215 package_name, class_names = ParseJavaSource(data, 216 self.services_map, 217 path=path) 218 source = self._srcjar_files.get(path, path) 219 for fully_qualified_name in self._ProcessInfo(path, package_name, 220 class_names, source): 221 if self._ShouldIncludeInJarInfo(fully_qualified_name): 222 entries[fully_qualified_name] = path 223 224 logging.info('Writing info file: %s', output_path) 225 with action_helpers.atomic_output(output_path, mode='wb') as f: 226 jar_info_utils.WriteJarInfoFile(f, entries, self._srcjar_files) 227 logging.info('Completed info file: %s', output_path) 228 229 230def _OnStaleMd5(changes, 231 options, 232 javac_cmd, 233 javac_args, 234 java_files, 235 kt_files, 236 use_errorprone=False): 237 logging.info('Starting _OnStaleMd5') 238 239 if options.enable_kythe_annotations: 240 # Kythe requires those env variables to be set and compile_java.py does the 241 # same 242 if not os.environ.get('KYTHE_ROOT_DIRECTORY') or \ 243 not os.environ.get('KYTHE_OUTPUT_DIRECTORY'): 244 raise Exception('--enable-kythe-annotations requires ' 245 'KYTHE_ROOT_DIRECTORY and KYTHE_OUTPUT_DIRECTORY ' 246 'environment variables to be set.') 247 javac_extractor_cmd = build_utils.JavaCmd() + [ 248 '--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', 249 '--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', 250 '--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', 251 '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', 252 '--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED', 253 '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', 254 '--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED', 255 '-jar', 256 _JAVAC_EXTRACTOR, 257 ] 258 try: 259 # _RunCompiler()'s partial javac implementation does not support 260 # generating outputs in $KYTHE_OUTPUT_DIRECTORY. 261 _RunCompiler(changes, 262 options, 263 javac_extractor_cmd + javac_args, 264 java_files, 265 options.jar_path + '.javac_extractor', 266 enable_partial_javac=False) 267 except build_utils.CalledProcessError as e: 268 # Having no index for particular target is better than failing entire 269 # codesearch. Log and error and move on. 270 logging.error('Could not generate kzip: %s', e) 271 272 intermediates_out_dir = None 273 jar_info_path = None 274 if not use_errorprone: 275 # Delete any stale files in the generated directory. The purpose of 276 # options.generated_dir is for codesearch and Android Studio. 277 shutil.rmtree(options.generated_dir, True) 278 intermediates_out_dir = options.generated_dir 279 280 # Write .info file only for the main javac invocation (no need to do it 281 # when running Error Prone. 282 jar_info_path = options.jar_path + '.info' 283 284 # Compiles with Error Prone take twice as long to run as pure javac. Thus GN 285 # rules run both in parallel, with Error Prone only used for checks. 286 try: 287 _RunCompiler(changes, 288 options, 289 javac_cmd + javac_args, 290 java_files, 291 options.jar_path, 292 use_errorprone=use_errorprone, 293 kt_files=kt_files, 294 jar_info_path=jar_info_path, 295 intermediates_out_dir=intermediates_out_dir, 296 enable_partial_javac=True) 297 except build_utils.CalledProcessError as e: 298 # Do not output stacktrace as it takes up space on gerrit UI, forcing 299 # you to click though to find the actual compilation error. It's never 300 # interesting to see the Python stacktrace for a Java compilation error. 301 sys.stderr.write(e.output) 302 sys.exit(1) 303 304 logging.info('Completed all steps in _OnStaleMd5') 305 306 307def _RunCompiler(changes, 308 options, 309 javac_cmd, 310 java_files, 311 jar_path, 312 use_errorprone=False, 313 kt_files=None, 314 jar_info_path=None, 315 intermediates_out_dir=None, 316 enable_partial_javac=False): 317 """Runs java compiler. 318 319 Args: 320 changes: md5_check.Changes object. 321 options: Object with command line flags. 322 javac_cmd: Command to execute. 323 java_files: List of java files passed from command line. 324 jar_path: Path of output jar file. 325 kt_files: List of Kotlin files passed from command line if any. 326 jar_info_path: Path of the .info file to generate. 327 If None, .info file will not be generated. 328 intermediates_out_dir: Directory for saving intermediate outputs. 329 If None a temporary directory is used. 330 enable_partial_javac: Enables compiling only Java files which have changed 331 in the special case that no method signatures have changed. This is 332 useful for large GN targets. 333 Not supported if compiling generates outputs other than |jar_path| and 334 |jar_info_path|. 335 """ 336 logging.info('Starting _RunCompiler') 337 338 java_files = java_files.copy() 339 java_srcjars = options.java_srcjars 340 parse_java_files = jar_info_path is not None 341 342 # Use jar_path's directory to ensure paths are relative (needed for rbe). 343 temp_dir = jar_path + '.staging' 344 build_utils.DeleteDirectory(temp_dir) 345 os.makedirs(temp_dir) 346 metadata_parser = _MetadataParser(options.chromium_code, 347 options.jar_info_exclude_globs, 348 options.jar_info_include_globs) 349 try: 350 classes_dir = os.path.join(temp_dir, 'classes') 351 352 if java_files: 353 os.makedirs(classes_dir) 354 355 if enable_partial_javac and changes: 356 all_changed_paths_are_java = all( 357 p.endswith(".java") for p in changes.IterChangedPaths()) 358 if (all_changed_paths_are_java and not changes.HasStringChanges() 359 and os.path.exists(jar_path) 360 and (jar_info_path is None or os.path.exists(jar_info_path))): 361 # Log message is used by tests to determine whether partial javac 362 # optimization was used. 363 logging.info('Using partial javac optimization for %s compile' % 364 (jar_path)) 365 366 # Header jar corresponding to |java_files| did not change. 367 # As a build speed optimization (crbug.com/1170778), re-compile only 368 # java files which have changed. Re-use old jar .info file. 369 java_files = list(changes.IterChangedPaths()) 370 371 # Disable srcjar extraction, since we know the srcjar didn't show as 372 # changed (only .java files). 373 java_srcjars = None 374 375 # @ServiceImpl has class retention, so will alter header jars when 376 # modified (and hence not reach this block). 377 # Likewise, nothing in .info files can change if header jar did not 378 # change. 379 parse_java_files = False 380 381 # Extracts .class as well as META-INF/services. 382 build_utils.ExtractAll(jar_path, classes_dir) 383 384 if intermediates_out_dir is None: 385 intermediates_out_dir = temp_dir 386 387 input_srcjars_dir = os.path.join(intermediates_out_dir, 'input_srcjars') 388 389 if java_srcjars: 390 logging.info('Extracting srcjars to %s', input_srcjars_dir) 391 build_utils.MakeDirectory(input_srcjars_dir) 392 for srcjar in options.java_srcjars: 393 extracted_files = build_utils.ExtractAll( 394 srcjar, no_clobber=True, path=input_srcjars_dir, pattern='*.java') 395 java_files.extend(extracted_files) 396 if parse_java_files: 397 metadata_parser.AddSrcJarSources(srcjar, extracted_files, 398 input_srcjars_dir) 399 logging.info('Done extracting srcjars') 400 401 if java_files: 402 # Don't include the output directory in the initial set of args since it 403 # being in a temp dir makes it unstable (breaks md5 stamping). 404 cmd = list(javac_cmd) 405 cmd += ['-d', classes_dir] 406 407 if options.classpath: 408 cmd += ['-classpath', ':'.join(options.classpath)] 409 410 # Pass source paths as response files to avoid extremely long command 411 # lines that are tedius to debug. 412 java_files_rsp_path = os.path.join(temp_dir, 'files_list.txt') 413 with open(java_files_rsp_path, 'w') as f: 414 f.write(' '.join(java_files)) 415 cmd += ['@' + java_files_rsp_path] 416 417 process_javac_output_partial = functools.partial( 418 ProcessJavacOutput, target_name=options.target_name) 419 420 logging.debug('Build command %s', cmd) 421 start = time.time() 422 before_join_callback = None 423 if parse_java_files: 424 before_join_callback = lambda: metadata_parser.ParseAndWriteInfoFile( 425 jar_info_path, java_files, kt_files) 426 427 if options.print_javac_command_line: 428 print(shlex.join(cmd)) 429 return 430 431 build_utils.CheckOutput(cmd, 432 print_stdout=options.chromium_code, 433 stdout_filter=process_javac_output_partial, 434 stderr_filter=process_javac_output_partial, 435 fail_on_output=options.warnings_as_errors, 436 before_join_callback=before_join_callback) 437 end = time.time() - start 438 logging.info('Java compilation took %ss', end) 439 elif parse_java_files: 440 if options.print_javac_command_line: 441 raise Exception('need java files for --print-javac-command-line.') 442 metadata_parser.ParseAndWriteInfoFile(jar_info_path, java_files, kt_files) 443 444 if use_errorprone: 445 # There is no jar file when running errorprone and jar_path is actually 446 # just the stamp file for that target. 447 server_utils.MaybeTouch(jar_path) 448 else: 449 CreateJarFile(jar_path, classes_dir, metadata_parser.services_map, 450 options.additional_jar_files, options.kotlin_jar_path) 451 452 453 # Remove input srcjars that confuse Android Studio: 454 # https://crbug.com/353326240 455 for root, _, files in os.walk(intermediates_out_dir): 456 for subpath in files: 457 p = os.path.join(root, subpath) 458 # JNI Zero placeholders 459 if '_jni_java/' in p and not p.endswith('Jni.java'): 460 os.unlink(p) 461 462 logging.info('Completed all steps in _RunCompiler') 463 finally: 464 # preserve temp_dir for rsp fie when --print-javac-command-line 465 if not options.print_javac_command_line: 466 shutil.rmtree(temp_dir) 467 468 469def _ParseOptions(argv): 470 parser = argparse.ArgumentParser() 471 action_helpers.add_depfile_arg(parser) 472 473 parser.add_argument('--target-name', help='Fully qualified GN target name.') 474 parser.add_argument('--java-srcjars', 475 action='append', 476 default=[], 477 help='List of srcjars to include in compilation.') 478 parser.add_argument( 479 '--generated-dir', 480 help='Subdirectory within target_gen_dir to place extracted srcjars and ' 481 'annotation processor output for codesearch to find.') 482 parser.add_argument('--classpath', action='append', help='Classpath to use.') 483 parser.add_argument( 484 '--processorpath', 485 action='append', 486 help='GN list of jars that comprise the classpath used for Annotation ' 487 'Processors.') 488 parser.add_argument('--processor-arg', 489 dest='processor_args', 490 action='append', 491 help='key=value arguments for the annotation processors.') 492 parser.add_argument( 493 '--additional-jar-file', 494 dest='additional_jar_files', 495 action='append', 496 help='Additional files to package into jar. By default, only Java .class ' 497 'files are packaged into the jar. Files should be specified in ' 498 'format <filename>:<path to be placed in jar>.') 499 parser.add_argument( 500 '--jar-info-exclude-globs', 501 help='GN list of exclude globs to filter from generated .info files.') 502 parser.add_argument( 503 '--jar-info-include-globs', 504 help='GN list of inlclude globs to filter from generated .info files.') 505 parser.add_argument( 506 '--chromium-code', 507 action='store_true', 508 help='Whether code being compiled should be built with stricter ' 509 'warnings for chromium code.') 510 parser.add_argument('--warnings-as-errors', 511 action='store_true', 512 help='Treat all warnings as errors.') 513 parser.add_argument('--jar-path', required=True, help='Jar output path.') 514 parser.add_argument('--javac-arg', 515 action='append', 516 default=[], 517 help='Additional arguments to pass to javac.') 518 parser.add_argument('--print-javac-command-line', 519 action='store_true', 520 help='Just show javac command line (for ide_query).') 521 parser.add_argument( 522 '--enable-kythe-annotations', 523 action='store_true', 524 help='Enable generation of Kythe kzip, used for codesearch. Ensure ' 525 'proper environment variables are set before using this flag.') 526 parser.add_argument( 527 '--header-jar', 528 help='This is the header jar for the current target that contains ' 529 'META-INF/services/* files to be included in the output jar.') 530 parser.add_argument( 531 '--kotlin-jar-path', 532 help='Kotlin jar to be merged into the output jar. This contains the ' 533 ".class files from this target's .kt files.") 534 parser.add_argument('sources', nargs='*') 535 536 options = parser.parse_args(argv) 537 538 options.classpath = action_helpers.parse_gn_list(options.classpath) 539 options.processorpath = action_helpers.parse_gn_list(options.processorpath) 540 options.java_srcjars = action_helpers.parse_gn_list(options.java_srcjars) 541 options.jar_info_exclude_globs = action_helpers.parse_gn_list( 542 options.jar_info_exclude_globs) 543 options.jar_info_include_globs = action_helpers.parse_gn_list( 544 options.jar_info_include_globs) 545 546 additional_jar_files = [] 547 for arg in options.additional_jar_files or []: 548 filepath, jar_filepath = arg.split(':') 549 additional_jar_files.append((filepath, jar_filepath)) 550 options.additional_jar_files = additional_jar_files 551 552 files = [] 553 for arg in options.sources: 554 # Interpret a path prefixed with @ as a file containing a list of sources. 555 if arg.startswith('@'): 556 files.extend(build_utils.ReadSourcesList(arg[1:])) 557 else: 558 files.append(arg) 559 560 # The target's .sources file contains both Java and Kotlin files. We use 561 # compile_kt.py to compile the Kotlin files to .class and header jars. Javac 562 # is run only on .java files. 563 java_files = [f for f in files if f.endswith('.java')] 564 # Kotlin files are needed to populate the info file and attribute size in 565 # supersize back to the appropriate Kotlin file. 566 kt_files = [f for f in files if f.endswith('.kt')] 567 568 return options, java_files, kt_files 569 570 571def main(argv, 572 extra_javac_args=None, 573 use_errorprone=False, 574 write_depfile_only=False): 575 build_utils.InitLogging('JAVAC_DEBUG') 576 argv = build_utils.ExpandFileArgs(argv) 577 options, java_files, kt_files = _ParseOptions(argv) 578 579 javac_cmd = [build_utils.JAVAC_PATH] 580 581 javac_args = [ 582 '-g', 583 # Required for Error Prone's /* paramName= */ check. 584 '-parameters', 585 # Jacoco does not currently support a higher value. 586 '--release', 587 '17', 588 # Chromium only allows UTF8 source files. Being explicit avoids 589 # javac pulling a default encoding from the user's environment. 590 '-encoding', 591 'UTF-8', 592 # Prevent compiler from compiling .java files not listed as inputs. 593 # See: http://blog.ltgt.net/most-build-tools-misuse-javac/ 594 '-sourcepath', 595 ':', 596 # protobuf-generated files fail this check (javadoc has @deprecated, 597 # but method missing @Deprecated annotation). 598 '-Xlint:-dep-ann', 599 # Do not warn about finalize() methods. Android still intends to support 600 # them. 601 '-Xlint:-removal', 602 # https://crbug.com/1441023 603 '-J-XX:+PerfDisableSharedMem', 604 605 # Disable all annotation processors (we run them via Turbine). 606 '-proc:none', 607 ] 608 609 if extra_javac_args: 610 javac_args.extend(extra_javac_args) 611 612 if options.processorpath: 613 javac_args.extend(['-processorpath', ':'.join(options.processorpath)]) 614 if options.processor_args: 615 for arg in options.processor_args: 616 javac_args.extend(['-A%s' % arg]) 617 618 javac_args.extend(options.javac_arg) 619 620 do_it = lambda changes: _OnStaleMd5(changes, 621 options, 622 javac_cmd, 623 javac_args, 624 java_files, 625 kt_files, 626 use_errorprone=use_errorprone) 627 628 if options.print_javac_command_line: 629 if options.java_srcjars: 630 raise Exception( 631 '--print-javac-command-line does not work with --java-srcjars') 632 do_it(None) 633 return 0 634 635 depfile_deps = options.classpath + options.processorpath 636 637 output_paths = [options.jar_path] 638 if not use_errorprone: 639 jar_info_path = options.jar_path + '.info' 640 output_paths.append(jar_info_path) 641 642 # Incremental build optimization doesn't work for ErrorProne. Skip md5 check. 643 if write_depfile_only: 644 action_helpers.write_depfile(options.depfile, output_paths[0], depfile_deps) 645 elif use_errorprone: 646 do_it(None) 647 action_helpers.write_depfile(options.depfile, output_paths[0], depfile_deps) 648 else: 649 # Files that are already inputs in GN should go in input_paths. 650 input_paths = ([build_utils.JAVAC_PATH] + depfile_deps + 651 options.java_srcjars + java_files + kt_files) 652 if options.header_jar: 653 input_paths.append(options.header_jar) 654 input_paths += [x[0] for x in options.additional_jar_files] 655 656 input_strings = ( 657 javac_cmd + javac_args + options.classpath + java_files + kt_files + [ 658 options.warnings_as_errors, options.jar_info_exclude_globs, 659 options.jar_info_include_globs 660 ]) 661 662 # Use md5_check for |pass_changes| feature. 663 md5_check.CallAndWriteDepfileIfStale(do_it, 664 options, 665 depfile_deps=depfile_deps, 666 input_paths=input_paths, 667 input_strings=input_strings, 668 output_paths=output_paths, 669 pass_changes=True) 670 return 0 671 672 673if __name__ == '__main__': 674 sys.exit(main(sys.argv[1:])) 675