Update run_tests.py to use Soong.

am: 26cd9b82f8

Change-Id: I0748261cf691ec81f681e6f95c639bcef6f5e2b9
This commit is contained in:
Peter Collingbourne
2018-12-05 18:20:08 -08:00
committed by android-build-merger
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 "-UNDEBUG",
// 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
// 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 os
import sys import sys
THIS_DIR = os.path.dirname(os.path.realpath(__file__)) THIS_DIR = os.path.dirname(os.path.realpath(__file__))
ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..')) 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) 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): class ArgParser(argparse.ArgumentParser):
"""Parses command line arguments.""" """Parses command line arguments."""
def __init__(self): def __init__(self):
super(ArgParser, self).__init__() super(ArgParser, self).__init__()
self.add_argument( self.add_argument('--bitness', choices=(32, 64), type=int, default=32)
'--compiler', choices=('clang', 'gcc'), default='clang')
self.add_argument(
'--bitness', choices=(32, 64), type=int, default=32)
self.add_argument('--host', action='store_true') self.add_argument('--host', action='store_true')
def gen_test_config(bitness, compiler, host): def extract_build_cmds(commands, exe_name):
"""Generates the test configuration makefile for buildcmds.""" """Extracts build command information from `ninja -t commands` output.
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)
if bitness == 32: Args:
print('LOCAL_MULTILIB := 32', file=test_config) commands: String containing the output of `ninja -t commands` for the
elif bitness == 64: libcxx_test_template.
print('LOCAL_MULTILIB := 64', file=test_config) exe_name: The basename of the built executable.
if compiler == 'clang': Returns:
print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc $(CLANG_CXX)', Tuple of (compiler, compiler_flags, linker_flags).
file=test_config) """
else: cc = None
if host: cflags = None
prefix = 'HOST_' ldflags = None
else: template_name = 'external/libcxx/libcxx_test_template.cpp'
prefix = 'TARGET_'
print('LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc '
'$($(LOCAL_2ND_ARCH_VAR_PREFIX){}CXX)'.format(prefix),
file=test_config)
if host: for cmd in commands.splitlines():
print('include $(BUILD_HOST_EXECUTABLE)', file=test_config) cmd_args = cmd.split()
else: if cc is None and template_name in cmd_args:
print('include $(BUILD_EXECUTABLE)', file=test_config) 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): def get_build_cmds(bitness, host):
"""Invokes the Android build command mmm.""" """Use ninja -t commands to find the build commands for an executable."""
makefile = os.path.join(path, 'Android.mk') out_dir = os.getenv('OUT_DIR', os.path.join(ANDROID_DIR, 'out'))
main_mk = 'build/core/main.mk' product_out = os.getenv('ANDROID_PRODUCT_OUT')
env = dict(os.environ) if host:
env['ONE_SHOT_MAKEFILE'] = makefile rel_out_dir = os.path.relpath(
env['LIBCXX_TESTING'] = 'true' os.path.join(out_dir, 'soong/host/linux-x86/bin'), ANDROID_DIR)
cmd = [ target = os.path.join(rel_out_dir, 'libcxx_test_template64')
'make', '-j', '-C', ANDROID_DIR, '-f', main_mk, else:
'MODULES-IN-' + path.replace('/', '-'), exe_name = 'libcxx_test_template' + str(bitness)
] rel_out_dir = os.path.relpath(product_out, ANDROID_DIR)
check_call(cmd, env=env) 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): ninja_path = os.path.join(
"""Generates the build commands file for the test runner.""" out_dir, 'combined-' + os.getenv('TARGET_PRODUCT') + '.ninja')
gen_test_config(bitness, compiler, host) commands = check_output([
mmm('external/libcxx/buildcmds') 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(): def main():
@@ -116,20 +148,27 @@ def main():
args, lit_args = ArgParser().parse_known_args() args, lit_args = ArgParser().parse_known_args()
lit_path = os.path.join(ANDROID_DIR, 'external/llvm/utils/lit/lit.py') 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' mode_str = 'host' if args.host else 'device'
android_mode_arg = '--param=android_mode=' + mode_str 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_path = os.path.join(THIS_DIR, 'test/lit.site.cfg')
site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path libcxx_site_cfg_arg = '--param=libcxx_site_config=' + site_cfg_path
default_test_path = os.path.join(THIS_DIR, 'test') 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 have_filter_args = False
for arg in lit_args: 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. # filter.
real_path = os.path.realpath(arg) 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 continue
if not os.path.exists(real_path): if not os.path.exists(real_path):
continue continue
@@ -137,10 +176,13 @@ def main():
have_filter_args = True have_filter_args = True
break # No need to keep scanning. 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 cmd = ['python', lit_path] + lit_args
if not have_filter_args: if not have_filter_args:
cmd.append(default_test_path) cmd += default_test_paths
sys.exit(call(cmd)) sys.exit(call(cmd))

View File

@@ -1,7 +1,6 @@
import os import os
import libcxx.test.config import libcxx.test.config
import libcxx.android.build
import libcxx.android.test.format import libcxx.android.test.format
@@ -9,7 +8,6 @@ class Configuration(libcxx.test.config.Configuration):
def __init__(self, lit_config, config): def __init__(self, lit_config, config):
super(Configuration, self).__init__(lit_config, config) super(Configuration, self).__init__(lit_config, config)
self.cxx_under_test = None self.cxx_under_test = None
self.build_cmds_dir = None
self.cxx_template = None self.cxx_template = None
self.link_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 re
import libcxx.test.config import libcxx.test.config
import libcxx.android.build
import libcxx.android.compiler import libcxx.android.compiler
import libcxx.android.test.format import libcxx.android.test.format
@@ -10,11 +9,9 @@ import libcxx.android.test.format
class Configuration(libcxx.test.config.Configuration): class Configuration(libcxx.test.config.Configuration):
def __init__(self, lit_config, config): def __init__(self, lit_config, config):
super(Configuration, self).__init__(lit_config, config) super(Configuration, self).__init__(lit_config, config)
self.build_cmds_dir = None
def configure(self): def configure(self):
self.configure_src_root() self.configure_src_root()
self.configure_build_cmds()
self.configure_obj_root() self.configure_obj_root()
self.configure_cxx() self.configure_cxx()
@@ -32,34 +29,24 @@ class Configuration(libcxx.test.config.Configuration):
list(self.config.available_features)) list(self.config.available_features))
def configure_obj_root(self): def configure_obj_root(self):
test_config_file = os.path.join(self.build_cmds_dir, 'testconfig.mk') if self.lit_config.params.get('android_mode') == 'host':
if 'HOST_NATIVE_TEST' in open(test_config_file).read():
self.libcxx_obj_root = os.getenv('ANDROID_HOST_OUT') self.libcxx_obj_root = os.getenv('ANDROID_HOST_OUT')
else: else:
self.libcxx_obj_root = os.getenv('ANDROID_PRODUCT_OUT') 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): def configure_cxx(self):
cxx_under_test_file = os.path.join(self.build_cmds_dir, cxx_under_test = self.lit_config.params.get('cxx_under_test')
'cxx_under_test') cxx_template = self.lit_config.params.get('cxx_template')
cxx_under_test = open(cxx_under_test_file).read().strip() link_template = self.lit_config.params.get('link_template')
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()
self.cxx = libcxx.android.compiler.AndroidCXXCompiler( self.cxx = libcxx.android.compiler.AndroidCXXCompiler(
cxx_under_test, cxx_template, link_template) cxx_under_test, cxx_template, link_template)
def configure_triple(self): 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() self.config.target_triple = self.cxx.get_triple()
def configure_features(self): def configure_features(self):