Build shader-tools using clang
Change-Id: I119403158e831ad9ecfd586255b48879d95616df
diff --git a/build/tools/build-shader-tools.py b/build/tools/build-shader-tools.py
deleted file mode 100755
index 716ed00..0000000
--- a/build/tools/build-shader-tools.py
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Builds the glslc, spirv-as, spirv-dis, and spirv-val host executables."""
-
-from __future__ import print_function
-
-import os
-import site
-import shutil
-import subprocess
-
-site.addsitedir(os.path.join(os.path.dirname(__file__), '../lib'))
-site.addsitedir(os.path.join(os.path.dirname(__file__), '../..'))
-
-# pylint: disable=import-error,wrong-import-position
-import build_support
-from build_support import ArgParser
-import ndk.hosts
-# pylint: enable=import-error,wrong-import-position
-
-
-def main(args):
- host_tag = build_support.host_to_tag(args.host)
- build_host_tag = build_support.get_default_host().value + "-x86"
-
- package_dir = args.dist_dir
-
- # TODO(danalbert): use ndk/sources/third_party/googletest/googletest
- # after it has been updated to a version with CMakeLists
- gtest_dir = build_support.android_path('external', 'googletest')
- gtest_cmd = f'-DSHADERC_GOOGLE_TEST_DIR={gtest_dir}'
-
- # SPIRV-Tools tests require effcee and re2.
- # Don't enable RE2 testing because it's long and not useful to us.
- effcee_dir = build_support.android_path('external', 'effcee')
- re2_dir = build_support.android_path('external', 'regex-re2')
- effcee_args = [('-DSHADERC_EFFCEE_DIR=' + effcee_dir),
- ('-DSHADERC_RE2_DIR=' + re2_dir),
- ('-DEFFCEE_GOOGLETEST_DIR=' + gtest_dir),
- ('-DEFFCEE_RE2_DIR=' + re2_dir),
- ('-DRE2_BUILD_TESTING=OFF')]
-
- obj_out = os.path.join(args.out_dir, 'shader_tools/obj')
- install_dir = os.path.join(args.out_dir, 'shader_tools/install')
-
- package_src = '-'.join([os.path.join(args.out_dir,
- 'shader_tools/shader-tools'),
- host_tag])
- package_name = '-'.join(['shader-tools', host_tag])
-
- source_root = build_support.android_path('external', 'shaderc')
- shaderc_shaderc_dir = os.path.join(source_root, 'shaderc')
- spirv_headers_dir = os.path.join(source_root, 'spirv-headers')
-
- cmake = build_support.android_path('prebuilts', 'cmake',
- build_host_tag, 'bin', 'cmake')
- ctest = build_support.android_path('prebuilts', 'cmake',
- build_host_tag, 'bin', 'ctest')
- ninja = build_support.android_path('prebuilts', 'ninja',
- build_host_tag, 'ninja')
- file_extension = ''
-
- additional_args = list(effcee_args)
- if args.host.is_windows:
- gtest_cmd = ''
- mingw_root = os.path.join(build_support.android_path(),
- 'prebuilts', 'gcc', build_host_tag, 'host',
- 'x86_64-w64-mingw32-4.8')
- mingw_compilers = os.path.join(mingw_root, 'bin', 'x86_64-w64-mingw32')
- mingw_toolchain = os.path.join(source_root, 'shaderc',
- 'cmake', 'linux-mingw-toolchain.cmake')
- gtest_root = build_support.android_path('external', 'googletest')
- additional_args.extend(['-DCMAKE_TOOLCHAIN_FILE=' + mingw_toolchain,
- '-DMINGW_SYSROOT=' + mingw_root,
- '-DMINGW_COMPILER_PREFIX=' + mingw_compilers,
- '-DSHADERC_GOOGLE_TEST_DIR=' + gtest_root])
- file_extension = '.exe'
- if args.host == ndk.hosts.Host.Windows64:
- additional_args.extend(
- ['-DCMAKE_CXX_FLAGS=-fno-rtti -fno-exceptions'])
- else:
- additional_args.extend(
- ['-DCMAKE_CXX_FLAGS=-m32 -fno-rtti -fno-exceptions',
- '-DCMAKE_C_FLAGS=-m32'])
-
- for d in [package_src, obj_out, install_dir]:
- try:
- os.makedirs(d)
- except:
- pass
-
- cmake_command = [cmake, '-GNinja', '-DCMAKE_MAKE_PROGRAM=' + ninja,
- '-DCMAKE_BUILD_TYPE=Release',
- '-DCMAKE_INSTALL_PREFIX=' + install_dir,
- '-DSHADERC_THIRD_PARTY_ROOT_DIR=' + source_root,
- '-DSPIRV-Headers_SOURCE_DIR=' + spirv_headers_dir,
- gtest_cmd,
- shaderc_shaderc_dir]
-
- cmake_command.extend(additional_args)
-
- subprocess.check_call(cmake_command, cwd=obj_out)
- subprocess.check_call([cmake, '--build', obj_out, '--', '-v'])
- subprocess.check_call([cmake, '--build', obj_out,
- '--target', 'install/strip'])
-
- files_to_copy = ['glslc' + file_extension,
- 'spirv-as' + file_extension,
- 'spirv-dis' + file_extension,
- 'spirv-val' + file_extension,
- 'spirv-cfg' + file_extension,
- 'spirv-opt' + file_extension,
- 'spirv-link' + file_extension,
- 'spirv-reduce' + file_extension]
- scripts_to_copy = ['spirv-lesspipe.sh',]
- files_to_copy.extend(scripts_to_copy)
-
- # Test, except on windows.
- if not args.host.is_windows:
- subprocess.check_call([ctest, '--verbose'], cwd=obj_out)
-
- # Copy to install tree.
- for src in files_to_copy:
- shutil.copy2(os.path.join(install_dir, 'bin', src),
- os.path.join(package_src, src))
- if args.host.is_windows:
- for src in scripts_to_copy:
- # Convert line endings on scripts.
- # Do it in place to preserve executable permissions.
- subprocess.check_call(['unix2dos', '-o',
- os.path.join(package_src, src)])
-
- build_support.make_package(package_name, package_src, package_dir)
-
-if __name__ == '__main__':
- build_support.run(main, ArgParser)
diff --git a/ndk/builds.py b/ndk/builds.py
index 336d2cb..ed011c5 100644
--- a/ndk/builds.py
+++ b/ndk/builds.py
@@ -23,6 +23,7 @@
# https://github.com/PyCQA/pylint/issues/73
from distutils.dir_util import copy_tree
from enum import auto, Enum, unique
+from ndk.cmake import CMakeBuilder
import os
from pathlib import Path, PureWindowsPath
import shutil
@@ -333,6 +334,48 @@
str(install_dir))
+class CMakeModule(Module):
+ # Path to the source code
+ src: Path
+ _builder: Optional[CMakeBuilder] = None
+ run_ctest: bool = False
+
+ @property
+ def builder(self) -> CMakeBuilder:
+ """Returns the lazily initialized builder for this module."""
+ if self._builder is None:
+ self._builder = CMakeBuilder(
+ self.src,
+ self.intermediate_out_dir,
+ self.host,
+ additional_flags=self.flags,
+ additional_env=self.env,
+ run_ctest=self.run_ctest)
+ return self._builder
+
+ @property
+ def env(self) -> Dict[str, str]:
+ return dict()
+
+ @property
+ def flags(self) -> List[str]:
+ return []
+
+ @property
+ def defines(self) -> Dict[str, str]:
+ return dict()
+
+ def build(self) -> None:
+ self.builder.build(self.defines)
+
+ def install(self) -> None:
+ install_dir = self.get_install_path()
+ install_dir.mkdir(parents=True, exist_ok=True)
+ copy_tree(
+ str(self.builder.install_directory),
+ str(install_dir))
+
+
class PackageModule(Module):
"""A directory to be installed to the NDK.
diff --git a/ndk/checkbuild.py b/ndk/checkbuild.py
index dd68104..75e5616 100755
--- a/ndk/checkbuild.py
+++ b/ndk/checkbuild.py
@@ -612,11 +612,13 @@
]
-class ShaderTools(ndk.builds.InvokeBuildModule):
+class ShaderTools(ndk.builds.CMakeModule):
name = 'shader-tools'
+ src = ANDROID_DIR / 'external' / 'shaderc' / 'shaderc'
path = Path('shader-tools/{host}')
- script = Path('build-shader-tools.py')
+ run_ctest = True
notice_group = ndk.builds.NoticeGroup.TOOLCHAIN
+ deps = {'clang'}
@property
def notices(self) -> Iterator[Path]:
@@ -629,6 +631,92 @@
yield glslang_dir / 'LICENSE.txt'
yield spirv_dir / 'LICENSE'
+ @property
+ def defines(self) -> Dict[str, str]:
+ gtest_dir = ANDROID_DIR / 'external' / 'googletest'
+ effcee_dir = ANDROID_DIR / 'external' / 'effcee'
+ re2_dir = ANDROID_DIR / 'external' / 'regex-re2'
+ spirv_headers_dir = self.src.parent / 'spirv-headers'
+ defines = {
+ 'SHADERC_EFFCEE_DIR': str(effcee_dir),
+ 'SHADERC_RE2_DIR': str(re2_dir),
+ 'SHADERC_GOOGLE_TEST_DIR': str(gtest_dir),
+ 'SHADERC_THIRD_PARTY_ROOT_DIR': str(self.src.parent),
+ 'EFFCEE_GOOGLETEST_DIR': str(gtest_dir),
+ 'EFFCEE_RE2_DIR': str(re2_dir),
+ # SPIRV-Tools tests require effcee and re2.
+ # Don't enable RE2 testing because it's long and not useful to us.
+ 'RE2_BUILD_TESTING': 'OFF',
+ 'SPIRV-Headers_SOURCE_DIR': str(spirv_headers_dir),
+ }
+ return defines
+
+ @property
+ def flags(self) -> List[str]:
+ return super().flags + [
+ '-Wno-unused-command-line-argument',
+ '-fno-rtti',
+ '-fno-exceptions',
+ ]
+
+ @property
+ def env(self) -> Dict[str, str]:
+ # Sets path for libc++, for ctest.
+ if self.host == Host.Linux:
+ return {'LD_LIBRARY_PATH': str(self._libcxx_dir)}
+ elif self.host == Host.Darwin:
+ return {'DYLD_LIBRARY_PATH': str(self._libcxx_dir)}
+ return {}
+
+ @property
+ def _libcxx_dir(self) -> List[Path]:
+ return self.get_dep('clang').get_build_host_install() / 'lib64'
+
+ @property
+ def _libcxx(self) -> List[Path]:
+ path = self._libcxx_dir
+ if self.host == Host.Linux:
+ return [
+ path / 'libc++.so.1',
+ path / 'libc++abi.so.1',
+ ]
+ elif self.host == Host.Darwin:
+ return [
+ path / 'libc++.1.dylib',
+ path / 'libc++abi.1.dylib',
+ ]
+ return []
+
+ def install(self) -> None:
+ self.get_install_path().mkdir(parents=True, exist_ok=True)
+ ext = '.exe' if self.host.is_windows else ''
+ files_to_copy = [
+ f'glslc{ext}', f'spirv-as{ext}', f'spirv-dis{ext}',
+ f'spirv-val{ext}', f'spirv-cfg{ext}', f'spirv-opt{ext}',
+ f'spirv-link{ext}', f'spirv-reduce{ext}'
+ ]
+ scripts_to_copy = ['spirv-lesspipe.sh']
+
+ # Copy to install tree.
+ for src in files_to_copy + scripts_to_copy:
+ shutil.copy2(self.builder.install_directory / 'bin' / src,
+ self.get_install_path())
+
+ if self.host.is_windows:
+ for src in scripts_to_copy:
+ # Convert line endings on scripts.
+ # Do it in place to preserve executable permissions.
+ subprocess.check_call(
+ ['unix2dos', '-o',
+ self.get_install_path() / src])
+
+ # Symlink libc++ to install path.
+ for lib in self._libcxx:
+ symlink_name = self.get_install_path() / lib.name
+ symlink_name.unlink(missing_ok=True)
+ symlink_name.symlink_to(
+ Path(os.path.relpath(lib, symlink_name.parent)))
+
class Make(ndk.builds.AutoconfModule):
name = 'make'
diff --git a/ndk/cmake.py b/ndk/cmake.py
index 98471aa..f9c40b7 100644
--- a/ndk/cmake.py
+++ b/ndk/cmake.py
@@ -49,8 +49,9 @@
src_path: Path,
build_dir: Path,
host: Host,
- additional_flags: List[str] = None,
- additional_env: Optional[Dict[str, str]] = None) -> None:
+ additional_flags: Optional[List[str]] = None,
+ additional_env: Optional[Dict[str, str]] = None,
+ run_ctest: bool = False) -> None:
"""Initializes an autoconf builder.
Args:
@@ -68,6 +69,7 @@
self.host = host
self.additional_flags = additional_flags
self.additional_env = additional_env
+ self.run_ctest = run_ctest
self.working_directory = self.build_directory / 'build'
self.install_directory = self.build_directory / 'install'
@@ -116,6 +118,11 @@
(get_default_host().value + '-x86') / 'ninja')
@property
+ def _ctest(self) -> Path:
+ return (ndk.paths.ANDROID_DIR / 'prebuilts' / 'cmake' /
+ (get_default_host().value + '-x86') / 'bin' / 'ctest')
+
+ @property
def cmake_defines(self) -> Dict[str, str]:
"""CMake defines."""
flags = self.toolchain.flags + self.flags
@@ -175,9 +182,13 @@
"""Builds the project."""
self._run([str(self._ninja)])
+ def test(self) -> None:
+ """Runs tests."""
+ self._run([str(self._ctest), '--verbose'])
+
def install(self) -> None:
"""Installs the project."""
- self._run([str(self._ninja), 'install'])
+ self._run([str(self._ninja), 'install/strip'])
def build(self,
additional_defines: Optional[Dict[str, str]] = None) -> None:
@@ -192,4 +203,6 @@
self.configure(
{} if additional_defines is None else additional_defines)
self.make()
+ if not self.host.is_windows and self.run_ctest:
+ self.test()
self.install()