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