Merge "Snap for 7174163 from b186ebf473b97d2c8c939d05b97f8b6925a68c37 to busytown-mac1010-release" into busytown-mac1010-release
diff --git a/build/core/default-build-commands.mk b/build/core/default-build-commands.mk
index 60ab955..8cf40dc 100644
--- a/build/core/default-build-commands.mk
+++ b/build/core/default-build-commands.mk
@@ -102,11 +102,8 @@
 # the toolchain's setup.mk script.
 TOOLCHAIN_PREFIX = $(TOOLCHAIN_ROOT)/bin/$(TOOLCHAIN_NAME)-
 
-ifneq ($(findstring ccc-analyzer,$(CC)),)
-    TARGET_CC = $(CC)
-else
-    TARGET_CC = $(LLVM_TOOLCHAIN_PREFIX)clang$(HOST_EXEEXT)
-endif
+TARGET_CC = $(LLVM_TOOLCHAIN_PREFIX)clang$(HOST_EXEEXT)
+TARGET_CXX = $(LLVM_TOOLCHAIN_PREFIX)clang++$(HOST_EXEEXT)
 
 CLANG_TIDY = $(LLVM_TOOLCHAIN_PREFIX)clang-tidy$(HOST_EXEEXT)
 
@@ -143,12 +140,6 @@
 TARGET_CONLYFLAGS =
 TARGET_CXXFLAGS = $(TARGET_CFLAGS)
 
-ifneq ($(findstring c++-analyzer,$(CXX)),)
-    TARGET_CXX = $(CXX)
-else
-    TARGET_CXX = $(LLVM_TOOLCHAIN_PREFIX)clang++$(HOST_EXEEXT)
-endif
-
 TARGET_RS_CC    = $(RENDERSCRIPT_TOOLCHAIN_PREFIX)llvm-rs-cc
 TARGET_RS_BCC   = $(RENDERSCRIPT_TOOLCHAIN_PREFIX)bcc_compat
 TARGET_RS_FLAGS = -Wall -Werror
diff --git a/build/ndk-build b/build/ndk-build
index 85d10e6..08e1e29 100755
--- a/build/ndk-build
+++ b/build/ndk-build
@@ -231,58 +231,11 @@
     log "Cygwin-compatible GNU make detected"
 fi
 
+NDK_ANALYZER_FLAGS=
 if [ "$NDK_ANALYZE" = 1 ]; then
-    . $PROGDIR/tools/dev-defaults.sh  # for DEFAULT_LLVM_VERSION
-
-    # Return flags send in env. or command line which are enough to retrive APP_ABI and TOOLCHAIN_PREFIX later
-    gen_flags ()
-    {
-        local FLAGS=
-
-        if [ -n "$PROJECT_PATH" ] ; then
-            FLAGS=$FLAGS" -C $PROJECT_PATH"
-        fi
-        if [ -n "$APP_ABI" ] ; then
-            FLAGS=$FLAGS" APP_ABI=$APP_ABI"
-        fi
-        echo "$FLAGS"
-    }
-
-    get_build_var ()
-    {
-        local VAR=$1
-        local FLAGS=`gen_flags`
-        $GNUMAKE --no-print-dir -f $PROGDIR/core/build-local.mk $FLAGS DUMP_${VAR} | tail -1
-    }
-
-    get_build_var_for_abi ()
-    {
-        local VAR=$1
-        local ABI=$2
-        local FLAGS=`gen_flags`
-        $GNUMAKE --no-print-dir -f $PROGDIR/core/build-local.mk $FLAGS DUMP_${VAR} APP_ABI=${ABI} | tail -1
-    }
-
-    APP_ABIS=`get_build_var APP_ABI`
-    for ABI in $APP_ABIS; do
-        LLVM_TOOLCHAIN_PREFIX=`get_build_var LLVM_TOOLCHAIN_PREFIX`
-        ANALYZER_OUT=`get_build_var NDK_APP_ANALYZER_OUT`
-
-        ANALYZER_CC=${LLVM_TOOLCHAIN_PREFIX}clang
-        ANALYZER_CXX=${LLVM_TOOLCHAIN_PREFIX}clang++
-
-        ANALYZER_OUT_FLAG=
-        if [ -n "$NDK_ANALYZER_OUT" ]; then
-            ANALYZER_OUT_FLAG="-o $NDK_ANALYZER_OUT/$ABI"
-        fi
-
-        perl ${LLVM_TOOLCHAIN_PREFIX}scan-build \
-            --use-cc $ANALYZER_CC \
-            --use-c++ $ANALYZER_CXX \
-            --status-bugs \
-            $ANALYZER_OUT_FLAG \
-            $GNUMAKE -f $PROGDIR/core/build-local.mk "$@" APP_ABI=$ABI
-    done
-else
-    $GNUMAKE -O -f $PROGDIR/core/build-local.mk "$@"
+    # Continue supporting the old interface to the static analyzer. clang-tidy
+    # does all the same checks by default (and some new ones).
+    NDK_ANALYZER_FLAGS=APP_CLANG_TIDY=true
 fi
+
+$GNUMAKE -O -f $PROGDIR/core/build-local.mk $NDK_ANALYZER_FLAGS "$@"
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/build/tools/prebuilt-common.sh b/build/tools/prebuilt-common.sh
index b8bf0e4..d84ce09 100644
--- a/build/tools/prebuilt-common.sh
+++ b/build/tools/prebuilt-common.sh
@@ -1408,13 +1408,6 @@
         echo "ERROR: Not a directory: '$SRC_DIR'"
         exit 1
     fi
-
-    if [ ! -f "$SRC_DIR/build/configure" -o ! -d "$SRC_DIR/gcc" ]; then
-        echo "ERROR: Either the file $SRC_DIR/build/configure or"
-        echo "       the directory $SRC_DIR/gcc does not exist."
-        echo "This is not the top of a toolchain tree: $SRC_DIR"
-        exit 1
-    fi
 }
 
 make_repo_prop () {
diff --git a/docs/changelogs/Changelog-r22.md b/docs/changelogs/Changelog-r22.md
index 328aec0..9295feb 100644
--- a/docs/changelogs/Changelog-r22.md
+++ b/docs/changelogs/Changelog-r22.md
@@ -21,11 +21,13 @@
 
 ## r22b
 
-  * [Issue 1388]: Fixed LLVM's incorrect conversion to list files for long command
-    lines on Windows.
-  * [Issue 1391]: Fixed missing symbols from libz.a.
-  * [Issue 1427]: Fixed Clang auto-detection for CMake 3.19 and older for Windows.
+* [Issue 1377]: Fix Clang backend crash in register scavenging.
+* [Issue 1388]: Fixed LLVM's incorrect conversion to list files for long command
+  lines on Windows.
+* [Issue 1391]: Fixed missing symbols from libz.a.
+* [Issue 1427]: Fixed Clang auto-detection for CMake 3.19 and older for Windows.
 
+[Issue 1377]: https://github.com/android/ndk/issues/1377
 [Issue 1388]: https://github.com/android/ndk/issues/1388
 [Issue 1391]: https://github.com/android/ndk/issues/1391
 [Issue 1427]: https://github.com/android/ndk/issues/1427
diff --git a/docs/changelogs/Changelog-r23.md b/docs/changelogs/Changelog-r23.md
index 61eec28..89b309c 100644
--- a/docs/changelogs/Changelog-r23.md
+++ b/docs/changelogs/Changelog-r23.md
@@ -13,8 +13,18 @@
   removed in the next release. If you are building with `-fno-integrated-as`,
   file bugs if anything is preventing you from removing that flag.
 
+* Support for GDB has ended. The GDB from r22 will continue to be included in
+  the NDK, but it will be removed if and when it stops working. Use LLDB
+  instead. Note that `ndk-gdb` uses LLDB by default.
+
 ## Changes
 
+* Includes preview Android S DP 1 APIs.
+* Updated LLVM to clang-r412851, based on LLVM 12 development.
+  * [Issue 1047]: Fixes crash when using ASan with the CFI unwinder.
+  * [Issue 1096]: Includes support for [Polly]. Enable by adding `-mllvm -polly`
+    to your cflags.
+  * [Issue 1406]: Fixes crash with Neon intrinsic.
 * Vulkan validation layer source and binaries are no longer shipped in the NDK.
   The latest are now posted directly to [GitHub](https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases).
 * Vulkan tools source is also removed, specifically vulkan_wrapper.
@@ -28,9 +38,18 @@
   static libraries.
 * [Issue 1390]: ndk-build now warns when building a static executable with the
   wrong API level.
+* [Issue 1452]: `NDK_ANALYZE=1` now sets `APP_CLANG_TIDY=true` rather than using
+  scan-build. clang-tidy performs all the same checks by default, and scan-build
+  was no longer working. See the bug for more details, but no user-side changes
+  should be needed.
 
 [Issue 929]: https://github.com/android/ndk/issues/929
+[Issue 1047]: https://github.com/android/ndk/issues/1047
+[Issue 1096]: https://github.com/android/ndk/issues/1096
 [Issue 1390]: https://github.com/android/ndk/issues/1390
+[Issue 1406]: https://github.com/android/ndk/issues/1406
+[Issue 1452]: https://github.com/android/ndk/issues/1452
+[Polly]: https://polly.llvm.org/
 
 ## Known Issues
 
diff --git a/meta/platforms.json b/meta/platforms.json
index a124f69..32ff583 100644
--- a/meta/platforms.json
+++ b/meta/platforms.json
@@ -1,6 +1,6 @@
 {
   "min": 16,
-  "max": 30,
+  "max": 31,
   "aliases": {
     "20": 19,
     "25": 24,
@@ -17,6 +17,7 @@
     "O-MR1": 27,
     "P": 28,
     "Q": 29,
-    "R": 30
+    "R": 30,
+    "S": 31
   }
 }
diff --git a/ndk-gdb.py b/ndk-gdb.py
index 5212287..3f68024 100755
--- a/ndk-gdb.py
+++ b/ndk-gdb.py
@@ -706,6 +706,10 @@
     device = args.device
     use_lldb = not args.no_lldb
 
+    if not use_lldb:
+        print("WARNING: --no-lldb was used by GDB is no longer supported.")
+        print("GDB will be used, but will be removed in a future release.")
+
     if device is None:
         error("Could not find a unique connected device/emulator.")
 
diff --git a/ndk/abis.py b/ndk/abis.py
index 57914ce..6430a8c 100644
--- a/ndk/abis.py
+++ b/ndk/abis.py
@@ -23,14 +23,14 @@
 
 
 LP32_ABIS = (
-    'armeabi-v7a',
-    'x86',
+    Abi('armeabi-v7a'),
+    Abi('x86'),
 )
 
 
 LP64_ABIS = (
-    'arm64-v8a',
-    'x86_64',
+    Abi('arm64-v8a'),
+    Abi('x86_64'),
 )
 
 
diff --git a/ndk/builds.py b/ndk/builds.py
index bd9a96b..ed011c5 100644
--- a/ndk/builds.py
+++ b/ndk/builds.py
@@ -23,15 +23,15 @@
 # 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
 import stat
 import subprocess
 import textwrap
-from typing import Any, Dict, Iterable, Iterator, List, Optional, Set
+from typing import Any, Dict, Iterator, List, Optional, Set
 
-from ndk.abis import Arch, ALL_ARCHITECTURES
 from ndk.autoconf import AutoconfBuilder
 import ndk.ext.shutil
 from ndk.hosts import Host
@@ -59,12 +59,11 @@
     """Class containing build context information."""
 
     def __init__(self, out_dir: Path, dist_dir: Path, modules: List[Module],
-                 host: Host, arches: List[Arch], build_number: str) -> None:
+                 host: Host, build_number: str) -> None:
         self.out_dir = out_dir
         self.dist_dir = dist_dir
         self.modules = {m.name: m for m in modules}
         self.host = host
-        self.arches = arches
         self.build_number = build_number
 
 
@@ -106,13 +105,6 @@
     # text being included in NOTICE.toolchain.
     notice_group = NoticeGroup.BASE
 
-    # If split_build_by_arch is set, one workqueue task will be created for
-    # each architecture. The Module object will be cloned for each arch and
-    # each will have build_arch set to the architecture that should be built by
-    # that module. If build_arch is None, the module has not yet been split.
-    split_build_by_arch = False
-    build_arch: Optional[Arch] = None
-
     # Set to True if this module is merely a build convenience and not intented
     # to be shipped. For example, Platforms has its own build steps but is
     # shipped within the Toolchain module. If this value is set, the module's
@@ -193,20 +185,17 @@
         assert self.context is not None
         return self.context.modules[name]
 
-    def get_build_host_install(self, arch: Optional[Arch] = None) -> Path:
+    def get_build_host_install(self) -> Path:
         """Returns the module's install path for the current host.
 
         In a cross-compiling context (i.e. building the Windows NDK from
         Linux), this will return the install directory for the build OS rather
         than the target OS.
 
-        Args:
-            arch: Architecture to fetch for architecture-specific modules.
-
         Returns:
             This module's install path for the build host.
         """
-        return self.get_install_path(Host.current(), arch)
+        return self.get_install_path(Host.current())
 
     @property
     def out_dir(self) -> Path:
@@ -226,12 +215,6 @@
         assert self.context is not None
         return self.context.host
 
-    @property
-    def arches(self) -> List[Arch]:
-        """Architectures targeted by the current build."""
-        assert self.context is not None
-        return self.context.arches
-
     def build(self) -> None:
         """Builds the module.
 
@@ -250,48 +233,26 @@
         The install phase should only copy files, not create them. Compilation
         should happen in the build phase.
         """
-        package_installs = ndk.packaging.expand_packages(
-            self.name, str(self.path), self.host, self.arches)
+        package_name, package_install = ndk.packaging.expand_package(
+            self.name, str(self.path), self.host)
 
         install_base = Path(
             ndk.paths.get_install_path(str(self.out_dir), self.host))
         if self.intermediate_module:
             install_base = self.intermediate_out_dir / 'install'
-        for package_name, package_install in package_installs:
-            assert self.context is not None
-            install_path = install_base / package_install
-            package = self.context.dist_dir / package_name
-            if install_path.exists():
-                shutil.rmtree(install_path)
-            ndk.packaging.extract_zip(str(package), str(install_path))
 
-    def get_install_paths(self, host: Host,
-                          arches: Optional[Iterable[Arch]]) -> List[Path]:
-        """Returns the install paths for the given archiectures."""
-        install_subdirs = [
-            Path(p)
-            for p in ndk.packaging.expand_paths(str(self.path), host, arches)
-        ]
-        install_base = Path(ndk.paths.get_install_path(str(self.out_dir),
-                                                       host))
-        if self.intermediate_module:
-            install_base = self.intermediate_out_dir / 'install'
-        return [install_base / d for d in install_subdirs]
+        assert self.context is not None
+        install_path = install_base / package_install
+        package = self.context.dist_dir / package_name
+        if install_path.exists():
+            shutil.rmtree(install_path)
+        ndk.packaging.extract_zip(str(package), str(install_path))
 
-    def get_install_path(self,
-                         host: Optional[Host] = None,
-                         arch: Optional[Arch] = None) -> Path:
+    def get_install_path(self, host: Optional[Host] = None) -> Path:
         """Returns the install path for the given module config.
 
-        For an architecture-independent module, there should only ever be one
-        install path.
-
-        For an architecture-dependent module, the optional arch argument must
-        be provided to select between the install paths.
-
         Args:
             host: The host to use for a host-specific install path.
-            arch: The architecture to use for an architecure-dependent module.
 
         Raises:
             ValueError: This is an architecture-dependent module and no
@@ -302,45 +263,19 @@
         if host is None:
             host = self.host
 
-        arch_dependent = False
-        if ndk.packaging.package_varies_by(str(self.path), 'abi'):
-            arch_dependent = True
-        elif ndk.packaging.package_varies_by(str(self.path), 'arch'):
-            arch_dependent = True
-        elif ndk.packaging.package_varies_by(str(self.path), 'toolchain'):
-            arch_dependent = True
-        elif ndk.packaging.package_varies_by(str(self.path), 'triple'):
-            arch_dependent = True
-
-        arches = None
-        if arch is not None:
-            arches = [arch]
-        elif self.build_arch is not None:
-            arches = [self.build_arch]
-        elif arch_dependent:
-            raise ValueError(
-                f'get_install_path for {arch} requires valid arch')
-
-        install_subdirs = self.get_install_paths(host, arches)
-
-        if len(install_subdirs) != 1:
-            raise RuntimeError(
-                f'non-unique install path for single arch: {self.path}')
-
-        return install_subdirs[0]
+        install_subdir = Path(ndk.packaging.expand_path(str(self.path), host))
+        install_base = Path(ndk.paths.get_install_path(str(self.out_dir),
+                                                       host))
+        if self.intermediate_module:
+            install_base = self.intermediate_out_dir / 'install'
+        return install_base / install_subdir
 
     @property
     def intermediate_out_dir(self) -> Path:
         """Path for intermediate outputs of this module."""
-        base_path = self.out_dir / self.host.value / self.name
-        if self.split_build_by_arch:
-            return base_path / self.build_arch
-        else:
-            return base_path
+        return self.out_dir / self.host.value / self.name
 
     def __str__(self) -> str:
-        if self.split_build_by_arch and self.build_arch is not None:
-            return f'{self.name} [{self.build_arch}]'
         return self.name
 
     def __hash__(self) -> int:
@@ -355,12 +290,7 @@
     @property
     def log_file(self) -> str:
         """Returns the basename of the log file for this module."""
-        if self.split_build_by_arch and self.build_arch is not None:
-            return f'{self.name}-{self.build_arch}.log'
-        elif self.split_build_by_arch:
-            raise RuntimeError('Called log_file on unsplit module')
-        else:
-            return f'{self.name}.log'
+        return f'{self.name}.log'
 
     def log_path(self, log_dir: Path) -> Path:
         """Returns the path to the log file for this module."""
@@ -404,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.
 
@@ -416,25 +388,11 @@
     def default_notice_path(self) -> Path:
         return self.src / 'NOTICE'
 
-    def validate(self) -> None:
-        super().validate()
-
-        if ndk.packaging.package_varies_by(str(self.path), 'abi'):
-            raise self.validate_error('PackageModule cannot vary by abi')
-        if ndk.packaging.package_varies_by(str(self.path), 'arch'):
-            raise self.validate_error('PackageModule cannot vary by arch')
-        if ndk.packaging.package_varies_by(str(self.path), 'toolchain'):
-            raise self.validate_error('PackageModule cannot vary by toolchain')
-        if ndk.packaging.package_varies_by(str(self.path), 'triple'):
-            raise self.validate_error('PackageModule cannot vary by triple')
-
     def build(self) -> None:
         pass
 
     def install(self) -> None:
-        install_paths = self.get_install_paths(self.host, ALL_ARCHITECTURES)
-        assert len(install_paths) == 1
-        install_path = install_paths[0]
+        install_path = self.get_install_path(self.host)
         install_directory(self.src, install_path)
 
 
@@ -448,20 +406,8 @@
     #: The path to the build script relative to the top of the source tree.
     script: Path
 
-    #: True if the module can be built in parallel per-architecture.
-    arch_specific = False
-
     def build(self) -> None:
         build_args = common_build_args(self.out_dir, self.dist_dir, self.host)
-        if self.split_build_by_arch:
-            build_args.append(f'--arch={self.build_arch}')
-        elif self.arch_specific and len(self.arches) == 1:
-            build_args.append(f'--arch={self.arches[0]}')
-        elif set(self.arches) == set(ALL_ARCHITECTURES):
-            pass
-        else:
-            raise NotImplementedError(
-                f'Module {self.name} can only build all architectures or none')
         script = self.get_script_path()
         invoke_external_build(script, build_args)
 
@@ -597,12 +543,7 @@
 
     def get_script_path(self) -> Path:
         """Returns the installed path of the script."""
-        scripts = [
-            Path(p) for p in ndk.packaging.expand_paths(
-                str(self.script), self.host, ALL_ARCHITECTURES)
-        ]
-        assert len(scripts) == 1
-        return scripts[0]
+        return Path(ndk.packaging.expand_path(str(self.script), self.host))
 
 
 class PythonPackage(Module):
diff --git a/ndk/checkbuild.py b/ndk/checkbuild.py
index a7a8304..05862bd 100755
--- a/ndk/checkbuild.py
+++ b/ndk/checkbuild.py
@@ -39,7 +39,6 @@
 import os
 from pathlib import Path
 import pipes
-import pprint
 import re
 import shutil
 import site
@@ -313,9 +312,6 @@
     with open(ndk.paths.ndk_path('qa_config.json')) as config_file:
         test_config = json.load(config_file)
 
-    if args.arch is not None:
-        test_config['abis'] = ndk.abis.arch_to_abis(args.arch)
-
     test_spec = ndk.test.builder.test_spec_from_config(test_config)
     builder = ndk.test.builder.TestBuilder(
         test_spec, test_options, printer)
@@ -396,7 +392,8 @@
             shutil.rmtree(install_path)
         if not install_path.parent.exists():
             install_path.parent.mkdir(parents=True)
-        shutil.copytree(ClangToolchain.path_for_host(self.host), install_path)
+        shutil.copytree(ClangToolchain.path_for_host(self.host), install_path,
+                        symlinks=not self.host.is_windows)
 
         # clang-4053586 was patched in the prebuilts directory to add the
         # libc++ includes. These are almost certainly a different revision than
@@ -418,18 +415,15 @@
             (bin_dir / 'clang.real').rename(clang)
             (bin_dir / 'clang++').symlink_to('clang')
 
-            # The prebuilts have duplicates as clang-MAJ. Remove these to save
-            # space.
-            for path in bin_dir.glob('clang-*'):
-                if re.search(r'^clang-\d+$', path.name) is not None:
-                    path.unlink()
-
-        # Remove LLD duplicates. We only need ld.lld.
-        # http://b/74250510
         bin_ext = '.exe' if self.host.is_windows else ''
-        (bin_dir / f'ld64.lld{bin_ext}').unlink()
-        (bin_dir / f'lld{bin_ext}').unlink()
-        (bin_dir / f'lld-link{bin_ext}').unlink()
+        if self.host.is_windows:
+            # Remove LLD duplicates. We only need ld.lld. For non-Windows these
+            # are all symlinks so we can keep them (and *need* to keep lld
+            # since that's the real binary).
+            # http://b/74250510
+            (bin_dir / f'ld64.lld{bin_ext}').unlink()
+            (bin_dir / f'lld{bin_ext}').unlink()
+            (bin_dir / f'lld-link{bin_ext}').unlink()
 
         install_clanglib = install_path / 'lib64/clang'
         linux_prebuilt_path = ClangToolchain.path_for_host(Host.Linux)
@@ -438,12 +432,17 @@
         if self.host != Host.Windows64:
             python_bin_dir = install_path / 'python3' / 'bin'
             python_files_to_remove = [
-                '2to3', '2to3-3.8', 'easy_install-3.8', 'idle3', 'idle3.8', 'pip3',
-                'pip3.8', 'pydoc3', 'pydoc3.8', 'python3-config',
-                'python3.8-config',
+                '2to3*', 'easy_install*', 'idle*', 'pip*',
+                'pydoc*', 'python*-config',
             ]
-            for pyfile in python_files_to_remove:
-                (python_bin_dir / pyfile).unlink()
+            for file_pattern in python_files_to_remove:
+                for pyfile in python_bin_dir.glob(file_pattern):
+                    pyfile.unlink()
+
+        # Remove lldb-argdumper in site-packages. libc++ is not available there.
+        # People should use bin/lldb-argdumper instead.
+        for pylib in (install_path / 'lib').glob('python*'):
+            (pylib / f'site-packages/lldb/lldb-argdumper{bin_ext}').unlink()
 
         if self.host != Host.Linux:
             # We don't build target binaries as part of the Darwin or Windows
@@ -478,14 +477,17 @@
         shutil.rmtree(install_path / 'lib64/cmake')
 
 
-def get_gcc_prebuilt_path(host: Host, arch: ndk.abis.Arch) -> Path:
-    """Returns the path to the GCC prebuilt for the given host/arch."""
-    toolchain = ndk.abis.arch_to_toolchain(arch) + '-4.9'
-    prebuilt_path = (ANDROID_DIR / 'prebuilts/ndk/current/toolchains' /
-                     host.tag / toolchain)
+def get_gcc_prebuilt_path(arch: ndk.abis.Arch) -> Path:
+    """Returns the path to the GCC prebuilt for the given arch.
+
+    Since this is only used for getting *target* binaries like libgcc, we
+    always use the Linux prebuilts.
+    """
+    prebuilt_path = (ANDROID_DIR /
+                     'prebuilts/ndk/current/toolchains/linux-x86_64' /
+                     f'{ndk.abis.arch_to_toolchain(arch)}-4.9')
     if not prebuilt_path.is_dir():
-        raise RuntimeError(
-            'Could not find prebuilt GCC at {}'.format(prebuilt_path))
+        raise RuntimeError(f'Could not find prebuilt GCC at {prebuilt_path}')
     return prebuilt_path
 
 
@@ -519,7 +521,6 @@
 
 
 def install_gcc_lib(install_path: Path,
-                    host: Host,
                     arch: ndk.abis.Arch,
                     subarch: str,
                     lib_subdir: Path,
@@ -533,25 +534,24 @@
         lib_install_dir.mkdir(parents=True)
 
     shutil.copy2(
-        get_gcc_prebuilt_path(host, arch) / src_subdir / subarch / libname,
+        get_gcc_prebuilt_path(arch) / src_subdir / subarch / libname,
         lib_install_dir / libname)
 
 
-def install_gcc_crtbegin(install_path: Path, host: Host, arch: ndk.abis.Arch,
+def install_gcc_crtbegin(install_path: Path, arch: ndk.abis.Arch,
                          subarch: str) -> None:
     triple = ndk.abis.arch_to_triple(arch)
     subdir = Path('lib/gcc') / triple / '4.9.x'
-    install_gcc_lib(install_path, host, arch, subarch, subdir, 'crtbegin.o')
+    install_gcc_lib(install_path, arch, subarch, subdir, 'crtbegin.o')
 
 
 def install_libgcc(install_path: Path,
-                   host: Host,
                    arch: ndk.abis.Arch,
                    subarch: str,
                    new_layout: bool = False) -> None:
     triple = ndk.abis.arch_to_triple(arch)
     subdir = Path('lib/gcc') / triple / '4.9.x'
-    install_gcc_lib(install_path, host, arch, subarch, subdir, 'libgcc.a')
+    install_gcc_lib(install_path, arch, subarch, subdir, 'libgcc.a')
 
     if new_layout:
         # For all architectures, we want to ensure that libcompiler_rt-extras
@@ -591,11 +591,11 @@
         libgcc_path.write_text('INPUT({})'.format(libs))
 
 
-def install_libatomic(install_path: Path, host: Host, arch: ndk.abis.Arch,
+def install_libatomic(install_path: Path, arch: ndk.abis.Arch,
                       subarch: str) -> None:
     triple = ndk.abis.arch_to_triple(arch)
     libdir_name = 'lib64' if arch.endswith('64') else 'lib'
-    install_gcc_lib(install_path, host, arch, subarch,
+    install_gcc_lib(install_path, arch, subarch,
                     Path('lib/gcc') / triple / '4.9.x', 'libatomic.a',
                     Path(triple) / libdir_name)
 
@@ -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) -> 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'
@@ -670,55 +758,65 @@
     src = NDK_DIR / 'ndk-which'
 
 
-class HostTools(ndk.builds.Module):
-    name = 'host-tools'
+class Python(ndk.builds.Module):
+    """Module for host Python 2 to support GDB.
+
+    This is now a prebuilt. Next time this or GDB breaks we'll be removing both
+    and migrating the tools we ship with ndk-build to Python 3.
+    """
+
+    name = 'python'
     path = Path('prebuilt/{host}')
+    PREBUILTS_BASE = ANDROID_DIR / 'prebuilts/ndk/python'
+    notice = ANDROID_DIR / 'prebuilts/ndk/python/NOTICE'
     notice_group = ndk.builds.NoticeGroup.TOOLCHAIN
 
-    @property
-    def notices(self) -> Iterator[Path]:
-        yield ANDROID_DIR / 'toolchain/python/Python-2.7.5/LICENSE'
-        yield NDK_DIR / 'sources/host-tools/toolbox/NOTICE'
-
     def build(self) -> None:
-        build_args = ndk.builds.common_build_args(self.out_dir, self.dist_dir,
-                                                  self.host)
-
-        if self.host.is_windows:
-            print('Building toolbox...')
-            ndk.builds.invoke_external_build(
-                NDK_DIR / 'sources/host-tools/toolbox/build.py', build_args)
-
-        print('Building Python...')
-        ndk.builds.invoke_external_build(
-            ANDROID_DIR / 'toolchain/python/build.py', build_args)
+        pass
 
     def install(self) -> None:
+        copy_tree(str(self.PREBUILTS_BASE / self.host.tag),
+                  str(self.get_install_path()))
+
+
+class Toolbox(ndk.builds.Module):
+    name = 'toolbox'
+    path = Path('prebuilt/{host}/bin')
+    notice_group = ndk.builds.NoticeGroup.TOOLCHAIN
+    notice = NDK_DIR / 'sources/host-tools/toolbox/NOTICE'
+
+    def build_exe(self, src: Path, name: str) -> None:
+        toolchain = ClangToolchain(self.host)
+        cmd = [
+            str(toolchain.cc),
+            '-s',
+            '-o',
+            str(self.intermediate_out_dir / f'{name}.exe'),
+            str(src),
+        ] + toolchain.flags
+        subprocess.run(cmd, check=True)
+
+    def build(self) -> None:
+        if not self.host.is_windows:
+            print(f'Nothing to do for {self.host}')
+            return
+
+        self.intermediate_out_dir.mkdir(parents=True, exist_ok=True)
+
+        src_dir = NDK_DIR / 'sources/host-tools/toolbox'
+        self.build_exe(src_dir / 'echo_win.c', 'echo')
+        self.build_exe(src_dir / 'cmp_win.c', 'cmp')
+
+    def install(self) -> None:
+        if not self.host.is_windows:
+            print(f'Nothing to do for {self.host}')
+            return
+
         install_dir = self.get_install_path()
         install_dir.mkdir(parents=True, exist_ok=True)
 
-        packages = [
-            'ndk-python'
-        ]
-
-        if self.host.is_windows:
-            packages.append('toolbox')
-
-        package_names = [f'{p}-{self.host.tag}.tar.bz2' for p in packages]
-        for package_name in package_names:
-            package_path = self.out_dir / self.host.value / package_name
-            subprocess.check_call(
-                ['tar', 'xf', str(package_path), '-C', str(install_dir),
-                 '--strip-components=1'])
-
-        # Remove unused python scripts.
-        exclude_files = [
-            'python2.7-config', 'python-config.sh', 'pydoc', 'idle', '2to3',
-            'smtpd.py', 'python2-config', 'python-config'
-        ]
-        for file_to_remove in exclude_files:
-            (install_dir / 'bin' / file_to_remove).unlink()
-
+        shutil.copy2(self.intermediate_out_dir / 'echo.exe', install_dir)
+        shutil.copy2(self.intermediate_out_dir / 'cmp.exe', install_dir)
 
 def install_exe(out_dir: str, install_dir: str, name: str, host: Host) -> None:
     ext = '.exe' if host.is_windows else ''
@@ -740,7 +838,6 @@
     path = Path('sources/cxx-stl/llvm-libc++')
     notice = src / 'LICENSE.TXT'
     notice_group = ndk.builds.NoticeGroup.TOOLCHAIN
-    arch_specific = True
     deps = {
         'base-toolchain',
         'libandroid_support',
@@ -756,13 +853,6 @@
     def lib_out(self) -> str:
         return os.path.join(self.out_dir, 'libcxx/libs')
 
-    @property
-    def abis(self) -> List[ndk.abis.Abi]:
-        abis = []
-        for arch in self.arches:
-            abis.extend(ndk.abis.arch_to_abis(arch))
-        return abis
-
     def build(self) -> None:
         ndk_build = os.path.join(
             self.get_dep('ndk-build').get_build_host_install(), 'ndk-build')
@@ -773,7 +863,6 @@
 
         build_cmd = [
             'bash', ndk_build, build_support.jobs_arg(), 'V=1',
-            'APP_ABI=' + ' '.join(self.abis),
 
             # Since nothing in this build depends on libc++_static, we need to
             # name it to force it to build.
@@ -811,7 +900,7 @@
             os.path.join(install_root, 'include'))
         shutil.copytree(self.lib_out, os.path.join(install_root, 'libs'))
 
-        for abi in self.abis:
+        for abi in ndk.abis.ALL_ABIS:
             lib_dir = os.path.join(install_root, 'libs', abi)
 
             # The static libraries installed to the obj dir, not the lib dir.
@@ -1085,373 +1174,43 @@
 class Gdb(ndk.builds.Module):
     """Module for multi-arch host GDB.
 
-    Note that the device side, gdbserver, is a separate module because it needs
-    to be cross compiled for all four Android ABIs.
+    This is now a prebuilt. GDB is no longer supported. Next time it breaks
+    we'll be removing it.
     """
 
     name = 'gdb'
-    path = Path('prebuilt/{host}')
+    path = Path('prebuilt')
 
-    deps = {
-        'make',
-        'host-tools',
-    }
-
-    GDB_VERSION = '8.3'
-
-    expat_src = ndk.paths.ANDROID_DIR / 'toolchain/expat/expat-2.0.1'
-    lzma_src = ndk.paths.ANDROID_DIR / 'toolchain/xz'
-    gdb_src = ndk.paths.ANDROID_DIR / f'toolchain/gdb/gdb-{GDB_VERSION}'
-
+    PREBUILTS_BASE = ANDROID_DIR / 'prebuilts/ndk/gdb'
+    notice = ANDROID_DIR / 'prebuilts/ndk/gdb/NOTICE'
     notice_group = ndk.builds.NoticeGroup.TOOLCHAIN
 
-    _expat_builder: Optional[ndk.autoconf.AutoconfBuilder] = None
-    _lzma_builder: Optional[ndk.cmake.CMakeBuilder] = None
-    _gdb_builder: Optional[ndk.autoconf.AutoconfBuilder] = None
-
-    @property
-    def notices(self) -> Iterator[Path]:
-        yield self.expat_src / 'COPYING'
-        yield self.gdb_src / 'COPYING'
-        yield self.lzma_src / 'COPYING'
-
-    @property
-    def expat_builder(self) -> ndk.autoconf.AutoconfBuilder:
-        """Returns the lazily initialized expat builder for this module."""
-        if self._expat_builder is None:
-            self._expat_builder = ndk.autoconf.AutoconfBuilder(
-                self.expat_src / 'configure',
-                self.intermediate_out_dir / 'expat',
-                self.host,
-                use_clang=True)
-        return self._expat_builder
-
-    @property
-    def lzma_builder(self) -> ndk.cmake.CMakeBuilder:
-        """Returns the lazily initialized lzma builder for this module."""
-        if self._lzma_builder is None:
-            self._lzma_builder = ndk.cmake.CMakeBuilder(
-                self.lzma_src,
-                self.intermediate_out_dir / 'lzma',
-                self.host)
-        return self._lzma_builder
-
-    @property
-    def gdb_builder(self) -> ndk.autoconf.AutoconfBuilder:
-        """Returns the lazily initialized gdb builder for this module."""
-        if self._gdb_builder is None:
-            no_build_or_host = False
-            additional_flags = []
-            if self.host == Host.Darwin:
-                # Awful Darwin hack. For some reason GDB doesn't produce a gdb
-                # executable when using --build/--host.
-                no_build_or_host = True
-                additional_flags.append('-Wl,-rpath,@loader_path/../lib')
-            if self.host == Host.Linux:
-                additional_flags.append('-Wl,-rpath,$$$$\\ORIGIN/../lib')
-            # Add path for libc++.
-            clang_path = ClangToolchain.path_for_host(self.host)
-            additional_flags.append('-L' + str(clang_path / 'lib64'))
-            self._gdb_builder = ndk.autoconf.AutoconfBuilder(
-                self.gdb_src / 'configure',
-                self.intermediate_out_dir / 'gdb',
-                self.host,
-                use_clang=True,
-                no_build_or_host=no_build_or_host,
-                # Since we statically link libpython, python dynamic libraries may
-                # depend on symbols in gdb binary.
-                no_strip=True,
-                additional_flags=additional_flags)
-        return self._gdb_builder
-
-    @property
-    def gdb_stub_install_path(self) -> Path:
-        """The gdb stub install path."""
-        return self.gdb_builder.install_directory / 'bin/gdb-stub'
-
-    def build_expat(self) -> None:
-        """Builds the expat dependency."""
-        self.expat_builder.build([
-            '--disable-shared',
-            '--enable-static',
-        ])
-
-    def build_lzma(self) -> None:
-        """Builds the liblzma dependency."""
-        self.lzma_builder.build({
-            'BUILD_SHARED_LIBS': 'OFF',
-        })
-
-    def build_gdb(self) -> None:
-        """Builds GDB itself."""
-        targets = ' '.join(ndk.abis.ALL_TRIPLES)
-        # TODO: Cleanup Python module so we don't need this explicit path.
-        python_config = (Path(self.out_dir) / self.host.value / 'python' /
-                         self.host.tag /
-                         'install/host-tools/bin/python-config.sh')
-        configure_args = [
-            '--with-expat',
-            f'--with-libexpat-prefix={self.expat_builder.install_directory}',
-            f'--with-python={python_config}',
-            f'--enable-targets={targets}',
-            '--disable-shared',
-            '--disable-werror',
-            '--disable-nls',
-            '--disable-docs',
-            '--without-mpc',
-            '--without-mpfr',
-            '--without-gmp',
-            '--without-isl',
-            '--disable-sim',
-            '--enable-gdbserver=no',
-        ]
-
-        configure_args.extend([
-            '--with-lzma',
-            f'--with-liblzma-prefix={self.lzma_builder.install_directory}',
-        ])
-
-        self.gdb_builder.build(configure_args)
-
-    def build_gdb_stub(self) -> None:
-        """Builds a gdb wrapper to setup PYTHONHOME.
-
-        We need to use gdb with the Python it was built against, so we need to
-        setup PYTHONHOME to point to the NDK's Python, not the host's.
-        """
-        if self.host.is_windows:
-            # TODO: Does it really need to be an executable?
-            # It's probably an executable because the original author wanted a
-            # .exe rather than a .cmd. Not sure how disruptive this change
-            # would be now. Presumably hardly at all because everyone needs to
-            # use ndk-gdb for reasonable behavior anyway?
-            self.build_exe_gdb_stub()
-        else:
-            self.build_sh_gdb_stub()
-
-    def build_exe_gdb_stub(self) -> None:
-        # Don't need to worry about extension here because it'll be renamed on
-        # install anyway.
-        gdb_stub_path = self.gdb_builder.install_directory / 'bin/gdb-stub'
-        stub_src = ndk.paths.NDK_DIR / 'sources/host-tools/gdb-stub/gdb-stub.c'
-        mingw_path = (ndk.paths.ANDROID_DIR /
-                      'prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/bin'
-                      / 'x86_64-w64-mingw32-gcc')
-
-        cmd = [
-            str(mingw_path),
-            '-O2',
-            '-s',
-            '-DNDEBUG',
-            str(stub_src),
-            '-o',
-            str(gdb_stub_path),
-        ]
-        pp_cmd = ' '.join([pipes.quote(arg) for arg in cmd])
-        print('Running: {}'.format(pp_cmd))
-        subprocess.run(cmd, check=True)
-
-    def build_sh_gdb_stub(self) -> None:
-        self.gdb_stub_install_path.write_text(
-            textwrap.dedent("""\
-            #!/bin/bash
-            GDBDIR=$(cd $(dirname $0) && pwd)
-            PYTHONHOME="$GDBDIR/.." "$GDBDIR/gdb-orig" "$@"
-            """))
-        self.gdb_stub_install_path.chmod(0o755)
-
     def build(self) -> None:
-        """Builds GDB."""
-        if self.intermediate_out_dir.exists():
-            shutil.rmtree(self.intermediate_out_dir)
+        pass
 
-        self.build_expat()
-        self.build_lzma()
-        self.build_gdb()
-        self.build_gdb_stub()
+    @property
+    def install_dir(self) -> Path:
+        return Path(self.get_install_path())
+
+    def gdbserver_for(self, arch: ndk.abis.Arch) -> Path:
+        return self.PREBUILTS_BASE / f'android-{arch}'
+
+    def install_gdbserver(self, arch: ndk.abis.Arch) -> None:
+        gdbserver_dir = Path(f'android-{arch}/gdbserver')
+        install_dir = self.install_dir / gdbserver_dir
+        if install_dir.exists():
+            shutil.rmtree(install_dir)
+        shutil.copytree(self.PREBUILTS_BASE / gdbserver_dir, install_dir)
+
+    def install_gdb(self) -> None:
+        copy_tree(str(self.PREBUILTS_BASE / self.host.tag),
+                  str(self.install_dir / self.host.tag))
 
     def install(self) -> None:
         """Installs GDB."""
-        install_dir = Path(self.get_install_path())
-        copy_tree(
-            str(self.gdb_builder.install_directory / 'bin'),
-            str(install_dir / 'bin'))
-        gdb_share_dir = self.gdb_builder.install_directory / 'share/gdb'
-        gdb_share_install_dir = install_dir / 'share/gdb'
-        if gdb_share_install_dir.exists():
-            shutil.rmtree(gdb_share_install_dir)
-        shutil.copytree(gdb_share_dir, gdb_share_install_dir)
-
-        exe_suffix = '.exe' if self.host.is_windows else ''
-        gdb_exe = install_dir / ('bin/gdb' + exe_suffix)
-
-        # gdb is currently gdb(.exe)? and the gdb stub is currently gdb-stub.
-        # Make them gdb-orig(.exe)? and gdb(.exe)? respectively.
-        gdb_exe.rename(install_dir / ('bin/gdb-orig' + exe_suffix))
-
-        gdb_stub = install_dir / 'bin/gdb-stub'
-        gdb_stub.rename(install_dir / ('bin/gdb' + exe_suffix))
-
-        # Install libc++.
-        clang_path = ClangToolchain.path_for_host(self.host)
-        libcxx_files: Dict[Host, List[str]] = {
-            Host.Darwin: ['libc++abi.1.dylib', 'libc++.1.dylib'],
-            Host.Linux: ['libc++abi.so.1', 'libc++.so.1'],
-            Host.Windows64: [],
-        }
-        for f in libcxx_files[self.host]:
-            shutil.copy(clang_path / 'lib64' / f, install_dir / 'lib')
-
-
-class GdbServer(ndk.builds.Module):
-    name = 'gdbserver'
-    path = Path('prebuilt/android-{arch}/gdbserver')
-    notice = ANDROID_DIR / f'toolchain/gdb/gdb-{Gdb.GDB_VERSION}/gdb/COPYING'
-    notice_group = ndk.builds.NoticeGroup.TOOLCHAIN
-    arch_specific = True
-    split_build_by_arch = True
-    deps = {
-        'toolchain',
-    }
-    max_api = Platforms().get_apis()[-1]
-
-    libthread_db_src_dir = ndk.paths.ndk_path('sources/android/libthread_db')
-    gdbserver_src_dir = ndk.paths.android_path(
-        f'toolchain/gdb/gdb-{Gdb.GDB_VERSION}/gdb/gdbserver')
-
-    @property
-    def build_dir(self) -> Path:
-        """Returns the build directory for the current architecture."""
-        assert self.build_arch is not None
-        return self.out_dir / self.name / self.build_arch
-
-    @property
-    def libthread_db_a_path(self) -> str:
-        """Returns the path to the built libthread_db.a."""
-        return os.path.join(self.build_dir, 'libthread_db.a')
-
-    def get_tool(self, name: str) -> Path:
-        """Returns the path to the given tool in the toolchain.
-
-        Args:
-            name: Name of the tool. e.g. 'ar'.
-
-        Returns:
-            Path to the specified tool.
-        """
-        toolchain = Path(self.get_dep('toolchain').get_build_host_install())
-        return toolchain / 'bin' / name
-
-    def build_libthread_db(self, api_level: int) -> None:
-        """Builds libthread_db.a for the current architecture."""
-        assert self.build_arch is not None
-
-        libthread_db_c = os.path.join(self.libthread_db_src_dir,
-                                      'libthread_db.c')
-        libthread_db_o = os.path.join(self.build_dir, 'libthread_db.o')
-        cc_args = [
-            str(self.get_tool('clang')),
-            '-target',
-            ndk.abis.clang_target(self.build_arch, api_level),
-            '-I',
-            self.libthread_db_src_dir,
-            '-o',
-            libthread_db_o,
-            '-c',
-            libthread_db_c,
-        ]
-
-        print('Running: {}'.format(' '.join(
-            [pipes.quote(arg) for arg in cc_args])))
-        subprocess.run(cc_args, check=True)
-
-        ar_args = [
-            str(self.get_tool('llvm-ar')),
-            'rD',
-            self.libthread_db_a_path,
-            libthread_db_o,
-        ]
-
-        print('Running: {}'.format(' '.join(
-            [pipes.quote(arg) for arg in ar_args])))
-        subprocess.run(ar_args, check=True)
-
-    def configure(self, api_level: int) -> None:
-        """Configures the gdbserver build for the current architecture."""
-        assert self.build_arch is not None
-        gdbserver_host = {
-            'arm': 'arm-eabi-linux',
-            'arm64': 'aarch64-eabi-linux',
-            'x86': 'i686-linux-android',
-            'x86_64': 'x86_64-linux-android',
-        }[self.build_arch]
-
-        cflags = ['-O2', '-I' + self.libthread_db_src_dir]
-        if self.build_arch.startswith('arm'):
-            cflags.append('-fno-short-enums')
-        if self.build_arch.endswith('64'):
-            cflags.append('-DUAPI_HEADERS')
-
-        ldflags = '-static -Wl,-z,nocopyreloc -Wl,--no-undefined'
-
-        # Use --target as part of CC so it is used when linking as well.
-        target = ndk.abis.clang_target(self.build_arch, api_level)
-        clang = f'{self.get_tool("clang")} --target={target}'
-        clangplusplus = f'{self.get_tool("clang++")} --target={target}'
-        configure_env = {
-            'CC': clang,
-            'CXX': clangplusplus,
-            'AR': str(self.get_tool('llvm-ar')),
-            'RANLIB': str(self.get_tool('llvm-ranlib')),
-            'CFLAGS': ' '.join(cflags),
-            'CXXFLAGS': ' '.join(cflags),
-            'LDFLAGS': ldflags,
-        }
-
-        configure_args = [
-            os.path.join(self.gdbserver_src_dir, 'configure'),
-            '--build=x86_64-linux-gnu',
-            f'--host={gdbserver_host}',
-            f'--with-libthread-db={self.libthread_db_a_path}',
-            '--disable-inprocess-agent',
-            '--enable-werror=no',
-        ]
-
-        subproc_env = dict(os.environ)
-        subproc_env.update(configure_env)
-        print('Running: {} with env:\n{}'.format(
-            ' '.join([pipes.quote(arg) for arg in configure_args]),
-            pprint.pformat(configure_env, indent=4)))
-        subprocess.run(configure_args, env=subproc_env, check=True)
-
-    def make(self) -> None:
-        """Runs make for the configured build."""
-        subprocess.run(['make', build_support.jobs_arg()], check=True)
-
-    def build(self) -> None:
-        """Builds gdbserver."""
-        if not os.path.exists(self.build_dir):
-            os.makedirs(self.build_dir)
-
-        max_api = Platforms().get_apis()[-1]
-        with ndk.ext.os.cd(str(self.build_dir)):
-            self.build_libthread_db(max_api)
-            self.configure(max_api)
-            self.make()
-
-    def install(self) -> None:
-        """Installs gdbserver."""
-        if os.path.exists(self.get_install_path()):
-            shutil.rmtree(self.get_install_path())
-        os.makedirs(self.get_install_path())
-
-        objcopy_args = [
-            str(self.get_tool('llvm-objcopy')),
-            '--strip-unneeded',
-            os.path.join(self.build_dir, 'gdbserver'),
-            os.path.join(self.get_install_path(), 'gdbserver'),
-        ]
-        subprocess.run(objcopy_args, check=True)
+        self.install_gdb()
+        for arch in ndk.abis.ALL_ARCHITECTURES:
+            self.install_gdbserver(arch)
 
 
 class LibShaderc(ndk.builds.Module):
@@ -1598,22 +1357,8 @@
 
     def install(self) -> None:
         super().install()
-
-        # GTest renamed these files to be all lower case, but the SDK patcher
-        # doesn't handle that properly. Rename them back to the old names so
-        # the SDK patches apply properly.
-        # http://b/122741472
-        install_dir = self.get_install_path()
-        docs_dir = os.path.join(install_dir, 'docs')
-        rename_map = {
-            'faq.md': 'FAQ.md',
-            'primer.md': 'Primer.md',
-            'samples.md': 'Samples.md',
-        }
-        for rename_from, rename_to in rename_map.items():
-            os.rename(
-                os.path.join(docs_dir, rename_from),
-                os.path.join(docs_dir, rename_to))
+        # Docs are moved to top level directory.
+        shutil.rmtree(self.get_install_path() / 'docs')
 
 
 class Sysroot(ndk.builds.Module):
@@ -1821,10 +1566,9 @@
         yield from Sysroot().notices
         yield from SystemStl().notices
         yield ANDROID_DIR / 'toolchain/binutils/binutils-2.27/gas/COPYING'
-        for host in Host:
-            for arch in ndk.abis.ALL_ARCHITECTURES:
-                # For libgcc/libatomic.
-                yield get_gcc_prebuilt_path(host, arch) / 'NOTICE'
+        for arch in ndk.abis.ALL_ARCHITECTURES:
+            # For libgcc/libatomic.
+            yield get_gcc_prebuilt_path(arch) / 'NOTICE'
 
     def build(self) -> None:
         pass
@@ -1852,7 +1596,7 @@
         shutil.copyfile(lld, new_bin_ld)
         shutil.copystat(lld, new_bin_ld)
 
-        for arch in self.arches:
+        for arch in ndk.abis.ALL_ARCHITECTURES:
             binutils_dir = get_binutils_prebuilt_path(self.host, arch)
             triple = ndk.abis.arch_to_triple(arch)
 
@@ -1862,13 +1606,12 @@
             # We still need libgcc/libatomic. Copy them from the old GCC
             # prebuilts.
             for subarch in get_subarches(arch):
-                install_libgcc(Path(install_dir), self.host, arch, subarch)
-                install_libatomic(Path(install_dir), self.host, arch, subarch)
+                install_libgcc(Path(install_dir), arch, subarch)
+                install_libatomic(Path(install_dir), arch, subarch)
 
                 # We don't actually want this, but Clang won't recognize a
                 # -gcc-toolchain without it.
-                install_gcc_crtbegin(Path(install_dir), self.host, arch,
-                                     subarch)
+                install_gcc_crtbegin(Path(install_dir), arch, subarch)
 
         platforms = self.get_dep('platforms')
         assert isinstance(platforms, Platforms)
@@ -1990,7 +1733,7 @@
         libcxxabi_inc_src = os.path.join(libcxxabi_dir, 'include')
         copy_tree(libcxxabi_inc_src, libcxx_inc_dst)
 
-        for arch in self.arches:
+        for arch in ndk.abis.ALL_ARCHITECTURES:
             # We need to replace libgcc with linker scripts that also use
             # libunwind on arm32.
             #
@@ -1998,7 +1741,6 @@
             # libunwind isn't available until libc++ has been built.
             for subarch in get_subarches(arch):
                 install_libgcc(Path(install_dir),
-                               self.host,
                                arch,
                                subarch,
                                new_layout=True)
@@ -2561,17 +2303,6 @@
     module.install()
 
 
-def split_module_by_arch(module: ndk.builds.Module, arches: List[ndk.abis.Arch]
-                         ) -> Iterator[ndk.builds.Module]:
-    if module.split_build_by_arch:
-        for arch in arches:
-            build_module = copy.deepcopy(module)
-            build_module.build_arch = arch
-            yield build_module
-    else:
-        yield module
-
-
 def _get_transitive_module_deps(
         module: ndk.builds.Module, deps: Set[ndk.builds.Module],
         unknown_deps: Set[str], seen: Set[ndk.builds.Module]) -> None:
@@ -2603,7 +2334,7 @@
 
 
 def get_modules_to_build(
-        module_names: Iterable[str], arches: List[ndk.abis.Arch]
+        module_names: Iterable[str]
 ) -> Tuple[List[ndk.builds.Module], Set[ndk.builds.Module]]:
     """Returns a list of modules to be built given a list of module names.
 
@@ -2644,8 +2375,7 @@
 
     build_modules = []
     for module in modules:
-        for build_module in split_module_by_arch(module, arches):
-            build_modules.append(build_module)
+        build_modules.append(module)
 
     return sorted(list(build_modules), key=str), deps_only
 
@@ -2658,9 +2388,7 @@
     Clang(),
     CpuFeatures(),
     Gdb(),
-    GdbServer(),
     Gtest(),
-    HostTools(),
     LibAndroidSupport(),
     LibShaderc(),
     Libcxx(),
@@ -2681,6 +2409,7 @@
     NdkWhich(),
     NdkWhichShortcut(),
     Platforms(),
+    Python(),
     PythonPackages(),
     Readme(),
     RenderscriptLibs(),
@@ -2690,6 +2419,7 @@
     SourceProperties(),
     Sysroot(),
     SystemStl(),
+    Toolbox(),
     Toolchain(),
     Vulkan(),
     WrapSh(),
@@ -2716,10 +2446,6 @@
         description=inspect.getdoc(sys.modules[__name__]))
 
     parser.add_argument(
-        '--arch',
-        choices=('arm', 'arm64', 'x86', 'x86_64'),
-        help='Build for the given architecture. Build all by default.')
-    parser.add_argument(
         '-j', '--jobs', type=int, default=multiprocessing.cpu_count(),
         help=('Number of parallel builds to run. Note that this will not '
               'affect the -j used for make; this just parallelizes '
@@ -2838,12 +2564,8 @@
 def build_ndk(modules: List[ndk.builds.Module],
               deps_only: Set[ndk.builds.Module], out_dir: Path, dist_dir: Path,
               args: argparse.Namespace) -> Path:
-    arches = list(ndk.abis.ALL_ARCHITECTURES)
-    if args.arch is not None:
-        arches = [args.arch]
-
     build_context = ndk.builds.BuildContext(
-        out_dir, dist_dir, ALL_MODULES, args.system, arches, args.build_number)
+        out_dir, dist_dir, ALL_MODULES, args.system, args.build_number)
 
     for module in modules:
         module.context = build_context
@@ -2876,14 +2598,14 @@
         workqueue.join()
 
 
-def build_ndk_for_cross_compile(out_dir: Path, arches: List[ndk.abis.Arch],
+def build_ndk_for_cross_compile(out_dir: Path,
                                 args: argparse.Namespace) -> None:
     args = copy.deepcopy(args)
     args.system = Host.current()
     if args.system != Host.Linux:
         raise NotImplementedError
     module_names = NAMES_TO_MODULES.keys()
-    modules, deps_only = get_modules_to_build(module_names, arches)
+    modules, deps_only = get_modules_to_build(module_names)
     print('Building Linux modules: {}'.format(' '.join(
         [str(m) for m in modules])))
     build_ndk(modules, deps_only, out_dir, out_dir, args)
@@ -2940,10 +2662,6 @@
 
     os.environ['ANDROID_BUILD_TOP'] = ndk.paths.android_path()
 
-    arches = list(ndk.abis.ALL_ARCHITECTURES)
-    if args.arch is not None:
-        arches = [args.arch]
-
     out_dir = ndk.paths.get_out_dir()
     dist_dir = ndk.paths.get_dist_dir(out_dir)
 
@@ -2952,9 +2670,9 @@
     if args.system.is_windows and not args.skip_deps:
         # Since the Windows NDK is cross compiled, we need to build a Linux NDK
         # first so we can build components like libc++.
-        build_ndk_for_cross_compile(Path(out_dir), arches, args)
+        build_ndk_for_cross_compile(Path(out_dir), args)
 
-    modules, deps_only = get_modules_to_build(module_names, arches)
+    modules, deps_only = get_modules_to_build(module_names)
     print('Building modules: {}'.format(' '.join(
         [str(m) for m in modules
          if not args.skip_deps or m not in deps_only])))
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()
diff --git a/ndk/packaging.py b/ndk/packaging.py
index 8ff653d..94642ba 100644
--- a/ndk/packaging.py
+++ b/ndk/packaging.py
@@ -36,48 +36,17 @@
 )
 
 
-def expand_paths(package: str, host: Host,
-                 arches: Optional[Iterable[ndk.abis.Arch]]) -> List[str]:
-    """Expands package definition tuple into list of full package names.
+def expand_path(package: str, host: Host) -> str:
+    """Expands package definition tuple into a package name.
 
-    >>> expand_paths('gcc-{toolchain}-{host}', Host.Linux, ['arm', 'x86_64'])
-    ['gcc-arm-linux-androideabi-linux-x86_64', 'gcc-x86_64-linux-x86_64']
+    >>> expand_path('llvm-{host}', Host.Linux)
+    'llvm-linux-x86_64'
 
-    >>> expand_paths('gdbserver-{arch}', Host.Linux, ['arm64', 'x86_64'])
-    ['gdbserver-arm64', 'gdbserver-x86_64']
-
-    >>> expand_paths('llvm-{host}', Host.Linux, None)
-    ['llvm-linux-x86_64']
-
-    >>> expand_paths('platforms', Host.Linux, ['arm'])
-    ['platforms']
-
-    >>> expand_paths('libc++-{abi}', Host.Linux, ['arm'])
-    ['libc++-armeabi-v7a']
-
-    >>> expand_paths('binutils/{triple}', Host.Linux, ['arm', 'x86_64'])
-    ['binutils/arm-linux-androideabi', 'binutils/x86_64-linux-android']
-
-    >> expand_paths('toolchains/{toolchain}-4.9', Host.Linux, ['arm', 'x86'])
-    ['toolchains/arm-linux-androideabi-4.9', 'toolchains/x86-4.9']
+    >>> expand_path('platforms', Host.Linux)
+    'platforms'
     """
     host_tag = host_to_tag(host)
-    if arches is None:
-        return [package.format(host=host_tag)]
-
-    seen_packages: Set[str] = set()
-    packages = []
-    for arch in arches:
-        triple = ndk.abis.arch_to_triple(arch)
-        toolchain = ndk.abis.arch_to_toolchain(arch)
-        for abi in ndk.abis.arch_to_abis(arch):
-            expanded = package.format(
-                abi=abi, arch=arch, host=host_tag, triple=triple,
-                toolchain=toolchain)
-            if expanded not in seen_packages:
-                packages.append(expanded)
-            seen_packages.add(expanded)
-    return packages
+    return package.format(host=host_tag)
 
 
 def package_varies_by(install_path: str, variant: str) -> bool:
@@ -100,17 +69,17 @@
     return variant_replacement_str in install_path
 
 
-def expand_packages(package: str, install_path: str, host: Host,
-                    arches: List[ndk.abis.Arch]) -> Iterable[Tuple[str, str]]:
-    """Returns a list of tuples of `(package, install_path)`."""
+def expand_package(package: str, install_path: str,
+                   host: Host) -> Tuple[str, str]:
+    """Returns a tuple of `(package, install_path)`."""
     package_template = package
     for variant in PACKAGE_VARIANTS:
         if package_varies_by(install_path, variant):
             package_template += '-{' + variant + '}'
 
-    expanded_packages = expand_paths(package_template, host, arches)
-    expanded_installs = expand_paths(install_path, host, arches)
-    return zip(expanded_packages, expanded_installs)
+    expanded_packages = expand_path(package_template, host)
+    expanded_installs = expand_path(install_path, host)
+    return expanded_packages, expanded_installs
 
 
 def extract_zip(package_path: str, install_path: str) -> None:
diff --git a/ndk/toolchains.py b/ndk/toolchains.py
index d73f64f..aa7a9b6 100644
--- a/ndk/toolchains.py
+++ b/ndk/toolchains.py
@@ -22,7 +22,7 @@
 import ndk.paths
 
 
-CLANG_VERSION = 'clang-r399163b'
+CLANG_VERSION = 'clang-r412851'
 
 
 HOST_TRIPLE_MAP = {
diff --git a/sources/android/libthread_db/README b/sources/android/libthread_db/README
deleted file mode 100644
index aadd763..0000000
--- a/sources/android/libthread_db/README
+++ /dev/null
@@ -1,10 +0,0 @@
-Here are the sources of the special libthread_db that will be statically
-linked against our gdbserver binary. These are uses automatically by the
-build-gdbserver.sh script.
-
-THIS IS NOT AN IMPORT MODULE.
-
-Applications don't need to link to libthread_db anyway, this library is
-a small interface used by gdbserver to manage the list of threads on the
-target process. Its API and ABI are not stable and may change in the
-future.
diff --git a/sources/android/libthread_db/libthread_db.c b/sources/android/libthread_db/libthread_db.c
deleted file mode 100644
index 16b4e6b..0000000
--- a/sources/android/libthread_db/libthread_db.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#include <dirent.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <thread_db.h>
-#include <unistd.h>
-
-extern pid_t ps_getpid(struct ps_prochandle*);
-
-// We don't have any symbols to cache.
-char const** td_symbol_list(void) {
-    static char const* symbols[] = { NULL };
-    return symbols;
-}
-
-//
-// Thread agents.
-//
-
-td_err_e td_ta_new(struct ps_prochandle* proc_handle, td_thragent_t** agent_out) {
-    td_thragent_t* agent = (td_thragent_t*) calloc(1, sizeof(td_thragent_t));
-    if (!agent) {
-        return TD_MALLOC;
-    }
-
-    agent->pid = ps_getpid(proc_handle);
-    agent->ph = proc_handle;
-    *agent_out = agent;
-
-    return TD_OK;
-}
-
-
-td_err_e td_ta_delete(td_thragent_t* ta) {
-    free(ta);
-    return TD_OK;
-}
-
-td_err_e td_ta_map_lwp2thr(td_thragent_t const* agent, lwpid_t lwpid, td_thrhandle_t* th) {
-    th->pid = ps_getpid(agent->ph);
-    th->tid = lwpid;
-    return TD_OK;
-}
-
-td_err_e td_ta_thr_iter(td_thragent_t const* agent,
-                        td_thr_iter_f* func,
-                        void* cookie,
-                        td_thr_state_e state,
-                        int32_t prio,
-                        sigset_t* sigmask,
-                        uint32_t user_flags) {
-    td_err_e err = TD_OK;
-    char path[32];
-    DIR * dir;
-    struct dirent * entry;
-    td_thrhandle_t handle;
-
-    snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid);
-    dir = opendir(path);
-    if (!dir) {
-        return TD_NOEVENT;
-    }
-
-    handle.pid = agent->pid;
-    while ((entry = readdir(dir)) != NULL) {
-        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
-            continue;
-        }
-        handle.tid = atoi(entry->d_name);
-        if (func(&handle, cookie) != 0) {
-	    err = TD_DBERR;
-            break;
-        }
-    }
-
-    closedir(dir);
-
-    return err;
-}
-
-//
-// Threads.
-//
-
-td_err_e td_thr_get_info(td_thrhandle_t const* handle, td_thrinfo_t* info) {
-    info->ti_tid = handle->tid;
-    info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids
-    info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>.
-                                      This is only used to see if the thread is a zombie or not */
-    return TD_OK;
-}
-
-//
-// TLS.
-//
-
-td_err_e td_thr_tlsbase(const td_thrhandle_t* unused1, unsigned long int unused2, psaddr_t* unused3) {
-  return TD_NOAPLIC; // TODO: fix this if/when we support ELF TLS.
-}
-
-td_err_e td_thr_tls_get_addr(const td_thrhandle_t* unused1, psaddr_t unused2, size_t unused3, psaddr_t* unused4) {
-  return TD_NOAPLIC; // TODO: fix this if/when we support ELF TLS.
-}
-
-//
-// Thread events.
-//
-
-// Thread events are no longer used by gdb >= 7.0.
-// Because we link gdbserver statically, though, we need definitions.
-td_err_e td_ta_set_event(td_thragent_t const* agent, td_thr_events_t* events) {
-    abort();
-}
-td_err_e td_ta_event_getmsg(td_thragent_t const* agent, td_event_msg_t* event) {
-    abort();
-}
-td_err_e td_thr_event_enable(const td_thrhandle_t* handle, int event) {
-    abort();
-}
-td_err_e td_ta_clear_event(const td_thragent_t* ta_arg, td_thr_events_t* event) {
-    abort();
-}
-td_err_e td_ta_event_addr(td_thragent_t const* agent, td_event_e event, td_notify_t* notify_out) {
-    abort();
-}
diff --git a/sources/android/libthread_db/thread_db.h b/sources/android/libthread_db/thread_db.h
deleted file mode 100644
index be57393..0000000
--- a/sources/android/libthread_db/thread_db.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#pragma once
-
-#include <pthread.h>
-#include <signal.h>
-#include <stdint.h>
-#include <sys/procfs.h>
-#include <sys/types.h>
-
-#define TD_THR_ANY_USER_FLAGS       0xffffffff
-#define TD_THR_LOWEST_PRIORITY      -20
-#define TD_SIGNO_MASK               NULL
-
-/* td_err_e values */
-enum {
-    TD_OK,
-    TD_ERR,
-    TD_NOTHR,
-    TD_NOSV,
-    TD_NOLWP,
-    TD_BADPH,
-    TD_BADTH,
-    TD_BADSH,
-    TD_BADTA,
-    TD_BADKEY,
-    TD_NOMSG,
-    TD_NOFPREGS,
-    TD_NOLIBTHREAD,
-    TD_NOEVENT,
-    TD_NOCAPAB,
-    TD_DBERR,
-    TD_NOAPLIC,
-    TD_NOTSD,
-    TD_MALLOC,
-    TD_PARTIALREG,
-    TD_NOXREGS,
-    TD_VERSION
-};
-
-/*
- * td_event_e values
- * NOTE: There is a max of 32 events
- */
-enum {
-    TD_CREATE,
-    TD_DEATH
-};
-
-/* td_thr_state_e values */
-enum {
-    TD_THR_ANY_STATE,
-    TD_THR_UNKNOWN,
-    TD_THR_SLEEP,
-    TD_THR_ZOMBIE
-};
-
-typedef int32_t td_err_e;
-typedef uint32_t td_event_e;
-typedef uint32_t td_notify_e;
-typedef uint32_t td_thr_state_e;
-typedef pthread_t thread_t;
-
-typedef struct
-{
-    pid_t pid;
-    struct ps_prochandle *ph;
-} td_thragent_t;
-
-typedef struct
-{
-    pid_t pid;
-    pid_t tid;
-    psaddr_t th_unique;
-} td_thrhandle_t;
-
-typedef struct
-{
-    td_event_e event;
-    td_thrhandle_t const * th_p;
-    union {
-        void * data;
-    } msg;
-} td_event_msg_t;
-
-typedef struct
-{
-    uint32_t events;
-} td_thr_events_t;
-
-typedef struct
-{
-    union {
-        void * bptaddr;
-    } u;
-} td_notify_t;
-
-typedef struct
-{
-    td_thr_state_e ti_state;
-    thread_t ti_tid; // pthread's id for the thread
-    int32_t ti_lid; // the kernel's id for the thread
-} td_thrinfo_t;
-
-
-#define td_event_emptyset(set) \
-    (set)->events = 0
-
-#define td_event_fillset(set) \
-    (set)->events = 0xffffffff
-
-#define td_event_addset(set, n) \
-    (set)->events |= (1 << n)
-
-
-typedef int td_thr_iter_f(td_thrhandle_t const *, void *);
-
-
-struct ps_prochandle;
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-extern td_err_e td_ta_new(struct ps_prochandle * proc_handle, td_thragent_t ** thread_agent);
-
-extern td_err_e td_ta_delete(td_thragent_t * ta);
-
-extern td_err_e td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * event);
-
-extern td_err_e td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify);
-
-extern td_err_e td_ta_clear_event(const td_thragent_t * ta_arg,
-				  td_thr_events_t * event);
-
-extern td_err_e td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event);
-
-extern td_err_e td_ta_map_lwp2thr(td_thragent_t const * agent, lwpid_t lwpid,
-				  td_thrhandle_t *th);
-
-extern td_err_e td_thr_get_info(td_thrhandle_t const * handle,
-				td_thrinfo_t * info);
-
-extern td_err_e td_thr_event_enable(const td_thrhandle_t * handle,
-				    int event);
-
-extern td_err_e td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
-                               td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags);
-
-extern char const ** td_symbol_list(void);
-
-extern td_err_e td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info);
-
-extern td_err_e td_thr_tlsbase(const td_thrhandle_t*, unsigned long int, psaddr_t*);
-
-extern td_err_e td_thr_tls_get_addr(const td_thrhandle_t*, psaddr_t, size_t, psaddr_t*);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/sources/host-tools/gdb-stub/gdb-stub.c b/sources/host-tools/gdb-stub/gdb-stub.c
deleted file mode 100644
index 488022d..0000000
--- a/sources/host-tools/gdb-stub/gdb-stub.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/***************************************************************************
-** The BSD 3-Clause License. http://www.opensource.org/licenses/BSD-3-Clause
-**
-** This file is part of 'mingw-builds' project.
-** Copyright (c) 2011,2012,2013 by niXman (i dotty nixman doggy gmail dotty com)
-** All rights reserved.
-**
-** Project: mingw-builds ( http://sourceforge.net/projects/mingwbuilds/ )
-**
-** Redistribution and use in source and binary forms, with or without 
-** modification, are permitted provided that the following conditions are met:
-** - Redistributions of source code must retain the above copyright 
-**     notice, this list of conditions and the following disclaimer.
-** - Redistributions in binary form must reproduce the above copyright 
-**     notice, this list of conditions and the following disclaimer in 
-**     the documentation and/or other materials provided with the distribution.
-** - Neither the name of the 'mingw-builds' nor the names of its contributors may 
-**     be used to endorse or promote products derived from this software 
-**     without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
-** A PARTICULAR PURPOSE ARE DISCLAIMED.
-** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 
-** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
-** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
-** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
-** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
-** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**
-***************************************************************************/
-
-#include <windows.h>
-
-#include <stdio.h>
-#include <strings.h>
-
-#ifdef _DEBUG
- #define dbg_printf(...) printf(__VA_ARGS__)
-#else
- #define dbg_printf(...) do {} while(0)
-#endif
-
-#define GDB_TO_PYTHON_REL_DIR "."
-
-#define GDB_EXECUTABLE_ORIG_FILENAME "gdb-orig.exe"
-
-// The stub is installed to $PREBUILTS/bin, PYTHONHOME is $PREBUILTS.
-#define PYTHONHOME_REL_DIR ".."
-
-#define DIE_IF_FALSE(var) \
-	do { \
-		if ( !(var) ) { \
-			fprintf(stderr, "%s(%d)[%d]: expression \"%s\" fail. terminate.\n" \
-				,__FILE__ \
-				,__LINE__ \
-				,GetLastError() \
-				,#var \
-			); \
-			exit(1); \
-		} \
-	} while (0)
-
-int main(int argc, char** argv) {
-	enum {
-		 envbufsize = 1024*32
-		,exebufsize = 1024
-		,cmdbufsize = envbufsize
-	};
-
-	char *envbuf, *sep, *resbuf, *cmdbuf;
-	DWORD len, exitCode;
-	STARTUPINFO si;
-	PROCESS_INFORMATION pi;
-
-	DIE_IF_FALSE(
-		(envbuf = (char *)malloc(envbufsize))
-	);
-	DIE_IF_FALSE(
-		(cmdbuf = (char *)malloc(cmdbufsize))
-	);
-	*cmdbuf = 0;
-
-	DIE_IF_FALSE(
-		GetEnvironmentVariable("PATH", envbuf, envbufsize)
-	);
-	dbg_printf("env: %s\n", envbuf);
-
-	DIE_IF_FALSE(
-		GetModuleFileName(0, cmdbuf, exebufsize)
-	);
-	dbg_printf("curdir: %s\n", cmdbuf);
-
-	DIE_IF_FALSE(
-		(sep = strrchr(cmdbuf, '\\'))
-	);
-	*(sep+1) = 0;
-	strcat(cmdbuf, GDB_TO_PYTHON_REL_DIR);
-	dbg_printf("sep: %s\n", cmdbuf);
-
-	len = strlen(envbuf)+strlen(cmdbuf)
-		+1  /* for envronment separator */
-		+1; /* for zero-terminator */
-
-	DIE_IF_FALSE(
-		(resbuf = (char *)malloc(len))
-	);
-
-	DIE_IF_FALSE(
-		(snprintf(resbuf, len, "%s;%s", cmdbuf, envbuf) > 0)
-	);
-	dbg_printf("PATH: %s\n", resbuf);
-
-	DIE_IF_FALSE(
-		SetEnvironmentVariable("PATH", resbuf)
-	);
-
-	*(sep+1) = 0;
-	strcat(cmdbuf, PYTHONHOME_REL_DIR);
-	dbg_printf("PYTHONHOME: %s\n", cmdbuf);
-	DIE_IF_FALSE(
-		SetEnvironmentVariable("PYTHONHOME", cmdbuf)
-	);
-
-	*(sep+1) = 0;
-	strcat(cmdbuf, GDB_EXECUTABLE_ORIG_FILENAME" ");
-
-	if ( argc > 1 ) {
-		for ( ++argv; *argv; ++argv ) {
-			len = strlen(cmdbuf);
-			snprintf(cmdbuf+len, cmdbufsize-len, "%s ", *argv);
-		}
-	}
-	dbg_printf("cmd: %s\n", cmdbuf);
-
-	HANDLE ghJob = CreateJobObject(NULL, "Gdb-Wrapper\0"/*NULL*/);
-	if ( ghJob == NULL ) {
-        fprintf(stderr, "Could not create job object\n");
-	}
-	else{
-		JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
-		// Configure all child processes associated with the job to terminate when the last handle to the job is closed
-		jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
-		if ( SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == 0 ) {
-            fprintf(stderr, "Could not SetInformationJobObject\n");
-		}
-	}
-
-	memset(&si, 0, sizeof(si));
-	si.cb = sizeof(si);
-	si.dwFlags |= STARTF_USESTDHANDLES;
-	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
-	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
-
-	memset(&pi, 0, sizeof(pi));
-	// If current process is being monitored by the Program Compatibility Assistant (PCA), it is placed into a
-	// compatibility job. Therefore, the child process must be created using CREATE_BREAKAWAY_FROM_JOB before it can be
-	// placed in another job.
-	DWORD creationFlags = CREATE_BREAKAWAY_FROM_JOB;
-	DIE_IF_FALSE(
-		CreateProcess(
-			0					// exe name
-			,cmdbuf				// command line
-			,0					// process security attributes
-			,0					// primary thread security attributes
-			,TRUE				// handles are inherited
-			,creationFlags		// creation flags
-			,0					// use parent's environment
-			,0					// use parent's current directory
-			,&si				// STARTUPINFO pointer
-			,&pi				// receives PROCESS_INFORMATION
-		)
-	);
-
-	if ( ghJob != NULL )
-		if ( AssignProcessToJobObject(ghJob, pi.hProcess) == 0 ) {
-            fprintf(stderr, "Could not AssignProcessToObject\n");
-		}
-
-	// Do not handle Ctrl-C in the wrapper
-	SetConsoleCtrlHandler(NULL, TRUE);
-
-	WaitForSingleObject(pi.hProcess, INFINITE);
-
-	DIE_IF_FALSE(
-		GetExitCodeProcess(pi.hProcess, &exitCode)
-	);
-
-	if ( ghJob != NULL )
-		CloseHandle(ghJob);
-	CloseHandle( pi.hProcess );
-	CloseHandle( pi.hThread );
-
-	free(envbuf);
-	free(resbuf);
-	free(cmdbuf);
-
-	dbg_printf("exiting with exitCode %d", exitCode);
-
-	return exitCode;
-}
diff --git a/sources/host-tools/toolbox/build-toolbox.sh b/sources/host-tools/toolbox/build-toolbox.sh
deleted file mode 100755
index d77e1e7..0000000
--- a/sources/host-tools/toolbox/build-toolbox.sh
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/bin/sh
-#
-# Copyright (C) 2011 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.
-#
-#  This shell script is used to rebuild the toolbox programs which sources
-#  are under $NDK/sources/host-tools/toolbox
-#
-
-# include common function and variable definitions
-. $NDK_BUILDTOOLS_PATH/prebuilt-common.sh
-. $NDK_BUILDTOOLS_PATH/builder-funcs.sh
-
-PROGRAM_PARAMETERS=""
-
-PROGRAM_DESCRIPTION=\
-"Rebuild the prebuilt host toolbox binaries for the Android NDK.
-
-These are simple command-line programs used by the NDK build script.
-
-By default, this will try to place the binaries inside the current NDK
-directory, unless you use the --ndk-dir=<path> option.
-"
-
-PACKAGE_DIR=
-register_var_option "--package-dir=<path>" PACKAGE_DIR "Put prebuilt tarballs into <path>."
-
-NDK_DIR=
-register_var_option "--ndk-dir=<path>" NDK_DIR "Specify NDK root path for the build."
-
-BUILD_DIR=
-register_var_option "--build-dir=<path>" BUILD_DIR "Specify temporary build dir."
-
-NO_MAKEFILE=
-register_var_option "--no-makefile" NO_MAKEFILE "Do not use makefile to speed-up build"
-
-PACKAGE_DIR=
-register_var_option "--package-dir=<path>" PACKAGE_DIR "Archive binaries into package directory"
-
-register_jobs_option
-register_try64_option
-
-extract_parameters "$@"
-
-# Handle NDK_DIR
-if [ -z "$NDK_DIR" ] ; then
-    NDK_DIR=$ANDROID_NDK_ROOT
-    log "Auto-config: --ndk-dir=$NDK_DIR"
-else
-    if [ ! -d "$NDK_DIR" ] ; then
-        echo "ERROR: NDK directory does not exists: $NDK_DIR"
-        exit 1
-    fi
-fi
-
-rm -rf $BUILD_DIR/* && mkdir -p $BUILD_DIR
-fail_panic "Could not create build directory: $BUILD_DIR"
-
-if [ -z "$NO_MAKEFILE" ]; then
-    MAKEFILE=$BUILD_DIR/Makefile
-else
-    MAKEFILE=
-fi
-
-TOOLBOX_SRCDIR=$ANDROID_NDK_ROOT/sources/host-tools/toolbox
-
-BUILD_WINDOWS_SOURCES=yes
-
-if [ "$BUILD_WINDOWS_SOURCES" ]; then
-    ORIGINAL_HOST_TAG=$HOST_TAG
-    MINGW=yes
-    handle_canadian_build
-    prepare_canadian_toolchain $BUILD_DIR
-
-    SUBDIR=$(get_prebuilt_install_prefix $HOST_TAG)/bin
-    DSTDIR=$NDK_DIR/$SUBDIR
-    mkdir -p "$DSTDIR"
-    fail_panic "Could not create destination directory: $DSTDIR"
-
-    # Build echo.exe
-    HOST_TAG=$ORIGINAL_HOST_TAG
-    builder_begin_host "$BUILD_DIR" "$MAKEFILE"
-    builder_set_srcdir "$TOOLBOX_SRCDIR"
-    builder_set_dstdir "$DSTDIR"
-    builder_cflags -std=c99
-    builder_sources echo_win.c
-    builder_host_executable echo
-    builder_end
-
-    # Build cmp.exe
-    HOST_TAG=$ORIGINAL_HOST_TAG
-    builder_begin_host "$BUILD_DIR" "$MAKEFILE"
-    builder_set_srcdir "$TOOLBOX_SRCDIR"
-    builder_set_dstdir "$DSTDIR"
-    builder_sources cmp_win.c
-    builder_host_executable cmp
-    builder_end
-
-    if [ "$PACKAGE_DIR" ]; then
-        ARCHIVE=toolbox-$HOST_TAG.tar.bz2
-        dump "Packaging : $ARCHIVE"
-        pack_archive "$PACKAGE_DIR/$ARCHIVE" "$NDK_DIR" "$SUBDIR/echo.exe" "$SUBDIR/cmp.exe"
-        fail_panic "Could not package toolbox binaires"
-    fi
-fi
diff --git a/sources/host-tools/toolbox/build.py b/sources/host-tools/toolbox/build.py
deleted file mode 100755
index 6d34955..0000000
--- a/sources/host-tools/toolbox/build.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2015 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 NDK toolbox.
-
-Toolbox is just a POSIX compatible cmp.exe and echo.exe for Windows.
-"""
-from __future__ import print_function
-
-import os
-import site
-import sys
-
-site.addsitedir(os.path.join(os.path.dirname(__file__), '../../../build/lib'))
-site.addsitedir(os.path.join(os.path.dirname(__file__), '../../..'))
-
-# pylint: disable=import-error,wrong-import-position
-import build_support
-from ndk.hosts import Host
-# pylint: enable=import-error,wrong-import-position
-
-
-def main(args):
-    if not args.host.is_windows:
-        sys.exit('Toolbox is only for Windows hosts.')
-
-    toolbox_src = os.path.join(args.out_dir, 'toolbox')
-    build_cmd = [
-        'bash',
-        'build-toolbox.sh',
-        '--try-64',
-        f'--build-dir={toolbox_src}',
-    ]
-    build_support.build(build_cmd, args, intermediate_package=True)
-
-
-if __name__ == '__main__':
-    build_support.run(main)
diff --git a/tests/build/NDK_ANALYZE/project/jni/foo.cpp b/tests/build/NDK_ANALYZE/project/jni/foo.cpp
index 6aaa547..7a86c46 100644
--- a/tests/build/NDK_ANALYZE/project/jni/foo.cpp
+++ b/tests/build/NDK_ANALYZE/project/jni/foo.cpp
@@ -1,5 +1,5 @@
 #include <malloc.h>
 
 void foo() {
-  malloc(0);
+  malloc(10);
 }
diff --git a/tests/build/NDK_ANALYZE/test.py b/tests/build/NDK_ANALYZE/test.py
index 6e9bd35..54e8181 100644
--- a/tests/build/NDK_ANALYZE/test.py
+++ b/tests/build/NDK_ANALYZE/test.py
@@ -15,34 +15,29 @@
 #
 import os
 import subprocess
+import sys
 from typing import Tuple
 
 from ndk.abis import Abi
 
 
 def run_test(ndk_path: str, abi: Abi, api: int) -> Tuple[bool, str]:
-    """Runs the static analyzer on a sample project."""
+    """Checks ndk-build output for clang-tidy warnings."""
     ndk_build = os.path.join(ndk_path, 'ndk-build')
+    if sys.platform == 'win32':
+        ndk_build += '.cmd'
     project_path = 'project'
-    analyzer_out = os.path.join(project_path, 'report')
     ndk_args = [
         f'APP_ABI={abi}',
         f'APP_PLATFORM=android-{api}',
         'NDK_ANALYZE=1',
-        f'NDK_ANALYZER_OUT={analyzer_out}',
     ]
     proc = subprocess.Popen([ndk_build, '-C', project_path] + ndk_args,
                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                             encoding='utf-8')
     out, _ = proc.communicate()
-    # We expect the analyzer to find an issue and exit with a failure.
-    if proc.returncode == 0:
-        return False, out
+    if proc.returncode != 0:
+        return proc.returncode == 0, out
 
-    analyzer_abi_out = os.path.join(analyzer_out, abi)
-    # The out directory gets created even if the analyzer fails, so we
-    # intentionally include bad code and make sure we get a failure report.
-    if not os.listdir(analyzer_abi_out):
-        return False, 'No analyzer output found in ' + analyzer_abi_out
-
-    return True, out
+    expect = "warning: Potential memory leak [clang-analyzer-unix.Malloc]"
+    return expect in out, out
diff --git a/tests/libc++/test/std/iterators/iterator.primitives/iterator.traits/test_config.py b/tests/libc++/test/std/iterators/iterator.primitives/iterator.traits/test_config.py
new file mode 100644
index 0000000..03bc9cf
--- /dev/null
+++ b/tests/libc++/test/std/iterators/iterator.primitives/iterator.traits/test_config.py
@@ -0,0 +1,6 @@
+def build_broken(test):
+    if test.case_name == 'empty.fail':
+        # Format of the diagnostic changed in clang and we don't have the
+        # libc++ update to match (https://reviews.llvm.org/D92239).
+        return 'all', 'https://github.com/android/ndk/issues/1454'
+    return None, None