Major change in this revision is that tests get placed into their own working
directory on the device rather than being lumped in together. This is done
because we need to also push any .dat files that live in the same directory as
the test source file to the device as well, and there are duplicate .dat files
in the test tree that prevent us from placing them all in the same directory.
There's also a small refactoring of some of the ADB calls.
http://reviews.llvm.org/D4594
Files:
test/lit.cfg
Index: test/lit.cfg
===================================================================
--- test/lit.cfg
+++ test/lit.cfg
@@ -91,6 +91,31 @@
# Evaluate the test.
return self._evaluate_test(test, lit_config)
+ def _build(self, exec_path, source_path, compile_only=False):
+ cmd = [self.cxx_under_test, self.cxx_under_test, '-o', exec_path,
+ source_path] + self.cpp_flags
+ if compile_only:
+ cmd += ['-c']
+ else:
+ cmd += self.ld_flags
+ out, err, exitCode = self.execute_command(cmd)
+ return cmd, out, err, exitCode
+
+ def _clean(self, exec_path):
+ os.remove(exec_path)
+
+ def _run(self, exec_path, lit_config, in_dir=None):
+ cmd = []
+ if self.exec_env:
+ cmd.append('env')
+ cmd.extend('%s=%s' % (name, value)
+ for name, value in self.exec_env.items())
+ cmd.append(exec_path)
+ if lit_config.useValgrind:
+ cmd = lit_config.valgrindArgs + cmd
+ out, err, exitCode = self.execute_command(cmd, in_dir)
+ return cmd, out, err, exitCode
+
def _evaluate_test(self, test, lit_config):
name = test.path_in_suite[-1]
source_path = test.getSourcePath()
@@ -102,9 +127,8 @@
# If this is a compile (failure) test, build it and check for failure.
if expected_compile_fail:
- cmd = [self.cxx_under_test, '-c',
- '-o', '/dev/null', source_path] + self.cpp_flags
- out, err, exitCode = self.execute_command(cmd)
+ cmd, out, err, exitCode = self._build('/dev/null', source_path,
+ compile_only=True)
if exitCode == 1:
return lit.Test.PASS, ""
else:
@@ -123,10 +147,8 @@
exec_file.close()
try:
- compile_cmd = [self.cxx_under_test, '-o', exec_path,
- source_path] + self.cpp_flags + self.ld_flags
- cmd = compile_cmd
- out, err, exitCode = self.execute_command(cmd)
+ cmd, out, err, exitCode = self._build(exec_path, source_path)
+ compile_cmd = cmd
if exitCode != 0:
report = """Command: %s\n""" % ' '.join(["'%s'" % a
for a in cmd])
@@ -138,15 +160,8 @@
report += "\n\nCompilation failed unexpectedly!"
return lit.Test.FAIL, report
- cmd = []
- if self.exec_env:
- cmd.append('env')
- cmd.extend('%s=%s' % (name, value)
- for name,value in self.exec_env.items())
- cmd.append(exec_path)
- if lit_config.useValgrind:
- cmd = lit_config.valgrindArgs + cmd
- out, err, exitCode = self.execute_command(cmd, source_dir)
+ cmd, out, err, exitCode = self._run(exec_path, lit_config,
+ source_dir)
if exitCode != 0:
report = """Compiled With: %s\n""" % \
' '.join(["'%s'" % a for a in compile_cmd])
@@ -161,11 +176,113 @@
return lit.Test.FAIL, report
finally:
try:
- os.remove(exec_path)
+ self._clean(exec_path)
except:
pass
return lit.Test.PASS, ""
+
+class AdbError(RuntimeError):
+ def __init__(cmd, out, err, exit_code):
+ self.cmd = cmd
+ self.out = out
+ self.err = err
+ self.exit_code = exit_code
+
+
+class AndroidLibcxxTestFormat(LibcxxTestFormat):
+ def __init__(self, cxx_under_test, libcxx_src_root, libcxx_obj_root,
+ cpp_flags, ld_flags, crtbegin, crtend, 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.cpp_flags = cpp_flags
+ self.ld_flags = ld_flags
+ self.crtbegin = crtbegin
+ self.crtend = crtend
+ self.device_dir = device_dir
+ self.timeout = timeout
+
+ def _working_directory(self, file_name):
+ return os.path.join(self.device_dir, file_name)
+
+ def _wd_path(self, test_name, file_name):
+ return os.path.join(self._working_directory(test_name), file_name)
+
+ def _adb_mkdir(self, path):
+ cmd = ['adb', 'shell', 'mkdir', path]
+ out, err, exit_code = self.execute_command(cmd)
+ if exit_code != 0:
+ raise AdbError(cmd, out, err, exit_code)
+
+ def _adb_push(self, src, dst):
+ cmd = ['adb', 'push', src, dst]
+ out, err, exit_code = self.execute_command(cmd)
+ if exit_code != 0:
+ raise AdbError(cmd, out, err, exit_code)
+
+ def _build(self, exec_path, source_path, compile_only=False):
+ cmd = [self.cxx_under_test, '-o', exec_path] + self.cpp_flags
+ if compile_only:
+ cmd += ['-c', source_path]
+ else:
+ cmd += [self.crtbegin, source_path] + self.ld_flags + [self.crtend]
+ try:
+ out, err, exit_code = self.execute_command(cmd)
+ if exit_code != 0:
+ return cmd, out, err, exit_code
+ exec_file = os.path.basename(exec_path)
+
+ self._adb_mkdir(self._working_directory(exec_file))
+ self._adb_push(exec_path, self._wd_path(exec_file, exec_file))
+
+ # Push any .dat files in the same directory as the source to the
+ # working directory.
+ src_dir = os.path.dirname(source_path)
+ data_files = [f for f in os.listdir(src_dir) if f.endswith('.dat')]
+ for data_file in data_files:
+ df_path = os.path.join(src_dir, data_file)
+ df_dev_path = self._wd_path(exec_file, data_file)
+ self._adb_push(df_path, df_dev_path)
+ return cmd, out, err, exit_code
+ except AdbError as ex:
+ return ex.cmd, ex.out, ex.err, ex.exit_code
+ except:
+ return cmd, out, err, exit_code
+
+ def _clean(self, exec_path):
+ exec_file = os.path.basename(exec_path)
+ cmd = ['adb', 'shell', 'rm', '-rf', self._working_directory(exec_file)]
+ self.execute_command(cmd)
+ os.remove(exec_path)
+
+ def _run(self, exec_path, lit_config, in_dir=None):
+ exec_file = os.path.basename(exec_path)
+ shell_cmd = 'cd {} && {}; echo $?'.format(
+ self._working_directory(exec_file),
+ self._wd_path(exec_file, exec_file))
+ cmd = ['timeout', self.timeout, 'adb', 'shell', shell_cmd]
+
+ # Tests will commonly fail with ETXTBSY. Possibly related to this bug:
+ # https://code.google.com/p/android/issues/detail?id=65857. Work around
+ # it by just waiting a second and then retrying.
+ for _ in range(10):
+ out, err, exit_code = self.execute_command(cmd)
+ if exit_code == 0:
+ if 'Text file busy' in out:
+ time.sleep(1)
+ else:
+ out = out.strip().split('\r\n')
+ status_line = out[-1:][0]
+ out = '\n'.join(out[:-1])
+ exit_code = int(status_line)
+ break
+ else:
+ err += '\nTimed out after {} seconds'.format(self.timeout)
+ break
+ return cmd, out, err, exit_code
+
+
# name: The name of this test suite.
config.name = 'libc++'
@@ -175,132 +292,162 @@
# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)
-# Gather various compiler parameters.
-cxx_under_test = lit_config.params.get('cxx_under_test', None)
-if cxx_under_test is None:
- cxx_under_test = getattr(config, 'cxx_under_test', None)
-
- # If no specific cxx_under_test was given, attempt to infer it as clang++.
+if getattr(config, 'android', False):
+ android_root = getattr(config, 'android_root', None)
+ if not android_root:
+ lit_config.fatal('config.android_root must be set')
+ cxx_under_test = lit_config.params.get('cxx_under_test', None)
if cxx_under_test is None:
- clangxx = lit.util.which('clang++', config.environment['PATH'])
- if clangxx is not None:
- cxx_under_test = clangxx
- lit_config.note("inferred cxx_under_test as: %r" % (cxx_under_test,))
-if cxx_under_test is None:
- lit_config.fatal('must specify user parameter cxx_under_test '
- '(e.g., --param=cxx_under_test=clang++)')
-
-libcxx_src_root = lit_config.params.get('libcxx_src_root', None)
-if libcxx_src_root is None:
- libcxx_src_root = getattr(config, 'libcxx_src_root', None)
+ cxx_under_test = getattr(config, 'cxx_under_test', None)
+ if cxx_under_test is None:
+ lit_config.fatal('config.cxx_under_test must be set')
+ libcxx_src_root = lit_config.params.get('libcxx_src_root', None)
if libcxx_src_root is None:
- libcxx_src_root = os.path.dirname(config.test_source_root)
+ libcxx_src_root = getattr(config, 'libcxx_src_root', None)
+ if libcxx_src_root is None:
+ libcxx_src_root = os.path.dirname(config.test_source_root)
+ libcxx_obj_root = lit_config.params.get('libcxx_obj_root', None)
+ if libcxx_obj_root is None:
+ libcxx_obj_root = getattr(config, 'libcxx_obj_root', None)
+ if libcxx_obj_root is None:
+ libcxx_obj_root = libcxx_src_root
+ config.test_format = AndroidLibcxxTestFormat(
+ cxx_under_test,
+ libcxx_src_root,
+ libcxx_obj_root,
+ config.cppflags,
+ config.ldflags,
+ config.crtbegin,
+ config.crtend,
+ getattr(config, 'device_dir', '/data/local/tmp/'),
+ getattr(config, 'timeout', '30'))
+else:
+ # Gather various compiler parameters.
+ cxx_under_test = lit_config.params.get('cxx_under_test', None)
+ if cxx_under_test is None:
+ cxx_under_test = getattr(config, 'cxx_under_test', None)
+
+ # If no specific cxx_under_test was given, attempt to infer it as clang++.
+ if cxx_under_test is None:
+ clangxx = lit.util.which('clang++', config.environment['PATH'])
+ if clangxx is not None:
+ cxx_under_test = clangxx
+ lit_config.note("inferred cxx_under_test as: %r" % (cxx_under_test,))
+ if cxx_under_test is None:
+ lit_config.fatal('must specify user parameter cxx_under_test '
+ '(e.g., --param=cxx_under_test=clang++)')
+
+ libcxx_src_root = lit_config.params.get('libcxx_src_root', None)
+ if libcxx_src_root is None:
+ libcxx_src_root = getattr(config, 'libcxx_src_root', None)
+ if libcxx_src_root is None:
+ libcxx_src_root = os.path.dirname(config.test_source_root)
-libcxx_obj_root = lit_config.params.get('libcxx_obj_root', None)
-if libcxx_obj_root is None:
- libcxx_obj_root = getattr(config, 'libcxx_obj_root', None)
+ libcxx_obj_root = lit_config.params.get('libcxx_obj_root', None)
if libcxx_obj_root is None:
- libcxx_obj_root = libcxx_src_root
-
-cxx_has_stdcxx0x_flag_str = lit_config.params.get('cxx_has_stdcxx0x_flag', None)
-if cxx_has_stdcxx0x_flag_str is not None:
- if cxx_has_stdcxx0x_flag_str.lower() in ('1', 'true'):
- cxx_has_stdcxx0x_flag = True
- elif cxx_has_stdcxx0x_flag_str.lower() in ('', '0', 'false'):
- cxx_has_stdcxx0x_flag = False
+ libcxx_obj_root = getattr(config, 'libcxx_obj_root', None)
+ if libcxx_obj_root is None:
+ libcxx_obj_root = libcxx_src_root
+
+ cxx_has_stdcxx0x_flag_str = lit_config.params.get('cxx_has_stdcxx0x_flag', None)
+ if cxx_has_stdcxx0x_flag_str is not None:
+ if cxx_has_stdcxx0x_flag_str.lower() in ('1', 'true'):
+ cxx_has_stdcxx0x_flag = True
+ elif cxx_has_stdcxx0x_flag_str.lower() in ('', '0', 'false'):
+ cxx_has_stdcxx0x_flag = False
+ else:
+ lit_config.fatal(
+ 'user parameter cxx_has_stdcxx0x_flag_str should be 0 or 1')
else:
- lit_config.fatal(
- 'user parameter cxx_has_stdcxx0x_flag_str should be 0 or 1')
-else:
- cxx_has_stdcxx0x_flag = getattr(config, 'cxx_has_stdcxx0x_flag', True)
-
-# This test suite supports testing against either the system library or the
-# locally built one; the former mode is useful for testing ABI compatibility
-# between the current headers and a shipping dynamic library.
-use_system_lib_str = lit_config.params.get('use_system_lib', None)
-if use_system_lib_str is not None:
- if use_system_lib_str.lower() in ('1', 'true'):
- use_system_lib = True
- elif use_system_lib_str.lower() in ('', '0', 'false'):
- use_system_lib = False
+ cxx_has_stdcxx0x_flag = getattr(config, 'cxx_has_stdcxx0x_flag', True)
+
+ # This test suite supports testing against either the system library or the
+ # locally built one; the former mode is useful for testing ABI compatibility
+ # between the current headers and a shipping dynamic library.
+ use_system_lib_str = lit_config.params.get('use_system_lib', None)
+ if use_system_lib_str is not None:
+ if use_system_lib_str.lower() in ('1', 'true'):
+ use_system_lib = True
+ elif use_system_lib_str.lower() in ('', '0', 'false'):
+ use_system_lib = False
+ else:
+ lit_config.fatal('user parameter use_system_lib should be 0 or 1')
else:
- lit_config.fatal('user parameter use_system_lib should be 0 or 1')
-else:
- # Default to testing against the locally built libc++ library.
- use_system_lib = False
- lit_config.note("inferred use_system_lib as: %r" % (use_system_lib,))
-
-link_flags = []
-link_flags_str = lit_config.params.get('link_flags', None)
-if link_flags_str is None:
- link_flags_str = getattr(config, 'link_flags', None)
+ # Default to testing against the locally built libc++ library.
+ use_system_lib = False
+ lit_config.note("inferred use_system_lib as: %r" % (use_system_lib,))
+
+ link_flags = []
+ link_flags_str = lit_config.params.get('link_flags', None)
if link_flags_str is None:
- cxx_abi = getattr(config, 'cxx_abi', 'libcxxabi')
- if cxx_abi == 'libstdc++':
- link_flags += ['-lstdc++']
- elif cxx_abi == 'libsupc++':
- link_flags += ['-lsupc++']
- elif cxx_abi == 'libcxxabi':
- link_flags += ['-lc++abi']
- elif cxx_abi == 'none':
- pass
- else:
- lit_config.fatal('C++ ABI setting %s unsupported for tests' % cxx_abi)
-
- if sys.platform == 'darwin':
- link_flags += ['-lSystem']
- elif sys.platform == 'linux2':
- link_flags += [ '-lgcc_eh', '-lc', '-lm', '-lpthread',
- '-lrt', '-lgcc_s']
- else:
+ link_flags_str = getattr(config, 'link_flags', None)
+ if link_flags_str is None:
+ cxx_abi = getattr(config, 'cxx_abi', 'libcxxabi')
+ if cxx_abi == 'libstdc++':
+ link_flags += ['-lstdc++']
+ elif cxx_abi == 'libsupc++':
+ link_flags += ['-lsupc++']
+ elif cxx_abi == 'libcxxabi':
+ link_flags += ['-lc++abi']
+ elif cxx_abi == 'none':
+ pass
+ else:
+ lit_config.fatal('C++ ABI setting %s unsupported for tests' % cxx_abi)
+
+ if sys.platform == 'darwin':
+ link_flags += ['-lSystem']
+ elif sys.platform == 'linux2':
+ link_flags += [ '-lgcc_eh', '-lc', '-lm', '-lpthread',
+ '-lrt', '-lgcc_s']
+ else:
+ lit_config.fatal("unrecognized system")
+
+ lit_config.note("inferred link_flags as: %r" % (link_flags,))
+ if not link_flags_str is None:
+ link_flags += shlex.split(link_flags_str)
+
+ # Configure extra compiler flags.
+ include_paths = ['-I' + libcxx_src_root + '/include',
+ '-I' + libcxx_src_root + '/test/support']
+ library_paths = ['-L' + libcxx_obj_root + '/lib']
+ compile_flags = []
+ if cxx_has_stdcxx0x_flag:
+ compile_flags += ['-std=c++0x']
+
+ # Configure extra linker parameters.
+ exec_env = {}
+ if sys.platform == 'darwin':
+ if not use_system_lib:
+ exec_env['DYLD_LIBRARY_PATH'] = os.path.join(libcxx_obj_root, 'lib')
+ elif sys.platform == 'linux2':
+ if not use_system_lib:
+ link_flags += ['-Wl,-R', libcxx_obj_root + '/lib']
+ compile_flags += ['-D__STDC_FORMAT_MACROS', '-D__STDC_LIMIT_MACROS',
+ '-D__STDC_CONSTANT_MACROS']
+ else:
lit_config.fatal("unrecognized system")
- lit_config.note("inferred link_flags as: %r" % (link_flags,))
-if not link_flags_str is None:
- link_flags += shlex.split(link_flags_str)
-
-# Configure extra compiler flags.
-include_paths = ['-I' + libcxx_src_root + '/include',
- '-I' + libcxx_src_root + '/test/support']
-library_paths = ['-L' + libcxx_obj_root + '/lib']
-compile_flags = []
-if cxx_has_stdcxx0x_flag:
- compile_flags += ['-std=c++0x']
-
-# Configure extra linker parameters.
-exec_env = {}
-if sys.platform == 'darwin':
- if not use_system_lib:
- exec_env['DYLD_LIBRARY_PATH'] = os.path.join(libcxx_obj_root, 'lib')
-elif sys.platform == 'linux2':
- if not use_system_lib:
- link_flags += ['-Wl,-R', libcxx_obj_root + '/lib']
- compile_flags += ['-D__STDC_FORMAT_MACROS', '-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS']
-else:
- lit_config.fatal("unrecognized system")
-
-config.test_format = LibcxxTestFormat(
- cxx_under_test,
- cpp_flags = ['-nostdinc++'] + compile_flags + include_paths,
- ld_flags = ['-nodefaultlibs'] + library_paths + ['-lc++'] + link_flags,
- exec_env = exec_env)
-
-# Get or infer the target triple.
-config.target_triple = lit_config.params.get('target_triple', None)
-# If no target triple was given, try to infer it from the compiler under test.
-if config.target_triple is None:
- config.target_triple = lit.util.capture(
- [cxx_under_test, '-dumpmachine']).strip()
- lit_config.note("inferred target_triple as: %r" % (config.target_triple,))
-
-# Write an "available feature" that combines the triple when use_system_lib is
-# enabled. This is so that we can easily write XFAIL markers for tests that are
-# known to fail with versions of libc++ as were shipped with a particular
-# triple.
-if use_system_lib:
- # Drop sub-major version components from the triple, because the current
- # XFAIL handling expects exact matches for feature checks.
- sanitized_triple = re.sub(r"([^-]+)-([^-]+)-([^-.]+).*", r"\1-\2-\3",
- config.target_triple)
- config.available_features.add('with_system_lib=%s' % (sanitized_triple,))
+ config.test_format = LibcxxTestFormat(
+ cxx_under_test,
+ cpp_flags = ['-nostdinc++'] + compile_flags + include_paths,
+ ld_flags = ['-nodefaultlibs'] + library_paths + ['-lc++'] + link_flags,
+ exec_env = exec_env)
+
+ # Get or infer the target triple.
+ config.target_triple = lit_config.params.get('target_triple', None)
+ # If no target triple was given, try to infer it from the compiler under test.
+ if config.target_triple is None:
+ config.target_triple = lit.util.capture(
+ [cxx_under_test, '-dumpmachine']).strip()
+ lit_config.note("inferred target_triple as: %r" % (config.target_triple,))
+
+ # Write an "available feature" that combines the triple when use_system_lib is
+ # enabled. This is so that we can easily write XFAIL markers for tests that are
+ # known to fail with versions of libc++ as were shipped with a particular
+ # triple.
+ if use_system_lib:
+ # Drop sub-major version components from the triple, because the current
+ # XFAIL handling expects exact matches for feature checks.
+ sanitized_triple = re.sub(r"([^-]+)-([^-]+)-([^-.]+).*", r"\1-\2-\3",
+ config.target_triple)
+ config.available_features.add('with_system_lib=%s' % (sanitized_triple,))
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits