1#!/usr/bin/env python 2# 3# Copyright 2015 The Chromium Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7import argparse 8import json 9import os 10import sys 11import tempfile 12 13from util import build_utils 14 15sys.path.append(os.path.abspath(os.path.join( 16 os.path.dirname(__file__), os.pardir))) 17from pylib import constants 18 19 20def main(args): 21 parser = argparse.ArgumentParser() 22 build_utils.AddDepfileOption(parser) 23 parser.add_argument('--android-sdk-tools', required=True, 24 help='Android sdk build tools directory.') 25 parser.add_argument('--main-dex-rules-path', action='append', default=[], 26 dest='main_dex_rules_paths', 27 help='A file containing a list of proguard rules to use ' 28 'in determining the class to include in the ' 29 'main dex.') 30 parser.add_argument('--main-dex-list-path', required=True, 31 help='The main dex list file to generate.') 32 parser.add_argument('--enabled-configurations', 33 help='The build configurations for which a main dex list' 34 ' should be generated.') 35 parser.add_argument('--configuration-name', 36 help='The current build configuration.') 37 parser.add_argument('--multidex-configuration-path', 38 help='A JSON file containing multidex build ' 39 'configuration.') 40 parser.add_argument('--inputs', 41 help='JARs for which a main dex list should be ' 42 'generated.') 43 parser.add_argument('paths', nargs='*', default=[], 44 help='JARs for which a main dex list should be ' 45 'generated.') 46 47 args = parser.parse_args(build_utils.ExpandFileArgs(args)) 48 49 if args.multidex_configuration_path: 50 with open(args.multidex_configuration_path) as multidex_config_file: 51 multidex_config = json.loads(multidex_config_file.read()) 52 53 if not multidex_config.get('enabled', False): 54 return 0 55 56 if args.inputs: 57 args.paths.extend(build_utils.ParseGypList(args.inputs)) 58 59 shrinked_android_jar = os.path.abspath( 60 os.path.join(args.android_sdk_tools, 'lib', 'shrinkedAndroid.jar')) 61 dx_jar = os.path.abspath( 62 os.path.join(args.android_sdk_tools, 'lib', 'dx.jar')) 63 rules_file = os.path.abspath( 64 os.path.join(args.android_sdk_tools, 'mainDexClasses.rules')) 65 66 proguard_cmd = [ 67 constants.PROGUARD_SCRIPT_PATH, 68 '-forceprocessing', 69 '-dontwarn', '-dontoptimize', '-dontobfuscate', '-dontpreverify', 70 '-libraryjars', shrinked_android_jar, 71 '-include', rules_file, 72 ] 73 for m in args.main_dex_rules_paths: 74 proguard_cmd.extend(['-include', m]) 75 76 main_dex_list_cmd = [ 77 'java', '-cp', dx_jar, 78 'com.android.multidex.MainDexListBuilder', 79 ] 80 81 input_paths = list(args.paths) 82 input_paths += [ 83 shrinked_android_jar, 84 dx_jar, 85 rules_file, 86 ] 87 input_paths += args.main_dex_rules_paths 88 89 input_strings = [ 90 proguard_cmd, 91 main_dex_list_cmd, 92 ] 93 94 output_paths = [ 95 args.main_dex_list_path, 96 ] 97 98 build_utils.CallAndWriteDepfileIfStale( 99 lambda: _OnStaleMd5(proguard_cmd, main_dex_list_cmd, args.paths, 100 args.main_dex_list_path), 101 args, 102 input_paths=input_paths, 103 input_strings=input_strings, 104 output_paths=output_paths) 105 106 return 0 107 108 109def _OnStaleMd5(proguard_cmd, main_dex_list_cmd, paths, main_dex_list_path): 110 paths_arg = ':'.join(paths) 111 main_dex_list = '' 112 try: 113 with tempfile.NamedTemporaryFile(suffix='.jar') as temp_jar: 114 proguard_cmd += [ 115 '-injars', paths_arg, 116 '-outjars', temp_jar.name 117 ] 118 build_utils.CheckOutput(proguard_cmd, print_stderr=False) 119 120 main_dex_list_cmd += [ 121 temp_jar.name, paths_arg 122 ] 123 main_dex_list = build_utils.CheckOutput(main_dex_list_cmd) 124 except build_utils.CalledProcessError as e: 125 if 'output jar is empty' in e.output: 126 pass 127 elif "input doesn't contain any classes" in e.output: 128 pass 129 else: 130 raise 131 132 with open(main_dex_list_path, 'w') as main_dex_list_file: 133 main_dex_list_file.write(main_dex_list) 134 135 136if __name__ == '__main__': 137 sys.exit(main(sys.argv[1:])) 138 139