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 = 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 324 if __name__ == '__main__': 325 main() 326