Build libc++ using the just-built NDK.

This gets us out of depending on prebuilts/ndk (and as such a
sometimes out of sync sysroot) when building libc++.

Test: ./checkbuild.py && ./run_tests.py
Test: ./checkbuild.py libc++
Bug: None
Change-Id: I195a2dba37731dac85e81c7c173399c0d0843346
diff --git a/build/core/definitions.mk b/build/core/definitions.mk
index 9df5b06..f7c998b 100644
--- a/build/core/definitions.mk
+++ b/build/core/definitions.mk
@@ -2204,8 +2204,9 @@
 # $1: STL name as it appears in APP_STL (e.g. system)
 #
 ndk-stl-select = \
-    $(call import-module,$(NDK_STL.$1.IMPORT_MODULE)) \
-    $(eval STL_DEFAULT_STD_VERSION := $(strip $(NDK_STL.$1.DEFAULT_STD_VERSION)))
+    $(if $(filter none,$1),,\
+        $(call import-module,$(NDK_STL.$1.IMPORT_MODULE)) \
+        $(eval STL_DEFAULT_STD_VERSION := $(strip $(NDK_STL.$1.DEFAULT_STD_VERSION))))
 
 # Called after all Android.mk files are parsed to add
 # proper STL dependencies to every C++ module.
@@ -2217,7 +2218,7 @@
         $(NDK_STL.$1.SHARED_LIBS),\
         $(NDK_STL.$1.LDLIBS))
 
-$(call ndk-stl-register,none,cxx-stl/system)
+$(call ndk-stl-register,none)
 $(call ndk-stl-register,system,cxx-stl/system,libstdc++)
 
 $(call ndk-stl-register,\
diff --git a/checkbuild.py b/checkbuild.py
index 312c98d..c4fd57e 100755
--- a/checkbuild.py
+++ b/checkbuild.py
@@ -628,11 +628,143 @@
         self.validate_notice(install_path)
 
 
-class Libcxx(ndk.builds.InvokeExternalBuildModule):
+def make_linker_script(path, libs):
+    with open(path, 'w') as linker_script:
+        linker_script.write('INPUT({})\n'.format(' '.join(libs)))
+
+
+def create_libcxx_linker_scripts(lib_dir, abi):
+    static_libs = ['-lc++_static', '-lc++abi']
+    is_arm = abi == 'armeabi-v7a'
+    needs_android_support = abi in ndk.abis.LP32_ABIS
+    if needs_android_support:
+        static_libs.append('-landroid_support')
+    if is_arm:
+        static_libs.extend(['-lunwind', '-ldl', '-latomic'])
+    make_linker_script(os.path.join(lib_dir, 'libc++.a'), static_libs)
+
+    shared_libs = []
+    if needs_android_support:
+        shared_libs.append('-landroid_support')
+    if is_arm:
+        shared_libs.extend(['-lunwind', '-latomic'])
+    shared_libs.append('-lc++_shared')
+    make_linker_script(os.path.join(lib_dir, 'libc++.so'), shared_libs)
+
+
+class Libcxx(ndk.builds.Module):
     name = 'libc++'
     path = 'sources/cxx-stl/llvm-libc++'
     script = 'ndk/sources/cxx-stl/llvm-libc++/build.py'
     arch_specific = True
+    deps = {
+        'clang',
+        'gcc',
+        'host-tools',
+        'libandroid_support',
+        'meta',
+        'ndk-build',
+        'ndk-build-shortcut',
+        'platforms',
+        'sysroot',
+    }
+
+    def __init__(self):
+        super(Libcxx, self).__init__()
+        self.abis = None
+        self.obj_out = None
+        self.lib_out = None
+        self.libcxx_path = ndk.paths.android_path('external/libcxx')
+
+    def set_abis(self, arch):
+        if arch is None:
+            self.abis = ndk.abis.ALL_ABIS
+        else:
+            self.abis = ndk.abis.arch_to_abis(arch)
+
+    def build(self, build_dir, _dist_dir, args):
+        ndk_path = ndk.paths.get_install_path(build_dir)
+        ndk_build = os.path.join(ndk_path, 'ndk-build')
+        bionic_path = ndk.paths.android_path('bionic')
+
+        self.obj_out = os.path.join(build_dir, 'libcxx/obj')
+        self.lib_out = os.path.join(build_dir, 'libcxx/libs')
+        self.set_abis(args.arch)
+
+        android_mk = os.path.join(self.libcxx_path, 'Android.mk')
+        application_mk = os.path.join(self.libcxx_path, 'Application.mk')
+
+        build_cmd = [
+            'bash', ndk_build, '-C', self.libcxx_path, 'V=1', 'NDK_LOG=1',
+            'APP_ABI={}'.format(' '.join(self.abis)),
+            'NDK_OUT=' + self.obj_out,
+            'NDK_LIBS_OUT=' + self.lib_out,
+            'LIBCXX_FORCE_REBUILD=true',
+            'BIONIC_PATH=' + bionic_path,
+
+            # Tell ndk-build where all of our makefiles are. The defaults in
+            # ndk-build are only valid if we have a typical ndk-build layout
+            # with a jni/{Android,Application}.mk.
+            'NDK_PROJECT_PATH=null',
+            'APP_BUILD_SCRIPT=' + android_mk,
+            'NDK_APPLICATION_MK=' + application_mk,
+        ]
+
+        print('Running: ' + ' '.join(build_cmd))
+        subprocess.check_call(build_cmd)
+
+    def install(self, out_dir, dist_dir, args):
+        ndk_path = ndk.paths.get_install_path(out_dir)
+        install_root = os.path.join(ndk_path, self.path)
+
+        if os.path.exists(install_root):
+            shutil.rmtree(install_root)
+        os.makedirs(install_root)
+
+        shutil.copy2(
+            os.path.join(self.libcxx_path, 'Android.mk'), install_root)
+        shutil.copy2(
+            os.path.join(self.libcxx_path, 'NOTICE'), install_root)
+        shutil.copytree(
+            os.path.join(self.libcxx_path, 'include'),
+            os.path.join(install_root, 'include'))
+        shutil.copytree(self.lib_out, os.path.join(install_root, 'libs'))
+
+        # TODO(danalbert): Fix the test runner to work with a separated test
+        # source and build output tree. The test runner itself works with this,
+        # but we need to do some work to separate the two when we invoke it.
+        shutil.copytree(
+            os.path.join(self.libcxx_path, 'test'),
+            os.path.join(install_root, 'test'),
+            symlinks=True)
+        shutil.copytree(
+            os.path.join(self.libcxx_path, 'utils'),
+            os.path.join(install_root, 'utils'))
+
+        for abi in self.abis:
+            lib_dir = os.path.join(install_root, 'libs', abi)
+
+            # The static libraries installed to the obj dir, not the lib dir.
+            self.install_static_libs(lib_dir, abi)
+
+            # Create linker scripts for the libraries we use so that we link
+            # things properly even when we're not using ndk-build. The linker
+            # will read the script in place of the library so that we link the
+            # unwinder and other support libraries appropriately.
+            create_libcxx_linker_scripts(lib_dir, abi)
+
+    def install_static_libs(self, lib_dir, abi):
+        static_lib_dir = os.path.join(self.obj_out, 'local', abi)
+
+        shutil.copy2(os.path.join(static_lib_dir, 'libc++abi.a'), lib_dir)
+        shutil.copy2(os.path.join(static_lib_dir, 'libc++_static.a'), lib_dir)
+
+        if abi == 'armeabi-v7a':
+            shutil.copy2(os.path.join(static_lib_dir, 'libunwind.a'), lib_dir)
+
+        if abi in ndk.abis.LP32_ABIS:
+            shutil.copy2(
+                os.path.join(static_lib_dir, 'libandroid_support.a'), lib_dir)
 
 
 class Platforms(ndk.builds.Module):
diff --git a/sources/android/support/Android.mk b/sources/android/support/Android.mk
index d0e0060..2c50a47 100644
--- a/sources/android/support/Android.mk
+++ b/sources/android/support/Android.mk
@@ -26,8 +26,6 @@
 
 # 32-bit ABIs
 
-BIONIC_PATH := ../../../../bionic
-
 android_support_c_includes += \
     $(BIONIC_PATH)/libc \
     $(BIONIC_PATH)/libc/upstream-openbsd/android/include \
diff --git a/sources/cxx-stl/llvm-libc++/build.py b/sources/cxx-stl/llvm-libc++/build.py
deleted file mode 100755
index 02ce9d0..0000000
--- a/sources/cxx-stl/llvm-libc++/build.py
+++ /dev/null
@@ -1,138 +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 libc++ for Android."""
-from __future__ import print_function
-
-import os
-import shutil
-import site
-import subprocess
-
-THIS_DIR = os.path.realpath(os.path.dirname(__file__))
-site.addsitedir(os.path.join(THIS_DIR, '../../../build/lib'))
-
-import build_support  # pylint: disable=import-error
-
-
-class ArgParser(build_support.ArgParser):
-    def __init__(self):  # pylint: disable=super-on-old-class
-        super(ArgParser, self).__init__()
-
-        self.add_argument(
-            '--arch', choices=build_support.ALL_ARCHITECTURES,
-            help='Architectures to build. Builds all if not present.')
-
-
-def make_linker_script(path, libs):
-    with open(path, 'w') as linker_script:
-        linker_script.write('INPUT({})\n'.format(' '.join(libs)))
-
-
-def main(args):
-    arches = build_support.ALL_ARCHITECTURES
-    if args.arch is not None:
-        arches = [args.arch]
-
-    abis = []
-    for arch in arches:
-        abis.extend(build_support.arch_to_abis(arch))
-
-    ndk_build = build_support.ndk_path('build/ndk-build')
-    prebuilt_ndk = build_support.android_path('prebuilts/ndk')
-    platform_prebuilts = os.path.join(prebuilt_ndk, 'platform')
-    platforms_root = os.path.join(prebuilt_ndk, 'current/platforms')
-    unified_sysroot_path = os.path.join(platform_prebuilts, 'sysroot')
-    toolchains_root = os.path.join(prebuilt_ndk, 'current/toolchains')
-    libcxx_path = build_support.android_path('external/libcxx')
-    obj_out = os.path.join(args.out_dir, 'libcxx/obj')
-
-    # TODO(danalbert): Stop building to the source directory.
-    # This is historical, and simplifies packaging a bit. We need to pack up
-    # all the source as well as the libraries. If build_support.make_package
-    # were to change to allow a list of directories instead of one directory,
-    # we could make this unnecessary.  Will be a follow up CL.
-    lib_out = os.path.join(libcxx_path, 'libs')
-
-    build_cmd = [
-        'bash', ndk_build, '-C', THIS_DIR, build_support.jobs_arg(), 'V=1',
-        'APP_ABI=' + ' '.join(abis),
-
-        # Use the prebuilt platforms and toolchains.
-        'NDK_UNIFIED_SYSROOT_PATH=' + unified_sysroot_path,
-        'NDK_PLATFORMS_ROOT=' + platforms_root,
-        'NDK_TOOLCHAINS_ROOT=' + toolchains_root,
-        'NDK_NEW_TOOLCHAINS_LAYOUT=true',
-
-        # Tell ndk-build where all of our makefiles are and where outputs
-        # should go. The defaults in ndk-build are only valid if we have a
-        # typical ndk-build layout with a jni/{Android,Application}.mk.
-        'NDK_PROJECT_PATH=null',
-        'APP_BUILD_SCRIPT=' + os.path.join(libcxx_path, 'Android.mk'),
-        'NDK_APPLICATION_MK=' + os.path.join(libcxx_path, 'Application.mk'),
-        'NDK_OUT=' + obj_out,
-        'NDK_LIBS_OUT=' + lib_out,
-
-        # Make sure we don't pick up a cached copy.
-        'LIBCXX_FORCE_REBUILD=true',
-    ]
-    print('Building libc++ for ABIs: {}'.format(', '.join(abis)))
-    print('Running: ' + ' '.join(build_cmd))
-    subprocess.check_call(build_cmd)
-
-    # The static libraries are installed to NDK_OUT, not NDK_LIB_OUT, so we
-    # need to install them to our package directory.
-    for abi in abis:
-        static_lib_dir = os.path.join(obj_out, 'local', abi)
-        install_dir = os.path.join(lib_out, abi)
-        is_arm = abi.startswith('armeabi')
-        needs_android_support = abi in ('armeabi-v7a', 'x86')
-
-        if is_arm:
-            shutil.copy2(
-                os.path.join(static_lib_dir, 'libunwind.a'), install_dir)
-
-        shutil.copy2(os.path.join(static_lib_dir, 'libc++abi.a'), install_dir)
-        if needs_android_support:
-            shutil.copy2(os.path.join(
-                static_lib_dir, 'libandroid_support.a'), install_dir)
-        shutil.copy2(
-            os.path.join(static_lib_dir, 'libc++_static.a'), install_dir)
-
-        # Create linker scripts for the libraries we use so that we link things
-        # properly even when we're not using ndk-build. The linker will read
-        # the script in place of the library so that we link the unwinder and
-        # other support libraries appropriately.
-        static_libs = ['-lc++_static', '-lc++abi']
-        if needs_android_support:
-            static_libs.append('-landroid_support')
-        if is_arm:
-            static_libs.extend(['-lunwind', '-ldl', '-latomic'])
-        make_linker_script(os.path.join(install_dir, 'libc++.a'), static_libs)
-
-        shared_libs = []
-        if needs_android_support:
-            shared_libs.append('-landroid_support')
-        if is_arm:
-            shared_libs.extend(['-lunwind', '-latomic'])
-        shared_libs.append('-lc++_shared')
-        make_linker_script(os.path.join(install_dir, 'libc++.so'), shared_libs)
-
-    build_support.make_package('libc++', libcxx_path, args.dist_dir)
-
-
-if __name__ == '__main__':
-    build_support.run(main, ArgParser)
diff --git a/sources/cxx-stl/llvm-libc++abi/Application.mk b/sources/cxx-stl/llvm-libc++abi/Application.mk
deleted file mode 100644
index f98280d..0000000
--- a/sources/cxx-stl/llvm-libc++abi/Application.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# 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.
-#
-
-NDK_TOOLCHAIN_VERSION := clang
-APP_STL := none
diff --git a/sources/cxx-stl/llvm-libc++abi/NOTICE b/sources/cxx-stl/llvm-libc++abi/NOTICE
deleted file mode 120000
index 72aac42..0000000
--- a/sources/cxx-stl/llvm-libc++abi/NOTICE
+++ /dev/null
@@ -1 +0,0 @@
-libcxxabi/LICENSE.TXT
\ No newline at end of file