Home | History | Annotate | Download | only in ndk
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (C) 2016 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #      http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 #
     17 """Clobbers all the per-API level headers with the current unified headers.
     18 
     19 This is just for testing purposes. Having unified headers isn't worth as much
     20 if we're still shipping N copies of them :)
     21 """
     22 from __future__ import absolute_import
     23 from __future__ import print_function
     24 
     25 import logging
     26 import os
     27 import shutil
     28 
     29 
     30 THIS_DIR = os.path.realpath(os.path.dirname(__file__))
     31 ANDROID_ROOT = os.path.dirname(os.path.dirname(THIS_DIR))
     32 
     33 
     34 ALL_ARCHITECTURES = (
     35     'arm',
     36     'arm64',
     37     'mips',
     38     'mips64',
     39     'x86',
     40     'x86_64',
     41 )
     42 
     43 
     44 def logger():
     45     """Return the main logger for this module."""
     46     return logging.getLogger(__name__)
     47 
     48 
     49 def android_path(*args):
     50     """Returns a full path from the base of the Android source tree."""
     51     return os.path.join(ANDROID_ROOT, *args)
     52 
     53 
     54 def copy_directory_contents(src, dst):
     55     """Copies the contents of a directory, merging with the destination.
     56 
     57     shutil.copytree requires that the destination does not exist. This function
     58     behaves like `cp -r`. That is, it merges the source and destination
     59     directories if appropriate.
     60     """
     61     for root, dirs, files in os.walk(src):
     62         subdir = os.path.relpath(root, src)
     63         dst_dir = os.path.join(dst, subdir)
     64         if not os.path.exists(dst_dir):
     65             os.makedirs(dst_dir)
     66 
     67         # This makes sure we copy even empty directories. We don't actually
     68         # need it, but for now it lets us diff between our result and the
     69         # legacy tool.
     70         for d in dirs:  # pylint: disable=invalid-name
     71             d_path = os.path.join(root, d)
     72             if os.path.islink(d_path):
     73                 linkto = os.readlink(d_path)
     74                 dst_file = os.path.join(dst_dir, d)
     75                 logger().debug('Symlinking %s to %s', dst_file, linkto)
     76                 os.symlink(linkto, dst_file)
     77             else:
     78                 new_dir = os.path.join(dst_dir, d)
     79                 if not os.path.exists(new_dir):
     80                     logger().debug('Making directory %s', new_dir)
     81                     os.makedirs(new_dir)
     82 
     83         for f in files:  # pylint: disable=invalid-name
     84             src_file = os.path.join(root, f)
     85             if os.path.islink(src_file):
     86                 linkto = os.readlink(src_file)
     87                 dst_file = os.path.join(dst_dir, f)
     88                 logger().debug('Symlinking %s to %s', dst_file, linkto)
     89                 os.symlink(linkto, dst_file)
     90             else:
     91                 logger().debug('Copying %s', src_file)
     92                 shutil.copy2(src_file, dst_dir)
     93 
     94 
     95 def get_preserve_path(platform_dir):
     96     """Returns the path used for preserving headers."""
     97     return os.path.join(platform_dir, 'preserve')
     98 
     99 
    100 def preserve_headers(keep_list, platform_dir):
    101     """Preserves a list of headers to be restored after the copy."""
    102     install_path = os.path.join(platform_dir, 'include')
    103     preserve_root = get_preserve_path(platform_dir)
    104     if os.path.exists(preserve_root):
    105         shutil.rmtree(preserve_root)
    106     for preserve in keep_list:
    107         path = os.path.join(install_path, preserve)
    108         if os.path.isdir(path):
    109             shutil.copytree(path, os.path.join(preserve_root, preserve))
    110         elif os.path.isfile(path):
    111             shutil.copy2(path, preserve_root)
    112 
    113 
    114 def restore_headers(keep_list, platform_dir):
    115     """Restores headers preserved by preserve_headers."""
    116     install_path = os.path.join(platform_dir, 'include')
    117     preserve_root = get_preserve_path(platform_dir)
    118     for preserve in keep_list:
    119         path = os.path.join(preserve_root, preserve)
    120         if os.path.isdir(path):
    121             # Bionic does have include/android, so we need to merge directories
    122             # here.
    123             copy_directory_contents(
    124                 path, os.path.join(install_path, preserve))
    125         elif os.path.isfile(path):
    126             shutil.copy2(path, install_path)
    127 
    128 
    129 def platform_path_to_api_level(platform_path):
    130     """Returns the API level for a platform path."""
    131     basename = os.path.split(platform_path)[-1]
    132     # android-\d+
    133     return int(basename.split('-')[1])
    134 
    135 
    136 def fixup_api_level_h(platform_dir):
    137     """Rewrites api-level.h for the correct platform."""
    138     api_level = platform_path_to_api_level(platform_dir)
    139     header = os.path.join(platform_dir, 'include/android/api-level.h')
    140     with open(header, 'w') as header_file:
    141         header_file.write(
    142             '#ifndef ANDROID_API_LEVEL_H\n'
    143             '#define ANDROID_API_LEVEL_H\n'
    144             '#ifndef __ANDROID_API__\n'
    145             '#define __ANDROID_API__ {}\n'
    146             '#endif /* __ANDROID_API__ */\n'
    147             '#endif /* ANDROID_API_LEVEL_H */\n'.format(api_level))
    148 
    149 
    150 def copy_current_headers(platform_dir):
    151     """Copies the unified headers into a per-API directory."""
    152     libc_path = android_path('bionic/libc')
    153     install_path = os.path.join(platform_dir, 'include')
    154 
    155     # None of the platform APIs have unified headers yet. Copy those out of the
    156     # way of the purge and copy them back in afterward.
    157     keep_list = (
    158         'EGL',
    159         'GLES',
    160         'GLES2',
    161         'GLES3',
    162         'KHR',
    163         'OMXAL',
    164         'SLES',
    165         'android',
    166         'camera',
    167         'jni.h',
    168         'media',
    169         'vulkan',
    170         'zlib.h',
    171         'zconf.h',
    172     )
    173     preserve_headers(keep_list, platform_dir)
    174 
    175     if os.path.exists(install_path):
    176         shutil.rmtree(install_path)
    177 
    178     shutil.copytree(os.path.join(libc_path, 'include'), install_path)
    179     shutil.copytree(os.path.join(libc_path, 'kernel/uapi/linux'),
    180                     os.path.join(install_path, 'linux'))
    181     shutil.copytree(os.path.join(libc_path, 'kernel/uapi/asm-generic'),
    182                     os.path.join(install_path, 'asm-generic'))
    183     shutil.copy2(os.path.join(libc_path, 'NOTICE'), install_path)
    184 
    185     restore_headers(keep_list, platform_dir)
    186 
    187     if os.path.exists(get_preserve_path(platform_dir)):
    188         shutil.rmtree(get_preserve_path(platform_dir))
    189 
    190     fixup_api_level_h(platform_dir)
    191 
    192     api_level = platform_path_to_api_level(platform_dir)
    193     for arch in ALL_ARCHITECTURES:
    194         if arch in ('arm64', 'mips64', 'x86_64') and api_level < 21:
    195             continue
    196 
    197         # For multilib architectures we need to copy the 32-bit headers into
    198         # the 64-bit directory. For MIPS this is true of asm and machine, for
    199         # Intel it's only for asm.
    200         asm_arch = arch
    201         machine_arch = arch
    202         if arch == 'mips64':
    203             asm_arch = 'mips'
    204             machine_arch = 'mips'
    205         elif arch == 'x86_64':
    206             asm_arch = 'x86'
    207 
    208         arch_install_path = os.path.join(
    209             platform_dir, 'arch-' + arch, 'include')
    210         if os.path.exists(arch_install_path):
    211             shutil.rmtree(arch_install_path)
    212 
    213         machine_path = os.path.join(
    214             libc_path, 'arch-' + machine_arch, 'include/machine')
    215         asm_path = os.path.join(
    216             libc_path, 'kernel/uapi/asm-' + asm_arch, 'asm')
    217 
    218         if os.path.exists(arch_install_path):
    219             shutil.rmtree(arch_install_path)
    220         os.makedirs(arch_install_path)
    221 
    222         shutil.copytree(
    223             machine_path, os.path.join(arch_install_path, 'machine'))
    224         shutil.copytree(asm_path, os.path.join(arch_install_path, 'asm'))
    225 
    226 
    227 def main():
    228     """Program entry point."""
    229     platforms_dir = os.path.join(THIS_DIR, 'platforms')
    230     for platform_dir in os.listdir(platforms_dir):
    231         path = os.path.join(platforms_dir, platform_dir)
    232         if not os.path.isdir(path):
    233             continue
    234         if platform_dir == 'common':
    235             # Just contains crtbrand.
    236             continue
    237         copy_current_headers(path)
    238 
    239 
    240 if __name__ == '__main__':
    241     main()
    242