Dan Albert | e236990 | 2016-06-09 14:25:09 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 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 | # |
Dan Albert | e92499f | 2017-01-26 18:47:23 -0800 | [diff] [blame] | 17 | """Runs the libc++ tests against the platform libc++.""" |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 18 | from __future__ import print_function |
| 19 | |
| 20 | import argparse |
Dan Albert | e92499f | 2017-01-26 18:47:23 -0800 | [diff] [blame] | 21 | import logging |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 22 | import os |
Dan Albert | 4d4d6a8 | 2018-12-12 13:45:05 -0800 | [diff] [blame] | 23 | import posixpath |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 24 | import sys |
| 25 | |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 26 | THIS_DIR = os.path.dirname(os.path.realpath(__file__)) |
| 27 | ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..')) |
| 28 | |
| 29 | |
Dan Albert | e92499f | 2017-01-26 18:47:23 -0800 | [diff] [blame] | 30 | def logger(): |
| 31 | """Returns the logger for the module.""" |
| 32 | return logging.getLogger(__name__) |
| 33 | |
| 34 | |
| 35 | def 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 | |
| 42 | def 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 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 49 | def check_output(cmd, *args, **kwargs): |
| 50 | """subprocess.check_output with logging.""" |
| 51 | import subprocess |
| 52 | logger().info('check_output %s', ' '.join(cmd)) |
| 53 | return subprocess.check_output(cmd, *args, **kwargs) |
| 54 | |
| 55 | |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 56 | class ArgParser(argparse.ArgumentParser): |
Dan Albert | e92499f | 2017-01-26 18:47:23 -0800 | [diff] [blame] | 57 | """Parses command line arguments.""" |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 58 | |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 59 | def __init__(self): |
| 60 | super(ArgParser, self).__init__() |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 61 | self.add_argument('--bitness', choices=(32, 64), type=int, default=32) |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 62 | self.add_argument('--host', action='store_true') |
| 63 | |
| 64 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 65 | def extract_build_cmds(commands, exe_name): |
| 66 | """Extracts build command information from `ninja -t commands` output. |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 67 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 68 | Args: |
| 69 | commands: String containing the output of `ninja -t commands` for the |
| 70 | libcxx_test_template. |
| 71 | exe_name: The basename of the built executable. |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 72 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 73 | Returns: |
| 74 | Tuple of (compiler, compiler_flags, linker_flags). |
| 75 | """ |
| 76 | cc = None |
| 77 | cflags = None |
| 78 | ldflags = None |
| 79 | template_name = 'external/libcxx/libcxx_test_template.cpp' |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 80 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 81 | for cmd in commands.splitlines(): |
| 82 | cmd_args = cmd.split() |
| 83 | if cc is None and template_name in cmd_args: |
| 84 | for i, arg in enumerate(cmd_args): |
| 85 | if arg == '-o': |
| 86 | cmd_args[i + 1] = '%OUT%' |
| 87 | elif arg == template_name: |
| 88 | cmd_args[i] = '%SOURCE%' |
| 89 | # Drop dependency tracking args since they can cause file |
| 90 | # not found errors at test time. |
| 91 | if arg == '-MD': |
| 92 | cmd_args[i] = '' |
| 93 | if arg == '-MF': |
| 94 | cmd_args[i] = '' |
| 95 | cmd_args[i + 1] = '' |
| 96 | if cmd_args[0] == 'PWD=/proc/self/cwd': |
| 97 | cmd_args = cmd_args[1:] |
| 98 | if cmd_args[0].endswith('gomacc'): |
| 99 | cmd_args = cmd_args[1:] |
| 100 | cc = cmd_args[0] |
| 101 | cflags = cmd_args[1:] |
| 102 | if ldflags is None: |
| 103 | is_ld = False |
| 104 | for i, arg in enumerate(cmd_args): |
| 105 | # Here we assume that the rspfile contains the path to the |
| 106 | # object file and nothing else. |
| 107 | if arg.startswith('@'): |
| 108 | cmd_args[i] = '%SOURCE%' |
| 109 | if arg == '-o' and cmd_args[i + 1].endswith(exe_name): |
| 110 | cmd_args[i + 1] = '%OUT%' |
| 111 | is_ld = True |
| 112 | if is_ld: |
| 113 | ldflags = cmd_args[1:] |
| 114 | |
| 115 | return cc, cflags, ldflags |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 116 | |
| 117 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 118 | def get_build_cmds(bitness, host): |
| 119 | """Use ninja -t commands to find the build commands for an executable.""" |
| 120 | out_dir = os.getenv('OUT_DIR', os.path.join(ANDROID_DIR, 'out')) |
| 121 | product_out = os.getenv('ANDROID_PRODUCT_OUT') |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 122 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 123 | if host: |
| 124 | rel_out_dir = os.path.relpath( |
| 125 | os.path.join(out_dir, 'soong/host/linux-x86/bin'), ANDROID_DIR) |
| 126 | target = os.path.join(rel_out_dir, 'libcxx_test_template64') |
| 127 | else: |
| 128 | exe_name = 'libcxx_test_template' + str(bitness) |
| 129 | rel_out_dir = os.path.relpath(product_out, ANDROID_DIR) |
| 130 | target = os.path.join(rel_out_dir, 'system/bin', exe_name) |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 131 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 132 | # Generate $OUT_DIR/combined-$TARGET_PRODUCT.ninja and build the |
| 133 | # template target's dependencies. |
Dan Albert | 45f1d99 | 2019-08-21 16:31:48 -0700 | [diff] [blame] | 134 | check_call([ |
| 135 | 'bash', |
| 136 | os.path.join(ANDROID_DIR, 'build/soong/soong_ui.bash'), '--make-mode', |
| 137 | target |
| 138 | ]) |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 139 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 140 | ninja_path = os.path.join( |
| 141 | out_dir, 'combined-' + os.getenv('TARGET_PRODUCT') + '.ninja') |
| 142 | commands = check_output([ |
| 143 | os.path.join(ANDROID_DIR, 'prebuilts/build-tools/linux-x86/bin/ninja'), |
| 144 | '-C', ANDROID_DIR, '-f', ninja_path, '-t', 'commands', target |
| 145 | ]) |
| 146 | |
| 147 | return extract_build_cmds(commands, os.path.basename(target)) |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 148 | |
| 149 | |
Dan Albert | 35cb7a0 | 2018-12-14 14:59:57 -0800 | [diff] [blame] | 150 | def setup_test_directory(): |
| 151 | """Prepares a device test directory for use by the shell user.""" |
Dan Albert | 4d4d6a8 | 2018-12-12 13:45:05 -0800 | [diff] [blame] | 152 | stdfs_test_data = os.path.join( |
| 153 | THIS_DIR, 'test/std/input.output/filesystems/Inputs/static_test_env') |
Dan Albert | 35cb7a0 | 2018-12-14 14:59:57 -0800 | [diff] [blame] | 154 | device_dir = '/data/local/tmp/libcxx' |
Dan Albert | 4d4d6a8 | 2018-12-12 13:45:05 -0800 | [diff] [blame] | 155 | dynamic_dir = posixpath.join(device_dir, 'dynamic_test_env') |
Dan Albert | 35cb7a0 | 2018-12-14 14:59:57 -0800 | [diff] [blame] | 156 | check_call(['adb', 'shell', 'rm', '-rf', device_dir]) |
| 157 | check_call(['adb', 'shell', 'mkdir', '-p', device_dir]) |
Dan Albert | 4d4d6a8 | 2018-12-12 13:45:05 -0800 | [diff] [blame] | 158 | check_call(['adb', 'shell', 'mkdir', '-p', dynamic_dir]) |
| 159 | check_call(['adb', 'push', '--sync', stdfs_test_data, device_dir]) |
Dan Albert | 35cb7a0 | 2018-12-14 14:59:57 -0800 | [diff] [blame] | 160 | check_call(['adb', 'shell', 'chown', '-R', 'shell:shell', device_dir]) |
| 161 | |
| 162 | |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 163 | def main(): |
Dan Albert | e92499f | 2017-01-26 18:47:23 -0800 | [diff] [blame] | 164 | """Program entry point.""" |
| 165 | logging.basicConfig(level=logging.INFO) |
| 166 | |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 167 | args, lit_args = ArgParser().parse_known_args() |
| 168 | lit_path = os.path.join(ANDROID_DIR, 'external/llvm/utils/lit/lit.py') |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 169 | cc, cflags, ldflags = get_build_cmds(args.bitness, args.host) |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 170 | |
| 171 | mode_str = 'host' if args.host else 'device' |
| 172 | android_mode_arg = '--param=android_mode=' + mode_str |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 173 | cxx_under_test_arg = '--param=cxx_under_test=' + cc |
| 174 | cxx_template_arg = '--param=cxx_template=' + ' '.join(cflags) |
| 175 | link_template_arg = '--param=link_template=' + ' '.join(ldflags) |
Dan Albert | e92499f | 2017-01-26 18:47:23 -0800 | [diff] [blame] | 176 | site_cfg_path = os.path.join(THIS_DIR, 'test/lit.site.cfg') |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 177 | libcxx_site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path |
| 178 | libcxxabi_site_cfg_arg = '--param=libcxxabi_site_config=' + site_cfg_path |
| 179 | default_test_paths = [ |
| 180 | os.path.join(THIS_DIR, 'test'), |
| 181 | os.path.join(ANDROID_DIR, 'external/libcxxabi/test') |
| 182 | ] |
Dan Albert | 10e979a | 2016-11-18 16:47:44 -0800 | [diff] [blame] | 183 | |
| 184 | have_filter_args = False |
| 185 | for arg in lit_args: |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 186 | # If the argument is a valid path with default_test_paths, it is a test |
Dan Albert | 10e979a | 2016-11-18 16:47:44 -0800 | [diff] [blame] | 187 | # filter. |
| 188 | real_path = os.path.realpath(arg) |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 189 | if not any(real_path.startswith(path) for path in default_test_paths): |
Dan Albert | 10e979a | 2016-11-18 16:47:44 -0800 | [diff] [blame] | 190 | continue |
| 191 | if not os.path.exists(real_path): |
| 192 | continue |
| 193 | |
| 194 | have_filter_args = True |
| 195 | break # No need to keep scanning. |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 196 | |
Dan Albert | 35cb7a0 | 2018-12-14 14:59:57 -0800 | [diff] [blame] | 197 | if not args.host: |
| 198 | setup_test_directory() |
| 199 | |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 200 | lit_args = [ |
| 201 | '-sv', android_mode_arg, cxx_under_test_arg, cxx_template_arg, |
| 202 | link_template_arg, libcxx_site_cfg_arg, libcxxabi_site_cfg_arg |
| 203 | ] + lit_args |
Dan Albert | 10e979a | 2016-11-18 16:47:44 -0800 | [diff] [blame] | 204 | cmd = ['python', lit_path] + lit_args |
| 205 | if not have_filter_args: |
Peter Collingbourne | 26cd9b8 | 2018-11-30 20:29:22 -0800 | [diff] [blame] | 206 | cmd += default_test_paths |
Dan Albert | e92499f | 2017-01-26 18:47:23 -0800 | [diff] [blame] | 207 | sys.exit(call(cmd)) |
Dan Albert | b434402 | 2015-10-14 14:41:54 -0700 | [diff] [blame] | 208 | |
| 209 | |
| 210 | if __name__ == '__main__': |
| 211 | main() |