
Summary: Detecting `-Wno-<warning>` flags can be tricky with GCC (See https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html). This patch adds a special `addWarningFlagIfSupported(<flag>)` method to the test compiler object that can be used to add warning flags. The goal of this patch is to help get the test suite running with more warnings. Reviewers: danalbert, jroelofs Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D11333 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@246069 91177308-0d34-0410-b5e6-96231b3b80d8
725 lines
32 KiB
Python
725 lines
32 KiB
Python
import importlib
|
|
import locale
|
|
import os
|
|
import platform
|
|
import pkgutil
|
|
import re
|
|
import shlex
|
|
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.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.cxx = None
|
|
self.libcxx_src_root = None
|
|
self.libcxx_obj_root = None
|
|
self.cxx_library_root = None
|
|
self.abi_library_root = None
|
|
self.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):
|
|
conf = self.get_lit_conf(name)
|
|
if conf is None:
|
|
return default
|
|
if conf.lower() in ('1', 'true'):
|
|
return True
|
|
if conf.lower() in ('', '0', 'false'):
|
|
return False
|
|
self.lit_config.fatal(
|
|
"parameter '{}' should be true or false".format(name))
|
|
|
|
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_library_root()
|
|
self.configure_use_system_cxx_lib()
|
|
self.configure_use_clang_verify()
|
|
self.configure_execute_external()
|
|
self.configure_ccache()
|
|
self.configure_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_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)
|
|
self.lit_config.note('Using compile flags: %s'
|
|
% self.cxx.compile_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.env)
|
|
|
|
def get_test_format(self):
|
|
return LibcxxTestFormat(
|
|
self.cxx,
|
|
self.use_clang_verify,
|
|
self.execute_external,
|
|
self.executor,
|
|
exec_env=self.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):
|
|
default = "libcxx.test.target_info.LocalTI"
|
|
info_str = self.get_lit_conf('target_info', default)
|
|
mod_path, _, info = info_str.rpartition('.')
|
|
mod = importlib.import_module(mod_path)
|
|
self.target_info = getattr(mod, info)()
|
|
if info_str != default:
|
|
self.lit_config.note("inferred target_info as: %r" % info_str)
|
|
|
|
def configure_cxx(self):
|
|
# Gather various compiler parameters.
|
|
cxx = self.get_lit_conf('cxx_under_test')
|
|
|
|
# If no specific cxx_under_test was given, attempt to infer it as
|
|
# clang++.
|
|
if cxx is None:
|
|
clangxx = lit.util.which('clang++',
|
|
self.config.environment['PATH'])
|
|
if clangxx:
|
|
cxx = clangxx
|
|
self.lit_config.note(
|
|
"inferred cxx_under_test as: %r" % cxx)
|
|
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)
|
|
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.%s' % (
|
|
cxx_type, maj_v, min_v))
|
|
|
|
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.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root')
|
|
|
|
def configure_cxx_library_root(self):
|
|
self.cxx_library_root = self.get_lit_conf('cxx_library_root',
|
|
self.libcxx_obj_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_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.hasCompileFlag(
|
|
['-Xclang', '-verify-ignore-unexpected'])
|
|
self.lit_config.note(
|
|
"inferred use_clang_verify as: %r" % self.use_clang_verify)
|
|
|
|
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 default to internal on Windows and
|
|
# external elsewhere, as bash on Windows is usually very slow.
|
|
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 = sys.platform == 'win32'
|
|
# 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())
|
|
|
|
# Figure out which of the required locales we support
|
|
locales = {
|
|
'Darwin': {
|
|
'en_US.UTF-8': 'en_US.UTF-8',
|
|
'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
|
|
'fr_FR.UTF-8': 'fr_FR.UTF-8',
|
|
'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1',
|
|
'ru_RU.UTF-8': 'ru_RU.UTF-8',
|
|
'zh_CN.UTF-8': 'zh_CN.UTF-8',
|
|
},
|
|
'FreeBSD': {
|
|
'en_US.UTF-8': 'en_US.UTF-8',
|
|
'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
|
|
'fr_FR.UTF-8': 'fr_FR.UTF-8',
|
|
'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1',
|
|
'ru_RU.UTF-8': 'ru_RU.UTF-8',
|
|
'zh_CN.UTF-8': 'zh_CN.UTF-8',
|
|
},
|
|
'Linux': {
|
|
'en_US.UTF-8': 'en_US.UTF-8',
|
|
'cs_CZ.ISO8859-2': 'cs_CZ.ISO-8859-2',
|
|
'fr_FR.UTF-8': 'fr_FR.UTF-8',
|
|
'fr_CA.ISO8859-1': 'fr_CA.ISO-8859-1',
|
|
'ru_RU.UTF-8': 'ru_RU.UTF-8',
|
|
'zh_CN.UTF-8': 'zh_CN.UTF-8',
|
|
},
|
|
'Windows': {
|
|
'en_US.UTF-8': 'English_United States.1252',
|
|
'cs_CZ.ISO8859-2': 'Czech_Czech Republic.1250',
|
|
'fr_FR.UTF-8': 'French_France.1252',
|
|
'fr_CA.ISO8859-1': 'French_Canada.1252',
|
|
'ru_RU.UTF-8': 'Russian_Russia.1251',
|
|
'zh_CN.UTF-8': 'Chinese_China.936',
|
|
},
|
|
}
|
|
|
|
target_system = self.target_info.system()
|
|
target_platform = self.target_info.platform()
|
|
|
|
if target_system in locales:
|
|
default_locale = locale.setlocale(locale.LC_ALL)
|
|
for feature, loc in locales[target_system].items():
|
|
try:
|
|
locale.setlocale(locale.LC_ALL, loc)
|
|
self.config.available_features.add(
|
|
'locale.{0}'.format(feature))
|
|
except locale.Error:
|
|
self.lit_config.warning('The locale {0} is not supported by '
|
|
'your platform. Some tests will be '
|
|
'unsupported.'.format(loc))
|
|
locale.setlocale(locale.LC_ALL, default_locale)
|
|
else:
|
|
# Warn that the user doesn't get any free XFAILs for locale issues
|
|
self.lit_config.warning("No locales entry for target_system: %s" %
|
|
target_system)
|
|
|
|
# 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=%s' % self.config.target_triple)
|
|
|
|
# Insert the platform name into the available features as a lower case.
|
|
self.config.available_features.add(target_platform)
|
|
|
|
# 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.
|
|
if target_platform == 'linux':
|
|
name = self.target_info.platform_name()
|
|
ver = self.target_info.platform_ver()
|
|
if name:
|
|
self.config.available_features.add(name)
|
|
if name and ver:
|
|
self.config.available_features.add('%s-%s' % (name, ver))
|
|
|
|
# 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')
|
|
|
|
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()
|
|
# Configure extra flags
|
|
compile_flags_str = self.get_lit_conf('compile_flags', '')
|
|
self.cxx.compile_flags += shlex.split(compile_flags_str)
|
|
|
|
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', 'c++11')
|
|
self.cxx.compile_flags += ['-std={0}'.format(std)]
|
|
self.config.available_features.add(std)
|
|
# Configure include paths
|
|
self.cxx.compile_flags += ['-nostdinc++']
|
|
self.configure_compile_flags_header_includes()
|
|
if self.target_info.platform() == 'linux':
|
|
self.cxx.compile_flags += ['-D__STDC_FORMAT_MACROS',
|
|
'-D__STDC_LIMIT_MACROS',
|
|
'-D__STDC_CONSTANT_MACROS']
|
|
# Configure feature flags.
|
|
self.configure_compile_flags_exceptions()
|
|
self.configure_compile_flags_rtti()
|
|
self.configure_compile_flags_no_global_filesystem_namespace()
|
|
self.configure_compile_flags_no_stdin()
|
|
self.configure_compile_flags_no_stdout()
|
|
enable_32bit = self.get_lit_bool('enable_32bit', False)
|
|
if enable_32bit:
|
|
self.cxx.flags += ['-m32']
|
|
# Configure threading features.
|
|
enable_threads = self.get_lit_bool('enable_threads', True)
|
|
enable_monotonic_clock = self.get_lit_bool('enable_monotonic_clock',
|
|
True)
|
|
if not enable_threads:
|
|
self.configure_compile_flags_no_threads()
|
|
if not enable_monotonic_clock:
|
|
self.configure_compile_flags_no_monotonic_clock()
|
|
elif not enable_monotonic_clock:
|
|
self.lit_config.fatal('enable_monotonic_clock cannot be false when'
|
|
' enable_threads is true.')
|
|
self.configure_compile_flags_no_thread_unsafe_c_functions()
|
|
|
|
# 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:
|
|
self.cxx.flags += ['-target', self.config.target_triple]
|
|
|
|
def configure_compile_flags_header_includes(self):
|
|
support_path = os.path.join(self.libcxx_src_root, 'test/support')
|
|
self.cxx.compile_flags += ['-I' + support_path]
|
|
self.cxx.compile_flags += ['-include', os.path.join(support_path, 'nasty_macros.hpp')]
|
|
libcxx_headers = self.get_lit_conf(
|
|
'libcxx_headers', os.path.join(self.libcxx_src_root, 'include'))
|
|
if not os.path.isdir(libcxx_headers):
|
|
self.lit_config.fatal("libcxx_headers='%s' is not a directory."
|
|
% libcxx_headers)
|
|
self.cxx.compile_flags += ['-I' + libcxx_headers]
|
|
|
|
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_no_global_filesystem_namespace(self):
|
|
enable_global_filesystem_namespace = self.get_lit_bool(
|
|
'enable_global_filesystem_namespace', True)
|
|
if not enable_global_filesystem_namespace:
|
|
self.config.available_features.add(
|
|
'libcpp-has-no-global-filesystem-namespace')
|
|
self.cxx.compile_flags += [
|
|
'-D_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE']
|
|
|
|
def configure_compile_flags_no_stdin(self):
|
|
enable_stdin = self.get_lit_bool('enable_stdin', True)
|
|
if not enable_stdin:
|
|
self.config.available_features.add('libcpp-has-no-stdin')
|
|
self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDIN']
|
|
|
|
def configure_compile_flags_no_stdout(self):
|
|
enable_stdout = self.get_lit_bool('enable_stdout', True)
|
|
if not enable_stdout:
|
|
self.config.available_features.add('libcpp-has-no-stdout')
|
|
self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDOUT']
|
|
|
|
def configure_compile_flags_no_threads(self):
|
|
self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_THREADS']
|
|
self.config.available_features.add('libcpp-has-no-threads')
|
|
|
|
def configure_compile_flags_no_thread_unsafe_c_functions(self):
|
|
enable_thread_unsafe_c_functions = self.get_lit_bool(
|
|
'enable_thread_unsafe_c_functions', True)
|
|
if not enable_thread_unsafe_c_functions:
|
|
self.cxx.compile_flags += [
|
|
'-D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS']
|
|
self.config.available_features.add(
|
|
'libcpp-has-no-thread-unsafe-c-functions')
|
|
|
|
def configure_compile_flags_no_monotonic_clock(self):
|
|
self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_MONOTONIC_CLOCK']
|
|
self.config.available_features.add('libcpp-has-no-monotonic-clock')
|
|
|
|
def configure_link_flags(self):
|
|
no_default_flags = self.get_lit_bool('no_default_flags', False)
|
|
if not no_default_flags:
|
|
self.cxx.link_flags += ['-nodefaultlibs']
|
|
|
|
# Configure library path
|
|
self.configure_link_flags_cxx_library_path()
|
|
self.configure_link_flags_abi_library_path()
|
|
|
|
# Configure libraries
|
|
self.configure_link_flags_cxx_library()
|
|
self.configure_link_flags_abi_library()
|
|
self.configure_extra_library_flags()
|
|
|
|
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):
|
|
libcxx_library = self.get_lit_conf('libcxx_library')
|
|
# Configure libc++ library paths.
|
|
if libcxx_library is not None:
|
|
# Check that the given value for libcxx_library is valid.
|
|
if not os.path.isfile(libcxx_library):
|
|
self.lit_config.fatal(
|
|
"libcxx_library='%s' is not a valid file." %
|
|
libcxx_library)
|
|
if self.use_system_cxx_lib:
|
|
self.lit_config.fatal(
|
|
"Conflicting options: 'libcxx_library' cannot be used "
|
|
"with 'use_system_cxx_lib=true'")
|
|
self.cxx.link_flags += ['-Wl,-rpath,' +
|
|
os.path.dirname(libcxx_library)]
|
|
elif not self.use_system_cxx_lib and self.cxx_library_root:
|
|
self.cxx.link_flags += ['-L' + self.cxx_library_root,
|
|
'-Wl,-rpath,' + self.cxx_library_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,
|
|
'-Wl,-rpath,' + self.abi_library_root]
|
|
|
|
def configure_link_flags_cxx_library(self):
|
|
libcxx_library = self.get_lit_conf('libcxx_library')
|
|
if libcxx_library:
|
|
self.cxx.link_flags += [libcxx_library]
|
|
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':
|
|
# Don't link libc++abi explicitly on OS X because the symbols
|
|
# should be available in libc++ directly.
|
|
if self.target_info.platform() != 'darwin':
|
|
self.cxx.link_flags += ['-lc++abi']
|
|
elif cxx_abi == 'libcxxrt':
|
|
self.cxx.link_flags += ['-lcxxrt']
|
|
elif cxx_abi == 'none':
|
|
pass
|
|
else:
|
|
self.lit_config.fatal(
|
|
'C++ ABI setting %s unsupported for tests' % cxx_abi)
|
|
|
|
def configure_extra_library_flags(self):
|
|
enable_threads = self.get_lit_bool('enable_threads', True)
|
|
llvm_unwinder = self.get_lit_bool('llvm_unwinder', False)
|
|
target_platform = self.target_info.platform()
|
|
if target_platform == 'darwin':
|
|
self.cxx.link_flags += ['-lSystem']
|
|
elif target_platform == 'linux':
|
|
if not llvm_unwinder:
|
|
self.cxx.link_flags += ['-lgcc_eh']
|
|
self.cxx.link_flags += ['-lc', '-lm']
|
|
if enable_threads:
|
|
self.cxx.link_flags += ['-lpthread']
|
|
self.cxx.link_flags += ['-lrt']
|
|
if llvm_unwinder:
|
|
self.cxx.link_flags += ['-lunwind', '-ldl']
|
|
else:
|
|
self.cxx.link_flags += ['-lgcc_s']
|
|
elif target_platform.startswith('freebsd'):
|
|
self.cxx.link_flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt']
|
|
else:
|
|
self.lit_config.fatal("unrecognized system: %r" % target_platform)
|
|
|
|
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):
|
|
enable_warnings = self.get_lit_bool('enable_warnings', False)
|
|
if enable_warnings:
|
|
self.cxx.compile_flags += [
|
|
'-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER',
|
|
'-Wall', '-Werror'
|
|
]
|
|
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')
|
|
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:
|
|
# 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)
|
|
# Setup the sanitizer compile flags
|
|
self.cxx.flags += ['-g', '-fno-omit-frame-pointer']
|
|
if self.target_info.platform() == 'linux':
|
|
self.cxx.link_flags += ['-ldl']
|
|
if san == 'Address':
|
|
self.cxx.flags += ['-fsanitize=address']
|
|
if llvm_symbolizer is not None:
|
|
self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
|
|
self.config.available_features.add('asan')
|
|
self.config.available_features.add('sanitizer-new-delete')
|
|
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.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
|
|
self.config.available_features.add('msan')
|
|
self.config.available_features.add('sanitizer-new-delete')
|
|
elif san == 'Undefined':
|
|
self.cxx.flags += ['-fsanitize=undefined',
|
|
'-fno-sanitize=vptr,function',
|
|
'-fno-sanitize-recover']
|
|
self.cxx.compile_flags += ['-O3']
|
|
self.config.available_features.add('ubsan')
|
|
if self.target_info.platform() == 'darwin':
|
|
self.config.available_features.add('sanitizer-new-delete')
|
|
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_substitutions(self):
|
|
sub = self.config.substitutions
|
|
# Configure compiler substitions
|
|
sub.append(('%cxx', self.cxx.path))
|
|
# Configure flags substitutions
|
|
flags_str = ' '.join(self.cxx.flags)
|
|
compile_flags_str = ' '.join(self.cxx.compile_flags)
|
|
link_flags_str = ' '.join(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))
|
|
# 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
|
|
sub.append(('%compile', compile_str))
|
|
sub.append(('%link', link_str))
|
|
sub.append(('%build', build_str))
|
|
# Configure exec prefix substitutions.
|
|
exec_env_str = 'env ' if len(self.env) != 0 else ''
|
|
for k, v in self.env.items():
|
|
exec_env_str += ' %s=%s' % (k, v)
|
|
# Configure run env substitution.
|
|
exec_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 substitions
|
|
not_py = os.path.join(self.libcxx_src_root, 'utils', 'not', '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 = bool(self.config.target_triple)
|
|
# If no target triple was given, try to infer it from the compiler
|
|
# under test.
|
|
if not self.use_target:
|
|
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):
|
|
if self.target_info.platform() == 'darwin':
|
|
library_paths = []
|
|
# Configure the library path for libc++
|
|
libcxx_library = self.get_lit_conf('libcxx_library')
|
|
if self.use_system_cxx_lib:
|
|
pass
|
|
elif libcxx_library:
|
|
library_paths += [os.path.dirname(libcxx_library)]
|
|
elif self.cxx_library_root:
|
|
library_paths += [self.cxx_library_root]
|
|
# Configure the abi library path
|
|
if self.abi_library_root:
|
|
library_paths += [self.abi_library_root]
|
|
if library_paths:
|
|
self.env['DYLD_LIBRARY_PATH'] = ':'.join(library_paths)
|