From 78f8c1981eed69d751b26958ea12262d4c663fe6 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Wed, 7 Jan 2015 16:16:05 -0800 Subject: [PATCH] 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 --- Android.mk | 49 +++++++++- buildcmds/.gitignore | 4 + buildcmds/Android.mk | 4 +- buildcmds/configtests.py | 61 ++++++++++++ test.mk | 6 +- test/lit.cfg | 135 +++++++++++++++++++------- test/lit.host.cfg | 15 --- test/{lit.device.cfg => lit.site.cfg} | 0 8 files changed, 212 insertions(+), 62 deletions(-) create mode 100644 buildcmds/.gitignore create mode 100644 buildcmds/configtests.py delete mode 100644 test/lit.host.cfg rename test/{lit.device.cfg => lit.site.cfg} (100%) diff --git a/Android.mk b/Android.mk index 0a10de147..9a1d4d01f 100644 --- a/Android.mk +++ b/Android.mk @@ -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 diff --git a/buildcmds/.gitignore b/buildcmds/.gitignore new file mode 100644 index 000000000..a77d525cd --- /dev/null +++ b/buildcmds/.gitignore @@ -0,0 +1,4 @@ +cxx_under_test +cxx.cmds +link.cmds +testconfig.mk diff --git a/buildcmds/Android.mk b/buildcmds/Android.mk index 601c25726..784924417 100644 --- a/buildcmds/Android.mk +++ b/buildcmds/Android.mk @@ -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 diff --git a/buildcmds/configtests.py b/buildcmds/configtests.py new file mode 100644 index 000000000..9a8b1e3b8 --- /dev/null +++ b/buildcmds/configtests.py @@ -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() diff --git a/test.mk b/test.mk index 31e8ed291..0837d11a2 100644 --- a/test.mk +++ b/test.mk @@ -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 diff --git a/test/lit.cfg b/test/lit.cfg index 33f181880..1fc7ceee4 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -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,23 +823,56 @@ 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): - return AndroidLibcxxTestFormat( - self.cxx_under_test, - self.src_root, - self.obj_root, - self.cxx_template, - self.link_template, - getattr(self.config, 'device_dir', '/data/local/tmp/'), - getattr(self.config, 'timeout', '60')) + mode = self.lit_config.params.get('android_mode', 'device') + if mode == 'device': + return AndroidLibcxxTestFormat( + self.cxx_under_test, + self.src_root, + self.obj_root, + self.cxx_template, + 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. diff --git a/test/lit.host.cfg b/test/lit.host.cfg deleted file mode 100644 index e2d98137d..000000000 --- a/test/lit.host.cfg +++ /dev/null @@ -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')) diff --git a/test/lit.device.cfg b/test/lit.site.cfg similarity index 100% rename from test/lit.device.cfg rename to test/lit.site.cfg