Update run_tests.py to use Soong.

run_tests.py had bitrotted since it was last run (e.g. it used perl
which is now not allowed and the warning flags were out of date).
I changed it to use a different way of extracting the compile command
which is based on Soong instead of makefiles. This way is also
compatible with multiple build directories since it doesn't clobber
the source directory and doesn't require OUT_DIR == out.

This also changes run_tests.py to run the libcxxabi tests as well,
since they can be run using the same mechanism.

Bug: 120510768
Test: ./run_tests.py --bitness 32
Test: ./run_tests.py --bitness 64
Test: ./run_tests.py --bitness 64 --host
Change-Id: Id30129161f8519fa6c1bc106727326373ca9ab82
This commit is contained in:
Peter Collingbourne
2018-11-30 20:29:22 -08:00
committed by Dan Albert
parent 20fc590391
commit 26cd9b82f8
12 changed files with 158 additions and 168 deletions

View File

@@ -128,13 +128,46 @@ cc_library_shared {
},
}
// This target is used to extract the build commands for a test executable.
// See run_tests.py.
cc_binary {
name: "libcxx_test_template",
srcs: [
"libcxx_test_template.cpp",
],
cppflags: [
"-fsized-deallocation",
"-fexceptions",
"-Wno-format-zero-length",
"-Wno-implicit-fallthrough",
"-Wno-non-virtual-dtor",
"-Wno-return-stack-address",
"-Wno-unused-local-typedef",
// ANDROIDMK TRANSLATION ERROR: unsupported conditional
// ifdef LIBCXX_TESTING
// ANDROIDMK TRANSLATION ERROR: unsupported include
// include $(LOCAL_PATH)/buildcmds/Android.mk
// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
// endif
// TARGET_BUILD_APPS
"-UNDEBUG",
// Optimization is causing relocation for nothrow new to be thrown away.
// http://llvm.org/bugs/show_bug.cgi?id=21421
"-O0",
],
ldflags: [
// This makes the tests run a little faster.
"-Wl,--strip-all",
],
rtti: true,
local_include_dirs: [
"test/support",
],
multilib: {
lib32: {
suffix: "32",
},
lib64: {
suffix: "64",
},
},
compile_multilib: "both",
host_supported: true,
gnu_extensions: false,
cpp_std: "c++17",
}

View File

@@ -1 +0,0 @@
# This empty Android.mk file is required to shadow buildcmds/Android.mk

View File

@@ -1,4 +0,0 @@
cxx_under_test
cxx.cmds
link.cmds
testconfig.mk

View File

@@ -1,45 +0,0 @@
#
# Copyright (C) 2014 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.
#
LOCAL_PATH := $(call my-dir)
# Don't build for unbundled branches
ifeq (,$(TARGET_BUILD_APPS))
include $(CLEAR_VARS)
LOCAL_MODULE := libc++_build_commands_$(ANDROID_DEVICE)
LOCAL_SRC_FILES := dummy.cpp
LOCAL_CXX_STL := libc++
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../test/support
LOCAL_CPPFLAGS := \
-std=c++17 \
-fsized-deallocation \
-fexceptions \
-UNDEBUG \
-Wno-error=non-virtual-dtor \
-Wno-format-zero-length \
-Wno-reserved-user-defined-literal \
-Wno-unused-local-typedef \
-Wno-unused-variable \
# Optimization is causing relocation for nothrow new to be thrown away.
# http://llvm.org/bugs/show_bug.cgi?id=21421
LOCAL_CPPFLAGS += -O0
LOCAL_RTTI_FLAG := -frtti
include $(LOCAL_PATH)/testconfig.mk
endif

View File

@@ -1,16 +0,0 @@
#!/bin/bash
CXX=$1
ARGS=${*:2}
DIR=external/libcxx/buildcmds
echo $ANDROID_BUILD_TOP/$CXX > $DIR/cxx_under_test
echo $ARGS | grep -P '\S+\.cpp\b' > /dev/null
if [ $? -eq 0 ]; then
echo $ARGS | perl -ne 's/\S+\.cpp\b/%SOURCE%/; print' \
| perl -ne 's/\S+\.o\b/%OUT%/; print' > $DIR/cxx.cmds
else
echo $ARGS | perl -ne 's/out\/\S+\/EXECUTABLES\/\S+\.o\b/%SOURCE%/; print' \
| perl -ne 's/-o\s+\S+\b/-o %OUT%/; print' > $DIR/link.cmds
fi
$CXX $ARGS

View File

@@ -1,3 +0,0 @@
int main() {
return 0;
}

1
libcxx_test_template.cpp Normal file
View File

@@ -0,0 +1 @@
int main() {}

11
pylintrc Normal file
View File

@@ -0,0 +1,11 @@
[MESSAGES CONTROL]
disable=design,fixme
[BASIC]
good-names=i,
j,
k,
ex,
Run,
_,
cc

View File

@@ -22,7 +22,6 @@ import logging
import os
import sys
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..'))
@@ -46,68 +45,101 @@ def check_call(cmd, *args, **kwargs):
return subprocess.check_call(cmd, *args, **kwargs)
def check_output(cmd, *args, **kwargs):
"""subprocess.check_output with logging."""
import subprocess
logger().info('check_output %s', ' '.join(cmd))
return subprocess.check_output(cmd, *args, **kwargs)
class ArgParser(argparse.ArgumentParser):
"""Parses command line arguments."""
def __init__(self):
super(ArgParser, self).__init__()
self.add_argument(
'--compiler', choices=('clang', 'gcc'), default='clang')
self.add_argument(
'--bitness', choices=(32, 64), type=int, default=32)
self.add_argument('--bitness', choices=(32, 64), type=int, default=32)
self.add_argument('--host', action='store_true')
def gen_test_config(bitness, compiler, host):
"""Generates the test configuration makefile for buildcmds."""
testconfig_mk_path = os.path.join(THIS_DIR, 'buildcmds/testconfig.mk')
with open(testconfig_mk_path, 'w') as test_config:
if compiler == 'clang':
print('LOCAL_CLANG := true', file=test_config)
elif compiler == 'gcc':
print('LOCAL_CLANG := false', file=test_config)
def extract_build_cmds(commands, exe_name):
"""Extracts build command information from `ninja -t commands` output.
if bitness == 32:
print('LOCAL_MULTILIB := 32', file=test_config)
elif bitness == 64:
print('LOCAL_MULTILIB := 64', file=test_config)
Args:
commands: String containing the output of `ninja -t commands` for the
libcxx_test_template.
exe_name: The basename of the built executable.
if compiler == 'clang':
print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc $(CLANG_CXX)',
file=test_config)
else:
if host:
prefix = 'HOST_'
else:
prefix = 'TARGET_'
print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc '
'$($(LOCAL_2ND_ARCH_VAR_PREFIX){}CXX)'.format(prefix),
file=test_config)
Returns:
Tuple of (compiler, compiler_flags, linker_flags).
"""
cc = None
cflags = None
ldflags = None
template_name = 'external/libcxx/libcxx_test_template.cpp'
if host:
print('include $(BUILD_HOST_EXECUTABLE)', file=test_config)
else:
print('include $(BUILD_EXECUTABLE)', file=test_config)
for cmd in commands.splitlines():
cmd_args = cmd.split()
if cc is None and template_name in cmd_args:
for i, arg in enumerate(cmd_args):
if arg == '-o':
cmd_args[i + 1] = '%OUT%'
elif arg == template_name:
cmd_args[i] = '%SOURCE%'
# Drop dependency tracking args since they can cause file
# not found errors at test time.
if arg == '-MD':
cmd_args[i] = ''
if arg == '-MF':
cmd_args[i] = ''
cmd_args[i + 1] = ''
if cmd_args[0] == 'PWD=/proc/self/cwd':
cmd_args = cmd_args[1:]
if cmd_args[0].endswith('gomacc'):
cmd_args = cmd_args[1:]
cc = cmd_args[0]
cflags = cmd_args[1:]
if ldflags is None:
is_ld = False
for i, arg in enumerate(cmd_args):
# Here we assume that the rspfile contains the path to the
# object file and nothing else.
if arg.startswith('@'):
cmd_args[i] = '%SOURCE%'
if arg == '-o' and cmd_args[i + 1].endswith(exe_name):
cmd_args[i + 1] = '%OUT%'
is_ld = True
if is_ld:
ldflags = cmd_args[1:]
return cc, cflags, ldflags
def mmm(path):
"""Invokes the Android build command mmm."""
makefile = os.path.join(path, 'Android.mk')
main_mk = 'build/core/main.mk'
def get_build_cmds(bitness, host):
"""Use ninja -t commands to find the build commands for an executable."""
out_dir = os.getenv('OUT_DIR', os.path.join(ANDROID_DIR, 'out'))
product_out = os.getenv('ANDROID_PRODUCT_OUT')
env = dict(os.environ)
env['ONE_SHOT_MAKEFILE'] = makefile
env['LIBCXX_TESTING'] = 'true'
cmd = [
'make', '-j', '-C', ANDROID_DIR, '-f', main_mk,
'MODULES-IN-' + path.replace('/', '-'),
]
check_call(cmd, env=env)
if host:
rel_out_dir = os.path.relpath(
os.path.join(out_dir, 'soong/host/linux-x86/bin'), ANDROID_DIR)
target = os.path.join(rel_out_dir, 'libcxx_test_template64')
else:
exe_name = 'libcxx_test_template' + str(bitness)
rel_out_dir = os.path.relpath(product_out, ANDROID_DIR)
target = os.path.join(rel_out_dir, 'system/bin', exe_name)
# Generate $OUT_DIR/combined-$TARGET_PRODUCT.ninja and build the
# template target's dependencies.
check_call(['make', '-C', ANDROID_DIR, target])
def gen_build_cmds(bitness, compiler, host):
"""Generates the build commands file for the test runner."""
gen_test_config(bitness, compiler, host)
mmm('external/libcxx/buildcmds')
ninja_path = os.path.join(
out_dir, 'combined-' + os.getenv('TARGET_PRODUCT') + '.ninja')
commands = check_output([
os.path.join(ANDROID_DIR, 'prebuilts/build-tools/linux-x86/bin/ninja'),
'-C', ANDROID_DIR, '-f', ninja_path, '-t', 'commands', target
])
return extract_build_cmds(commands, os.path.basename(target))
def main():
@@ -116,20 +148,27 @@ def main():
args, lit_args = ArgParser().parse_known_args()
lit_path = os.path.join(ANDROID_DIR, 'external/llvm/utils/lit/lit.py')
gen_build_cmds(args.bitness, args.compiler, args.host)
cc, cflags, ldflags = get_build_cmds(args.bitness, args.host)
mode_str = 'host' if args.host else 'device'
android_mode_arg = '--param=android_mode=' + mode_str
cxx_under_test_arg = '--param=cxx_under_test=' + cc
cxx_template_arg = '--param=cxx_template=' + ' '.join(cflags)
link_template_arg = '--param=link_template=' + ' '.join(ldflags)
site_cfg_path = os.path.join(THIS_DIR, 'test/lit.site.cfg')
site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path
default_test_path = os.path.join(THIS_DIR, 'test')
libcxx_site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path
libcxxabi_site_cfg_arg = '--param=libcxxabi_site_config=' + site_cfg_path
default_test_paths = [
os.path.join(THIS_DIR, 'test'),
os.path.join(ANDROID_DIR, 'external/libcxxabi/test')
]
have_filter_args = False
for arg in lit_args:
# If the argument is a valid path with default_test_path, it is a test
# If the argument is a valid path with default_test_paths, it is a test
# filter.
real_path = os.path.realpath(arg)
if not real_path.startswith(default_test_path):
if not any(real_path.startswith(path) for path in default_test_paths):
continue
if not os.path.exists(real_path):
continue
@@ -137,10 +176,13 @@ def main():
have_filter_args = True
break # No need to keep scanning.
lit_args = ['-sv', android_mode_arg, site_cfg_arg] + lit_args
lit_args = [
'-sv', android_mode_arg, cxx_under_test_arg, cxx_template_arg,
link_template_arg, libcxx_site_cfg_arg, libcxxabi_site_cfg_arg
] + lit_args
cmd = ['python', lit_path] + lit_args
if not have_filter_args:
cmd.append(default_test_path)
cmd += default_test_paths
sys.exit(call(cmd))

View File

@@ -1,7 +1,6 @@
import os
import libcxx.test.config
import libcxx.android.build
import libcxx.android.test.format
@@ -9,7 +8,6 @@ class Configuration(libcxx.test.config.Configuration):
def __init__(self, lit_config, config):
super(Configuration, self).__init__(lit_config, config)
self.cxx_under_test = None
self.build_cmds_dir = None
self.cxx_template = None
self.link_template = None

View File

@@ -1,13 +0,0 @@
import os
import subprocess
def mm(path, android_build_top):
env = os.environ
env['ONE_SHOT_MAKEFILE'] = os.path.join(path, 'Android.mk')
cmd = [
'make', '-C', android_build_top, '-f', 'build/core/main.mk',
'MODULES-IN-' + path.replace('/', '-'), '-B'
]
return not subprocess.Popen(cmd, stdout=None, stderr=None, env=env).wait()

View File

@@ -2,7 +2,6 @@ import os
import re
import libcxx.test.config
import libcxx.android.build
import libcxx.android.compiler
import libcxx.android.test.format
@@ -10,11 +9,9 @@ import libcxx.android.test.format
class Configuration(libcxx.test.config.Configuration):
def __init__(self, lit_config, config):
super(Configuration, self).__init__(lit_config, config)
self.build_cmds_dir = None
def configure(self):
self.configure_src_root()
self.configure_build_cmds()
self.configure_obj_root()
self.configure_cxx()
@@ -32,34 +29,24 @@ class Configuration(libcxx.test.config.Configuration):
list(self.config.available_features))
def configure_obj_root(self):
test_config_file = os.path.join(self.build_cmds_dir, 'testconfig.mk')
if 'HOST_NATIVE_TEST' in open(test_config_file).read():
if self.lit_config.params.get('android_mode') == 'host':
self.libcxx_obj_root = os.getenv('ANDROID_HOST_OUT')
else:
self.libcxx_obj_root = os.getenv('ANDROID_PRODUCT_OUT')
def configure_build_cmds(self):
os.chdir(self.config.android_root)
self.build_cmds_dir = 'external/libcxx/buildcmds'
if not libcxx.android.build.mm(self.build_cmds_dir,
self.config.android_root):
raise RuntimeError('Could not generate build commands.')
def configure_cxx(self):
cxx_under_test_file = os.path.join(self.build_cmds_dir,
'cxx_under_test')
cxx_under_test = open(cxx_under_test_file).read().strip()
cxx_template_file = os.path.join(self.build_cmds_dir, 'cxx.cmds')
cxx_template = open(cxx_template_file).read().strip()
link_template_file = os.path.join(self.build_cmds_dir, 'link.cmds')
link_template = open(link_template_file).read().strip()
cxx_under_test = self.lit_config.params.get('cxx_under_test')
cxx_template = self.lit_config.params.get('cxx_template')
link_template = self.lit_config.params.get('link_template')
self.cxx = libcxx.android.compiler.AndroidCXXCompiler(
cxx_under_test, cxx_template, link_template)
def configure_triple(self):
# The libcxxabi test suite needs this but it doesn't actually
# use it for anything important.
self.config.host_triple = ''
self.config.target_triple = self.cxx.get_triple()
def configure_features(self):