Home | History | Annotate | Download | only in build-android
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (C) 2015 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 
     18 import argparse
     19 import multiprocessing
     20 import os
     21 import shutil
     22 import subprocess
     23 import sys
     24 import time
     25 
     26 from subprocess import PIPE, STDOUT
     27 
     28 def install_file(file_name, src_dir, dst_dir):
     29     src_file = os.path.join(src_dir, file_name)
     30     dst_file = os.path.join(dst_dir, file_name)
     31 
     32     print('Copying {} to {}...'.format(src_file, dst_file))
     33     if os.path.isdir(src_file):
     34         _install_dir(src_file, dst_file)
     35     elif os.path.islink(src_file):
     36         _install_symlink(src_file, dst_file)
     37     else:
     38         _install_file(src_file, dst_file)
     39 
     40 
     41 def _install_dir(src_dir, dst_dir):
     42     parent_dir = os.path.normpath(os.path.join(dst_dir, '..'))
     43     if not os.path.exists(parent_dir):
     44         os.makedirs(parent_dir)
     45     shutil.copytree(src_dir, dst_dir, symlinks=True)
     46 
     47 
     48 def _install_symlink(src_file, dst_file):
     49     dirname = os.path.dirname(dst_file)
     50     if not os.path.exists(dirname):
     51         os.makedirs(dirname)
     52     link_target = os.readlink(src_file)
     53     os.symlink(link_target, dst_file)
     54 
     55 
     56 def _install_file(src_file, dst_file):
     57     dirname = os.path.dirname(dst_file)
     58     if not os.path.exists(dirname):
     59         os.makedirs(dirname)
     60     # copy2 is just copy followed by copystat (preserves file metadata).
     61     shutil.copy2(src_file, dst_file)
     62 
     63 THIS_DIR = os.path.realpath(os.path.dirname(__file__))
     64 
     65 ALL_ARCHITECTURES = (
     66   'arm',
     67   'arm64',
     68   'mips',
     69   'mips64',
     70   'x86',
     71   'x86_64',
     72 )
     73 
     74 # According to vk_platform.h, armeabi is not supported for Vulkan
     75 # so remove it from the abis list.
     76 ALL_ABIS = (
     77   'armeabi-v7a',
     78   'arm64-v8a',
     79   'mips',
     80   'mips64',
     81   'x86',
     82   'x86_64',
     83 )
     84 
     85 def jobs_arg():
     86   return '-j{}'.format(multiprocessing.cpu_count() * 2)
     87 
     88 def arch_to_abis(arch):
     89   return {
     90     'arm': ['armeabi-v7a'],
     91     'arm64': ['arm64-v8a'],
     92     'mips': ['mips'],
     93     'mips64': ['mips64'],
     94     'x86': ['x86'],
     95     'x86_64': ['x86_64'],
     96   }[arch]
     97 
     98 class ArgParser(argparse.ArgumentParser):
     99   def __init__(self):
    100     super(ArgParser, self).__init__()
    101 
    102     self.add_argument(
    103       '--out-dir', help='Directory to place temporary build files.',
    104       type=os.path.realpath, default=os.path.join(THIS_DIR, 'out'))
    105 
    106     self.add_argument(
    107       '--arch', choices=ALL_ARCHITECTURES,
    108       help='Architectures to build. Builds all if not present.')
    109 
    110     self.add_argument('--installdir', dest='installdir', required=True,
    111       help='Installation directory. Required.')
    112 
    113     # The default for --dist-dir has to be handled after parsing all
    114     # arguments because the default is derived from --out-dir. This is
    115     # handled in run().
    116     self.add_argument(
    117       '--dist-dir', help='Directory to place the packaged artifact.',
    118       type=os.path.realpath)
    119 
    120 
    121 def main():
    122   print('THIS_DIR: %s' % THIS_DIR)
    123   parser = ArgParser()
    124   args = parser.parse_args()
    125 
    126   arches = ALL_ARCHITECTURES
    127   if args.arch is not None:
    128     arches = [args.arch]
    129 
    130   # Make paths absolute, and ensure directories exist.
    131   installdir = os.path.abspath(args.installdir)
    132 
    133   abis = []
    134   for arch in arches:
    135     abis.extend(arch_to_abis(arch))
    136 
    137   shaderc_path = installdir + '/shaderc/android_test'
    138   print('shaderc_path = %s' % shaderc_path)
    139 
    140   ndk_dir = os.path.join(THIS_DIR, '../../../prebuilts/toolchain')
    141 
    142   ndk_build = os.path.join(ndk_dir, 'ndk-build')
    143   platforms_root = os.path.join(ndk_dir, 'platforms')
    144   toolchains_root = os.path.join(ndk_dir, 'toolchains')
    145   build_dir = THIS_DIR
    146 
    147   print('installdir: %s' % installdir)
    148   print('ndk_dir: %s' % ndk_dir)
    149   print('ndk_build: %s' % ndk_build)
    150   print('platforms_root: %s' % platforms_root)
    151 
    152   compiler = 'clang'
    153   stl = 'c++_static'
    154   obj_out = os.path.join(THIS_DIR, stl, 'obj')
    155   lib_out = os.path.join(THIS_DIR, 'jniLibs')
    156 
    157   print('obj_out: %s' % obj_out)
    158   print('lib_out: %s' % lib_out)
    159 
    160   print('Constructing shaderc build tree...')
    161   shaderc_root_dir = os.path.join(THIS_DIR, '../../shaderc')
    162 
    163   copies = [
    164       {
    165           'source_dir': os.path.join(shaderc_root_dir, 'shaderc'),
    166           'dest_dir': 'third_party/shaderc',
    167           'files': [
    168               'Android.mk', 'libshaderc/Android.mk',
    169               'libshaderc_util/Android.mk',
    170               'third_party/Android.mk',
    171               'utils/update_build_version.py',
    172               'CHANGES',
    173           ],
    174           'dirs': [
    175               'libshaderc/include', 'libshaderc/src',
    176               'libshaderc_util/include', 'libshaderc_util/src',
    177               'android_test'
    178           ],
    179       },
    180       {
    181           'source_dir': os.path.join(shaderc_root_dir, 'spirv-tools'),
    182           'dest_dir': 'third_party/shaderc/third_party/spirv-tools',
    183           'files': [
    184               'utils/generate_grammar_tables.py',
    185               'utils/generate_language_headers.py',
    186               'utils/generate_registry_tables.py',
    187               'utils/update_build_version.py',
    188               'Android.mk',
    189               'CHANGES',
    190           ],
    191           'dirs': ['include', 'source'],
    192       },
    193       {
    194           'source_dir': os.path.join(shaderc_root_dir, 'spirv-headers'),
    195           'dest_dir':
    196               'third_party/shaderc/third_party/spirv-tools/external/spirv-headers',
    197           'dirs': ['include',],
    198           'files': [
    199               'include/spirv/1.0/spirv.py',
    200               'include/spirv/1.1/spirv.py',
    201               'include/spirv/1.2/spirv.py',
    202           ],
    203       },
    204       {
    205           'source_dir': os.path.join(shaderc_root_dir, 'glslang'),
    206           'dest_dir': 'third_party/shaderc/third_party/glslang',
    207           'files': ['glslang/OSDependent/osinclude.h'],
    208           'dirs': [
    209               'SPIRV',
    210               'OGLCompilersDLL',
    211               'glslang/GenericCodeGen',
    212               'hlsl',
    213               'glslang/Include',
    214               'glslang/MachineIndependent',
    215               'glslang/OSDependent/Unix',
    216               'glslang/Public',
    217           ],
    218       },
    219   ]
    220 
    221   default_ignore_patterns = shutil.ignore_patterns(
    222       "*CMakeLists.txt",
    223       "*.py",
    224       "*test.h",
    225       "*test.cc")
    226 
    227   for properties in copies:
    228       source_dir = properties['source_dir']
    229       dest_dir = os.path.join(installdir, properties['dest_dir'])
    230       for d in properties['dirs']:
    231           src = os.path.join(source_dir, d)
    232           dst = os.path.join(dest_dir, d)
    233           print(src, " -> ", dst)
    234           shutil.copytree(src, dst,
    235                           ignore=default_ignore_patterns)
    236       for f in properties['files']:
    237           print(source_dir, ':', dest_dir, ":", f)
    238           # Only copy if the source file exists.  That way
    239           # we can update this script in anticipation of
    240           # source files yet-to-come.
    241           if os.path.exists(os.path.join(source_dir, f)):
    242               install_file(f, source_dir, dest_dir)
    243           else:
    244               print(source_dir, ':', dest_dir, ":", f, "SKIPPED")
    245 
    246   print('Constructing Vulkan validation layer source...')
    247 
    248   build_cmd = [
    249     'bash', THIS_DIR + '/android-generate.sh'
    250   ]
    251   print('Generating generated layers...')
    252   subprocess.check_call(build_cmd)
    253   print('Generation finished')
    254 
    255   build_cmd = [
    256     'bash', ndk_build, '-C', build_dir,
    257     jobs_arg(),
    258     'APP_ABI=' + ' '.join(abis),
    259     # Use the prebuilt platforms and toolchains.
    260     'NDK_PLATFORMS_ROOT=' + platforms_root,
    261     'NDK_TOOLCHAINS_ROOT=' + toolchains_root,
    262     'NDK_MODULE_PATH=' + installdir,
    263     'GNUSTL_PREFIX=',
    264     'APP_STL=' + stl,
    265     'NDK_TOOLCHAIN_VERSION=' + compiler,
    266 
    267     # Tell ndk-build where to put the results
    268     'NDK_OUT=' + obj_out,
    269     'NDK_LIBS_OUT=' + lib_out,
    270   ]
    271 
    272   print('Building Vulkan validation layers for ABIs:' +
    273     ' {}'.format(', '.join(abis)) + "...")
    274   print(' '.join(build_cmd))
    275 
    276   subprocess.check_call(build_cmd)
    277 
    278   print('Finished building Vulkan validation layers')
    279   out_package = os.path.join(installdir, 'vulkan_validation_layers.zip')
    280   os.chdir(lib_out)
    281   build_cmd = [
    282       'zip', '-9qr', out_package, "."
    283   ]
    284 
    285   print('Packaging Vulkan validation layers')
    286   subprocess.check_call(build_cmd)
    287   print('Finished Packaging Vulkan validation layers')
    288 
    289   for properties in copies:
    290       dest_dir = os.path.join(installdir, properties['dest_dir'])
    291       for d in properties['dirs']:
    292           dst = os.path.join(dest_dir, d)
    293           print('Remove: %s' % dst)
    294           shutil.rmtree(dst)
    295 
    296   return 0
    297 
    298 
    299 if __name__ == '__main__':
    300   main()
    301