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
diff --git a/Android.mk b/Android.mk
index 0a10de1..9a1d4d0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,15 +126,56 @@
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 0000000..a77d525
--- /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 601c257..7849244 100644
--- a/buildcmds/Android.mk
+++ b/buildcmds/Android.mk
@@ -21,7 +21,6 @@
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 += -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 0000000..9a8b1e3
--- /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 31e8ed2..0837d11 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 33f1818..1fc7cee 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -204,6 +204,52 @@
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 @@
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 @@
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 @@
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 e2d9813..0000000
--- 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