Make it easier to run test variants.

This adds all the permutations for tests as make targets of the form
test-libcxx-(host|target)-(clang|gcc)-(32|64).

This also changes the host tests to use the Android build system (like
I had done with https://android-review.googlesource.com/#/c/111924/).
This probably should have been a separate patch, but I got carried
away (and wanted to make sure this new approach would work for both),
and now they're non-trivial to split.

Change-Id: Ie99caf6c3ff21c833408f99d37299d966ee7bc94
This commit is contained in:
Dan Albert
2015-01-07 16:16:05 -08:00
parent 3461be0c17
commit 78f8c1981e
8 changed files with 212 additions and 62 deletions

View File

@@ -126,15 +126,56 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_SHARED_LIBRARY)
LIT := $(ANDROID_BUILD_TOP)/external/llvm/utils/lit/lit.py
test-libcxx-host: libc++
LIT=$(LIT) LIT_MODE=host make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
test-libcxx-target: libc++
LIT=$(LIT) LIT_MODE=device make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
LIBCXX_CONFIGTESTS := $(ANDROID_BUILD_TOP)/external/libcxx/buildcmds/configtests.py
LIBCXX_TEST_MK := $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
test-libcxx-target: test-libcxx-target-clang
test-libcxx-host: test-libcxx-host-clang
test-libcxx-target-clang: libc++
python $(LIBCXX_CONFIGTESTS) --compiler=clang
LIT=$(LIT) LIT_MODE=device make -f $(LIBCXX_TEST_MK)
test-libcxx-target-gcc: libc++
python $(LIBCXX_CONFIGTESTS) --compiler=gcc
LIT=$(LIT) LIT_MODE=device make -f $(LIBCXX_TEST_MK)
test-libcxx-target-clang-32: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=32 --compiler=clang
LIT=$(LIT) LIT_MODE=device make -f $(LIBCXX_TEST_MK)
test-libcxx-target-gcc-32: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=32 --compiler=gcc
LIT=$(LIT) LIT_MODE=device make -f $(LIBCXX_TEST_MK)
test-libcxx-target-clang-64: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=64 --compiler=clang
LIT=$(LIT) LIT_MODE=device make -f $(LIBCXX_TEST_MK)
test-libcxx-target-gcc-64: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=64 --compiler=gcc
LIT=$(LIT) LIT_MODE=device make -f $(LIBCXX_TEST_MK)
test-libcxx-host-clang: libc++
python $(LIBCXX_CONFIGTESTS) --compiler=clang --host
LIT=$(LIT) LIT_MODE=host make -f $(LIBCXX_TEST_MK)
test-libcxx-host-gcc: libc++
python $(LIBCXX_CONFIGTESTS) --compiler=gcc --host
LIT=$(LIT) LIT_MODE=host make -f $(LIBCXX_TEST_MK)
test-libcxx-host-clang-32: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=32 --compiler=clang --host
LIT=$(LIT) LIT_MODE=host make -f $(LIBCXX_TEST_MK)
test-libcxx-host-gcc-32: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=32 --compiler=gcc --host
LIT=$(LIT) LIT_MODE=host make -f $(LIBCXX_TEST_MK)
test-libcxx-host-clang-64: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=64 --compiler=clang --host
LIT=$(LIT) LIT_MODE=host make -f $(LIBCXX_TEST_MK)
test-libcxx-host-gcc-64: libc++
python $(LIBCXX_CONFIGTESTS) --bitness=64 --compiler=gcc --host
LIT=$(LIT) LIT_MODE=host make -f $(LIBCXX_TEST_MK)
# Don't want to just make test-libcxx-(host|target) dependencies of this because
# the two families can't be run concurrently.
test-libcxx: libc++
python buildcmds/configtests.py --host
LIT=$(LIT) LIT_MODE=host make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
python buildcmds/configtests.py
LIT=$(LIT) LIT_MODE=device make -f $(ANDROID_BUILD_TOP)/external/libcxx/test.mk
endif # TARGET_BUILD_APPS

4
buildcmds/.gitignore vendored Normal file
View File

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

View File

@@ -21,7 +21,6 @@ ifeq (,$(TARGET_BUILD_APPS))
include $(CLEAR_VARS)
LOCAL_MODULE := libc++_build_commands_$(ANDROID_DEVICE)
LOCAL_CXX := $(LOCAL_PATH)/buildcmdscc $(CLANG_CXX)
LOCAL_SRC_FILES := dummy.cpp
LOCAL_CXX_STL := libc++
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../test/support
@@ -37,7 +36,6 @@ LOCAL_CPPFLAGS := \
LOCAL_CPPFLAGS += -O0
LOCAL_RTTI_FLAG := -frtti
LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)
include $(LOCAL_PATH)/testconfig.mk
endif

61
buildcmds/configtests.py Normal file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python
from __future__ import print_function
import getopt
import sys
def main():
try:
opts, _ = getopt.getopt(sys.argv[1:], '', [
'bitness=', 'compiler=', 'host'])
except getopt.GetoptError as err:
sys.exit(err)
bitness = None
compiler = 'clang'
host = False
for opt, val in opts:
if opt == '--bitness':
bitness = int(val)
if bitness not in (32, 64):
sys.exit('Invalid bitness: {}'.format(bitness))
elif opt == '--compiler':
if val not in ('clang', 'gcc'):
sys.exit('Unknown compiler: {}'.format(val))
compiler = val
elif opt == '--host':
host = True
else:
raise NotImplementedError('unhandled option: {}'.format(opt))
with open('external/libcxx/buildcmds/testconfig.mk', '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:
print('LOCAL_MULTILIB := 32', file=test_config)
elif bitness == 64:
print('LOCAL_MULTILIB := 64', file=test_config)
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)
if host:
print('include $(BUILD_HOST_EXECUTABLE)', file=test_config)
else:
print('include $(BUILD_EXECUTABLE)', file=test_config)
if __name__ == '__main__':
main()

View File

@@ -1,6 +1,4 @@
.NOTPARALLEL:
default:
cp $(ANDROID_BUILD_TOP)/external/libcxx/test/lit.$(LIT_MODE).cfg \
$(ANDROID_BUILD_TOP)/external/libcxx/test/lit.site.cfg
-python $(LIT) -sv $(ANDROID_BUILD_TOP)/external/libcxx/test
rm $(ANDROID_BUILD_TOP)/external/libcxx/test/lit.site.cfg
-python $(LIT) -sv --param android_mode=$(LIT_MODE) \
$(ANDROID_BUILD_TOP)/external/libcxx/test

View File

@@ -204,6 +204,52 @@ class LibcxxTestFormat(lit.formats.FileBasedTest):
return lit.Test.PASS, ""
class AndroidHostLibcxxTestFormat(LibcxxTestFormat):
def __init__(self, cxx_under_test, libcxx_src_root, libcxx_obj_root,
cxx_template, link_template, timeout):
self.cxx_under_test = cxx_under_test
self.libcxx_src_root = libcxx_src_root
self.libcxx_obj_root = libcxx_obj_root
self.cxx_template = cxx_template
self.link_template = link_template
self.timeout = timeout
self.use_verify_for_fail = False
def _compile(self, output_path, source_path, use_verify=False):
if use_verify:
raise NotImplementedError(
'AndroidConfiguration does not support use_verify mode.')
cxx_args = self.cxx_template.replace('%OUT%', output_path)
cxx_args = cxx_args.replace('%SOURCE%', source_path)
cmd = [self.cxx_under_test] + shlex.split(cxx_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _link(self, exec_path, object_path):
link_args = self.link_template.replace('%OUT%', exec_path)
link_args = link_args.replace('%SOURCE%', object_path)
cmd = [self.cxx_under_test] + shlex.split(link_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _run(self, exec_path, lit_config, in_dir=None):
cmd = [exec_path]
# We need to use LD_LIBRARY_PATH because the build system's rpath is
# relative, which won't work since we're running from /tmp. We can
# either scan `cxx_under_test`/`link_template` to determine whether
# we're 32-bit or 64-bit, scan testconfig.mk, or just add both
# directories and let the linker sort it out. I'm choosing the lazy
# option.
outdir = os.getenv('ANDROID_HOST_OUT')
libpath = os.pathsep.join([
os.path.join(outdir, 'lib'),
os.path.join(outdir, 'lib64'),
])
out, err, rc = lit.util.executeCommand(
cmd, cwd=in_dir, env={'LD_LIBRARY_PATH': libpath})
return self._make_report(cmd, out, err, rc)
class AdbError(RuntimeError):
def __init__(self, cmd, out, err, exit_code):
self.cmd = cmd
@@ -212,17 +258,18 @@ class AdbError(RuntimeError):
self.exit_code = exit_code
class AndroidLibcxxTestFormat(LibcxxTestFormat):
class AndroidLibcxxTestFormat(AndroidHostLibcxxTestFormat):
def __init__(self, cxx_under_test, libcxx_src_root, libcxx_obj_root,
cxx_template, link_template, device_dir, timeout):
self.cxx_under_test = cxx_under_test
self.libcxx_src_root = libcxx_src_root
self.libcxx_obj_root = libcxx_obj_root
self.cxx_template = cxx_template
self.link_template = link_template
AndroidHostLibcxxTestFormat.__init__(
self,
cxx_under_test,
libcxx_src_root,
libcxx_obj_root,
cxx_template,
link_template,
timeout)
self.device_dir = device_dir
self.timeout = timeout
self.use_verify_for_fail = False
def _working_directory(self, file_name):
return os.path.join(self.device_dir, file_name)
@@ -242,23 +289,6 @@ class AndroidLibcxxTestFormat(LibcxxTestFormat):
if exit_code != 0:
raise AdbError(cmd, out, err, exit_code)
def _compile(self, output_path, source_path, use_verify=False):
if use_verify:
raise NotImplementedError(
'AndroidConfiguration does not support use_verify mode.')
cxx_args = self.cxx_template.replace('%OUT%', output_path)
cxx_args = cxx_args.replace('%SOURCE%', source_path)
cmd = [self.cxx_under_test] + shlex.split(cxx_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _link(self, exec_path, object_path):
link_args = self.link_template.replace('%OUT%', exec_path)
link_args = link_args.replace('%SOURCE%', object_path)
cmd = [self.cxx_under_test] + shlex.split(link_args)
out, err, exit_code = lit.util.executeCommand(cmd)
return cmd, out, err, exit_code
def _build(self, exec_path, source_path, compile_only=False,
use_verify=False):
cmd, report, rc = LibcxxTestFormat._build(
@@ -793,15 +823,38 @@ class AndroidConfiguration(Configuration):
self.link_template = open(link_template_file).read().strip()
def configure_triple(self):
match = re.search(r'-target\s+(\S+)', self.cxx_template)
if not match:
if 'clang' in self.cxx_under_test:
triple = self.configure_clang_triple()
else:
triple = self.configure_gcc_triple()
if not triple:
raise RuntimeError('Could not determine target triple.')
self.config.target_triple = match.group(1)
self.config.target_triple = triple
def configure_clang_triple(self):
match = re.search(r'-target\s+(\S+)', self.cxx_template)
if match:
return match.group(1)
return None
def configure_gcc_triple(self):
proc = subprocess.Popen([self.cxx_under_test, '-v'],
stderr=subprocess.PIPE)
_, stderr = proc.communicate()
for line in stderr.split('\n'):
print 'Checking {}'.format(line)
match = re.search(r'^Target: (.+)$', line)
if match:
return match.group(1)
return None
def configure_features(self):
self.config.available_features.add('long_tests')
def get_test_format(self):
mode = self.lit_config.params.get('android_mode', 'device')
if mode == 'device':
return AndroidLibcxxTestFormat(
self.cxx_under_test,
self.src_root,
@@ -810,6 +863,16 @@ class AndroidConfiguration(Configuration):
self.link_template,
getattr(self.config, 'device_dir', '/data/local/tmp/'),
getattr(self.config, 'timeout', '60'))
elif mode == 'host':
return AndroidHostLibcxxTestFormat(
self.cxx_under_test,
self.src_root,
self.obj_root,
self.cxx_template,
self.link_template,
getattr(self.config, 'timeout', '60'))
else:
raise RuntimeError('Invalid android_mode: {}'.format(mode))
# name: The name of this test suite.

View File

@@ -1,15 +0,0 @@
import os
android_root = os.getenv('ANDROID_BUILD_TOP')
config.cxx_under_test = os.path.join(
android_root, 'prebuilts/clang/linux-x86/host/3.5/bin/clang++')
config.cxx_has_stdcxx0x_flag = True
config.libcxx_src_root = os.path.join(android_root, 'external/libcxx')
config.libcxx_obj_root = os.getenv('ANDROID_HOST_OUT')
config.python_executable = "/usr/bin/python"
config.enable_shared = True
config.cxx_abi = "none"
# Let the main config do the real work.
lit_config.load_config(
config, os.path.join(config.libcxx_src_root, 'test/lit.cfg'))