• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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