• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#
3# Copyright (C) 2015 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Runs the libc++ tests against the platform libc++."""
18from __future__ import print_function
19
20import argparse
21import logging
22import os
23import sys
24
25
26THIS_DIR = os.path.dirname(os.path.realpath(__file__))
27ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..'))
28
29
30def logger():
31    """Returns the logger for the module."""
32    return logging.getLogger(__name__)
33
34
35def call(cmd, *args, **kwargs):
36    """subprocess.call with logging."""
37    import subprocess
38    logger().info('call %s', ' '.join(cmd))
39    return subprocess.call(cmd, *args, **kwargs)
40
41
42def check_call(cmd, *args, **kwargs):
43    """subprocess.check_call with logging."""
44    import subprocess
45    logger().info('check_call %s', ' '.join(cmd))
46    return subprocess.check_call(cmd, *args, **kwargs)
47
48
49class ArgParser(argparse.ArgumentParser):
50    """Parses command line arguments."""
51    def __init__(self):
52        super(ArgParser, self).__init__()
53        self.add_argument(
54            '--compiler', choices=('clang', 'gcc'), default='clang')
55        self.add_argument(
56            '--bitness', choices=(32, 64), type=int, default=32)
57        self.add_argument('--host', action='store_true')
58
59
60def gen_test_config(bitness, compiler, host):
61    """Generates the test configuration makefile for buildcmds."""
62    testconfig_mk_path = os.path.join(THIS_DIR, 'buildcmds/testconfig.mk')
63    with open(testconfig_mk_path, 'w') as test_config:
64        if compiler == 'clang':
65            print('LOCAL_CLANG := true', file=test_config)
66        elif compiler == 'gcc':
67            print('LOCAL_CLANG := false', file=test_config)
68
69        if bitness == 32:
70            print('LOCAL_MULTILIB := 32', file=test_config)
71        elif bitness == 64:
72            print('LOCAL_MULTILIB := 64', file=test_config)
73
74        if compiler == 'clang':
75            print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc $(CLANG_CXX)',
76                  file=test_config)
77        else:
78            if host:
79                prefix = 'HOST_'
80            else:
81                prefix = 'TARGET_'
82            print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc '
83                  '$($(LOCAL_2ND_ARCH_VAR_PREFIX){}CXX)'.format(prefix),
84                  file=test_config)
85
86        if host:
87            print('include $(BUILD_HOST_EXECUTABLE)', file=test_config)
88        else:
89            print('include $(BUILD_EXECUTABLE)', file=test_config)
90
91
92def mmm(path):
93    """Invokes the Android build command mmm."""
94    makefile = os.path.join(path, 'Android.mk')
95    main_mk = 'build/core/main.mk'
96
97    env = dict(os.environ)
98    env['ONE_SHOT_MAKEFILE'] = makefile
99    env['LIBCXX_TESTING'] = 'true'
100    cmd = [
101        'make', '-j', '-C', ANDROID_DIR, '-f', main_mk,
102        'MODULES-IN-' + path.replace('/', '-'),
103    ]
104    check_call(cmd, env=env)
105
106
107def gen_build_cmds(bitness, compiler, host):
108    """Generates the build commands file for the test runner."""
109    gen_test_config(bitness, compiler, host)
110    mmm('external/libcxx/buildcmds')
111
112
113def main():
114    """Program entry point."""
115    logging.basicConfig(level=logging.INFO)
116
117    args, lit_args = ArgParser().parse_known_args()
118    lit_path = os.path.join(ANDROID_DIR, 'external/llvm/utils/lit/lit.py')
119    gen_build_cmds(args.bitness, args.compiler, args.host)
120
121    mode_str = 'host' if args.host else 'device'
122    android_mode_arg = '--param=android_mode=' + mode_str
123    site_cfg_path = os.path.join(THIS_DIR, 'test/lit.site.cfg')
124    site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path
125    default_test_path = os.path.join(THIS_DIR, 'test')
126
127    have_filter_args = False
128    for arg in lit_args:
129        # If the argument is a valid path with default_test_path, it is a test
130        # filter.
131        real_path = os.path.realpath(arg)
132        if not real_path.startswith(default_test_path):
133            continue
134        if not os.path.exists(real_path):
135            continue
136
137        have_filter_args = True
138        break  # No need to keep scanning.
139
140    lit_args = ['-sv', android_mode_arg, site_cfg_arg] + lit_args
141    cmd = ['python', lit_path] + lit_args
142    if not have_filter_args:
143        cmd.append(default_test_path)
144    sys.exit(call(cmd))
145
146
147if __name__ == '__main__':
148    main()
149