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 18import argparse 19import multiprocessing 20import os 21import shutil 22import subprocess 23import sys 24import time 25 26from subprocess import PIPE, STDOUT 27 28def 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 41def _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 48def _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 56def _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 63THIS_DIR = os.path.realpath(os.path.dirname(__file__)) 64 65ALL_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. 76ALL_ABIS = ( 77 'armeabi-v7a', 78 'arm64-v8a', 79 'mips', 80 'mips64', 81 'x86', 82 'x86_64', 83) 84 85def jobs_arg(): 86 return '-j{}'.format(multiprocessing.cpu_count() * 2) 87 88def 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 98class 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 121def 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 = installdir 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 print('Pulling in vulkan headers and layers...') 164 vulkan_root_dir = os.path.join(THIS_DIR, '../../vulkan-validation-layers') 165 vulkan_headers_root_dir = os.path.join(THIS_DIR, '../../vulkan-headers') 166 167 copies = [ 168 { 169 'source_dir': os.path.join(shaderc_root_dir, 'shaderc'), 170 'dest_dir': 'third_party/shaderc', 171 'files': [ 172 'Android.mk', 'libshaderc/Android.mk', 173 'libshaderc_util/Android.mk', 174 'third_party/Android.mk', 175 'utils/update_build_version.py', 176 'CHANGES', 177 ], 178 'dirs': [ 179 'libshaderc/include', 'libshaderc/src', 180 'libshaderc_util/include', 'libshaderc_util/src', 181 'android_test' 182 ], 183 }, 184 { 185 'source_dir': os.path.join(shaderc_root_dir, 'spirv-tools'), 186 'dest_dir': 'third_party/shaderc/third_party/spirv-tools', 187 'files': [ 188 'utils/generate_grammar_tables.py', 189 'utils/generate_language_headers.py', 190 'utils/generate_registry_tables.py', 191 'utils/update_build_version.py', 192 'Android.mk', 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 'include/spirv/1.2/spirv.py', 206 ], 207 }, 208 { 209 'source_dir': os.path.join(shaderc_root_dir, 'glslang'), 210 'dest_dir': 'third_party/shaderc/third_party/glslang', 211 'files': ['glslang/OSDependent/osinclude.h', 212 'Android.mk', 213 ], 214 'dirs': [ 215 'SPIRV', 216 'OGLCompilersDLL', 217 'glslang/GenericCodeGen', 218 'hlsl', 219 'glslang/Include', 220 'glslang/MachineIndependent', 221 'glslang/OSDependent/Unix', 222 'glslang/Public', 223 ], 224 }, 225 { 226 'source_dir': vulkan_root_dir, 227 'dest_dir': 'vulkan/src', 228 'files': [ 229 ], 230 'dirs': [ 231 'layers', 'scripts', 'build-android' 232 ], 233 }, 234 235 { 236 'source_dir': vulkan_headers_root_dir, 237 'dest_dir': 'vulkan/src', 238 'files': [ 239 ], 240 'dirs': [ 241 'include', 'registry' 242 ], 243 }, 244 ] 245 246 default_ignore_patterns = shutil.ignore_patterns( 247 "*CMakeLists.txt", 248 "*test.h", 249 "*test.cc") 250 251 for properties in copies: 252 source_dir = properties['source_dir'] 253 dest_dir = os.path.join(installdir, properties['dest_dir']) 254 for d in properties['dirs']: 255 src = os.path.join(source_dir, d) 256 dst = os.path.join(dest_dir, d) 257 print(src, " -> ", dst) 258 shutil.copytree(src, dst, 259 ignore=default_ignore_patterns) 260 for f in properties['files']: 261 print(source_dir, ':', dest_dir, ":", f) 262 # Only copy if the source file exists. That way 263 # we can update this script in anticipation of 264 # source files yet-to-come. 265 if os.path.exists(os.path.join(source_dir, f)): 266 install_file(f, source_dir, dest_dir) 267 else: 268 print(source_dir, ':', dest_dir, ":", f, "SKIPPED") 269 270 print('Constructing Vulkan validation layer source...') 271 272 build_cmd = [ 273 'bash', build_dir + '/vulkan/src/build-android/android-generate.sh', 274 build_dir + '/vulkan/src/registry' 275 ] 276 print('Generating generated layers...') 277 subprocess.check_call(build_cmd) 278 print('Generation finished') 279 280 build_cmd = [ 281 'bash', ndk_build, '-C', build_dir + '/vulkan/src/build-android', 282 jobs_arg(), 283 'APP_ABI=' + ' '.join(abis), 284 # Use the prebuilt platforms and toolchains. 285 'NDK_PLATFORMS_ROOT=' + platforms_root, 286 'NDK_TOOLCHAINS_ROOT=' + toolchains_root, 287 'NDK_MODULE_PATH=' + installdir, 288 'GNUSTL_PREFIX=', 289 'APP_STL=' + stl, 290 'NDK_TOOLCHAIN_VERSION=' + compiler, 291 292 # Tell ndk-build where to put the results 293 'NDK_OUT=' + obj_out, 294 'NDK_LIBS_OUT=' + lib_out, 295 ] 296 297 print('Building Vulkan validation layers for ABIs:' + 298 ' {}'.format(', '.join(abis)) + "...") 299 print(' '.join(build_cmd)) 300 301 subprocess.check_call(build_cmd) 302 303 print('Finished building Vulkan validation layers') 304 out_package = os.path.join(installdir, 'vulkan_validation_layers.zip') 305 os.chdir(lib_out) 306 build_cmd = [ 307 'zip', '-9qr', out_package, "." 308 ] 309 310 print('Packaging Vulkan validation layers') 311 subprocess.check_call(build_cmd) 312 print('Finished Packaging Vulkan validation layers') 313 314 for properties in copies: 315 dest_dir = os.path.join(installdir, properties['dest_dir']) 316 for d in properties['dirs']: 317 dst = os.path.join(dest_dir, d) 318 print('Remove: %s' % dst) 319 shutil.rmtree(dst) 320 321 return 0 322 323 324if __name__ == '__main__': 325 main() 326