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