blob: 1648665cbd4eb05692a3ff5197e25664509b7a8e [file] [log] [blame]
Dan Alberte2369902016-06-09 14:25:09 -07001#!/usr/bin/env python
Dan Albertb4344022015-10-14 14:41:54 -07002#
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 Alberte92499f2017-01-26 18:47:23 -080017"""Runs the libc++ tests against the platform libc++."""
Dan Albertb4344022015-10-14 14:41:54 -070018from __future__ import print_function
19
20import argparse
Dan Alberte92499f2017-01-26 18:47:23 -080021import logging
Dan Albertb4344022015-10-14 14:41:54 -070022import os
Dan Albert4d4d6a82018-12-12 13:45:05 -080023import posixpath
Dan Albertb4344022015-10-14 14:41:54 -070024import sys
25
Dan Albertb4344022015-10-14 14:41:54 -070026THIS_DIR = os.path.dirname(os.path.realpath(__file__))
27ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..'))
28
29
Dan Alberte92499f2017-01-26 18:47:23 -080030def 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
Peter Collingbourne26cd9b82018-11-30 20:29:22 -080049def 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 Albertb4344022015-10-14 14:41:54 -070056class ArgParser(argparse.ArgumentParser):
Dan Alberte92499f2017-01-26 18:47:23 -080057 """Parses command line arguments."""
Peter Collingbourne26cd9b82018-11-30 20:29:22 -080058
Dan Albertb4344022015-10-14 14:41:54 -070059 def __init__(self):
60 super(ArgParser, self).__init__()
Peter Collingbourne26cd9b82018-11-30 20:29:22 -080061 self.add_argument('--bitness', choices=(32, 64), type=int, default=32)
Dan Albertb4344022015-10-14 14:41:54 -070062 self.add_argument('--host', action='store_true')
63
64
Peter Collingbourne26cd9b82018-11-30 20:29:22 -080065def extract_build_cmds(commands, exe_name):
66 """Extracts build command information from `ninja -t commands` output.
Dan Albertb4344022015-10-14 14:41:54 -070067
Peter Collingbourne26cd9b82018-11-30 20:29:22 -080068 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 Albertb4344022015-10-14 14:41:54 -070072
Peter Collingbourne26cd9b82018-11-30 20:29:22 -080073 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 Albertb4344022015-10-14 14:41:54 -070080
Peter Collingbourne26cd9b82018-11-30 20:29:22 -080081 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 Albertb4344022015-10-14 14:41:54 -0700116
117
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800118def 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 Albertb4344022015-10-14 14:41:54 -0700122
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800123 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 Albertb4344022015-10-14 14:41:54 -0700131
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800132 # Generate $OUT_DIR/combined-$TARGET_PRODUCT.ninja and build the
133 # template target's dependencies.
Dan Albert45f1d992019-08-21 16:31:48 -0700134 check_call([
135 'bash',
136 os.path.join(ANDROID_DIR, 'build/soong/soong_ui.bash'), '--make-mode',
137 target
138 ])
Dan Albertb4344022015-10-14 14:41:54 -0700139
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800140 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 Albertb4344022015-10-14 14:41:54 -0700148
149
Dan Albert35cb7a02018-12-14 14:59:57 -0800150def setup_test_directory():
151 """Prepares a device test directory for use by the shell user."""
Dan Albert4d4d6a82018-12-12 13:45:05 -0800152 stdfs_test_data = os.path.join(
153 THIS_DIR, 'test/std/input.output/filesystems/Inputs/static_test_env')
Dan Albert35cb7a02018-12-14 14:59:57 -0800154 device_dir = '/data/local/tmp/libcxx'
Dan Albert4d4d6a82018-12-12 13:45:05 -0800155 dynamic_dir = posixpath.join(device_dir, 'dynamic_test_env')
Dan Albert35cb7a02018-12-14 14:59:57 -0800156 check_call(['adb', 'shell', 'rm', '-rf', device_dir])
157 check_call(['adb', 'shell', 'mkdir', '-p', device_dir])
Dan Albert4d4d6a82018-12-12 13:45:05 -0800158 check_call(['adb', 'shell', 'mkdir', '-p', dynamic_dir])
159 check_call(['adb', 'push', '--sync', stdfs_test_data, device_dir])
Dan Albert35cb7a02018-12-14 14:59:57 -0800160 check_call(['adb', 'shell', 'chown', '-R', 'shell:shell', device_dir])
161
162
Dan Albertb4344022015-10-14 14:41:54 -0700163def main():
Dan Alberte92499f2017-01-26 18:47:23 -0800164 """Program entry point."""
165 logging.basicConfig(level=logging.INFO)
166
Dan Albertb4344022015-10-14 14:41:54 -0700167 args, lit_args = ArgParser().parse_known_args()
168 lit_path = os.path.join(ANDROID_DIR, 'external/llvm/utils/lit/lit.py')
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800169 cc, cflags, ldflags = get_build_cmds(args.bitness, args.host)
Dan Albertb4344022015-10-14 14:41:54 -0700170
171 mode_str = 'host' if args.host else 'device'
172 android_mode_arg = '--param=android_mode=' + mode_str
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800173 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 Alberte92499f2017-01-26 18:47:23 -0800176 site_cfg_path = os.path.join(THIS_DIR, 'test/lit.site.cfg')
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800177 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 Albert10e979a2016-11-18 16:47:44 -0800183
184 have_filter_args = False
185 for arg in lit_args:
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800186 # If the argument is a valid path with default_test_paths, it is a test
Dan Albert10e979a2016-11-18 16:47:44 -0800187 # filter.
188 real_path = os.path.realpath(arg)
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800189 if not any(real_path.startswith(path) for path in default_test_paths):
Dan Albert10e979a2016-11-18 16:47:44 -0800190 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 Albertb4344022015-10-14 14:41:54 -0700196
Dan Albert35cb7a02018-12-14 14:59:57 -0800197 if not args.host:
198 setup_test_directory()
199
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800200 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 Albert10e979a2016-11-18 16:47:44 -0800204 cmd = ['python', lit_path] + lit_args
205 if not have_filter_args:
Peter Collingbourne26cd9b82018-11-30 20:29:22 -0800206 cmd += default_test_paths
Dan Alberte92499f2017-01-26 18:47:23 -0800207 sys.exit(call(cmd))
Dan Albertb4344022015-10-14 14:41:54 -0700208
209
210if __name__ == '__main__':
211 main()