Move libcxx/test/libcxx python package into libcxx/utils/libcxx.
This patch merges the test python package with the newly created package in utils. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@294651 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -1,291 +0,0 @@
|
||||
#===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.TXT for details.
|
||||
#
|
||||
#===----------------------------------------------------------------------===##
|
||||
|
||||
import platform
|
||||
import os
|
||||
import lit.util
|
||||
import libcxx.util
|
||||
|
||||
|
||||
class CXXCompiler(object):
|
||||
CM_Default = 0
|
||||
CM_PreProcess = 1
|
||||
CM_Compile = 2
|
||||
CM_Link = 3
|
||||
|
||||
def __init__(self, path, flags=None, compile_flags=None, link_flags=None,
|
||||
warning_flags=None, verify_supported=None,
|
||||
verify_flags=None, use_verify=False,
|
||||
modules_flags=None, use_modules=False,
|
||||
use_ccache=False, use_warnings=False, compile_env=None,
|
||||
cxx_type=None, cxx_version=None):
|
||||
self.path = path
|
||||
self.flags = list(flags or [])
|
||||
self.compile_flags = list(compile_flags or [])
|
||||
self.link_flags = list(link_flags or [])
|
||||
self.warning_flags = list(warning_flags or [])
|
||||
self.verify_supported = verify_supported
|
||||
self.use_verify = use_verify
|
||||
self.verify_flags = list(verify_flags or [])
|
||||
assert not use_verify or verify_supported
|
||||
assert not use_verify or verify_flags is not None
|
||||
self.modules_flags = list(modules_flags or [])
|
||||
self.use_modules = use_modules
|
||||
assert not use_modules or modules_flags is not None
|
||||
self.use_ccache = use_ccache
|
||||
self.use_warnings = use_warnings
|
||||
if compile_env is not None:
|
||||
self.compile_env = dict(compile_env)
|
||||
else:
|
||||
self.compile_env = None
|
||||
self.type = cxx_type
|
||||
self.version = cxx_version
|
||||
if self.type is None or self.version is None:
|
||||
self._initTypeAndVersion()
|
||||
|
||||
def isVerifySupported(self):
|
||||
if self.verify_supported is None:
|
||||
self.verify_supported = self.hasCompileFlag(['-Xclang',
|
||||
'-verify-ignore-unexpected'])
|
||||
if self.verify_supported:
|
||||
self.verify_flags = [
|
||||
'-Xclang', '-verify',
|
||||
'-Xclang', '-verify-ignore-unexpected=note',
|
||||
'-ferror-limit=1024'
|
||||
]
|
||||
return self.verify_supported
|
||||
|
||||
def useVerify(self, value=True):
|
||||
self.use_verify = value
|
||||
assert not self.use_verify or self.verify_flags is not None
|
||||
|
||||
def useModules(self, value=True):
|
||||
self.use_modules = value
|
||||
assert not self.use_modules or self.modules_flags is not None
|
||||
|
||||
def useCCache(self, value=True):
|
||||
self.use_ccache = value
|
||||
|
||||
def useWarnings(self, value=True):
|
||||
self.use_warnings = value
|
||||
|
||||
def _initTypeAndVersion(self):
|
||||
# Get compiler type and version
|
||||
macros = self.dumpMacros()
|
||||
if macros is None:
|
||||
return
|
||||
compiler_type = None
|
||||
major_ver = minor_ver = patchlevel = None
|
||||
if '__clang__' in macros.keys():
|
||||
compiler_type = 'clang'
|
||||
# Treat apple's llvm fork differently.
|
||||
if '__apple_build_version__' in macros.keys():
|
||||
compiler_type = 'apple-clang'
|
||||
major_ver = macros['__clang_major__']
|
||||
minor_ver = macros['__clang_minor__']
|
||||
patchlevel = macros['__clang_patchlevel__']
|
||||
elif '__GNUC__' in macros.keys():
|
||||
compiler_type = 'gcc'
|
||||
major_ver = macros['__GNUC__']
|
||||
minor_ver = macros['__GNUC_MINOR__']
|
||||
patchlevel = macros['__GNUC_PATCHLEVEL__']
|
||||
self.type = compiler_type
|
||||
self.version = (major_ver, minor_ver, patchlevel)
|
||||
|
||||
def _basicCmd(self, source_files, out, mode=CM_Default, flags=[],
|
||||
input_is_cxx=False):
|
||||
cmd = []
|
||||
if self.use_ccache \
|
||||
and not mode == self.CM_Link \
|
||||
and not mode == self.CM_PreProcess:
|
||||
cmd += ['ccache']
|
||||
cmd += [self.path]
|
||||
if out is not None:
|
||||
cmd += ['-o', out]
|
||||
if input_is_cxx:
|
||||
cmd += ['-x', 'c++']
|
||||
if isinstance(source_files, list):
|
||||
cmd += source_files
|
||||
elif isinstance(source_files, str):
|
||||
cmd += [source_files]
|
||||
else:
|
||||
raise TypeError('source_files must be a string or list')
|
||||
if mode == self.CM_PreProcess:
|
||||
cmd += ['-E']
|
||||
elif mode == self.CM_Compile:
|
||||
cmd += ['-c']
|
||||
cmd += self.flags
|
||||
if self.use_verify:
|
||||
cmd += self.verify_flags
|
||||
assert mode in [self.CM_Default, self.CM_Compile]
|
||||
if self.use_modules:
|
||||
cmd += self.modules_flags
|
||||
if mode != self.CM_Link:
|
||||
cmd += self.compile_flags
|
||||
if self.use_warnings:
|
||||
cmd += self.warning_flags
|
||||
if mode != self.CM_PreProcess and mode != self.CM_Compile:
|
||||
cmd += self.link_flags
|
||||
cmd += flags
|
||||
return cmd
|
||||
|
||||
def preprocessCmd(self, source_files, out=None, flags=[]):
|
||||
return self._basicCmd(source_files, out, flags=flags,
|
||||
mode=self.CM_PreProcess,
|
||||
input_is_cxx=True)
|
||||
|
||||
def compileCmd(self, source_files, out=None, flags=[]):
|
||||
return self._basicCmd(source_files, out, flags=flags,
|
||||
mode=self.CM_Compile,
|
||||
input_is_cxx=True) + ['-c']
|
||||
|
||||
def linkCmd(self, source_files, out=None, flags=[]):
|
||||
return self._basicCmd(source_files, out, flags=flags,
|
||||
mode=self.CM_Link)
|
||||
|
||||
def compileLinkCmd(self, source_files, out=None, flags=[]):
|
||||
return self._basicCmd(source_files, out, flags=flags)
|
||||
|
||||
def preprocess(self, source_files, out=None, flags=[], cwd=None):
|
||||
cmd = self.preprocessCmd(source_files, out, flags)
|
||||
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
|
||||
cwd=cwd)
|
||||
return cmd, out, err, rc
|
||||
|
||||
def compile(self, source_files, out=None, flags=[], cwd=None):
|
||||
cmd = self.compileCmd(source_files, out, flags)
|
||||
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
|
||||
cwd=cwd)
|
||||
return cmd, out, err, rc
|
||||
|
||||
def link(self, source_files, out=None, flags=[], cwd=None):
|
||||
cmd = self.linkCmd(source_files, out, flags)
|
||||
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
|
||||
cwd=cwd)
|
||||
return cmd, out, err, rc
|
||||
|
||||
def compileLink(self, source_files, out=None, flags=[],
|
||||
cwd=None):
|
||||
cmd = self.compileLinkCmd(source_files, out, flags)
|
||||
out, err, rc = lit.util.executeCommand(cmd, env=self.compile_env,
|
||||
cwd=cwd)
|
||||
return cmd, out, err, rc
|
||||
|
||||
def compileLinkTwoSteps(self, source_file, out=None, object_file=None,
|
||||
flags=[], cwd=None):
|
||||
if not isinstance(source_file, str):
|
||||
raise TypeError('This function only accepts a single input file')
|
||||
if object_file is None:
|
||||
# Create, use and delete a temporary object file if none is given.
|
||||
with_fn = lambda: libcxx.util.guardedTempFilename(suffix='.o')
|
||||
else:
|
||||
# Otherwise wrap the filename in a context manager function.
|
||||
with_fn = lambda: libcxx.util.nullContext(object_file)
|
||||
with with_fn() as object_file:
|
||||
cc_cmd, cc_stdout, cc_stderr, rc = self.compile(
|
||||
source_file, object_file, flags=flags, cwd=cwd)
|
||||
if rc != 0:
|
||||
return cc_cmd, cc_stdout, cc_stderr, rc
|
||||
|
||||
link_cmd, link_stdout, link_stderr, rc = self.link(
|
||||
object_file, out=out, flags=flags, cwd=cwd)
|
||||
return (cc_cmd + ['&&'] + link_cmd, cc_stdout + link_stdout,
|
||||
cc_stderr + link_stderr, rc)
|
||||
|
||||
def dumpMacros(self, source_files=None, flags=[], cwd=None):
|
||||
if source_files is None:
|
||||
source_files = os.devnull
|
||||
flags = ['-dM'] + flags
|
||||
cmd, out, err, rc = self.preprocess(source_files, flags=flags, cwd=cwd)
|
||||
if rc != 0:
|
||||
return None
|
||||
parsed_macros = {}
|
||||
lines = [l.strip() for l in out.split('\n') if l.strip()]
|
||||
for l in lines:
|
||||
assert l.startswith('#define ')
|
||||
l = l[len('#define '):]
|
||||
macro, _, value = l.partition(' ')
|
||||
parsed_macros[macro] = value
|
||||
return parsed_macros
|
||||
|
||||
def getTriple(self):
|
||||
cmd = [self.path] + self.flags + ['-dumpmachine']
|
||||
return lit.util.capture(cmd).strip()
|
||||
|
||||
def hasCompileFlag(self, flag):
|
||||
if isinstance(flag, list):
|
||||
flags = list(flag)
|
||||
else:
|
||||
flags = [flag]
|
||||
# Add -Werror to ensure that an unrecognized flag causes a non-zero
|
||||
# exit code. -Werror is supported on all known compiler types.
|
||||
if self.type is not None:
|
||||
flags += ['-Werror', '-fsyntax-only']
|
||||
cmd, out, err, rc = self.compile(os.devnull, out=os.devnull,
|
||||
flags=flags)
|
||||
return rc == 0
|
||||
|
||||
def addFlagIfSupported(self, flag):
|
||||
if isinstance(flag, list):
|
||||
flags = list(flag)
|
||||
else:
|
||||
flags = [flag]
|
||||
if self.hasCompileFlag(flags):
|
||||
self.flags += flags
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def addCompileFlagIfSupported(self, flag):
|
||||
if isinstance(flag, list):
|
||||
flags = list(flag)
|
||||
else:
|
||||
flags = [flag]
|
||||
if self.hasCompileFlag(flags):
|
||||
self.compile_flags += flags
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def hasWarningFlag(self, flag):
|
||||
"""
|
||||
hasWarningFlag - Test if the compiler supports a given warning flag.
|
||||
Unlike addCompileFlagIfSupported, this function detects when
|
||||
"-Wno-<warning>" flags are unsupported. If flag is a
|
||||
"-Wno-<warning>" GCC will not emit an unknown option diagnostic unless
|
||||
another error is triggered during compilation.
|
||||
"""
|
||||
assert isinstance(flag, str)
|
||||
assert flag.startswith('-W')
|
||||
if not flag.startswith('-Wno-'):
|
||||
return self.hasCompileFlag(flag)
|
||||
flags = ['-Werror', flag]
|
||||
old_use_warnings = self.use_warnings
|
||||
self.useWarnings(False)
|
||||
cmd = self.compileCmd('-', os.devnull, flags)
|
||||
self.useWarnings(old_use_warnings)
|
||||
# Remove '-v' because it will cause the command line invocation
|
||||
# to be printed as part of the error output.
|
||||
# TODO(EricWF): Are there other flags we need to worry about?
|
||||
if '-v' in cmd:
|
||||
cmd.remove('-v')
|
||||
out, err, rc = lit.util.executeCommand(
|
||||
cmd, input=lit.util.to_bytes('#error\n'))
|
||||
|
||||
assert rc != 0
|
||||
if flag in err:
|
||||
return False
|
||||
return True
|
||||
|
||||
def addWarningFlagIfSupported(self, flag):
|
||||
if self.hasWarningFlag(flag):
|
||||
if flag not in self.warning_flags:
|
||||
self.warning_flags += [flag]
|
||||
return True
|
||||
return False
|
||||
@@ -1,975 +0,0 @@
|
||||
#===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.TXT for details.
|
||||
#
|
||||
#===----------------------------------------------------------------------===##
|
||||
|
||||
import locale
|
||||
import os
|
||||
import platform
|
||||
import pkgutil
|
||||
import pipes
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import lit.Test # pylint: disable=import-error,no-name-in-module
|
||||
import lit.util # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
from libcxx.test.format import LibcxxTestFormat
|
||||
from libcxx.compiler import CXXCompiler
|
||||
from libcxx.test.target_info import make_target_info
|
||||
from libcxx.test.executor import *
|
||||
from libcxx.test.tracing import *
|
||||
|
||||
def loadSiteConfig(lit_config, config, param_name, env_name):
|
||||
# We haven't loaded the site specific configuration (the user is
|
||||
# probably trying to run on a test file directly, and either the site
|
||||
# configuration hasn't been created by the build system, or we are in an
|
||||
# out-of-tree build situation).
|
||||
site_cfg = lit_config.params.get(param_name,
|
||||
os.environ.get(env_name))
|
||||
if not site_cfg:
|
||||
lit_config.warning('No site specific configuration file found!'
|
||||
' Running the tests in the default configuration.')
|
||||
elif not os.path.isfile(site_cfg):
|
||||
lit_config.fatal(
|
||||
"Specified site configuration file does not exist: '%s'" %
|
||||
site_cfg)
|
||||
else:
|
||||
lit_config.note('using site specific configuration at %s' % site_cfg)
|
||||
ld_fn = lit_config.load_config
|
||||
|
||||
# Null out the load_config function so that lit.site.cfg doesn't
|
||||
# recursively load a config even if it tries.
|
||||
# TODO: This is one hell of a hack. Fix it.
|
||||
def prevent_reload_fn(*args, **kwargs):
|
||||
pass
|
||||
lit_config.load_config = prevent_reload_fn
|
||||
ld_fn(config, site_cfg)
|
||||
lit_config.load_config = ld_fn
|
||||
|
||||
class Configuration(object):
|
||||
# pylint: disable=redefined-outer-name
|
||||
def __init__(self, lit_config, config):
|
||||
self.lit_config = lit_config
|
||||
self.config = config
|
||||
self.is_windows = platform.system() == 'Windows'
|
||||
self.cxx = None
|
||||
self.cxx_is_clang_cl = None
|
||||
self.cxx_stdlib_under_test = None
|
||||
self.project_obj_root = None
|
||||
self.libcxx_src_root = None
|
||||
self.libcxx_obj_root = None
|
||||
self.cxx_library_root = None
|
||||
self.cxx_runtime_root = None
|
||||
self.abi_library_root = None
|
||||
self.link_shared = self.get_lit_bool('enable_shared', default=True)
|
||||
self.debug_build = self.get_lit_bool('debug_build', default=False)
|
||||
self.exec_env = {}
|
||||
self.use_target = False
|
||||
self.use_system_cxx_lib = False
|
||||
self.use_clang_verify = False
|
||||
self.long_tests = None
|
||||
self.execute_external = False
|
||||
|
||||
def get_lit_conf(self, name, default=None):
|
||||
val = self.lit_config.params.get(name, None)
|
||||
if val is None:
|
||||
val = getattr(self.config, name, None)
|
||||
if val is None:
|
||||
val = default
|
||||
return val
|
||||
|
||||
def get_lit_bool(self, name, default=None, env_var=None):
|
||||
def check_value(value, var_name):
|
||||
if value is None:
|
||||
return default
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
if not isinstance(value, str):
|
||||
raise TypeError('expected bool or string')
|
||||
if value.lower() in ('1', 'true'):
|
||||
return True
|
||||
if value.lower() in ('', '0', 'false'):
|
||||
return False
|
||||
self.lit_config.fatal(
|
||||
"parameter '{}' should be true or false".format(var_name))
|
||||
|
||||
conf_val = self.get_lit_conf(name)
|
||||
if env_var is not None and env_var in os.environ and \
|
||||
os.environ[env_var] is not None:
|
||||
val = os.environ[env_var]
|
||||
if conf_val is not None:
|
||||
self.lit_config.warning(
|
||||
'Environment variable %s=%s is overriding explicit '
|
||||
'--param=%s=%s' % (env_var, val, name, conf_val))
|
||||
return check_value(val, env_var)
|
||||
return check_value(conf_val, name)
|
||||
|
||||
def make_static_lib_name(self, name):
|
||||
"""Return the full filename for the specified library name"""
|
||||
if self.is_windows:
|
||||
return name + '.lib'
|
||||
else:
|
||||
return 'lib' + name + '.a'
|
||||
|
||||
def configure(self):
|
||||
self.configure_executor()
|
||||
self.configure_target_info()
|
||||
self.configure_cxx()
|
||||
self.configure_triple()
|
||||
self.configure_src_root()
|
||||
self.configure_obj_root()
|
||||
self.configure_cxx_stdlib_under_test()
|
||||
self.configure_cxx_library_root()
|
||||
self.configure_use_system_cxx_lib()
|
||||
self.configure_use_clang_verify()
|
||||
self.configure_use_thread_safety()
|
||||
self.configure_execute_external()
|
||||
self.configure_ccache()
|
||||
self.configure_compile_flags()
|
||||
self.configure_filesystem_compile_flags()
|
||||
self.configure_link_flags()
|
||||
self.configure_env()
|
||||
self.configure_color_diagnostics()
|
||||
self.configure_debug_mode()
|
||||
self.configure_warnings()
|
||||
self.configure_sanitizer()
|
||||
self.configure_coverage()
|
||||
self.configure_modules()
|
||||
self.configure_substitutions()
|
||||
self.configure_features()
|
||||
|
||||
def print_config_info(self):
|
||||
# Print the final compile and link flags.
|
||||
self.lit_config.note('Using compiler: %s' % self.cxx.path)
|
||||
self.lit_config.note('Using flags: %s' % self.cxx.flags)
|
||||
if self.cxx.use_modules:
|
||||
self.lit_config.note('Using modules flags: %s' %
|
||||
self.cxx.modules_flags)
|
||||
self.lit_config.note('Using compile flags: %s'
|
||||
% self.cxx.compile_flags)
|
||||
if len(self.cxx.warning_flags):
|
||||
self.lit_config.note('Using warnings: %s' % self.cxx.warning_flags)
|
||||
self.lit_config.note('Using link flags: %s' % self.cxx.link_flags)
|
||||
# Print as list to prevent "set([...])" from being printed.
|
||||
self.lit_config.note('Using available_features: %s' %
|
||||
list(self.config.available_features))
|
||||
self.lit_config.note('Using environment: %r' % self.exec_env)
|
||||
sys.stderr.flush() # Force flushing to avoid broken output on Windows
|
||||
|
||||
def get_test_format(self):
|
||||
return LibcxxTestFormat(
|
||||
self.cxx,
|
||||
self.use_clang_verify,
|
||||
self.execute_external,
|
||||
self.executor,
|
||||
exec_env=self.exec_env)
|
||||
|
||||
def configure_executor(self):
|
||||
exec_str = self.get_lit_conf('executor', "None")
|
||||
te = eval(exec_str)
|
||||
if te:
|
||||
self.lit_config.note("Using executor: %r" % exec_str)
|
||||
if self.lit_config.useValgrind:
|
||||
# We have no way of knowing where in the chain the
|
||||
# ValgrindExecutor is supposed to go. It is likely
|
||||
# that the user wants it at the end, but we have no
|
||||
# way of getting at that easily.
|
||||
selt.lit_config.fatal("Cannot infer how to create a Valgrind "
|
||||
" executor.")
|
||||
else:
|
||||
te = LocalExecutor()
|
||||
if self.lit_config.useValgrind:
|
||||
te = ValgrindExecutor(self.lit_config.valgrindArgs, te)
|
||||
self.executor = te
|
||||
|
||||
def configure_target_info(self):
|
||||
self.target_info = make_target_info(self)
|
||||
|
||||
def configure_cxx(self):
|
||||
# Gather various compiler parameters.
|
||||
cxx = self.get_lit_conf('cxx_under_test')
|
||||
self.cxx_is_clang_cl = cxx is not None and \
|
||||
os.path.basename(cxx) == 'clang-cl.exe'
|
||||
# If no specific cxx_under_test was given, attempt to infer it as
|
||||
# clang++.
|
||||
if cxx is None or self.cxx_is_clang_cl:
|
||||
clangxx = lit.util.which('clang++',
|
||||
self.config.environment['PATH'])
|
||||
if clangxx:
|
||||
cxx = clangxx
|
||||
self.lit_config.note(
|
||||
"inferred cxx_under_test as: %r" % cxx)
|
||||
elif self.cxx_is_clang_cl:
|
||||
self.lit_config.fatal('Failed to find clang++ substitution for'
|
||||
' clang-cl')
|
||||
if not cxx:
|
||||
self.lit_config.fatal('must specify user parameter cxx_under_test '
|
||||
'(e.g., --param=cxx_under_test=clang++)')
|
||||
self.cxx = CXXCompiler(cxx) if not self.cxx_is_clang_cl else \
|
||||
self._configure_clang_cl(cxx)
|
||||
cxx_type = self.cxx.type
|
||||
if cxx_type is not None:
|
||||
assert self.cxx.version is not None
|
||||
maj_v, min_v, _ = self.cxx.version
|
||||
self.config.available_features.add(cxx_type)
|
||||
self.config.available_features.add('%s-%s' % (cxx_type, maj_v))
|
||||
self.config.available_features.add('%s-%s.%s' % (
|
||||
cxx_type, maj_v, min_v))
|
||||
self.cxx.compile_env = dict(os.environ)
|
||||
# 'CCACHE_CPP2' prevents ccache from stripping comments while
|
||||
# preprocessing. This is required to prevent stripping of '-verify'
|
||||
# comments.
|
||||
self.cxx.compile_env['CCACHE_CPP2'] = '1'
|
||||
|
||||
def _configure_clang_cl(self, clang_path):
|
||||
assert self.cxx_is_clang_cl
|
||||
flags = []
|
||||
compile_flags = []
|
||||
link_flags = []
|
||||
if 'INCLUDE' in os.environ:
|
||||
compile_flags += ['-isystem %s' % p.strip()
|
||||
for p in os.environ['INCLUDE'].split(';')
|
||||
if p.strip()]
|
||||
if 'LIB' in os.environ:
|
||||
for p in os.environ['LIB'].split(';'):
|
||||
p = p.strip()
|
||||
if not p:
|
||||
continue
|
||||
link_flags += ['-L%s' % p]
|
||||
self.add_path(self.exec_env, p)
|
||||
return CXXCompiler(clang_path, flags=flags,
|
||||
compile_flags=compile_flags,
|
||||
link_flags=link_flags)
|
||||
|
||||
|
||||
def configure_src_root(self):
|
||||
self.libcxx_src_root = self.get_lit_conf(
|
||||
'libcxx_src_root', os.path.dirname(self.config.test_source_root))
|
||||
|
||||
def configure_obj_root(self):
|
||||
self.project_obj_root = self.get_lit_conf('project_obj_root')
|
||||
self.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root')
|
||||
if not self.libcxx_obj_root and self.project_obj_root is not None:
|
||||
possible_root = os.path.join(self.project_obj_root, 'projects', 'libcxx')
|
||||
if os.path.isdir(possible_root):
|
||||
self.libcxx_obj_root = possible_root
|
||||
else:
|
||||
self.libcxx_obj_root = self.project_obj_root
|
||||
|
||||
def configure_cxx_library_root(self):
|
||||
self.cxx_library_root = self.get_lit_conf('cxx_library_root',
|
||||
self.libcxx_obj_root)
|
||||
self.cxx_runtime_root = self.get_lit_conf('cxx_runtime_root',
|
||||
self.cxx_library_root)
|
||||
|
||||
def configure_use_system_cxx_lib(self):
|
||||
# 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.
|
||||
self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib')
|
||||
if self.use_system_cxx_lib is None:
|
||||
# Default to testing against the locally built libc++ library.
|
||||
self.use_system_cxx_lib = False
|
||||
self.lit_config.note(
|
||||
"inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)
|
||||
|
||||
def configure_cxx_stdlib_under_test(self):
|
||||
self.cxx_stdlib_under_test = self.get_lit_conf(
|
||||
'cxx_stdlib_under_test', 'libc++')
|
||||
if self.cxx_stdlib_under_test not in \
|
||||
['libc++', 'libstdc++', 'msvc', 'cxx_default']:
|
||||
self.lit_config.fatal(
|
||||
'unsupported value for "cxx_stdlib_under_test": %s'
|
||||
% self.cxx_stdlib_under_test)
|
||||
self.config.available_features.add(self.cxx_stdlib_under_test)
|
||||
if self.cxx_stdlib_under_test == 'libstdc++':
|
||||
self.config.available_features.add('libstdc++')
|
||||
# Manually enable the experimental and filesystem tests for libstdc++
|
||||
# if the options aren't present.
|
||||
# FIXME this is a hack.
|
||||
if self.get_lit_conf('enable_experimental') is None:
|
||||
self.config.enable_experimental = 'true'
|
||||
if self.get_lit_conf('enable_filesystem') is None:
|
||||
self.config.enable_filesystem = 'true'
|
||||
|
||||
def configure_use_clang_verify(self):
|
||||
'''If set, run clang with -verify on failing tests.'''
|
||||
self.use_clang_verify = self.get_lit_bool('use_clang_verify')
|
||||
if self.use_clang_verify is None:
|
||||
# NOTE: We do not test for the -verify flag directly because
|
||||
# -verify will always exit with non-zero on an empty file.
|
||||
self.use_clang_verify = self.cxx.isVerifySupported()
|
||||
if self.use_clang_verify:
|
||||
self.config.available_features.add('verify-support')
|
||||
self.lit_config.note(
|
||||
"inferred use_clang_verify as: %r" % self.use_clang_verify)
|
||||
|
||||
def configure_use_thread_safety(self):
|
||||
'''If set, run clang with -verify on failing tests.'''
|
||||
has_thread_safety = self.cxx.hasCompileFlag('-Werror=thread-safety')
|
||||
if has_thread_safety:
|
||||
self.cxx.compile_flags += ['-Werror=thread-safety']
|
||||
self.config.available_features.add('thread-safety')
|
||||
self.lit_config.note("enabling thread-safety annotations")
|
||||
|
||||
def configure_execute_external(self):
|
||||
# Choose between lit's internal shell pipeline runner and a real shell.
|
||||
# If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
|
||||
# default value. Otherwise we ask the target_info.
|
||||
use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL')
|
||||
if use_lit_shell_default is not None:
|
||||
use_lit_shell_default = use_lit_shell_default != '0'
|
||||
else:
|
||||
use_lit_shell_default = self.target_info.use_lit_shell_default()
|
||||
# Check for the command line parameter using the default value if it is
|
||||
# not present.
|
||||
use_lit_shell = self.get_lit_bool('use_lit_shell',
|
||||
use_lit_shell_default)
|
||||
self.execute_external = not use_lit_shell
|
||||
|
||||
def configure_ccache(self):
|
||||
use_ccache_default = os.environ.get('LIBCXX_USE_CCACHE') is not None
|
||||
use_ccache = self.get_lit_bool('use_ccache', use_ccache_default)
|
||||
if use_ccache:
|
||||
self.cxx.use_ccache = True
|
||||
self.lit_config.note('enabling ccache')
|
||||
|
||||
def configure_features(self):
|
||||
additional_features = self.get_lit_conf('additional_features')
|
||||
if additional_features:
|
||||
for f in additional_features.split(','):
|
||||
self.config.available_features.add(f.strip())
|
||||
self.target_info.add_locale_features(self.config.available_features)
|
||||
|
||||
target_platform = self.target_info.platform()
|
||||
|
||||
# Write an "available feature" that combines the triple when
|
||||
# use_system_cxx_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 self.use_system_cxx_lib:
|
||||
self.config.available_features.add('with_system_cxx_lib')
|
||||
self.config.available_features.add(
|
||||
'with_system_cxx_lib=%s' % self.config.target_triple)
|
||||
|
||||
# Insert the platform name into the available features as a lower case.
|
||||
self.config.available_features.add(target_platform)
|
||||
|
||||
# Simulator testing can take a really long time for some of these tests
|
||||
# so add a feature check so we can REQUIRES: long_tests in them
|
||||
self.long_tests = self.get_lit_bool('long_tests')
|
||||
if self.long_tests is None:
|
||||
# Default to running long tests.
|
||||
self.long_tests = True
|
||||
self.lit_config.note(
|
||||
"inferred long_tests as: %r" % self.long_tests)
|
||||
|
||||
if self.long_tests:
|
||||
self.config.available_features.add('long_tests')
|
||||
|
||||
# Run a compile test for the -fsized-deallocation flag. This is needed
|
||||
# in test/std/language.support/support.dynamic/new.delete
|
||||
if self.cxx.hasCompileFlag('-fsized-deallocation'):
|
||||
self.config.available_features.add('fsized-deallocation')
|
||||
|
||||
if self.cxx.hasCompileFlag('-faligned-allocation'):
|
||||
self.config.available_features.add('-faligned-allocation')
|
||||
else:
|
||||
# FIXME remove this once more than just clang-4.0 support
|
||||
# C++17 aligned allocation.
|
||||
self.config.available_features.add('no-aligned-allocation')
|
||||
|
||||
if self.get_lit_bool('has_libatomic', False):
|
||||
self.config.available_features.add('libatomic')
|
||||
|
||||
macros = self.cxx.dumpMacros()
|
||||
if '__cpp_if_constexpr' not in macros:
|
||||
self.config.available_features.add('libcpp-no-if-constexpr')
|
||||
|
||||
if '__cpp_structured_bindings' not in macros:
|
||||
self.config.available_features.add('libcpp-no-structured-bindings')
|
||||
|
||||
if self.is_windows:
|
||||
self.config.available_features.add('windows')
|
||||
|
||||
def configure_compile_flags(self):
|
||||
no_default_flags = self.get_lit_bool('no_default_flags', False)
|
||||
if not no_default_flags:
|
||||
self.configure_default_compile_flags()
|
||||
# This include is always needed so add so add it regardless of
|
||||
# 'no_default_flags'.
|
||||
support_path = os.path.join(self.libcxx_src_root, 'test/support')
|
||||
self.cxx.compile_flags += ['-I' + support_path]
|
||||
# Configure extra flags
|
||||
compile_flags_str = self.get_lit_conf('compile_flags', '')
|
||||
self.cxx.compile_flags += shlex.split(compile_flags_str)
|
||||
# FIXME: Can we remove this?
|
||||
if self.is_windows:
|
||||
self.cxx.compile_flags += ['-D_CRT_SECURE_NO_WARNINGS']
|
||||
|
||||
def configure_default_compile_flags(self):
|
||||
# Try and get the std version from the command line. Fall back to
|
||||
# default given in lit.site.cfg is not present. If default is not
|
||||
# present then force c++11.
|
||||
std = self.get_lit_conf('std')
|
||||
if not std:
|
||||
# Choose the newest possible language dialect if none is given.
|
||||
possible_stds = ['c++1z', 'c++14', 'c++11', 'c++03']
|
||||
if self.cxx.type == 'gcc':
|
||||
maj_v, _, _ = self.cxx.version
|
||||
maj_v = int(maj_v)
|
||||
if maj_v < 7:
|
||||
possible_stds.remove('c++1z')
|
||||
# FIXME: How many C++14 tests actually fail under GCC 5 and 6?
|
||||
# Should we XFAIL them individually instead?
|
||||
if maj_v <= 6:
|
||||
possible_stds.remove('c++14')
|
||||
for s in possible_stds:
|
||||
if self.cxx.hasCompileFlag('-std=%s' % s):
|
||||
std = s
|
||||
self.lit_config.note(
|
||||
'inferred language dialect as: %s' % std)
|
||||
break
|
||||
if not std:
|
||||
self.lit_config.fatal(
|
||||
'Failed to infer a supported language dialect from one of %r'
|
||||
% possible_stds)
|
||||
self.cxx.compile_flags += ['-std={0}'.format(std)]
|
||||
self.config.available_features.add(std.replace('gnu++', 'c++'))
|
||||
# Configure include paths
|
||||
self.configure_compile_flags_header_includes()
|
||||
self.target_info.add_cxx_compile_flags(self.cxx.compile_flags)
|
||||
# Configure feature flags.
|
||||
self.configure_compile_flags_exceptions()
|
||||
self.configure_compile_flags_rtti()
|
||||
self.configure_compile_flags_abi_version()
|
||||
enable_32bit = self.get_lit_bool('enable_32bit', False)
|
||||
if enable_32bit:
|
||||
self.cxx.flags += ['-m32']
|
||||
# Use verbose output for better errors
|
||||
self.cxx.flags += ['-v']
|
||||
sysroot = self.get_lit_conf('sysroot')
|
||||
if sysroot:
|
||||
self.cxx.flags += ['--sysroot', sysroot]
|
||||
gcc_toolchain = self.get_lit_conf('gcc_toolchain')
|
||||
if gcc_toolchain:
|
||||
self.cxx.flags += ['-gcc-toolchain', gcc_toolchain]
|
||||
if self.use_target:
|
||||
if not self.cxx.addFlagIfSupported(
|
||||
['-target', self.config.target_triple]):
|
||||
self.lit_config.warning('use_target is true but -target is '\
|
||||
'not supported by the compiler')
|
||||
if self.is_windows and self.debug_build:
|
||||
self.cxx.compile_flags += ['-D_DEBUG']
|
||||
|
||||
def configure_compile_flags_header_includes(self):
|
||||
support_path = os.path.join(self.libcxx_src_root, 'test', 'support')
|
||||
if self.cxx_stdlib_under_test != 'libstdc++' and \
|
||||
not self.is_windows:
|
||||
self.cxx.compile_flags += [
|
||||
'-include', os.path.join(support_path, 'nasty_macros.hpp')]
|
||||
if self.cxx_stdlib_under_test == 'msvc':
|
||||
self.cxx.compile_flags += [
|
||||
'-include', os.path.join(support_path,
|
||||
'msvc_stdlib_force_include.hpp')]
|
||||
pass
|
||||
if self.is_windows and self.debug_build and \
|
||||
self.cxx_stdlib_under_test != 'msvc':
|
||||
self.cxx.compile_flags += [
|
||||
'-include', os.path.join(support_path,
|
||||
'set_windows_crt_report_mode.h')
|
||||
]
|
||||
self.configure_config_site_header()
|
||||
cxx_headers = self.get_lit_conf('cxx_headers')
|
||||
if cxx_headers == '' or (cxx_headers is None
|
||||
and self.cxx_stdlib_under_test != 'libc++'):
|
||||
self.lit_config.note('using the system cxx headers')
|
||||
return
|
||||
self.cxx.compile_flags += ['-nostdinc++']
|
||||
if cxx_headers is None:
|
||||
cxx_headers = os.path.join(self.libcxx_src_root, 'include')
|
||||
if not os.path.isdir(cxx_headers):
|
||||
self.lit_config.fatal("cxx_headers='%s' is not a directory."
|
||||
% cxx_headers)
|
||||
self.cxx.compile_flags += ['-I' + cxx_headers]
|
||||
if self.libcxx_obj_root is not None:
|
||||
cxxabi_headers = os.path.join(self.libcxx_obj_root, 'include',
|
||||
'c++build')
|
||||
if os.path.isdir(cxxabi_headers):
|
||||
self.cxx.compile_flags += ['-I' + cxxabi_headers]
|
||||
|
||||
def configure_config_site_header(self):
|
||||
# Check for a possible __config_site in the build directory. We
|
||||
# use this if it exists.
|
||||
if self.libcxx_obj_root is None:
|
||||
return
|
||||
config_site_header = os.path.join(self.libcxx_obj_root, '__config_site')
|
||||
if not os.path.isfile(config_site_header):
|
||||
return
|
||||
contained_macros = self.parse_config_site_and_add_features(
|
||||
config_site_header)
|
||||
self.lit_config.note('Using __config_site header %s with macros: %r'
|
||||
% (config_site_header, contained_macros))
|
||||
# FIXME: This must come after the call to
|
||||
# 'parse_config_site_and_add_features(...)' in order for it to work.
|
||||
self.cxx.compile_flags += ['-include', config_site_header]
|
||||
|
||||
def parse_config_site_and_add_features(self, header):
|
||||
""" parse_config_site_and_add_features - Deduce and add the test
|
||||
features that that are implied by the #define's in the __config_site
|
||||
header. Return a dictionary containing the macros found in the
|
||||
'__config_site' header.
|
||||
"""
|
||||
# Parse the macro contents of __config_site by dumping the macros
|
||||
# using 'c++ -dM -E' and filtering the predefines.
|
||||
predefines = self.cxx.dumpMacros()
|
||||
macros = self.cxx.dumpMacros(header)
|
||||
feature_macros_keys = set(macros.keys()) - set(predefines.keys())
|
||||
feature_macros = {}
|
||||
for k in feature_macros_keys:
|
||||
feature_macros[k] = macros[k]
|
||||
# We expect the header guard to be one of the definitions
|
||||
assert '_LIBCPP_CONFIG_SITE' in feature_macros
|
||||
del feature_macros['_LIBCPP_CONFIG_SITE']
|
||||
# The __config_site header should be non-empty. Otherwise it should
|
||||
# have never been emitted by CMake.
|
||||
assert len(feature_macros) > 0
|
||||
# Transform each macro name into the feature name used in the tests.
|
||||
# Ex. _LIBCPP_HAS_NO_THREADS -> libcpp-has-no-threads
|
||||
for m in feature_macros:
|
||||
if m == '_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS':
|
||||
continue
|
||||
if m == '_LIBCPP_ABI_VERSION':
|
||||
self.config.available_features.add('libcpp-abi-version-v%s'
|
||||
% feature_macros[m])
|
||||
continue
|
||||
assert m.startswith('_LIBCPP_HAS_') or m == '_LIBCPP_ABI_UNSTABLE'
|
||||
m = m.lower()[1:].replace('_', '-')
|
||||
self.config.available_features.add(m)
|
||||
return feature_macros
|
||||
|
||||
|
||||
|
||||
def configure_compile_flags_exceptions(self):
|
||||
enable_exceptions = self.get_lit_bool('enable_exceptions', True)
|
||||
if not enable_exceptions:
|
||||
self.config.available_features.add('libcpp-no-exceptions')
|
||||
self.cxx.compile_flags += ['-fno-exceptions']
|
||||
|
||||
def configure_compile_flags_rtti(self):
|
||||
enable_rtti = self.get_lit_bool('enable_rtti', True)
|
||||
if not enable_rtti:
|
||||
self.config.available_features.add('libcpp-no-rtti')
|
||||
self.cxx.compile_flags += ['-fno-rtti', '-D_LIBCPP_NO_RTTI']
|
||||
|
||||
def configure_compile_flags_abi_version(self):
|
||||
abi_version = self.get_lit_conf('abi_version', '').strip()
|
||||
abi_unstable = self.get_lit_bool('abi_unstable')
|
||||
# Only add the ABI version when it is non-default.
|
||||
# FIXME(EricWF): Get the ABI version from the "__config_site".
|
||||
if abi_version and abi_version != '1':
|
||||
self.cxx.compile_flags += ['-D_LIBCPP_ABI_VERSION=' + abi_version]
|
||||
if abi_unstable:
|
||||
self.config.available_features.add('libcpp-abi-unstable')
|
||||
self.cxx.compile_flags += ['-D_LIBCPP_ABI_UNSTABLE']
|
||||
|
||||
def configure_filesystem_compile_flags(self):
|
||||
enable_fs = self.get_lit_bool('enable_filesystem', default=False)
|
||||
if not enable_fs:
|
||||
return
|
||||
enable_experimental = self.get_lit_bool('enable_experimental', default=False)
|
||||
if not enable_experimental:
|
||||
self.lit_config.fatal(
|
||||
'filesystem is enabled but libc++experimental.a is not.')
|
||||
self.config.available_features.add('c++filesystem')
|
||||
static_env = os.path.join(self.libcxx_src_root, 'test', 'std',
|
||||
'experimental', 'filesystem', 'Inputs', 'static_test_env')
|
||||
static_env = os.path.realpath(static_env)
|
||||
assert os.path.isdir(static_env)
|
||||
self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_STATIC_TEST_ROOT="%s"' % static_env]
|
||||
|
||||
dynamic_env = os.path.join(self.config.test_exec_root,
|
||||
'filesystem', 'Output', 'dynamic_env')
|
||||
dynamic_env = os.path.realpath(dynamic_env)
|
||||
if not os.path.isdir(dynamic_env):
|
||||
os.makedirs(dynamic_env)
|
||||
self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT="%s"' % dynamic_env]
|
||||
self.exec_env['LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT'] = ("%s" % dynamic_env)
|
||||
|
||||
dynamic_helper = os.path.join(self.libcxx_src_root, 'test', 'support',
|
||||
'filesystem_dynamic_test_helper.py')
|
||||
assert os.path.isfile(dynamic_helper)
|
||||
|
||||
self.cxx.compile_flags += ['-DLIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER="%s %s"'
|
||||
% (sys.executable, dynamic_helper)]
|
||||
|
||||
|
||||
def configure_link_flags(self):
|
||||
no_default_flags = self.get_lit_bool('no_default_flags', False)
|
||||
if not no_default_flags:
|
||||
# Configure library path
|
||||
self.configure_link_flags_cxx_library_path()
|
||||
self.configure_link_flags_abi_library_path()
|
||||
|
||||
# Configure libraries
|
||||
if self.cxx_stdlib_under_test == 'libc++':
|
||||
self.cxx.link_flags += ['-nodefaultlibs']
|
||||
# FIXME: Handle MSVCRT as part of the ABI library handling.
|
||||
if self.is_windows:
|
||||
self.cxx.link_flags += ['-nostdlib']
|
||||
self.configure_link_flags_cxx_library()
|
||||
self.configure_link_flags_abi_library()
|
||||
self.configure_extra_library_flags()
|
||||
elif self.cxx_stdlib_under_test == 'libstdc++':
|
||||
enable_fs = self.get_lit_bool('enable_filesystem',
|
||||
default=False)
|
||||
if enable_fs:
|
||||
self.config.available_features.add('c++experimental')
|
||||
self.cxx.link_flags += ['-lstdc++fs']
|
||||
self.cxx.link_flags += ['-lm', '-pthread']
|
||||
elif self.cxx_stdlib_under_test == 'msvc':
|
||||
# FIXME: Correctly setup debug/release flags here.
|
||||
pass
|
||||
elif self.cxx_stdlib_under_test == 'cxx_default':
|
||||
self.cxx.link_flags += ['-pthread']
|
||||
else:
|
||||
self.lit_config.fatal(
|
||||
'unsupported value for "use_stdlib_type": %s'
|
||||
% use_stdlib_type)
|
||||
|
||||
link_flags_str = self.get_lit_conf('link_flags', '')
|
||||
self.cxx.link_flags += shlex.split(link_flags_str)
|
||||
|
||||
def configure_link_flags_cxx_library_path(self):
|
||||
if not self.use_system_cxx_lib:
|
||||
if self.cxx_library_root:
|
||||
self.cxx.link_flags += ['-L' + self.cxx_library_root]
|
||||
if self.is_windows and self.link_shared:
|
||||
self.add_path(self.cxx.compile_env, self.cxx_library_root)
|
||||
if self.cxx_runtime_root:
|
||||
if not self.is_windows:
|
||||
self.cxx.link_flags += ['-Wl,-rpath,' +
|
||||
self.cxx_runtime_root]
|
||||
elif self.is_windows and self.link_shared:
|
||||
self.add_path(self.exec_env, self.cxx_runtime_root)
|
||||
|
||||
def configure_link_flags_abi_library_path(self):
|
||||
# Configure ABI library paths.
|
||||
self.abi_library_root = self.get_lit_conf('abi_library_path')
|
||||
if self.abi_library_root:
|
||||
self.cxx.link_flags += ['-L' + self.abi_library_root]
|
||||
if not self.is_windows:
|
||||
self.cxx.link_flags += ['-Wl,-rpath,' + self.abi_library_root]
|
||||
else:
|
||||
self.add_path(self.exec_env, self.abi_library_root)
|
||||
|
||||
def configure_link_flags_cxx_library(self):
|
||||
libcxx_experimental = self.get_lit_bool('enable_experimental', default=False)
|
||||
if libcxx_experimental:
|
||||
self.config.available_features.add('c++experimental')
|
||||
self.cxx.link_flags += ['-lc++experimental']
|
||||
if self.link_shared:
|
||||
self.cxx.link_flags += ['-lc++']
|
||||
else:
|
||||
cxx_library_root = self.get_lit_conf('cxx_library_root')
|
||||
if cxx_library_root:
|
||||
libname = self.make_static_lib_name('c++')
|
||||
abs_path = os.path.join(cxx_library_root, libname)
|
||||
assert os.path.exists(abs_path) and \
|
||||
"static libc++ library does not exist"
|
||||
self.cxx.link_flags += [abs_path]
|
||||
else:
|
||||
self.cxx.link_flags += ['-lc++']
|
||||
|
||||
def configure_link_flags_abi_library(self):
|
||||
cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi')
|
||||
if cxx_abi == 'libstdc++':
|
||||
self.cxx.link_flags += ['-lstdc++']
|
||||
elif cxx_abi == 'libsupc++':
|
||||
self.cxx.link_flags += ['-lsupc++']
|
||||
elif cxx_abi == 'libcxxabi':
|
||||
if self.target_info.allow_cxxabi_link():
|
||||
libcxxabi_shared = self.get_lit_bool('libcxxabi_shared', default=True)
|
||||
if libcxxabi_shared:
|
||||
self.cxx.link_flags += ['-lc++abi']
|
||||
else:
|
||||
cxxabi_library_root = self.get_lit_conf('abi_library_path')
|
||||
if cxxabi_library_root:
|
||||
libname = self.make_static_lib_name('c++abi')
|
||||
abs_path = os.path.join(cxxabi_library_root, libname)
|
||||
self.cxx.link_flags += [abs_path]
|
||||
else:
|
||||
self.cxx.link_flags += ['-lc++abi']
|
||||
elif cxx_abi == 'libcxxrt':
|
||||
self.cxx.link_flags += ['-lcxxrt']
|
||||
elif cxx_abi == 'vcruntime':
|
||||
debug_suffix = 'd' if self.debug_build else ''
|
||||
self.cxx.link_flags += ['-l%s%s' % (lib, debug_suffix) for lib in
|
||||
['vcruntime', 'ucrt', 'msvcrt']]
|
||||
elif cxx_abi == 'none' or cxx_abi == 'default':
|
||||
if self.is_windows:
|
||||
debug_suffix = 'd' if self.debug_build else ''
|
||||
self.cxx.link_flags += ['-lmsvcrt%s' % debug_suffix]
|
||||
else:
|
||||
self.lit_config.fatal(
|
||||
'C++ ABI setting %s unsupported for tests' % cxx_abi)
|
||||
|
||||
def configure_extra_library_flags(self):
|
||||
if self.get_lit_bool('cxx_ext_threads', default=False):
|
||||
self.cxx.link_flags += ['-lc++external_threads']
|
||||
self.target_info.add_cxx_link_flags(self.cxx.link_flags)
|
||||
|
||||
def configure_color_diagnostics(self):
|
||||
use_color = self.get_lit_conf('color_diagnostics')
|
||||
if use_color is None:
|
||||
use_color = os.environ.get('LIBCXX_COLOR_DIAGNOSTICS')
|
||||
if use_color is None:
|
||||
return
|
||||
if use_color != '':
|
||||
self.lit_config.fatal('Invalid value for color_diagnostics "%s".'
|
||||
% use_color)
|
||||
color_flag = '-fdiagnostics-color=always'
|
||||
# Check if the compiler supports the color diagnostics flag. Issue a
|
||||
# warning if it does not since color diagnostics have been requested.
|
||||
if not self.cxx.hasCompileFlag(color_flag):
|
||||
self.lit_config.warning(
|
||||
'color diagnostics have been requested but are not supported '
|
||||
'by the compiler')
|
||||
else:
|
||||
self.cxx.flags += [color_flag]
|
||||
|
||||
def configure_debug_mode(self):
|
||||
debug_level = self.get_lit_conf('debug_level', None)
|
||||
if not debug_level:
|
||||
return
|
||||
if debug_level not in ['0', '1']:
|
||||
self.lit_config.fatal('Invalid value for debug_level "%s".'
|
||||
% debug_level)
|
||||
self.cxx.compile_flags += ['-D_LIBCPP_DEBUG=%s' % debug_level]
|
||||
|
||||
def configure_warnings(self):
|
||||
# Turn on warnings by default for Clang based compilers when C++ >= 11
|
||||
default_enable_warnings = self.cxx.type in ['clang', 'apple-clang'] \
|
||||
and len(self.config.available_features.intersection(
|
||||
['c++11', 'c++14', 'c++1z'])) != 0
|
||||
enable_warnings = self.get_lit_bool('enable_warnings',
|
||||
default_enable_warnings)
|
||||
self.cxx.useWarnings(enable_warnings)
|
||||
self.cxx.warning_flags += [
|
||||
'-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER',
|
||||
'-Wall', '-Wextra', '-Werror'
|
||||
]
|
||||
if self.cxx.hasWarningFlag('-Wuser-defined-warnings'):
|
||||
self.cxx.warning_flags += ['-Wuser-defined-warnings']
|
||||
self.config.available_features.add('diagnose-if-support')
|
||||
self.cxx.addWarningFlagIfSupported('-Wshadow')
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-unused-command-line-argument')
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-attributes')
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move')
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions')
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals')
|
||||
# These warnings should be enabled in order to support the MSVC
|
||||
# team using the test suite; They enable the warnings below and
|
||||
# expect the test suite to be clean.
|
||||
self.cxx.addWarningFlagIfSupported('-Wsign-compare')
|
||||
self.cxx.addWarningFlagIfSupported('-Wunused-variable')
|
||||
self.cxx.addWarningFlagIfSupported('-Wunused-parameter')
|
||||
self.cxx.addWarningFlagIfSupported('-Wunreachable-code')
|
||||
# FIXME: Enable the two warnings below.
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-conversion')
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')
|
||||
std = self.get_lit_conf('std', None)
|
||||
if std in ['c++98', 'c++03']:
|
||||
# The '#define static_assert' provided by libc++ in C++03 mode
|
||||
# causes an unused local typedef whenever it is used.
|
||||
self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')
|
||||
|
||||
def configure_sanitizer(self):
|
||||
san = self.get_lit_conf('use_sanitizer', '').strip()
|
||||
if san:
|
||||
self.target_info.add_sanitizer_features(san, self.config.available_features)
|
||||
# Search for llvm-symbolizer along the compiler path first
|
||||
# and then along the PATH env variable.
|
||||
symbolizer_search_paths = os.environ.get('PATH', '')
|
||||
cxx_path = lit.util.which(self.cxx.path)
|
||||
if cxx_path is not None:
|
||||
symbolizer_search_paths = (
|
||||
os.path.dirname(cxx_path) +
|
||||
os.pathsep + symbolizer_search_paths)
|
||||
llvm_symbolizer = lit.util.which('llvm-symbolizer',
|
||||
symbolizer_search_paths)
|
||||
|
||||
def add_ubsan():
|
||||
self.cxx.flags += ['-fsanitize=undefined',
|
||||
'-fno-sanitize=vptr,function,float-divide-by-zero',
|
||||
'-fno-sanitize-recover=all']
|
||||
self.exec_env['UBSAN_OPTIONS'] = 'print_stacktrace=1'
|
||||
self.config.available_features.add('ubsan')
|
||||
|
||||
# Setup the sanitizer compile flags
|
||||
self.cxx.flags += ['-g', '-fno-omit-frame-pointer']
|
||||
if san == 'Address' or san == 'Address;Undefined' or san == 'Undefined;Address':
|
||||
self.cxx.flags += ['-fsanitize=address']
|
||||
if llvm_symbolizer is not None:
|
||||
self.exec_env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
|
||||
# FIXME: Turn ODR violation back on after PR28391 is resolved
|
||||
# https://llvm.org/bugs/show_bug.cgi?id=28391
|
||||
self.exec_env['ASAN_OPTIONS'] = 'detect_odr_violation=0'
|
||||
self.config.available_features.add('asan')
|
||||
self.config.available_features.add('sanitizer-new-delete')
|
||||
self.cxx.compile_flags += ['-O1']
|
||||
if san == 'Address;Undefined' or san == 'Undefined;Address':
|
||||
add_ubsan()
|
||||
elif san == 'Memory' or san == 'MemoryWithOrigins':
|
||||
self.cxx.flags += ['-fsanitize=memory']
|
||||
if san == 'MemoryWithOrigins':
|
||||
self.cxx.compile_flags += [
|
||||
'-fsanitize-memory-track-origins']
|
||||
if llvm_symbolizer is not None:
|
||||
self.exec_env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
|
||||
self.config.available_features.add('msan')
|
||||
self.config.available_features.add('sanitizer-new-delete')
|
||||
self.cxx.compile_flags += ['-O1']
|
||||
elif san == 'Undefined':
|
||||
add_ubsan()
|
||||
self.cxx.compile_flags += ['-O2']
|
||||
elif san == 'Thread':
|
||||
self.cxx.flags += ['-fsanitize=thread']
|
||||
self.config.available_features.add('tsan')
|
||||
self.config.available_features.add('sanitizer-new-delete')
|
||||
else:
|
||||
self.lit_config.fatal('unsupported value for '
|
||||
'use_sanitizer: {0}'.format(san))
|
||||
san_lib = self.get_lit_conf('sanitizer_library')
|
||||
if san_lib:
|
||||
self.cxx.link_flags += [
|
||||
san_lib, '-Wl,-rpath,%s' % os.path.dirname(san_lib)]
|
||||
|
||||
def configure_coverage(self):
|
||||
self.generate_coverage = self.get_lit_bool('generate_coverage', False)
|
||||
if self.generate_coverage:
|
||||
self.cxx.flags += ['-g', '--coverage']
|
||||
self.cxx.compile_flags += ['-O0']
|
||||
|
||||
def configure_modules(self):
|
||||
modules_flags = ['-fmodules']
|
||||
if platform.system() != 'Darwin':
|
||||
modules_flags += ['-Xclang', '-fmodules-local-submodule-visibility']
|
||||
supports_modules = self.cxx.hasCompileFlag(modules_flags)
|
||||
enable_modules = self.get_lit_bool('enable_modules',
|
||||
default=False,
|
||||
env_var='LIBCXX_ENABLE_MODULES')
|
||||
if enable_modules and not supports_modules:
|
||||
self.lit_config.fatal(
|
||||
'-fmodules is enabled but not supported by the compiler')
|
||||
if not supports_modules:
|
||||
return
|
||||
self.config.available_features.add('modules-support')
|
||||
module_cache = os.path.join(self.config.test_exec_root,
|
||||
'modules.cache')
|
||||
module_cache = os.path.realpath(module_cache)
|
||||
if os.path.isdir(module_cache):
|
||||
shutil.rmtree(module_cache)
|
||||
os.makedirs(module_cache)
|
||||
self.cxx.modules_flags = modules_flags + \
|
||||
['-fmodules-cache-path=' + module_cache]
|
||||
if enable_modules:
|
||||
self.config.available_features.add('-fmodules')
|
||||
self.cxx.useModules()
|
||||
|
||||
def configure_substitutions(self):
|
||||
sub = self.config.substitutions
|
||||
# Configure compiler substitutions
|
||||
sub.append(('%cxx', self.cxx.path))
|
||||
# Configure flags substitutions
|
||||
flags_str = ' '.join([pipes.quote(f) for f in self.cxx.flags])
|
||||
compile_flags_str = ' '.join([pipes.quote(f) for f in self.cxx.compile_flags])
|
||||
link_flags_str = ' '.join([pipes.quote(f) for f in self.cxx.link_flags])
|
||||
all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str)
|
||||
sub.append(('%flags', flags_str))
|
||||
sub.append(('%compile_flags', compile_flags_str))
|
||||
sub.append(('%link_flags', link_flags_str))
|
||||
sub.append(('%all_flags', all_flags))
|
||||
if self.cxx.isVerifySupported():
|
||||
verify_str = ' ' + ' '.join(self.cxx.verify_flags) + ' '
|
||||
sub.append(('%verify', verify_str))
|
||||
# Add compile and link shortcuts
|
||||
compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str
|
||||
+ ' ' + compile_flags_str)
|
||||
link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str + ' '
|
||||
+ link_flags_str)
|
||||
assert type(link_str) is str
|
||||
build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
|
||||
if self.cxx.use_modules:
|
||||
sub.append(('%compile_module', compile_str))
|
||||
sub.append(('%build_module', build_str))
|
||||
elif self.cxx.modules_flags is not None:
|
||||
modules_str = ' '.join(self.cxx.modules_flags) + ' '
|
||||
sub.append(('%compile_module', compile_str + ' ' + modules_str))
|
||||
sub.append(('%build_module', build_str + ' ' + modules_str))
|
||||
sub.append(('%compile', compile_str))
|
||||
sub.append(('%link', link_str))
|
||||
sub.append(('%build', build_str))
|
||||
# Configure exec prefix substitutions.
|
||||
exec_env_str = ''
|
||||
if not self.is_windows and len(self.exec_env) != 0:
|
||||
exec_env_str = 'env '
|
||||
for k, v in self.exec_env.items():
|
||||
exec_env_str += ' %s=%s' % (k, v)
|
||||
# Configure run env substitution.
|
||||
exec_str = exec_env_str
|
||||
if self.lit_config.useValgrind:
|
||||
exec_str = ' '.join(self.lit_config.valgrindArgs) + exec_env_str
|
||||
sub.append(('%exec', exec_str))
|
||||
# Configure run shortcut
|
||||
sub.append(('%run', exec_str + ' %t.exe'))
|
||||
# Configure not program substitutions
|
||||
not_py = os.path.join(self.libcxx_src_root, 'utils', 'not.py')
|
||||
not_str = '%s %s ' % (sys.executable, not_py)
|
||||
sub.append(('not ', not_str))
|
||||
|
||||
def configure_triple(self):
|
||||
# Get or infer the target triple.
|
||||
self.config.target_triple = self.get_lit_conf('target_triple')
|
||||
self.use_target = self.get_lit_bool('use_target', False)
|
||||
if self.use_target and self.config.target_triple:
|
||||
self.lit_config.warning('use_target is true but no triple is specified')
|
||||
# If no target triple was given, try to infer it from the compiler
|
||||
# under test.
|
||||
if not self.config.target_triple:
|
||||
target_triple = self.cxx.getTriple()
|
||||
# Drop sub-major version components from the triple, because the
|
||||
# current XFAIL handling expects exact matches for feature checks.
|
||||
# Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
|
||||
# The 5th group handles triples greater than 3 parts
|
||||
# (ex x86_64-pc-linux-gnu).
|
||||
target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)',
|
||||
r'\1-\2-\3\5', target_triple)
|
||||
# linux-gnu is needed in the triple to properly identify linuxes
|
||||
# that use GLIBC. Handle redhat and opensuse triples as special
|
||||
# cases and append the missing `-gnu` portion.
|
||||
if (target_triple.endswith('redhat-linux') or
|
||||
target_triple.endswith('suse-linux')):
|
||||
target_triple += '-gnu'
|
||||
self.config.target_triple = target_triple
|
||||
self.lit_config.note(
|
||||
"inferred target_triple as: %r" % self.config.target_triple)
|
||||
|
||||
def configure_env(self):
|
||||
self.target_info.configure_env(self.exec_env)
|
||||
|
||||
def add_path(self, dest_env, new_path):
|
||||
if 'PATH' not in dest_env:
|
||||
dest_env['PATH'] = new_path
|
||||
else:
|
||||
split_char = ';' if self.is_windows else ':'
|
||||
dest_env['PATH'] = '%s%s%s' % (new_path, split_char,
|
||||
dest_env['PATH'])
|
||||
@@ -1,223 +0,0 @@
|
||||
#===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.TXT for details.
|
||||
#
|
||||
#===----------------------------------------------------------------------===##
|
||||
|
||||
import platform
|
||||
import os
|
||||
|
||||
from libcxx.test import tracing
|
||||
|
||||
from lit.util import executeCommand # pylint: disable=import-error
|
||||
|
||||
|
||||
class Executor(object):
|
||||
def run(self, exe_path, cmd, local_cwd, file_deps=None, env=None):
|
||||
"""Execute a command.
|
||||
Be very careful not to change shared state in this function.
|
||||
Executor objects are shared between python processes in `lit -jN`.
|
||||
Args:
|
||||
exe_path: str: Local path to the executable to be run
|
||||
cmd: [str]: subprocess.call style command
|
||||
local_cwd: str: Local path to the working directory
|
||||
file_deps: [str]: Files required by the test
|
||||
env: {str: str}: Environment variables to execute under
|
||||
Returns:
|
||||
cmd, out, err, exitCode
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LocalExecutor(Executor):
|
||||
def __init__(self):
|
||||
super(LocalExecutor, self).__init__()
|
||||
self.is_windows = platform.system() == 'Windows'
|
||||
|
||||
def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None):
|
||||
cmd = cmd or [exe_path]
|
||||
env_cmd = []
|
||||
if env:
|
||||
env_cmd += ['env']
|
||||
env_cmd += ['%s=%s' % (k, v) for k, v in env.items()]
|
||||
if work_dir == '.':
|
||||
work_dir = os.getcwd()
|
||||
if not self.is_windows:
|
||||
out, err, rc = executeCommand(env_cmd + cmd, cwd=work_dir)
|
||||
else:
|
||||
out, err, rc = executeCommand(cmd, cwd=work_dir,
|
||||
env=self._build_windows_env(env))
|
||||
return (env_cmd + cmd, out, err, rc)
|
||||
|
||||
def _build_windows_env(self, exec_env):
|
||||
# FIXME: Finding Windows DLL's at runtime requires modifying the
|
||||
# PATH environment variables. However we don't want to print out
|
||||
# the entire PATH as part of the diagnostic for every failing test.
|
||||
# Therefore this hack builds a new executable environment that
|
||||
# merges the current environment and the supplied environment while
|
||||
# still only printing the supplied environment in diagnostics.
|
||||
if not self.is_windows or exec_env is None:
|
||||
return None
|
||||
new_env = dict(os.environ)
|
||||
for key, value in exec_env.items():
|
||||
if key == 'PATH':
|
||||
assert value.strip() != '' and "expected non-empty path"
|
||||
new_env['PATH'] = "%s;%s" % (value, os.environ['PATH'])
|
||||
else:
|
||||
new_env[key] = value
|
||||
return new_env
|
||||
|
||||
class PrefixExecutor(Executor):
|
||||
"""Prefix an executor with some other command wrapper.
|
||||
|
||||
Most useful for setting ulimits on commands, or running an emulator like
|
||||
qemu and valgrind.
|
||||
"""
|
||||
def __init__(self, commandPrefix, chain):
|
||||
super(PrefixExecutor, self).__init__()
|
||||
|
||||
self.commandPrefix = commandPrefix
|
||||
self.chain = chain
|
||||
|
||||
def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None):
|
||||
cmd = cmd or [exe_path]
|
||||
return self.chain.run(exe_path, self.commandPrefix + cmd, work_dir,
|
||||
file_deps, env=env)
|
||||
|
||||
|
||||
class PostfixExecutor(Executor):
|
||||
"""Postfix an executor with some args."""
|
||||
def __init__(self, commandPostfix, chain):
|
||||
super(PostfixExecutor, self).__init__()
|
||||
|
||||
self.commandPostfix = commandPostfix
|
||||
self.chain = chain
|
||||
|
||||
def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None):
|
||||
cmd = cmd or [exe_path]
|
||||
return self.chain.run(cmd + self.commandPostfix, work_dir, file_deps,
|
||||
env=env)
|
||||
|
||||
|
||||
|
||||
class TimeoutExecutor(PrefixExecutor):
|
||||
"""Execute another action under a timeout.
|
||||
|
||||
Deprecated. http://reviews.llvm.org/D6584 adds timeouts to LIT.
|
||||
"""
|
||||
def __init__(self, duration, chain):
|
||||
super(TimeoutExecutor, self).__init__(
|
||||
['timeout', duration], chain)
|
||||
|
||||
|
||||
class RemoteExecutor(Executor):
|
||||
def __init__(self):
|
||||
self.local_run = executeCommand
|
||||
|
||||
def remote_temp_dir(self):
|
||||
return self._remote_temp(True)
|
||||
|
||||
def remote_temp_file(self):
|
||||
return self._remote_temp(False)
|
||||
|
||||
def _remote_temp(self, is_dir):
|
||||
raise NotImplementedError()
|
||||
|
||||
def copy_in(self, local_srcs, remote_dsts):
|
||||
# This could be wrapped up in a tar->scp->untar for performance
|
||||
# if there are lots of files to be copied/moved
|
||||
for src, dst in zip(local_srcs, remote_dsts):
|
||||
self._copy_in_file(src, dst)
|
||||
|
||||
def _copy_in_file(self, src, dst):
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete_remote(self, remote):
|
||||
try:
|
||||
self._execute_command_remote(['rm', '-rf', remote])
|
||||
except OSError:
|
||||
# TODO: Log failure to delete?
|
||||
pass
|
||||
|
||||
def run(self, exe_path, cmd=None, work_dir='.', file_deps=None, env=None):
|
||||
target_exe_path = None
|
||||
target_cwd = None
|
||||
try:
|
||||
target_cwd = self.remote_temp_dir()
|
||||
target_exe_path = os.path.join(target_cwd, 'libcxx_test.exe')
|
||||
if cmd:
|
||||
# Replace exe_path with target_exe_path.
|
||||
cmd = [c if c != exe_path else target_exe_path for c in cmd]
|
||||
else:
|
||||
cmd = [target_exe_path]
|
||||
|
||||
srcs = [exe_path]
|
||||
dsts = [target_exe_path]
|
||||
if file_deps is not None:
|
||||
dev_paths = [os.path.join(target_cwd, os.path.basename(f))
|
||||
for f in file_deps]
|
||||
srcs.extend(file_deps)
|
||||
dsts.extend(dev_paths)
|
||||
self.copy_in(srcs, dsts)
|
||||
# TODO(jroelofs): capture the copy_in and delete_remote commands,
|
||||
# and conjugate them with '&&'s around the first tuple element
|
||||
# returned here:
|
||||
return self._execute_command_remote(cmd, target_cwd, env)
|
||||
finally:
|
||||
if target_cwd:
|
||||
self.delete_remote(target_cwd)
|
||||
|
||||
def _execute_command_remote(self, cmd, remote_work_dir='.', env=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class SSHExecutor(RemoteExecutor):
|
||||
def __init__(self, host, username=None):
|
||||
super(SSHExecutor, self).__init__()
|
||||
|
||||
self.user_prefix = username + '@' if username else ''
|
||||
self.host = host
|
||||
self.scp_command = 'scp'
|
||||
self.ssh_command = 'ssh'
|
||||
|
||||
# TODO(jroelofs): switch this on some -super-verbose-debug config flag
|
||||
if False:
|
||||
self.local_run = tracing.trace_function(
|
||||
self.local_run, log_calls=True, log_results=True,
|
||||
label='ssh_local')
|
||||
|
||||
def _remote_temp(self, is_dir):
|
||||
# TODO: detect what the target system is, and use the correct
|
||||
# mktemp command for it. (linux and darwin differ here, and I'm
|
||||
# sure windows has another way to do it)
|
||||
|
||||
# Not sure how to do suffix on osx yet
|
||||
dir_arg = '-d' if is_dir else ''
|
||||
cmd = 'mktemp -q {} /tmp/libcxx.XXXXXXXXXX'.format(dir_arg)
|
||||
temp_path, err, exitCode = self._execute_command_remote([cmd])
|
||||
temp_path = temp_path.strip()
|
||||
if exitCode != 0:
|
||||
raise RuntimeError(err)
|
||||
return temp_path
|
||||
|
||||
def _copy_in_file(self, src, dst):
|
||||
scp = self.scp_command
|
||||
remote = self.host
|
||||
remote = self.user_prefix + remote
|
||||
cmd = [scp, '-p', src, remote + ':' + dst]
|
||||
self.local_run(cmd)
|
||||
|
||||
def _execute_command_remote(self, cmd, remote_work_dir='.', env=None):
|
||||
remote = self.user_prefix + self.host
|
||||
ssh_cmd = [self.ssh_command, '-oBatchMode=yes', remote]
|
||||
if env:
|
||||
env_cmd = ['env'] + ['%s=%s' % (k, v) for k, v in env.items()]
|
||||
else:
|
||||
env_cmd = []
|
||||
remote_cmd = ' '.join(env_cmd + cmd)
|
||||
if remote_work_dir != '.':
|
||||
remote_cmd = 'cd ' + remote_work_dir + ' && ' + remote_cmd
|
||||
return self.local_run(ssh_cmd + [remote_cmd])
|
||||
@@ -1,240 +0,0 @@
|
||||
#===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.TXT for details.
|
||||
#
|
||||
#===----------------------------------------------------------------------===##
|
||||
|
||||
import copy
|
||||
import errno
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
|
||||
import lit.Test # pylint: disable=import-error
|
||||
import lit.TestRunner # pylint: disable=import-error
|
||||
from lit.TestRunner import ParserKind, IntegratedTestKeywordParser \
|
||||
# pylint: disable=import-error
|
||||
import lit.util # pylint: disable=import-error
|
||||
|
||||
|
||||
from libcxx.test.executor import LocalExecutor as LocalExecutor
|
||||
import libcxx.util
|
||||
|
||||
|
||||
class LibcxxTestFormat(object):
|
||||
"""
|
||||
Custom test format handler for use with the test format use by libc++.
|
||||
|
||||
Tests fall into two categories:
|
||||
FOO.pass.cpp - Executable test which should compile, run, and exit with
|
||||
code 0.
|
||||
FOO.fail.cpp - Negative test case which is expected to fail compilation.
|
||||
FOO.sh.cpp - A test that uses LIT's ShTest format.
|
||||
"""
|
||||
|
||||
def __init__(self, cxx, use_verify_for_fail, execute_external,
|
||||
executor, exec_env):
|
||||
self.cxx = copy.deepcopy(cxx)
|
||||
self.use_verify_for_fail = use_verify_for_fail
|
||||
self.execute_external = execute_external
|
||||
self.executor = executor
|
||||
self.exec_env = dict(exec_env)
|
||||
|
||||
@staticmethod
|
||||
def _make_custom_parsers():
|
||||
return [
|
||||
IntegratedTestKeywordParser('FLAKY_TEST.', ParserKind.TAG,
|
||||
initial_value=False),
|
||||
IntegratedTestKeywordParser('MODULES_DEFINES:', ParserKind.LIST,
|
||||
initial_value=[])
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def _get_parser(key, parsers):
|
||||
for p in parsers:
|
||||
if p.keyword == key:
|
||||
return p
|
||||
assert False and "parser not found"
|
||||
|
||||
# TODO: Move this into lit's FileBasedTest
|
||||
def getTestsInDirectory(self, testSuite, path_in_suite,
|
||||
litConfig, localConfig):
|
||||
source_path = testSuite.getSourcePath(path_in_suite)
|
||||
for filename in os.listdir(source_path):
|
||||
# Ignore dot files and excluded tests.
|
||||
if filename.startswith('.') or filename in localConfig.excludes:
|
||||
continue
|
||||
|
||||
filepath = os.path.join(source_path, filename)
|
||||
if not os.path.isdir(filepath):
|
||||
if any([filename.endswith(ext)
|
||||
for ext in localConfig.suffixes]):
|
||||
yield lit.Test.Test(testSuite, path_in_suite + (filename,),
|
||||
localConfig)
|
||||
|
||||
def execute(self, test, lit_config):
|
||||
while True:
|
||||
try:
|
||||
return self._execute(test, lit_config)
|
||||
except OSError as oe:
|
||||
if oe.errno != errno.ETXTBSY:
|
||||
raise
|
||||
time.sleep(0.1)
|
||||
|
||||
def _execute(self, test, lit_config):
|
||||
name = test.path_in_suite[-1]
|
||||
name_root, name_ext = os.path.splitext(name)
|
||||
is_libcxx_test = test.path_in_suite[0] == 'libcxx'
|
||||
is_sh_test = name_root.endswith('.sh')
|
||||
is_pass_test = name.endswith('.pass.cpp')
|
||||
is_fail_test = name.endswith('.fail.cpp')
|
||||
assert is_sh_test or name_ext == '.cpp', 'non-cpp file must be sh test'
|
||||
|
||||
if test.config.unsupported:
|
||||
return (lit.Test.UNSUPPORTED,
|
||||
"A lit.local.cfg marked this unsupported")
|
||||
|
||||
parsers = self._make_custom_parsers()
|
||||
script = lit.TestRunner.parseIntegratedTestScript(
|
||||
test, additional_parsers=parsers, require_script=is_sh_test)
|
||||
# Check if a result for the test was returned. If so return that
|
||||
# result.
|
||||
if isinstance(script, lit.Test.Result):
|
||||
return script
|
||||
if lit_config.noExecute:
|
||||
return lit.Test.Result(lit.Test.PASS)
|
||||
|
||||
# Check that we don't have run lines on tests that don't support them.
|
||||
if not is_sh_test and len(script) != 0:
|
||||
lit_config.fatal('Unsupported RUN line found in test %s' % name)
|
||||
|
||||
tmpDir, tmpBase = lit.TestRunner.getTempPaths(test)
|
||||
substitutions = lit.TestRunner.getDefaultSubstitutions(test, tmpDir,
|
||||
tmpBase)
|
||||
script = lit.TestRunner.applySubstitutions(script, substitutions)
|
||||
|
||||
test_cxx = copy.deepcopy(self.cxx)
|
||||
if is_fail_test:
|
||||
test_cxx.useCCache(False)
|
||||
test_cxx.useWarnings(False)
|
||||
extra_modules_defines = self._get_parser('MODULES_DEFINES:',
|
||||
parsers).getValue()
|
||||
if '-fmodules' in test.config.available_features:
|
||||
test_cxx.compile_flags += [('-D%s' % mdef.strip()) for
|
||||
mdef in extra_modules_defines]
|
||||
test_cxx.addWarningFlagIfSupported('-Wno-macro-redefined')
|
||||
# FIXME: libc++ debug tests #define _LIBCPP_ASSERT to override it
|
||||
# If we see this we need to build the test against uniquely built
|
||||
# modules.
|
||||
if is_libcxx_test:
|
||||
with open(test.getSourcePath(), 'r') as f:
|
||||
contents = f.read()
|
||||
if '#define _LIBCPP_ASSERT' in contents:
|
||||
test_cxx.useModules(False)
|
||||
|
||||
# Dispatch the test based on its suffix.
|
||||
if is_sh_test:
|
||||
if not isinstance(self.executor, LocalExecutor):
|
||||
# We can't run ShTest tests with a executor yet.
|
||||
# For now, bail on trying to run them
|
||||
return lit.Test.UNSUPPORTED, 'ShTest format not yet supported'
|
||||
test.config.enviroment = dict(self.exec_env)
|
||||
return lit.TestRunner._runShTest(test, lit_config,
|
||||
self.execute_external, script,
|
||||
tmpBase)
|
||||
elif is_fail_test:
|
||||
return self._evaluate_fail_test(test, test_cxx, parsers)
|
||||
elif is_pass_test:
|
||||
return self._evaluate_pass_test(test, tmpBase, lit_config,
|
||||
test_cxx, parsers)
|
||||
else:
|
||||
# No other test type is supported
|
||||
assert False
|
||||
|
||||
def _clean(self, exec_path): # pylint: disable=no-self-use
|
||||
libcxx.util.cleanFile(exec_path)
|
||||
|
||||
def _evaluate_pass_test(self, test, tmpBase, lit_config,
|
||||
test_cxx, parsers):
|
||||
execDir = os.path.dirname(test.getExecPath())
|
||||
source_path = test.getSourcePath()
|
||||
exec_path = tmpBase + '.exe'
|
||||
object_path = tmpBase + '.o'
|
||||
# Create the output directory if it does not already exist.
|
||||
lit.util.mkdir_p(os.path.dirname(tmpBase))
|
||||
try:
|
||||
# Compile the test
|
||||
cmd, out, err, rc = test_cxx.compileLinkTwoSteps(
|
||||
source_path, out=exec_path, object_file=object_path,
|
||||
cwd=execDir)
|
||||
compile_cmd = cmd
|
||||
if rc != 0:
|
||||
report = libcxx.util.makeReport(cmd, out, err, rc)
|
||||
report += "Compilation failed unexpectedly!"
|
||||
return lit.Test.FAIL, report
|
||||
# Run the test
|
||||
local_cwd = os.path.dirname(source_path)
|
||||
env = None
|
||||
if self.exec_env:
|
||||
env = self.exec_env
|
||||
# TODO: Only list actually needed files in file_deps.
|
||||
# Right now we just mark all of the .dat files in the same
|
||||
# directory as dependencies, but it's likely less than that. We
|
||||
# should add a `// FILE-DEP: foo.dat` to each test to track this.
|
||||
data_files = [os.path.join(local_cwd, f)
|
||||
for f in os.listdir(local_cwd) if f.endswith('.dat')]
|
||||
is_flaky = self._get_parser('FLAKY_TEST.', parsers).getValue()
|
||||
max_retry = 3 if is_flaky else 1
|
||||
for retry_count in range(max_retry):
|
||||
cmd, out, err, rc = self.executor.run(exec_path, [exec_path],
|
||||
local_cwd, data_files,
|
||||
env)
|
||||
if rc == 0:
|
||||
res = lit.Test.PASS if retry_count == 0 else lit.Test.FLAKYPASS
|
||||
return res, ''
|
||||
elif rc != 0 and retry_count + 1 == max_retry:
|
||||
report = libcxx.util.makeReport(cmd, out, err, rc)
|
||||
report = "Compiled With: %s\n%s" % (compile_cmd, report)
|
||||
report += "Compiled test failed unexpectedly!"
|
||||
return lit.Test.FAIL, report
|
||||
|
||||
assert False # Unreachable
|
||||
finally:
|
||||
# Note that cleanup of exec_file happens in `_clean()`. If you
|
||||
# override this, cleanup is your reponsibility.
|
||||
libcxx.util.cleanFile(object_path)
|
||||
self._clean(exec_path)
|
||||
|
||||
def _evaluate_fail_test(self, test, test_cxx, parsers):
|
||||
source_path = test.getSourcePath()
|
||||
# FIXME: lift this detection into LLVM/LIT.
|
||||
with open(source_path, 'r') as f:
|
||||
contents = f.read()
|
||||
verify_tags = ['expected-note', 'expected-remark', 'expected-warning',
|
||||
'expected-error', 'expected-no-diagnostics']
|
||||
use_verify = self.use_verify_for_fail and \
|
||||
any([tag in contents for tag in verify_tags])
|
||||
# FIXME(EricWF): GCC 5 does not evaluate static assertions that
|
||||
# are dependant on a template parameter when '-fsyntax-only' is passed.
|
||||
# This is fixed in GCC 6. However for now we only pass "-fsyntax-only"
|
||||
# when using Clang.
|
||||
if test_cxx.type != 'gcc':
|
||||
test_cxx.flags += ['-fsyntax-only']
|
||||
if use_verify:
|
||||
test_cxx.useVerify()
|
||||
test_cxx.useWarnings()
|
||||
if '-Wuser-defined-warnings' in test_cxx.warning_flags:
|
||||
test_cxx.warning_flags += ['-Wno-error=user-defined-warnings']
|
||||
|
||||
cmd, out, err, rc = test_cxx.compile(source_path, out=os.devnull)
|
||||
expected_rc = 0 if use_verify else 1
|
||||
if rc == expected_rc:
|
||||
return lit.Test.PASS, ''
|
||||
else:
|
||||
report = libcxx.util.makeReport(cmd, out, err, rc)
|
||||
report_msg = ('Expected compilation to fail!' if not use_verify else
|
||||
'Expected compilation using verify to pass!')
|
||||
return lit.Test.FAIL, report + report_msg + '\n'
|
||||
@@ -1,224 +0,0 @@
|
||||
#===----------------------------------------------------------------------===//
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.TXT for details.
|
||||
#
|
||||
#===----------------------------------------------------------------------===//
|
||||
|
||||
import importlib
|
||||
import lit.util # pylint: disable=import-error,no-name-in-module
|
||||
import locale
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
class DefaultTargetInfo(object):
|
||||
def __init__(self, full_config):
|
||||
self.full_config = full_config
|
||||
|
||||
def platform(self):
|
||||
return sys.platform.lower().strip()
|
||||
|
||||
def add_locale_features(self, features):
|
||||
self.full_config.lit_config.warning(
|
||||
"No locales entry for target_system: %s" % self.platform())
|
||||
|
||||
def add_cxx_compile_flags(self, flags): pass
|
||||
def add_cxx_link_flags(self, flags): pass
|
||||
def configure_env(self, env): pass
|
||||
def allow_cxxabi_link(self): return True
|
||||
def add_sanitizer_features(self, sanitizer_type, features): pass
|
||||
def use_lit_shell_default(self): return False
|
||||
|
||||
|
||||
def test_locale(loc):
|
||||
assert loc is not None
|
||||
default_locale = locale.setlocale(locale.LC_ALL)
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, loc)
|
||||
return True
|
||||
except locale.Error:
|
||||
return False
|
||||
finally:
|
||||
locale.setlocale(locale.LC_ALL, default_locale)
|
||||
|
||||
|
||||
def add_common_locales(features, lit_config):
|
||||
# A list of locales needed by the test-suite.
|
||||
# The list uses the canonical name for the locale used in the test-suite
|
||||
# TODO: On Linux ISO8859 *may* needs to hyphenated.
|
||||
locales = [
|
||||
'en_US.UTF-8',
|
||||
'fr_FR.UTF-8',
|
||||
'ru_RU.UTF-8',
|
||||
'zh_CN.UTF-8',
|
||||
'fr_CA.ISO8859-1',
|
||||
'cs_CZ.ISO8859-2'
|
||||
]
|
||||
for loc in locales:
|
||||
if test_locale(loc):
|
||||
features.add('locale.{0}'.format(loc))
|
||||
else:
|
||||
lit_config.warning('The locale {0} is not supported by '
|
||||
'your platform. Some tests will be '
|
||||
'unsupported.'.format(loc))
|
||||
|
||||
|
||||
class DarwinLocalTI(DefaultTargetInfo):
|
||||
def __init__(self, full_config):
|
||||
super(DarwinLocalTI, self).__init__(full_config)
|
||||
|
||||
def add_locale_features(self, features):
|
||||
add_common_locales(features, self.full_config.lit_config)
|
||||
|
||||
def add_cxx_compile_flags(self, flags):
|
||||
try:
|
||||
out = lit.util.capture(['xcrun', '--show-sdk-path']).strip()
|
||||
res = 0
|
||||
except OSError:
|
||||
res = -1
|
||||
if res == 0 and out:
|
||||
sdk_path = out
|
||||
self.full_config.lit_config.note('using SDKROOT: %r' % sdk_path)
|
||||
flags += ["-isysroot", sdk_path]
|
||||
|
||||
def add_cxx_link_flags(self, flags):
|
||||
flags += ['-lSystem']
|
||||
|
||||
def configure_env(self, env):
|
||||
library_paths = []
|
||||
# Configure the library path for libc++
|
||||
if self.full_config.use_system_cxx_lib:
|
||||
pass
|
||||
elif self.full_config.cxx_runtime_root:
|
||||
library_paths += [self.full_config.cxx_runtime_root]
|
||||
# Configure the abi library path
|
||||
if self.full_config.abi_library_root:
|
||||
library_paths += [self.full_config.abi_library_root]
|
||||
if library_paths:
|
||||
env['DYLD_LIBRARY_PATH'] = ':'.join(library_paths)
|
||||
|
||||
def allow_cxxabi_link(self):
|
||||
# FIXME: PR27405
|
||||
# libc++ *should* export all of the symbols found in libc++abi on OS X.
|
||||
# For this reason LibcxxConfiguration will not link libc++abi in OS X.
|
||||
# However __cxa_throw_bad_new_array_length doesn't get exported into
|
||||
# libc++ yet so we still need to explicitly link libc++abi when testing
|
||||
# libc++abi
|
||||
# See PR22654.
|
||||
if(self.full_config.get_lit_conf('name', '') == 'libc++abi'):
|
||||
return True
|
||||
# Don't link libc++abi explicitly on OS X because the symbols
|
||||
# should be available in libc++ directly.
|
||||
return False
|
||||
|
||||
def add_sanitizer_features(self, sanitizer_type, features):
|
||||
if sanitizer_type == 'Undefined':
|
||||
features.add('sanitizer-new-delete')
|
||||
|
||||
|
||||
class FreeBSDLocalTI(DefaultTargetInfo):
|
||||
def __init__(self, full_config):
|
||||
super(FreeBSDLocalTI, self).__init__(full_config)
|
||||
|
||||
def add_locale_features(self, features):
|
||||
add_common_locales(features, self.full_config.lit_config)
|
||||
|
||||
def add_cxx_link_flags(self, flags):
|
||||
flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt']
|
||||
|
||||
|
||||
class LinuxLocalTI(DefaultTargetInfo):
|
||||
def __init__(self, full_config):
|
||||
super(LinuxLocalTI, self).__init__(full_config)
|
||||
|
||||
def platform(self):
|
||||
return 'linux'
|
||||
|
||||
def platform_name(self):
|
||||
name, _, _ = platform.linux_distribution()
|
||||
name = name.lower().strip()
|
||||
return name # Permitted to be None
|
||||
|
||||
def platform_ver(self):
|
||||
_, ver, _ = platform.linux_distribution()
|
||||
ver = ver.lower().strip()
|
||||
return ver # Permitted to be None.
|
||||
|
||||
def add_locale_features(self, features):
|
||||
add_common_locales(features, self.full_config.lit_config)
|
||||
# Some linux distributions have different locale data than others.
|
||||
# Insert the distributions name and name-version into the available
|
||||
# features to allow tests to XFAIL on them.
|
||||
name = self.platform_name()
|
||||
ver = self.platform_ver()
|
||||
if name:
|
||||
features.add(name)
|
||||
if name and ver:
|
||||
features.add('%s-%s' % (name, ver))
|
||||
|
||||
def add_cxx_compile_flags(self, flags):
|
||||
flags += ['-D__STDC_FORMAT_MACROS',
|
||||
'-D__STDC_LIMIT_MACROS',
|
||||
'-D__STDC_CONSTANT_MACROS']
|
||||
|
||||
def add_cxx_link_flags(self, flags):
|
||||
enable_threads = ('libcpp-has-no-threads' not in
|
||||
self.full_config.config.available_features)
|
||||
llvm_unwinder = self.full_config.get_lit_bool('llvm_unwinder', False)
|
||||
shared_libcxx = self.full_config.get_lit_bool('enable_shared', True)
|
||||
flags += ['-lm']
|
||||
if not llvm_unwinder:
|
||||
flags += ['-lgcc_s', '-lgcc']
|
||||
if enable_threads:
|
||||
flags += ['-lpthread']
|
||||
if not shared_libcxx:
|
||||
flags += ['-lrt']
|
||||
flags += ['-lc']
|
||||
if llvm_unwinder:
|
||||
flags += ['-lunwind', '-ldl']
|
||||
else:
|
||||
flags += ['-lgcc_s']
|
||||
flags += ['-lgcc']
|
||||
use_libatomic = self.full_config.get_lit_bool('use_libatomic', False)
|
||||
if use_libatomic:
|
||||
flags += ['-latomic']
|
||||
san = self.full_config.get_lit_conf('use_sanitizer', '').strip()
|
||||
if san:
|
||||
# The libraries and their order are taken from the
|
||||
# linkSanitizerRuntimeDeps function in
|
||||
# clang/lib/Driver/Tools.cpp
|
||||
flags += ['-lpthread', '-lrt', '-lm', '-ldl']
|
||||
|
||||
|
||||
class WindowsLocalTI(DefaultTargetInfo):
|
||||
def __init__(self, full_config):
|
||||
super(WindowsLocalTI, self).__init__(full_config)
|
||||
|
||||
def add_locale_features(self, features):
|
||||
add_common_locales(features, self.full_config.lit_config)
|
||||
|
||||
def use_lit_shell_default(self):
|
||||
# Default to the internal shell on Windows, as bash on Windows is
|
||||
# usually very slow.
|
||||
return True
|
||||
|
||||
|
||||
def make_target_info(full_config):
|
||||
default = "libcxx.test.target_info.LocalTI"
|
||||
info_str = full_config.get_lit_conf('target_info', default)
|
||||
if info_str != default:
|
||||
mod_path, _, info = info_str.rpartition('.')
|
||||
mod = importlib.import_module(mod_path)
|
||||
target_info = getattr(mod, info)(full_config)
|
||||
full_config.lit_config.note("inferred target_info as: %r" % info_str)
|
||||
return target_info
|
||||
target_system = platform.system()
|
||||
if target_system == 'Darwin': return DarwinLocalTI(full_config)
|
||||
if target_system == 'FreeBSD': return FreeBSDLocalTI(full_config)
|
||||
if target_system == 'Linux': return LinuxLocalTI(full_config)
|
||||
if target_system == 'Windows': return WindowsLocalTI(full_config)
|
||||
return DefaultTargetInfo(full_config)
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.TXT for details.
|
||||
#
|
||||
#===----------------------------------------------------------------------===##
|
||||
|
||||
import os
|
||||
import inspect
|
||||
|
||||
|
||||
def trace_function(function, log_calls, log_results, label=''):
|
||||
def wrapper(*args, **kwargs):
|
||||
kwarg_strs = ['{}={}'.format(k, v) for (k, v) in kwargs]
|
||||
arg_str = ', '.join([str(a) for a in args] + kwarg_strs)
|
||||
call_str = '{}({})'.format(function.func_name, arg_str)
|
||||
|
||||
# Perform the call itself, logging before, after, and anything thrown.
|
||||
try:
|
||||
if log_calls:
|
||||
print('{}: Calling {}'.format(label, call_str))
|
||||
res = function(*args, **kwargs)
|
||||
if log_results:
|
||||
print('{}: {} -> {}'.format(label, call_str, res))
|
||||
return res
|
||||
except Exception as ex:
|
||||
if log_results:
|
||||
print('{}: {} raised {}'.format(label, call_str, type(ex)))
|
||||
raise ex
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def trace_object(obj, log_calls, log_results, label=''):
|
||||
for name, member in inspect.getmembers(obj):
|
||||
if inspect.ismethod(member):
|
||||
# Skip meta-functions, decorate everything else
|
||||
if not member.func_name.startswith('__'):
|
||||
setattr(obj, name, trace_function(member, log_calls,
|
||||
log_results, label))
|
||||
return obj
|
||||
@@ -1,55 +0,0 @@
|
||||
#===----------------------------------------------------------------------===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is dual licensed under the MIT and the University of Illinois Open
|
||||
# Source Licenses. See LICENSE.TXT for details.
|
||||
#
|
||||
#===----------------------------------------------------------------------===##
|
||||
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
|
||||
def cleanFile(filename):
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
@contextmanager
|
||||
def guardedTempFilename(suffix='', prefix='', dir=None):
|
||||
# Creates and yeilds a temporary filename within a with statement. The file
|
||||
# is removed upon scope exit.
|
||||
handle, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir)
|
||||
os.close(handle)
|
||||
yield name
|
||||
cleanFile(name)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def guardedFilename(name):
|
||||
# yeilds a filename within a with statement. The file is removed upon scope
|
||||
# exit.
|
||||
yield name
|
||||
cleanFile(name)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def nullContext(value):
|
||||
# yeilds a variable within a with statement. No action is taken upon scope
|
||||
# exit.
|
||||
yield value
|
||||
|
||||
|
||||
def makeReport(cmd, out, err, rc):
|
||||
report = "Command: %s\n" % cmd
|
||||
report += "Exit Code: %d\n" % rc
|
||||
if out:
|
||||
report += "Standard Output:\n--\n%s--\n" % out
|
||||
if err:
|
||||
report += "Standard Error:\n--\n%s--\n" % err
|
||||
report += '\n'
|
||||
return report
|
||||
Reference in New Issue
Block a user