1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6777b538SAndroid Build Coastguard Worker# 3*6777b538SAndroid Build Coastguard Worker# Copyright 2013 The Chromium Authors 4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Workerimport argparse 8*6777b538SAndroid Build Coastguard Workerimport collections 9*6777b538SAndroid Build Coastguard Workerimport logging 10*6777b538SAndroid Build Coastguard Workerimport os 11*6777b538SAndroid Build Coastguard Workerimport re 12*6777b538SAndroid Build Coastguard Workerimport shutil 13*6777b538SAndroid Build Coastguard Workerimport shlex 14*6777b538SAndroid Build Coastguard Workerimport sys 15*6777b538SAndroid Build Coastguard Workerimport tempfile 16*6777b538SAndroid Build Coastguard Workerimport zipfile 17*6777b538SAndroid Build Coastguard Worker 18*6777b538SAndroid Build Coastguard Workerfrom util import build_utils 19*6777b538SAndroid Build Coastguard Workerfrom util import md5_check 20*6777b538SAndroid Build Coastguard Workerimport action_helpers # build_utils adds //build to sys.path. 21*6777b538SAndroid Build Coastguard Workerimport zip_helpers 22*6777b538SAndroid Build Coastguard Worker 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker_DEX_XMX = '2G' # Increase this when __final_dex OOMs. 25*6777b538SAndroid Build Coastguard Worker 26*6777b538SAndroid Build Coastguard WorkerDEFAULT_IGNORE_WARNINGS = ( 27*6777b538SAndroid Build Coastguard Worker # Warning: Running R8 version main (build engineering), which cannot be 28*6777b538SAndroid Build Coastguard Worker # represented as a semantic version. Using an artificial version newer than 29*6777b538SAndroid Build Coastguard Worker # any known version for selecting Proguard configurations embedded under 30*6777b538SAndroid Build Coastguard Worker # META-INF/. This means that all rules with a '-upto-' qualifier will be 31*6777b538SAndroid Build Coastguard Worker # excluded and all rules with a -from- qualifier will be included. 32*6777b538SAndroid Build Coastguard Worker r'Running R8 version main', ) 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard WorkerINTERFACE_DESUGARING_WARNINGS = (r'default or static interface methods', ) 35*6777b538SAndroid Build Coastguard Worker 36*6777b538SAndroid Build Coastguard Worker_SKIPPED_CLASS_FILE_NAMES = ( 37*6777b538SAndroid Build Coastguard Worker 'module-info.class', # Explicitly skipped by r8/utils/FileUtils#isClassFile 38*6777b538SAndroid Build Coastguard Worker) 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Workerdef _ParseArgs(args): 42*6777b538SAndroid Build Coastguard Worker args = build_utils.ExpandFileArgs(args) 43*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 44*6777b538SAndroid Build Coastguard Worker 45*6777b538SAndroid Build Coastguard Worker action_helpers.add_depfile_arg(parser) 46*6777b538SAndroid Build Coastguard Worker parser.add_argument('--output', required=True, help='Dex output path.') 47*6777b538SAndroid Build Coastguard Worker parser.add_argument( 48*6777b538SAndroid Build Coastguard Worker '--class-inputs', 49*6777b538SAndroid Build Coastguard Worker action='append', 50*6777b538SAndroid Build Coastguard Worker help='GN-list of .jars with .class files.') 51*6777b538SAndroid Build Coastguard Worker parser.add_argument( 52*6777b538SAndroid Build Coastguard Worker '--class-inputs-filearg', 53*6777b538SAndroid Build Coastguard Worker action='append', 54*6777b538SAndroid Build Coastguard Worker help='GN-list of .jars with .class files (added to depfile).') 55*6777b538SAndroid Build Coastguard Worker parser.add_argument( 56*6777b538SAndroid Build Coastguard Worker '--dex-inputs', action='append', help='GN-list of .jars with .dex files.') 57*6777b538SAndroid Build Coastguard Worker parser.add_argument( 58*6777b538SAndroid Build Coastguard Worker '--dex-inputs-filearg', 59*6777b538SAndroid Build Coastguard Worker action='append', 60*6777b538SAndroid Build Coastguard Worker help='GN-list of .jars with .dex files (added to depfile).') 61*6777b538SAndroid Build Coastguard Worker parser.add_argument( 62*6777b538SAndroid Build Coastguard Worker '--incremental-dir', 63*6777b538SAndroid Build Coastguard Worker help='Path of directory to put intermediate dex files.') 64*6777b538SAndroid Build Coastguard Worker parser.add_argument('--library', 65*6777b538SAndroid Build Coastguard Worker action='store_true', 66*6777b538SAndroid Build Coastguard Worker help='Allow numerous dex files within output.') 67*6777b538SAndroid Build Coastguard Worker parser.add_argument('--r8-jar-path', required=True, help='Path to R8 jar.') 68*6777b538SAndroid Build Coastguard Worker parser.add_argument('--skip-custom-d8', 69*6777b538SAndroid Build Coastguard Worker action='store_true', 70*6777b538SAndroid Build Coastguard Worker help='When rebuilding the CustomD8 jar, this may be ' 71*6777b538SAndroid Build Coastguard Worker 'necessary to avoid incompatibility with the new r8 ' 72*6777b538SAndroid Build Coastguard Worker 'jar.') 73*6777b538SAndroid Build Coastguard Worker parser.add_argument('--custom-d8-jar-path', 74*6777b538SAndroid Build Coastguard Worker required=True, 75*6777b538SAndroid Build Coastguard Worker help='Path to our customized d8 jar.') 76*6777b538SAndroid Build Coastguard Worker parser.add_argument('--desugar-dependencies', 77*6777b538SAndroid Build Coastguard Worker help='Path to store desugar dependencies.') 78*6777b538SAndroid Build Coastguard Worker parser.add_argument('--desugar', action='store_true') 79*6777b538SAndroid Build Coastguard Worker parser.add_argument( 80*6777b538SAndroid Build Coastguard Worker '--bootclasspath', 81*6777b538SAndroid Build Coastguard Worker action='append', 82*6777b538SAndroid Build Coastguard Worker help='GN-list of bootclasspath. Needed for --desugar') 83*6777b538SAndroid Build Coastguard Worker parser.add_argument('--show-desugar-default-interface-warnings', 84*6777b538SAndroid Build Coastguard Worker action='store_true', 85*6777b538SAndroid Build Coastguard Worker help='Enable desugaring warnings.') 86*6777b538SAndroid Build Coastguard Worker parser.add_argument( 87*6777b538SAndroid Build Coastguard Worker '--classpath', 88*6777b538SAndroid Build Coastguard Worker action='append', 89*6777b538SAndroid Build Coastguard Worker help='GN-list of full classpath. Needed for --desugar') 90*6777b538SAndroid Build Coastguard Worker parser.add_argument('--release', 91*6777b538SAndroid Build Coastguard Worker action='store_true', 92*6777b538SAndroid Build Coastguard Worker help='Run D8 in release mode.') 93*6777b538SAndroid Build Coastguard Worker parser.add_argument( 94*6777b538SAndroid Build Coastguard Worker '--min-api', help='Minimum Android API level compatibility.') 95*6777b538SAndroid Build Coastguard Worker parser.add_argument('--force-enable-assertions', 96*6777b538SAndroid Build Coastguard Worker action='store_true', 97*6777b538SAndroid Build Coastguard Worker help='Forcefully enable javac generated assertion code.') 98*6777b538SAndroid Build Coastguard Worker parser.add_argument('--assertion-handler', 99*6777b538SAndroid Build Coastguard Worker help='The class name of the assertion handler class.') 100*6777b538SAndroid Build Coastguard Worker parser.add_argument('--warnings-as-errors', 101*6777b538SAndroid Build Coastguard Worker action='store_true', 102*6777b538SAndroid Build Coastguard Worker help='Treat all warnings as errors.') 103*6777b538SAndroid Build Coastguard Worker parser.add_argument('--dump-inputs', 104*6777b538SAndroid Build Coastguard Worker action='store_true', 105*6777b538SAndroid Build Coastguard Worker help='Use when filing D8 bugs to capture inputs.' 106*6777b538SAndroid Build Coastguard Worker ' Stores inputs to d8inputs.zip') 107*6777b538SAndroid Build Coastguard Worker options = parser.parse_args(args) 108*6777b538SAndroid Build Coastguard Worker 109*6777b538SAndroid Build Coastguard Worker if options.force_enable_assertions and options.assertion_handler: 110*6777b538SAndroid Build Coastguard Worker parser.error('Cannot use both --force-enable-assertions and ' 111*6777b538SAndroid Build Coastguard Worker '--assertion-handler') 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker options.class_inputs = action_helpers.parse_gn_list(options.class_inputs) 114*6777b538SAndroid Build Coastguard Worker options.class_inputs_filearg = action_helpers.parse_gn_list( 115*6777b538SAndroid Build Coastguard Worker options.class_inputs_filearg) 116*6777b538SAndroid Build Coastguard Worker options.bootclasspath = action_helpers.parse_gn_list(options.bootclasspath) 117*6777b538SAndroid Build Coastguard Worker options.classpath = action_helpers.parse_gn_list(options.classpath) 118*6777b538SAndroid Build Coastguard Worker options.dex_inputs = action_helpers.parse_gn_list(options.dex_inputs) 119*6777b538SAndroid Build Coastguard Worker options.dex_inputs_filearg = action_helpers.parse_gn_list( 120*6777b538SAndroid Build Coastguard Worker options.dex_inputs_filearg) 121*6777b538SAndroid Build Coastguard Worker 122*6777b538SAndroid Build Coastguard Worker return options 123*6777b538SAndroid Build Coastguard Worker 124*6777b538SAndroid Build Coastguard Worker 125*6777b538SAndroid Build Coastguard Workerdef CreateStderrFilter(filters): 126*6777b538SAndroid Build Coastguard Worker def filter_stderr(output): 127*6777b538SAndroid Build Coastguard Worker # Set this when debugging R8 output. 128*6777b538SAndroid Build Coastguard Worker if os.environ.get('R8_SHOW_ALL_OUTPUT', '0') != '0': 129*6777b538SAndroid Build Coastguard Worker return output 130*6777b538SAndroid Build Coastguard Worker 131*6777b538SAndroid Build Coastguard Worker # All missing definitions are logged as a single warning, but start on a 132*6777b538SAndroid Build Coastguard Worker # new line like "Missing class ...". 133*6777b538SAndroid Build Coastguard Worker warnings = re.split(r'^(?=Warning|Error|Missing (?:class|field|method))', 134*6777b538SAndroid Build Coastguard Worker output, 135*6777b538SAndroid Build Coastguard Worker flags=re.MULTILINE) 136*6777b538SAndroid Build Coastguard Worker preamble, *warnings = warnings 137*6777b538SAndroid Build Coastguard Worker 138*6777b538SAndroid Build Coastguard Worker combined_pattern = '|'.join(filters) 139*6777b538SAndroid Build Coastguard Worker preamble = build_utils.FilterLines(preamble, combined_pattern) 140*6777b538SAndroid Build Coastguard Worker 141*6777b538SAndroid Build Coastguard Worker compiled_re = re.compile(combined_pattern, re.DOTALL) 142*6777b538SAndroid Build Coastguard Worker warnings = [w for w in warnings if not compiled_re.search(w)] 143*6777b538SAndroid Build Coastguard Worker 144*6777b538SAndroid Build Coastguard Worker return preamble + ''.join(warnings) 145*6777b538SAndroid Build Coastguard Worker 146*6777b538SAndroid Build Coastguard Worker return filter_stderr 147*6777b538SAndroid Build Coastguard Worker 148*6777b538SAndroid Build Coastguard Worker 149*6777b538SAndroid Build Coastguard Workerdef _RunD8(dex_cmd, input_paths, output_path, warnings_as_errors, 150*6777b538SAndroid Build Coastguard Worker show_desugar_default_interface_warnings): 151*6777b538SAndroid Build Coastguard Worker dex_cmd = dex_cmd + ['--output', output_path] + input_paths 152*6777b538SAndroid Build Coastguard Worker 153*6777b538SAndroid Build Coastguard Worker # Missing deps can happen for prebuilts that are missing transitive deps 154*6777b538SAndroid Build Coastguard Worker # and have set enable_bytecode_checks=false. 155*6777b538SAndroid Build Coastguard Worker filters = list(DEFAULT_IGNORE_WARNINGS) 156*6777b538SAndroid Build Coastguard Worker if not show_desugar_default_interface_warnings: 157*6777b538SAndroid Build Coastguard Worker filters += INTERFACE_DESUGARING_WARNINGS 158*6777b538SAndroid Build Coastguard Worker 159*6777b538SAndroid Build Coastguard Worker stderr_filter = CreateStderrFilter(filters) 160*6777b538SAndroid Build Coastguard Worker 161*6777b538SAndroid Build Coastguard Worker is_debug = logging.getLogger().isEnabledFor(logging.DEBUG) 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker # Avoid deleting the flag file when DEX_DEBUG is set in case the flag file 164*6777b538SAndroid Build Coastguard Worker # needs to be examined after the build. 165*6777b538SAndroid Build Coastguard Worker with tempfile.NamedTemporaryFile(mode='w', delete=not is_debug) as flag_file: 166*6777b538SAndroid Build Coastguard Worker # Chosen arbitrarily. Needed to avoid command-line length limits. 167*6777b538SAndroid Build Coastguard Worker MAX_ARGS = 50 168*6777b538SAndroid Build Coastguard Worker orig_dex_cmd = dex_cmd 169*6777b538SAndroid Build Coastguard Worker if len(dex_cmd) > MAX_ARGS: 170*6777b538SAndroid Build Coastguard Worker # Add all flags to D8 (anything after the first --) as well as all 171*6777b538SAndroid Build Coastguard Worker # positional args at the end to the flag file. 172*6777b538SAndroid Build Coastguard Worker for idx, cmd in enumerate(dex_cmd): 173*6777b538SAndroid Build Coastguard Worker if cmd.startswith('--'): 174*6777b538SAndroid Build Coastguard Worker flag_file.write('\n'.join(dex_cmd[idx:])) 175*6777b538SAndroid Build Coastguard Worker flag_file.flush() 176*6777b538SAndroid Build Coastguard Worker dex_cmd = dex_cmd[:idx] 177*6777b538SAndroid Build Coastguard Worker dex_cmd.append('@' + flag_file.name) 178*6777b538SAndroid Build Coastguard Worker break 179*6777b538SAndroid Build Coastguard Worker 180*6777b538SAndroid Build Coastguard Worker # stdout sometimes spams with things like: 181*6777b538SAndroid Build Coastguard Worker # Stripped invalid locals information from 1 method. 182*6777b538SAndroid Build Coastguard Worker try: 183*6777b538SAndroid Build Coastguard Worker build_utils.CheckOutput(dex_cmd, 184*6777b538SAndroid Build Coastguard Worker stderr_filter=stderr_filter, 185*6777b538SAndroid Build Coastguard Worker fail_on_output=warnings_as_errors) 186*6777b538SAndroid Build Coastguard Worker except Exception as e: 187*6777b538SAndroid Build Coastguard Worker if isinstance(e, build_utils.CalledProcessError): 188*6777b538SAndroid Build Coastguard Worker output = e.output # pylint: disable=no-member 189*6777b538SAndroid Build Coastguard Worker if "global synthetic for 'Record desugaring'" in output: 190*6777b538SAndroid Build Coastguard Worker sys.stderr.write('Java records are not supported.\n') 191*6777b538SAndroid Build Coastguard Worker sys.stderr.write( 192*6777b538SAndroid Build Coastguard Worker 'See https://chromium.googlesource.com/chromium/src/+/' + 193*6777b538SAndroid Build Coastguard Worker 'main/styleguide/java/java.md#Records\n') 194*6777b538SAndroid Build Coastguard Worker sys.exit(1) 195*6777b538SAndroid Build Coastguard Worker if orig_dex_cmd is not dex_cmd: 196*6777b538SAndroid Build Coastguard Worker sys.stderr.write('Full command: ' + shlex.join(orig_dex_cmd) + '\n') 197*6777b538SAndroid Build Coastguard Worker raise 198*6777b538SAndroid Build Coastguard Worker 199*6777b538SAndroid Build Coastguard Worker 200*6777b538SAndroid Build Coastguard Workerdef _ZipAligned(dex_files, output_path): 201*6777b538SAndroid Build Coastguard Worker """Creates a .dex.jar with 4-byte aligned files. 202*6777b538SAndroid Build Coastguard Worker 203*6777b538SAndroid Build Coastguard Worker Args: 204*6777b538SAndroid Build Coastguard Worker dex_files: List of dex files. 205*6777b538SAndroid Build Coastguard Worker output_path: The output file in which to write the zip. 206*6777b538SAndroid Build Coastguard Worker """ 207*6777b538SAndroid Build Coastguard Worker with zipfile.ZipFile(output_path, 'w') as z: 208*6777b538SAndroid Build Coastguard Worker for i, dex_file in enumerate(dex_files): 209*6777b538SAndroid Build Coastguard Worker name = 'classes{}.dex'.format(i + 1 if i > 0 else '') 210*6777b538SAndroid Build Coastguard Worker zip_helpers.add_to_zip_hermetic(z, name, src_path=dex_file, alignment=4) 211*6777b538SAndroid Build Coastguard Worker 212*6777b538SAndroid Build Coastguard Worker 213*6777b538SAndroid Build Coastguard Workerdef _CreateFinalDex(d8_inputs, output, tmp_dir, dex_cmd, options=None): 214*6777b538SAndroid Build Coastguard Worker tmp_dex_output = os.path.join(tmp_dir, 'tmp_dex_output.zip') 215*6777b538SAndroid Build Coastguard Worker needs_dexing = not all(f.endswith('.dex') for f in d8_inputs) 216*6777b538SAndroid Build Coastguard Worker needs_dexmerge = output.endswith('.dex') or not (options and options.library) 217*6777b538SAndroid Build Coastguard Worker if needs_dexing or needs_dexmerge: 218*6777b538SAndroid Build Coastguard Worker tmp_dex_dir = os.path.join(tmp_dir, 'tmp_dex_dir') 219*6777b538SAndroid Build Coastguard Worker os.mkdir(tmp_dex_dir) 220*6777b538SAndroid Build Coastguard Worker 221*6777b538SAndroid Build Coastguard Worker _RunD8(dex_cmd, d8_inputs, tmp_dex_dir, 222*6777b538SAndroid Build Coastguard Worker (not options or options.warnings_as_errors), 223*6777b538SAndroid Build Coastguard Worker (options and options.show_desugar_default_interface_warnings)) 224*6777b538SAndroid Build Coastguard Worker logging.debug('Performed dex merging') 225*6777b538SAndroid Build Coastguard Worker 226*6777b538SAndroid Build Coastguard Worker dex_files = [os.path.join(tmp_dex_dir, f) for f in os.listdir(tmp_dex_dir)] 227*6777b538SAndroid Build Coastguard Worker 228*6777b538SAndroid Build Coastguard Worker if output.endswith('.dex'): 229*6777b538SAndroid Build Coastguard Worker if len(dex_files) > 1: 230*6777b538SAndroid Build Coastguard Worker raise Exception('%d files created, expected 1' % len(dex_files)) 231*6777b538SAndroid Build Coastguard Worker tmp_dex_output = dex_files[0] 232*6777b538SAndroid Build Coastguard Worker else: 233*6777b538SAndroid Build Coastguard Worker _ZipAligned(sorted(dex_files), tmp_dex_output) 234*6777b538SAndroid Build Coastguard Worker else: 235*6777b538SAndroid Build Coastguard Worker # Skip dexmerger. Just put all incrementals into the .jar individually. 236*6777b538SAndroid Build Coastguard Worker _ZipAligned(sorted(d8_inputs), tmp_dex_output) 237*6777b538SAndroid Build Coastguard Worker logging.debug('Quick-zipped %d files', len(d8_inputs)) 238*6777b538SAndroid Build Coastguard Worker 239*6777b538SAndroid Build Coastguard Worker # The dex file is complete and can be moved out of tmp_dir. 240*6777b538SAndroid Build Coastguard Worker shutil.move(tmp_dex_output, output) 241*6777b538SAndroid Build Coastguard Worker 242*6777b538SAndroid Build Coastguard Worker 243*6777b538SAndroid Build Coastguard Workerdef _IntermediateDexFilePathsFromInputJars(class_inputs, incremental_dir): 244*6777b538SAndroid Build Coastguard Worker """Returns a list of all intermediate dex file paths.""" 245*6777b538SAndroid Build Coastguard Worker dex_files = [] 246*6777b538SAndroid Build Coastguard Worker for jar in class_inputs: 247*6777b538SAndroid Build Coastguard Worker with zipfile.ZipFile(jar, 'r') as z: 248*6777b538SAndroid Build Coastguard Worker for subpath in z.namelist(): 249*6777b538SAndroid Build Coastguard Worker if _IsClassFile(subpath): 250*6777b538SAndroid Build Coastguard Worker subpath = subpath[:-5] + 'dex' 251*6777b538SAndroid Build Coastguard Worker dex_files.append(os.path.join(incremental_dir, subpath)) 252*6777b538SAndroid Build Coastguard Worker return dex_files 253*6777b538SAndroid Build Coastguard Worker 254*6777b538SAndroid Build Coastguard Worker 255*6777b538SAndroid Build Coastguard Workerdef _DeleteStaleIncrementalDexFiles(dex_dir, dex_files): 256*6777b538SAndroid Build Coastguard Worker """Deletes intermediate .dex files that are no longer needed.""" 257*6777b538SAndroid Build Coastguard Worker all_files = build_utils.FindInDirectory(dex_dir) 258*6777b538SAndroid Build Coastguard Worker desired_files = set(dex_files) 259*6777b538SAndroid Build Coastguard Worker for path in all_files: 260*6777b538SAndroid Build Coastguard Worker if path not in desired_files: 261*6777b538SAndroid Build Coastguard Worker os.unlink(path) 262*6777b538SAndroid Build Coastguard Worker 263*6777b538SAndroid Build Coastguard Worker 264*6777b538SAndroid Build Coastguard Workerdef _ParseDesugarDeps(desugar_dependencies_file): 265*6777b538SAndroid Build Coastguard Worker # pylint: disable=line-too-long 266*6777b538SAndroid Build Coastguard Worker """Returns a dict of dependent/dependency mapping parsed from the file. 267*6777b538SAndroid Build Coastguard Worker 268*6777b538SAndroid Build Coastguard Worker Example file format: 269*6777b538SAndroid Build Coastguard Worker $ tail out/Debug/gen/base/base_java__dex.desugardeps 270*6777b538SAndroid Build Coastguard Worker org/chromium/base/task/SingleThreadTaskRunnerImpl.class 271*6777b538SAndroid Build Coastguard Worker <- org/chromium/base/task/SingleThreadTaskRunner.class 272*6777b538SAndroid Build Coastguard Worker <- org/chromium/base/task/TaskRunnerImpl.class 273*6777b538SAndroid Build Coastguard Worker org/chromium/base/task/TaskRunnerImpl.class 274*6777b538SAndroid Build Coastguard Worker <- org/chromium/base/task/TaskRunner.class 275*6777b538SAndroid Build Coastguard Worker org/chromium/base/task/TaskRunnerImplJni$1.class 276*6777b538SAndroid Build Coastguard Worker <- obj/base/jni_java.turbine.jar:org/jni_zero/JniStaticTestMocker.class 277*6777b538SAndroid Build Coastguard Worker org/chromium/base/task/TaskRunnerImplJni.class 278*6777b538SAndroid Build Coastguard Worker <- org/chromium/base/task/TaskRunnerImpl$Natives.class 279*6777b538SAndroid Build Coastguard Worker """ 280*6777b538SAndroid Build Coastguard Worker # pylint: enable=line-too-long 281*6777b538SAndroid Build Coastguard Worker dependents_from_dependency = collections.defaultdict(set) 282*6777b538SAndroid Build Coastguard Worker if desugar_dependencies_file and os.path.exists(desugar_dependencies_file): 283*6777b538SAndroid Build Coastguard Worker with open(desugar_dependencies_file, 'r') as f: 284*6777b538SAndroid Build Coastguard Worker dependent = None 285*6777b538SAndroid Build Coastguard Worker for line in f: 286*6777b538SAndroid Build Coastguard Worker line = line.rstrip() 287*6777b538SAndroid Build Coastguard Worker if line.startswith(' <- '): 288*6777b538SAndroid Build Coastguard Worker dependency = line[len(' <- '):] 289*6777b538SAndroid Build Coastguard Worker # Note that this is a reversed mapping from the one in CustomD8.java. 290*6777b538SAndroid Build Coastguard Worker dependents_from_dependency[dependency].add(dependent) 291*6777b538SAndroid Build Coastguard Worker else: 292*6777b538SAndroid Build Coastguard Worker dependent = line 293*6777b538SAndroid Build Coastguard Worker return dependents_from_dependency 294*6777b538SAndroid Build Coastguard Worker 295*6777b538SAndroid Build Coastguard Worker 296*6777b538SAndroid Build Coastguard Workerdef _ComputeRequiredDesugarClasses(changes, desugar_dependencies_file, 297*6777b538SAndroid Build Coastguard Worker class_inputs, classpath): 298*6777b538SAndroid Build Coastguard Worker dependents_from_dependency = _ParseDesugarDeps(desugar_dependencies_file) 299*6777b538SAndroid Build Coastguard Worker required_classes = set() 300*6777b538SAndroid Build Coastguard Worker # Gather classes that need to be re-desugared from changes in the classpath. 301*6777b538SAndroid Build Coastguard Worker for jar in classpath: 302*6777b538SAndroid Build Coastguard Worker for subpath in changes.IterChangedSubpaths(jar): 303*6777b538SAndroid Build Coastguard Worker dependency = '{}:{}'.format(jar, subpath) 304*6777b538SAndroid Build Coastguard Worker required_classes.update(dependents_from_dependency[dependency]) 305*6777b538SAndroid Build Coastguard Worker 306*6777b538SAndroid Build Coastguard Worker for jar in class_inputs: 307*6777b538SAndroid Build Coastguard Worker for subpath in changes.IterChangedSubpaths(jar): 308*6777b538SAndroid Build Coastguard Worker required_classes.update(dependents_from_dependency[subpath]) 309*6777b538SAndroid Build Coastguard Worker 310*6777b538SAndroid Build Coastguard Worker return required_classes 311*6777b538SAndroid Build Coastguard Worker 312*6777b538SAndroid Build Coastguard Worker 313*6777b538SAndroid Build Coastguard Workerdef _IsClassFile(path): 314*6777b538SAndroid Build Coastguard Worker if os.path.basename(path) in _SKIPPED_CLASS_FILE_NAMES: 315*6777b538SAndroid Build Coastguard Worker return False 316*6777b538SAndroid Build Coastguard Worker return path.endswith('.class') 317*6777b538SAndroid Build Coastguard Worker 318*6777b538SAndroid Build Coastguard Worker 319*6777b538SAndroid Build Coastguard Workerdef _ExtractClassFiles(changes, tmp_dir, class_inputs, required_classes_set): 320*6777b538SAndroid Build Coastguard Worker classes_list = [] 321*6777b538SAndroid Build Coastguard Worker for jar in class_inputs: 322*6777b538SAndroid Build Coastguard Worker if changes: 323*6777b538SAndroid Build Coastguard Worker changed_class_list = (set(changes.IterChangedSubpaths(jar)) 324*6777b538SAndroid Build Coastguard Worker | required_classes_set) 325*6777b538SAndroid Build Coastguard Worker predicate = lambda x: x in changed_class_list and _IsClassFile(x) 326*6777b538SAndroid Build Coastguard Worker else: 327*6777b538SAndroid Build Coastguard Worker predicate = _IsClassFile 328*6777b538SAndroid Build Coastguard Worker 329*6777b538SAndroid Build Coastguard Worker classes_list.extend( 330*6777b538SAndroid Build Coastguard Worker build_utils.ExtractAll(jar, path=tmp_dir, predicate=predicate)) 331*6777b538SAndroid Build Coastguard Worker return classes_list 332*6777b538SAndroid Build Coastguard Worker 333*6777b538SAndroid Build Coastguard Worker 334*6777b538SAndroid Build Coastguard Workerdef _CreateIntermediateDexFiles(changes, options, tmp_dir, dex_cmd): 335*6777b538SAndroid Build Coastguard Worker # Create temporary directory for classes to be extracted to. 336*6777b538SAndroid Build Coastguard Worker tmp_extract_dir = os.path.join(tmp_dir, 'tmp_extract_dir') 337*6777b538SAndroid Build Coastguard Worker os.mkdir(tmp_extract_dir) 338*6777b538SAndroid Build Coastguard Worker 339*6777b538SAndroid Build Coastguard Worker # Do a full rebuild when changes occur in non-input files. 340*6777b538SAndroid Build Coastguard Worker allowed_changed = set(options.class_inputs) 341*6777b538SAndroid Build Coastguard Worker allowed_changed.update(options.dex_inputs) 342*6777b538SAndroid Build Coastguard Worker allowed_changed.update(options.classpath) 343*6777b538SAndroid Build Coastguard Worker strings_changed = changes.HasStringChanges() 344*6777b538SAndroid Build Coastguard Worker non_direct_input_changed = next( 345*6777b538SAndroid Build Coastguard Worker (p for p in changes.IterChangedPaths() if p not in allowed_changed), None) 346*6777b538SAndroid Build Coastguard Worker 347*6777b538SAndroid Build Coastguard Worker if strings_changed or non_direct_input_changed: 348*6777b538SAndroid Build Coastguard Worker logging.debug('Full dex required: strings_changed=%s path_changed=%s', 349*6777b538SAndroid Build Coastguard Worker strings_changed, non_direct_input_changed) 350*6777b538SAndroid Build Coastguard Worker changes = None 351*6777b538SAndroid Build Coastguard Worker 352*6777b538SAndroid Build Coastguard Worker if changes is None: 353*6777b538SAndroid Build Coastguard Worker required_desugar_classes_set = set() 354*6777b538SAndroid Build Coastguard Worker else: 355*6777b538SAndroid Build Coastguard Worker required_desugar_classes_set = _ComputeRequiredDesugarClasses( 356*6777b538SAndroid Build Coastguard Worker changes, options.desugar_dependencies, options.class_inputs, 357*6777b538SAndroid Build Coastguard Worker options.classpath) 358*6777b538SAndroid Build Coastguard Worker logging.debug('Class files needing re-desugar: %d', 359*6777b538SAndroid Build Coastguard Worker len(required_desugar_classes_set)) 360*6777b538SAndroid Build Coastguard Worker class_files = _ExtractClassFiles(changes, tmp_extract_dir, 361*6777b538SAndroid Build Coastguard Worker options.class_inputs, 362*6777b538SAndroid Build Coastguard Worker required_desugar_classes_set) 363*6777b538SAndroid Build Coastguard Worker logging.debug('Extracted class files: %d', len(class_files)) 364*6777b538SAndroid Build Coastguard Worker 365*6777b538SAndroid Build Coastguard Worker # If the only change is deleting a file, class_files will be empty. 366*6777b538SAndroid Build Coastguard Worker if class_files: 367*6777b538SAndroid Build Coastguard Worker # Dex necessary classes into intermediate dex files. 368*6777b538SAndroid Build Coastguard Worker dex_cmd = dex_cmd + ['--intermediate', '--file-per-class-file'] 369*6777b538SAndroid Build Coastguard Worker if options.desugar_dependencies and not options.skip_custom_d8: 370*6777b538SAndroid Build Coastguard Worker # Adding os.sep to remove the entire prefix. 371*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--file-tmp-prefix', tmp_extract_dir + os.sep] 372*6777b538SAndroid Build Coastguard Worker if changes is None and os.path.exists(options.desugar_dependencies): 373*6777b538SAndroid Build Coastguard Worker # Since incremental dexing only ever adds to the desugar_dependencies 374*6777b538SAndroid Build Coastguard Worker # file, whenever full dexes are required the .desugardeps files need to 375*6777b538SAndroid Build Coastguard Worker # be manually removed. 376*6777b538SAndroid Build Coastguard Worker os.unlink(options.desugar_dependencies) 377*6777b538SAndroid Build Coastguard Worker _RunD8(dex_cmd, class_files, options.incremental_dir, 378*6777b538SAndroid Build Coastguard Worker options.warnings_as_errors, 379*6777b538SAndroid Build Coastguard Worker options.show_desugar_default_interface_warnings) 380*6777b538SAndroid Build Coastguard Worker logging.debug('Dexed class files.') 381*6777b538SAndroid Build Coastguard Worker 382*6777b538SAndroid Build Coastguard Worker 383*6777b538SAndroid Build Coastguard Workerdef _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd): 384*6777b538SAndroid Build Coastguard Worker logging.debug('_OnStaleMd5') 385*6777b538SAndroid Build Coastguard Worker with build_utils.TempDir() as tmp_dir: 386*6777b538SAndroid Build Coastguard Worker if options.incremental_dir: 387*6777b538SAndroid Build Coastguard Worker # Create directory for all intermediate dex files. 388*6777b538SAndroid Build Coastguard Worker if not os.path.exists(options.incremental_dir): 389*6777b538SAndroid Build Coastguard Worker os.makedirs(options.incremental_dir) 390*6777b538SAndroid Build Coastguard Worker 391*6777b538SAndroid Build Coastguard Worker _DeleteStaleIncrementalDexFiles(options.incremental_dir, final_dex_inputs) 392*6777b538SAndroid Build Coastguard Worker logging.debug('Stale files deleted') 393*6777b538SAndroid Build Coastguard Worker _CreateIntermediateDexFiles(changes, options, tmp_dir, dex_cmd) 394*6777b538SAndroid Build Coastguard Worker 395*6777b538SAndroid Build Coastguard Worker _CreateFinalDex( 396*6777b538SAndroid Build Coastguard Worker final_dex_inputs, options.output, tmp_dir, dex_cmd, options=options) 397*6777b538SAndroid Build Coastguard Worker 398*6777b538SAndroid Build Coastguard Worker 399*6777b538SAndroid Build Coastguard Workerdef MergeDexForIncrementalInstall(r8_jar_path, src_paths, dest_dex_jar, 400*6777b538SAndroid Build Coastguard Worker min_api): 401*6777b538SAndroid Build Coastguard Worker dex_cmd = build_utils.JavaCmd(xmx=_DEX_XMX) + [ 402*6777b538SAndroid Build Coastguard Worker '-cp', 403*6777b538SAndroid Build Coastguard Worker r8_jar_path, 404*6777b538SAndroid Build Coastguard Worker 'com.android.tools.r8.D8', 405*6777b538SAndroid Build Coastguard Worker '--min-api', 406*6777b538SAndroid Build Coastguard Worker min_api, 407*6777b538SAndroid Build Coastguard Worker ] 408*6777b538SAndroid Build Coastguard Worker with build_utils.TempDir() as tmp_dir: 409*6777b538SAndroid Build Coastguard Worker _CreateFinalDex(src_paths, dest_dex_jar, tmp_dir, dex_cmd) 410*6777b538SAndroid Build Coastguard Worker 411*6777b538SAndroid Build Coastguard Worker 412*6777b538SAndroid Build Coastguard Workerdef main(args): 413*6777b538SAndroid Build Coastguard Worker build_utils.InitLogging('DEX_DEBUG') 414*6777b538SAndroid Build Coastguard Worker options = _ParseArgs(args) 415*6777b538SAndroid Build Coastguard Worker 416*6777b538SAndroid Build Coastguard Worker options.class_inputs += options.class_inputs_filearg 417*6777b538SAndroid Build Coastguard Worker options.dex_inputs += options.dex_inputs_filearg 418*6777b538SAndroid Build Coastguard Worker 419*6777b538SAndroid Build Coastguard Worker input_paths = ([ 420*6777b538SAndroid Build Coastguard Worker build_utils.JAVA_PATH_FOR_INPUTS, options.r8_jar_path, 421*6777b538SAndroid Build Coastguard Worker options.custom_d8_jar_path 422*6777b538SAndroid Build Coastguard Worker ] + options.class_inputs + options.dex_inputs) 423*6777b538SAndroid Build Coastguard Worker 424*6777b538SAndroid Build Coastguard Worker depfile_deps = options.class_inputs_filearg + options.dex_inputs_filearg 425*6777b538SAndroid Build Coastguard Worker 426*6777b538SAndroid Build Coastguard Worker output_paths = [options.output] 427*6777b538SAndroid Build Coastguard Worker 428*6777b538SAndroid Build Coastguard Worker track_subpaths_allowlist = [] 429*6777b538SAndroid Build Coastguard Worker if options.incremental_dir: 430*6777b538SAndroid Build Coastguard Worker final_dex_inputs = _IntermediateDexFilePathsFromInputJars( 431*6777b538SAndroid Build Coastguard Worker options.class_inputs, options.incremental_dir) 432*6777b538SAndroid Build Coastguard Worker output_paths += final_dex_inputs 433*6777b538SAndroid Build Coastguard Worker track_subpaths_allowlist += options.class_inputs 434*6777b538SAndroid Build Coastguard Worker else: 435*6777b538SAndroid Build Coastguard Worker final_dex_inputs = list(options.class_inputs) 436*6777b538SAndroid Build Coastguard Worker final_dex_inputs += options.dex_inputs 437*6777b538SAndroid Build Coastguard Worker 438*6777b538SAndroid Build Coastguard Worker dex_cmd = build_utils.JavaCmd(xmx=_DEX_XMX) 439*6777b538SAndroid Build Coastguard Worker 440*6777b538SAndroid Build Coastguard Worker if options.dump_inputs: 441*6777b538SAndroid Build Coastguard Worker dex_cmd += ['-Dcom.android.tools.r8.dumpinputtofile=d8inputs.zip'] 442*6777b538SAndroid Build Coastguard Worker 443*6777b538SAndroid Build Coastguard Worker if not options.skip_custom_d8: 444*6777b538SAndroid Build Coastguard Worker dex_cmd += [ 445*6777b538SAndroid Build Coastguard Worker '-cp', 446*6777b538SAndroid Build Coastguard Worker '{}:{}'.format(options.r8_jar_path, options.custom_d8_jar_path), 447*6777b538SAndroid Build Coastguard Worker 'org.chromium.build.CustomD8', 448*6777b538SAndroid Build Coastguard Worker ] 449*6777b538SAndroid Build Coastguard Worker else: 450*6777b538SAndroid Build Coastguard Worker dex_cmd += [ 451*6777b538SAndroid Build Coastguard Worker '-cp', 452*6777b538SAndroid Build Coastguard Worker options.r8_jar_path, 453*6777b538SAndroid Build Coastguard Worker 'com.android.tools.r8.D8', 454*6777b538SAndroid Build Coastguard Worker ] 455*6777b538SAndroid Build Coastguard Worker 456*6777b538SAndroid Build Coastguard Worker if options.release: 457*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--release'] 458*6777b538SAndroid Build Coastguard Worker if options.min_api: 459*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--min-api', options.min_api] 460*6777b538SAndroid Build Coastguard Worker 461*6777b538SAndroid Build Coastguard Worker if not options.desugar: 462*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--no-desugaring'] 463*6777b538SAndroid Build Coastguard Worker elif options.classpath: 464*6777b538SAndroid Build Coastguard Worker # The classpath is used by D8 to for interface desugaring. 465*6777b538SAndroid Build Coastguard Worker if options.desugar_dependencies and not options.skip_custom_d8: 466*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--desugar-dependencies', options.desugar_dependencies] 467*6777b538SAndroid Build Coastguard Worker if track_subpaths_allowlist: 468*6777b538SAndroid Build Coastguard Worker track_subpaths_allowlist += options.classpath 469*6777b538SAndroid Build Coastguard Worker depfile_deps += options.classpath 470*6777b538SAndroid Build Coastguard Worker input_paths += options.classpath 471*6777b538SAndroid Build Coastguard Worker # Still pass the entire classpath in case a new dependency is needed by 472*6777b538SAndroid Build Coastguard Worker # desugar, so that desugar_dependencies will be updated for the next build. 473*6777b538SAndroid Build Coastguard Worker for path in options.classpath: 474*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--classpath', path] 475*6777b538SAndroid Build Coastguard Worker 476*6777b538SAndroid Build Coastguard Worker if options.classpath: 477*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--lib', build_utils.JAVA_HOME] 478*6777b538SAndroid Build Coastguard Worker for path in options.bootclasspath: 479*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--lib', path] 480*6777b538SAndroid Build Coastguard Worker depfile_deps += options.bootclasspath 481*6777b538SAndroid Build Coastguard Worker input_paths += options.bootclasspath 482*6777b538SAndroid Build Coastguard Worker 483*6777b538SAndroid Build Coastguard Worker 484*6777b538SAndroid Build Coastguard Worker if options.assertion_handler: 485*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--force-assertions-handler:' + options.assertion_handler] 486*6777b538SAndroid Build Coastguard Worker if options.force_enable_assertions: 487*6777b538SAndroid Build Coastguard Worker dex_cmd += ['--force-enable-assertions'] 488*6777b538SAndroid Build Coastguard Worker 489*6777b538SAndroid Build Coastguard Worker # The changes feature from md5_check allows us to only re-dex the class files 490*6777b538SAndroid Build Coastguard Worker # that have changed and the class files that need to be re-desugared by D8. 491*6777b538SAndroid Build Coastguard Worker md5_check.CallAndWriteDepfileIfStale( 492*6777b538SAndroid Build Coastguard Worker lambda changes: _OnStaleMd5(changes, options, final_dex_inputs, dex_cmd), 493*6777b538SAndroid Build Coastguard Worker options, 494*6777b538SAndroid Build Coastguard Worker input_paths=input_paths, 495*6777b538SAndroid Build Coastguard Worker input_strings=dex_cmd + [str(bool(options.incremental_dir))], 496*6777b538SAndroid Build Coastguard Worker output_paths=output_paths, 497*6777b538SAndroid Build Coastguard Worker pass_changes=True, 498*6777b538SAndroid Build Coastguard Worker track_subpaths_allowlist=track_subpaths_allowlist, 499*6777b538SAndroid Build Coastguard Worker depfile_deps=depfile_deps) 500*6777b538SAndroid Build Coastguard Worker 501*6777b538SAndroid Build Coastguard Worker 502*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 503*6777b538SAndroid Build Coastguard Worker sys.exit(main(sys.argv[1:])) 504