• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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