1#!/usr/bin/env python3 2 3import argparse 4import os 5import time 6 7from utils import ( 8 AOSP_DIR, SOURCE_ABI_DUMP_EXT_END, SO_EXT, Target, 9 copy_reference_dump, find_lib_lsdumps, get_build_vars_for_product, 10 make_libraries, make_tree, read_lsdump_paths) 11 12 13PRODUCTS_DEFAULT = ['aosp_arm', 'aosp_arm64', 'aosp_x86', 'aosp_x86_64'] 14 15PREBUILTS_ABI_DUMPS_DIR = os.path.join(AOSP_DIR, 'prebuilts', 'abi-dumps') 16PREBUILTS_ABI_DUMPS_SUBDIRS = ('ndk', 'platform', 'vndk') 17NON_AOSP_TAGS = {'VENDOR', 'PRODUCT', 'VNDK-ext', 'VNDK-SP-ext'} 18 19SOONG_DIR = os.path.join(AOSP_DIR, 'out', 'soong', '.intermediates') 20 21 22class GetRefDumpDirStem: 23 def __init__(self, ref_dump_dir): 24 self.ref_dump_dir = ref_dump_dir 25 26 def __call__(self, subdir, arch): 27 return os.path.join(self.ref_dump_dir, arch) 28 29 30class GetVersionedRefDumpDirStem: 31 def __init__(self, chosen_vndk_version, chosen_platform_version, 32 binder_bitness): 33 self.chosen_vndk_version = chosen_vndk_version 34 self.chosen_platform_version = chosen_platform_version 35 self.binder_bitness = binder_bitness 36 37 def __call__(self, subdir, arch): 38 if subdir not in PREBUILTS_ABI_DUMPS_SUBDIRS: 39 raise ValueError(f'"{subdir}" is not a valid dump directory under ' 40 f'{PREBUILTS_ABI_DUMPS_DIR}.') 41 version_stem = (self.chosen_vndk_version 42 if subdir == 'vndk' 43 else self.chosen_platform_version) 44 return os.path.join(PREBUILTS_ABI_DUMPS_DIR, subdir, version_stem, 45 self.binder_bitness, arch) 46 47 48def make_libs_for_product(libs, product, variant, vndk_version, targets, 49 exclude_tags): 50 print('making libs for', product + '-' + variant) 51 if libs: 52 make_libraries(product, variant, vndk_version, targets, libs, 53 exclude_tags) 54 else: 55 make_tree(product, variant) 56 57 58def tag_to_dir_name(tag): 59 if tag in NON_AOSP_TAGS: 60 return '' 61 if tag == 'NDK': 62 return 'ndk' 63 if tag in ('PLATFORM', 'LLNDK'): 64 return 'platform' 65 if tag.startswith('VNDK'): 66 return 'vndk' 67 raise ValueError(tag + ' is not a known tag.') 68 69 70def find_and_copy_lib_lsdumps(get_ref_dump_dir_stem, target, libs, 71 lsdump_paths): 72 arch_lsdump_paths = find_lib_lsdumps(lsdump_paths, libs, target) 73 num_created = 0 74 for tag, path in arch_lsdump_paths: 75 ref_dump_dir_stem = get_ref_dump_dir_stem(tag_to_dir_name(tag), 76 target.get_arch_str()) 77 copy_reference_dump( 78 path, os.path.join(ref_dump_dir_stem, 'source-based')) 79 num_created += 1 80 return num_created 81 82 83def create_source_abi_reference_dumps(args, get_ref_dump_dir_stem, 84 lsdump_paths, targets): 85 num_libs_copied = 0 86 for target in targets: 87 assert target.primary_arch != '' 88 print(f'Creating dumps for arch: {target.arch}, ' 89 f'primary arch: {target.primary_arch}') 90 91 num_libs_copied += find_and_copy_lib_lsdumps( 92 get_ref_dump_dir_stem, target, args.libs, lsdump_paths) 93 return num_libs_copied 94 95 96def create_source_abi_reference_dumps_for_all_products(args): 97 """Create reference ABI dumps for all specified products.""" 98 99 num_processed = 0 100 101 for product in args.products: 102 build_vars = get_build_vars_for_product( 103 ['PLATFORM_VNDK_VERSION', 'BOARD_VNDK_VERSION', 'BINDER32BIT', 104 'PLATFORM_VERSION_CODENAME', 'PLATFORM_SDK_VERSION'], 105 product, args.build_variant) 106 107 platform_vndk_version = build_vars[0] 108 board_vndk_version = build_vars[1] 109 platform_version_codename = build_vars[3] 110 platform_sdk_version = build_vars[4] 111 if build_vars[2] == 'true': 112 binder_bitness = '32' 113 else: 114 binder_bitness = '64' 115 116 # This logic must be in sync with the logic for reference ABI dumps 117 # directory in `build/soong/cc/library.go`. 118 # chosen_vndk_version is either the codename or the finalized 119 # PLATFORM_SDK_VERSION. 120 chosen_vndk_version = (platform_vndk_version 121 if board_vndk_version in ('current', '') 122 else board_vndk_version) 123 # chosen_platform_version is expected to be the finalized 124 # PLATFORM_SDK_VERSION if the codename is REL. 125 chosen_platform_version = (platform_sdk_version 126 if platform_version_codename == 'REL' 127 else 'current') 128 129 targets = [t for t in (Target(True, product), Target(False, product)) 130 if t.arch] 131 132 if args.ref_dump_dir: 133 get_ref_dump_dir_stem = GetRefDumpDirStem(args.ref_dump_dir) 134 exclude_tags = () 135 else: 136 get_ref_dump_dir_stem = GetVersionedRefDumpDirStem( 137 chosen_vndk_version, 138 chosen_platform_version, 139 binder_bitness) 140 exclude_tags = NON_AOSP_TAGS 141 142 try: 143 if not args.no_make_lib: 144 # Build .lsdump for all the specified libs, or build 145 # `findlsdumps` if no libs are specified. 146 make_libs_for_product(args.libs, product, args.build_variant, 147 platform_vndk_version, targets, 148 exclude_tags) 149 150 lsdump_paths = read_lsdump_paths(product, args.build_variant, 151 platform_vndk_version, targets, 152 exclude_tags, build=False) 153 154 num_processed += create_source_abi_reference_dumps( 155 args, get_ref_dump_dir_stem, lsdump_paths, targets) 156 except KeyError as e: 157 if args.libs or not args.ref_dump_dir: 158 raise RuntimeError('Please check the lib name or specify ' 159 '-ref-dump-dir if you are updating ' 160 'reference dumps for product or vendor ' 161 'libraries.') from e 162 raise 163 164 return num_processed 165 166 167def _parse_args(): 168 """Parse the command line arguments.""" 169 170 parser = argparse.ArgumentParser() 171 parser.add_argument('--version', help=argparse.SUPPRESS) 172 parser.add_argument('--no-make-lib', action='store_true', 173 help='skip building dumps while creating references') 174 parser.add_argument('-libs', action='append', 175 help='libs to create references for') 176 parser.add_argument('-products', action='append', 177 help='products to create references for') 178 parser.add_argument('--build-variant', default='userdebug', 179 help='build variant to create references for') 180 parser.add_argument('--compress', action='store_true', 181 help=argparse.SUPPRESS) 182 parser.add_argument('-ref-dump-dir', 183 help='directory to copy reference abi dumps into') 184 185 args = parser.parse_args() 186 187 if args.version is not None: 188 parser.error('--version is deprecated. Please specify the version in ' 189 'the reference dump directory path. e.g., ' 190 '-ref-dump-dir prebuilts/abi-dumps/platform/current/64') 191 192 if args.compress: 193 parser.error("Compressed reference dumps are deprecated.") 194 195 if args.libs: 196 if any(lib_name.endswith(SOURCE_ABI_DUMP_EXT_END) or 197 lib_name.endswith(SO_EXT) for lib_name in args.libs): 198 parser.error('-libs should be followed by a base name without ' 199 'file extension.') 200 201 if args.ref_dump_dir and not args.libs: 202 parser.error('-libs must be given if -ref-dump-dir is given.') 203 204 if args.products is None: 205 # If `args.products` is unspecified, generate reference ABI dumps for 206 # all products. 207 args.products = PRODUCTS_DEFAULT 208 209 return args 210 211 212def main(): 213 args = _parse_args() 214 215 # Clear SKIP_ABI_CHECKS as it forbids ABI dumps from being built. 216 os.environ.pop('SKIP_ABI_CHECKS', None) 217 218 start = time.time() 219 num_processed = create_source_abi_reference_dumps_for_all_products(args) 220 end = time.time() 221 222 print() 223 print('msg: Processed', num_processed, 'libraries in ', (end - start) / 60, 224 ' minutes') 225 226 227if __name__ == '__main__': 228 main() 229