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   if os.path.isdir('/buildbot/android-ndk'):
    141     ndk_dir = '/buildbot/android-ndk'
    142   elif os.path.isdir(os.environ['NDK_PATH']):
    143     ndk_dir = os.environ['NDK_PATH'];
    144   else:
    145     print('Error: No NDK environment found')
    146     return
    147 
    148   ndk_build = os.path.join(ndk_dir, 'ndk-build')
    149   platforms_root = os.path.join(ndk_dir, 'platforms')
    150   toolchains_root = os.path.join(ndk_dir, 'toolchains')
    151   build_dir = THIS_DIR
    152 
    153   print('installdir: %s' % installdir)
    154   print('ndk_dir: %s' % ndk_dir)
    155   print('ndk_build: %s' % ndk_build)
    156   print('platforms_root: %s' % platforms_root)
    157 
    158   compiler = 'clang'
    159   stl = 'gnustl_static'
    160   obj_out = os.path.join(THIS_DIR, stl, 'obj')
    161   lib_out = os.path.join(THIS_DIR, 'jniLibs')
    162 
    163   print('obj_out: %s' % obj_out)
    164   print('lib_out: %s' % lib_out)
    165 
    166   print('Constructing shaderc build tree...')
    167   shaderc_root_dir = os.path.join(THIS_DIR, '../../shaderc')
    168 
    169   copies = [
    170       {
    171           'source_dir': os.path.join(shaderc_root_dir, 'shaderc'),
    172           'dest_dir': 'third_party/shaderc',
    173           'files': [
    174               'Android.mk', 'libshaderc/Android.mk',
    175               'libshaderc_util/Android.mk',
    176               'third_party/Android.mk',
    177               'utils/update_build_version.py',
    178               'CHANGES',
    179           ],
    180           'dirs': [
    181               'libshaderc/include', 'libshaderc/src',
    182               'libshaderc_util/include', 'libshaderc_util/src',
    183               'android_test'
    184           ],
    185       },
    186       {
    187           'source_dir': os.path.join(shaderc_root_dir, 'spirv-tools'),
    188           'dest_dir': 'third_party/shaderc/third_party/spirv-tools',
    189           'files': [
    190               'utils/generate_grammar_tables.py',
    191               'utils/generate_registry_tables.py',
    192               'utils/update_build_version.py',
    193               'CHANGES',
    194           ],
    195           'dirs': ['include', 'source'],
    196       },
    197       {
    198           'source_dir': os.path.join(shaderc_root_dir, 'spirv-headers'),
    199           'dest_dir':
    200               'third_party/shaderc/third_party/spirv-tools/external/spirv-headers',
    201           'dirs': ['include',],
    202           'files': [
    203               'include/spirv/1.0/spirv.py',
    204               'include/spirv/1.1/spirv.py'
    205           ],
    206       },
    207       {
    208           'source_dir': os.path.join(shaderc_root_dir, 'glslang'),
    209           'dest_dir': 'third_party/shaderc/third_party/glslang',
    210           'files': ['glslang/OSDependent/osinclude.h'],
    211           'dirs': [
    212               'SPIRV',
    213               'OGLCompilersDLL',
    214               'glslang/GenericCodeGen',
    215               'hlsl',
    216               'glslang/Include',
    217               'glslang/MachineIndependent',
    218               'glslang/OSDependent/Unix',
    219               'glslang/Public',
    220           ],
    221       },
    222   ]
    223 
    224   default_ignore_patterns = shutil.ignore_patterns(
    225       "*CMakeLists.txt",
    226       "*.py",
    227       "*test.h",
    228       "*test.cc")
    229 
    230   for properties in copies:
    231       source_dir = properties['source_dir']
    232       dest_dir = os.path.join(installdir, properties['dest_dir'])
    233       for d in properties['dirs']:
    234           src = os.path.join(source_dir, d)
    235           dst = os.path.join(dest_dir, d)
    236           print(src, " -> ", dst)
    237           shutil.copytree(src, dst,
    238                           ignore=default_ignore_patterns)
    239       for f in properties['files']:
    240           print(source_dir, ':', dest_dir, ":", f)
    241           # Only copy if the source file exists.  That way
    242           # we can update this script in anticipation of
    243           # source files yet-to-come.
    244           if os.path.exists(os.path.join(source_dir, f)):
    245               install_file(f, source_dir, dest_dir)
    246           else:
    247               print(source_dir, ':', dest_dir, ":", f, "SKIPPED")
    248 
    249   print('Constructing Vulkan validation layer source...')
    250 
    251   build_cmd = [
    252     'bash', THIS_DIR + '/android-generate.sh'
    253   ]
    254   print('Generating generated layers...')
    255   subprocess.check_call(build_cmd)
    256   print('Generation finished')
    257 
    258   build_cmd = [
    259     'bash', ndk_build, '-C', build_dir,
    260     jobs_arg(),
    261     'APP_ABI=' + ' '.join(abis),
    262     # Use the prebuilt platforms and toolchains.
    263     'NDK_PLATFORMS_ROOT=' + platforms_root,
    264     'NDK_TOOLCHAINS_ROOT=' + toolchains_root,
    265     'NDK_MODULE_PATH=' + installdir,
    266     'GNUSTL_PREFIX=',
    267     'APP_STL=' + stl,
    268     'NDK_TOOLCHAIN_VERSION=' + compiler,
    269 
    270     # Tell ndk-build where to put the results
    271     'NDK_OUT=' + obj_out,
    272     'NDK_LIBS_OUT=' + lib_out,
    273   ]
    274 
    275   print('Building Vulkan validation layers for ABIs:' +
    276     ' {}'.format(', '.join(abis)) + "...")
    277   print(' '.join(build_cmd))
    278 
    279   subprocess.check_call(build_cmd)
    280 
    281   print('Finished building Vulkan validation layers')
    282   out_package = os.path.join(installdir, 'vulkan_validation_layers.zip')
    283   os.chdir(lib_out)
    284   build_cmd = [
    285       'zip', '-9qr', out_package, "."
    286   ]
    287 
    288   print('Packaging Vulkan validation layers')
    289   subprocess.check_call(build_cmd)
    290   print('Finished Packaging Vulkan validation layers')
    291 
    292   for properties in copies:
    293       dest_dir = os.path.join(installdir, properties['dest_dir'])
    294       for d in properties['dirs']:
    295           dst = os.path.join(dest_dir, d)
    296           print('Remove: %s' % dst)
    297           shutil.rmtree(dst)
    298 
    299   return 0
    300 
    301 
    302 if __name__ == '__main__':
    303   main()
    304