Files
android_external_libcxx/utils/libcxx/test/config.py
Saleem Abdulrasool 958d196f22 test: prevent incorrect quoting of paths
The path would previously get an extra leading space as the arguments
would be parsed when generating the final command to run.  Pretokenise
the arguments to permit proper quoting of the paths.  This avoids a
number of ignoring non-existent path warnings from clang.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@295511 91177308-0d34-0410-b5e6-96231b3b80d8
2017-02-17 23:08:46 +00:00

982 lines
46 KiB
Python

#===----------------------------------------------------------------------===##
#
# 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
from libcxx.compiler import CXXCompiler
from libcxx.test.target_info import make_target_info
from libcxx.test.executor import *
from libcxx.test.tracing import *
import libcxx.util
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):
from libcxx.test.format import LibcxxTestFormat
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:
search_paths = self.config.environment['PATH']
if cxx is not None and os.path.isabs(cxx):
search_paths = os.path.dirname(cxx)
clangxx = libcxx.util.which('clang++', search_paths)
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):
def _split_env_var(var):
return [p.strip() for p in os.environ.get(var, '').split(';') if p.strip()]
def _prefixed_env_list(var, prefix):
from itertools import chain
return list(chain.from_iterable((prefix, path) for path in _split_env_var(var)))
assert self.cxx_is_clang_cl
flags = []
compile_flags = _prefixed_env_list('INCLUDE', '-isystem')
link_flags = _prefixed_env_list('LIB', '-L')
for path in _list_env_var('LIB'):
self.add_path(self.exec_env, path)
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 '__cpp_deduction_guides' not in macros:
self.config.available_features.add('libcpp-no-deduction-guides')
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]
# NOTE: the _DEBUG definition must preceed the triple check because for
# the Windows build of libc++, the forced inclusion of a header requires
# that _DEBUG is defined. Incorrect ordering will result in -target
# being elided.
if self.is_windows and self.debug_build:
self.cxx.compile_flags += ['-D_DEBUG']
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')
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 = libcxx.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 = libcxx.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://bugs.llvm.org/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
cxx_path = pipes.quote(self.cxx.path)
# Configure compiler substitutions
sub.append(('%cxx', 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 = (cxx_path + ' -o %t.o %s -c ' + flags_str
+ ' ' + compile_flags_str)
link_str = (cxx_path + ' -o %t.exe %t.o ' + flags_str + ' '
+ link_flags_str)
assert type(link_str) is str
build_str = 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 ' % (pipes.quote(sys.executable), pipes.quote(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'])