1#!/usr/bin/env python
2#
3# Copyright (C) 2015 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Builds libc++ for Android."""
18from __future__ import print_function
19
20import os
21import shutil
22import site
23import subprocess
24
25THIS_DIR = os.path.realpath(os.path.dirname(__file__))
26site.addsitedir(os.path.join(THIS_DIR, '../../../build/lib'))
27
28import build_support  # pylint: disable=import-error
29
30
31class ArgParser(build_support.ArgParser):
32    def __init__(self):  # pylint: disable=super-on-old-class
33        super(ArgParser, self).__init__()
34
35        self.add_argument(
36            '--arch', choices=build_support.ALL_ARCHITECTURES,
37            help='Architectures to build. Builds all if not present.')
38
39
40def main(args):
41    arches = build_support.ALL_ARCHITECTURES
42    if args.arch is not None:
43        arches = [args.arch]
44
45    abis = []
46    for arch in arches:
47        abis.extend(build_support.arch_to_abis(arch))
48
49    ndk_build = build_support.ndk_path('build/ndk-build')
50    prebuilt_ndk = build_support.android_path('prebuilts/ndk/current')
51    platforms_root = os.path.join(prebuilt_ndk, 'platforms')
52    toolchains_root = os.path.join(prebuilt_ndk, 'toolchains')
53    libcxx_path = build_support.ndk_path('sources/cxx-stl/llvm-libc++')
54    obj_out = os.path.join(args.out_dir, 'libcxx/obj')
55
56    # TODO(danalbert): Stop building to the source directory.
57    # This is historical, and simplifies packaging a bit. We need to pack up
58    # all the source as well as the libraries. If build_support.make_package
59    # were to change to allow a list of directories instead of one directory,
60    # we could make this unnecessary.  Will be a follow up CL.
61    lib_out = os.path.join(libcxx_path, 'libs')
62
63    build_cmd = [
64        'bash', ndk_build, '-C', THIS_DIR, build_support.jobs_arg(), 'V=1',
65        'APP_ABI=' + ' '.join(abis),
66
67        # Use the prebuilt platforms and toolchains.
68        'NDK_PLATFORMS_ROOT=' + platforms_root,
69        'NDK_TOOLCHAINS_ROOT=' + toolchains_root,
70        'NDK_NEW_TOOLCHAINS_LAYOUT=true',
71
72        # Tell ndk-build where all of our makefiles are and where outputs
73        # should go. The defaults in ndk-build are only valid if we have a
74        # typical ndk-build layout with a jni/{Android,Application}.mk.
75        'NDK_PROJECT_PATH=null',
76        'APP_BUILD_SCRIPT=' + os.path.join(THIS_DIR, 'Android.mk'),
77        'NDK_APPLICATION_MK=' + os.path.join(THIS_DIR, 'Application.mk'),
78        'NDK_OUT=' + obj_out,
79        'NDK_LIBS_OUT=' + lib_out,
80
81        # Make sure we don't pick up a cached copy.
82        'LIBCXX_FORCE_REBUILD=true',
83
84        # Put armeabi-v7a-hard in its own directory.
85        '_NDK_TESTING_ALL_=yes',
86    ]
87    print('Building libc++ for ABIs: {}'.format(', '.join(abis)))
88    subprocess.check_call(build_cmd)
89
90    # The static libraries are installed to NDK_OUT, not NDK_LIB_OUT, so we
91    # need to install them to our package directory.
92    for abi in abis:
93        static_lib_dir = os.path.join(obj_out, 'local', abi)
94        install_dir = os.path.join(lib_out, abi)
95        is_arm = abi.startswith('armeabi')
96
97        if is_arm:
98            shutil.copy2(
99                os.path.join(static_lib_dir, 'libunwind.a'), install_dir)
100
101        shutil.copy2(os.path.join(static_lib_dir, 'libc++abi.a'), install_dir)
102        shutil.copy2(
103            os.path.join(static_lib_dir, 'libandroid_support.a'), install_dir)
104        shutil.copy2(
105            os.path.join(static_lib_dir, 'libc++_static.a'), install_dir)
106
107    build_support.make_package('libcxx', libcxx_path, args.dist_dir)
108
109
110if __name__ == '__main__':
111    build_support.run(main, ArgParser)
112