Files
android_external_libcxx/utils/libcxx/test/config.py
Eric Fiselier b2e9337b06 Fix filesystem build on platforms with weird time_t types.
32-bit powerpc provides a 64 bit time_t type and older ppc64 systems
provide time_t as a floating point type. This caused problems when building
operations.cpp since operations.cpp contained compile time tests for conversions
between time_t and filesystem time type.

When these tests failed they caused the libc++ build to fail as well. This is unfortunate.

This patch moves the tests out of the source file and into the test suite. It also
expands the tests to allow testing of the weird time_t configurations on all platforms.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@307461 91177308-0d34-0410-b5e6-96231b3b80d8
2017-07-08 04:18:41 +00:00

1152 lines
54 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 = dict(os.environ)
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 get_modules_enabled(self):
return self.get_lit_bool('enable_modules',
default=False,
env_var='LIBCXX_ENABLE_MODULES')
def make_static_lib_name(self, name):
"""Return the full filename for the specified library name"""
if self.is_windows:
assert name == 'c++' # Only allow libc++ to use this function for now.
return 'lib' + name + '.lib'
else:
return 'lib' + name + '.a'
def configure(self):
self.configure_executor()
self.configure_use_system_cxx_lib()
self.configure_target_info()
self.configure_cxx()
self.configure_triple()
self.configure_deployment()
self.configure_availability()
self.configure_src_root()
self.configure_obj_root()
self.configure_cxx_stdlib_under_test()
self.configure_cxx_library_root()
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_coroutines()
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))
show_env_vars = {}
for k,v in self.exec_env.items():
if k not in os.environ or os.environ[k] != v:
show_env_vars[k] = v
self.lit_config.note('Adding environment variables: %r' % show_env_vars)
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 _split_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.
# Default to testing against the locally built libc++ library.
self.use_system_cxx_lib = self.get_lit_conf('use_system_cxx_lib')
if self.use_system_cxx_lib == 'true':
self.use_system_cxx_lib = True
elif self.use_system_cxx_lib == 'false':
self.use_system_cxx_lib = False
elif self.use_system_cxx_lib:
assert os.path.isdir(self.use_system_cxx_lib)
self.lit_config.note(
"inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)
def configure_availability(self):
# See http://llvm.org/docs/AvailabilityMarkup.html
self.with_availability = self.get_lit_bool('with_availability', False)
self.lit_config.note(
"inferred with_availability as: %r" % self.with_availability)
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.'''
if self.with_availability:
self.use_clang_verify = False
return
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()
self.lit_config.note(
"inferred use_clang_verify as: %r" % self.use_clang_verify)
if self.use_clang_verify:
self.config.available_features.add('verify-support')
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 add_deployment_feature(self, feature):
(arch, name, version) = self.config.deployment
self.config.available_features.add('%s=%s-%s' % (feature, arch, name))
self.config.available_features.add('%s=%s' % (feature, name))
self.config.available_features.add('%s=%s%s' % (feature, name, version))
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)
# Add subcomponents individually.
target_components = self.config.target_triple.split('-')
for component in target_components:
self.config.available_features.add(
'with_system_cxx_lib=%s' % component)
# Add available features for more generic versions of the target
# triple attached to with_system_cxx_lib.
if self.use_deployment:
self.add_deployment_feature('with_system_cxx_lib')
# Configure the availability markup checks features.
if self.with_availability:
self.config.available_features.add('availability_markup')
self.add_deployment_feature('availability_markup')
if self.use_system_cxx_lib or self.with_availability:
self.config.available_features.add('availability')
self.add_deployment_feature('availability')
if platform.system() == 'Darwin':
self.config.available_features.add('apple-darwin')
# 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.cxx.hasCompileFlag('-fdelayed-template-parsing'):
self.config.available_features.add('fdelayed-template-parsing')
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')
if self.cxx_stdlib_under_test == 'libc++':
# LIBCXX-WINDOWS-FIXME is the feature name used to XFAIL the
# initial Windows failures until they can be properly diagnosed
# and fixed. This allows easier detection of new test failures
# and regressions. Note: New failures should not be suppressed
# using this feature. (Also see llvm.org/PR32730)
self.config.available_features.add('LIBCXX-WINDOWS-FIXME')
# Attempt to detect the glibc version by querying for __GLIBC__
# in 'features.h'.
macros = self.cxx.dumpMacros(flags=['-include', 'features.h'])
if macros is not None and '__GLIBC__' in macros:
maj_v, min_v = (macros['__GLIBC__'], macros['__GLIBC_MINOR__'])
self.config.available_features.add('glibc')
self.config.available_features.add('glibc-%s' % maj_v)
self.config.available_features.add('glibc-%s.%s' % (maj_v, min_v))
# Support Objective-C++ only on MacOS and if the compiler supports it.
if self.target_info.platform() == "darwin" and \
self.target_info.is_host_macosx() and \
self.cxx.hasCompileFlag(["-x", "objective-c++", "-fobjc-arc"]):
self.config.available_features.add("objective-c++")
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)
if self.is_windows:
# FIXME: Can we remove this?
self.cxx.compile_flags += ['-D_CRT_SECURE_NO_WARNINGS']
# Required so that tests using min/max don't fail on Windows,
# and so that those tests don't have to be changed to tolerate
# this insanity.
self.cxx.compile_flags += ['-DNOMINMAX']
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')
if self.use_deployment:
arch, name, version = self.config.deployment
self.cxx.flags += ['-arch', arch]
self.cxx.flags += ['-m' + name + '-version-min=' + version]
# Disable availability unless explicitely requested
if not self.with_availability:
self.cxx.flags += ['-D_LIBCPP_DISABLE_AVAILABILITY']
def configure_compile_flags_header_includes(self):
support_path = os.path.join(self.libcxx_src_root, 'test', 'support')
self.configure_config_site_header()
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')
]
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
# FIXME: This is a hack that should be fixed using module maps (or something)
# If modules are enabled then we have to lift all of the definitions
# in __config_site onto the command line.
modules_enabled = self.get_modules_enabled()
self.cxx.compile_flags += ['-Wno-macro-redefined']
# 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 modules_enabled:
define = '-D%s' % m
if feature_macros[m]:
define += '=%s' % (feature_macros[m])
self.cxx.compile_flags += [define]
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)
elif os.path.isdir(str(self.use_system_cxx_lib)):
self.cxx.link_flags += ['-L' + self.use_system_cxx_lib]
if not self.is_windows:
self.cxx.link_flags += ['-Wl,-rpath,' +
self.use_system_cxx_lib]
if self.is_windows and self.link_shared:
self.add_path(self.cxx.compile_env, self.use_system_cxx_lib)
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')
self.cxx.addWarningFlagIfSupported('-Wno-noexcept-type')
self.cxx.addWarningFlagIfSupported('-Wno-aligned-allocation-unavailable')
# 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')
# FIXME: Remove this warning once the min/max handling patch lands
# See https://reviews.llvm.org/D33080
self.cxx.addWarningFlagIfSupported('-Wno-#warnings')
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_coroutines(self):
if self.cxx.hasCompileFlag('-fcoroutines-ts'):
macros = self.cxx.dumpMacros(flags=['-fcoroutines-ts'])
if '__cpp_coroutines' not in macros:
self.lit_config.warning('-fcoroutines-ts is supported but '
'__cpp_coroutines is not defined')
# Consider coroutines supported only when the feature test macro
# reflects a recent value.
val = macros['__cpp_coroutines'].replace('L', '')
if int(val) >= 201703:
self.config.available_features.add('fcoroutines-ts')
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_modules_enabled()
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))
sub.append(('%libcxx_src_root', self.libcxx_src_root))
# 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.
# Configure run env substitution.
sub.append(('%run', '%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 can_use_deployment(self):
# Check if the host is on an Apple platform using clang.
if not self.target_info.platform() == "darwin":
return False
if not self.target_info.is_host_macosx():
return False
if not self.cxx.type.endswith('clang'):
return False
return True
def configure_triple(self):
# Get or infer the target triple.
target_triple = self.get_lit_conf('target_triple')
self.use_target = self.get_lit_bool('use_target', False)
if self.use_target and target_triple:
self.lit_config.warning('use_target is true but no triple is specified')
# Use deployment if possible.
self.use_deployment = not self.use_target and self.can_use_deployment()
if self.use_deployment:
return
# Save the triple (and warn on Apple platforms).
self.config.target_triple = target_triple
if self.use_target and 'apple' in target_triple:
self.lit_config.warning('consider using arch and platform instead'
' of target_triple on Apple platforms')
# 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_deployment(self):
assert not self.use_deployment is None
assert not self.use_target is None
if not self.use_deployment:
# Warn about ignored parameters.
if self.get_lit_conf('arch'):
self.lit_config.warning('ignoring arch, using target_triple')
if self.get_lit_conf('platform'):
self.lit_config.warning('ignoring platform, using target_triple')
return
assert not self.use_target
assert self.target_info.is_host_macosx()
# Always specify deployment explicitly on Apple platforms, since
# otherwise a platform is picked up from the SDK. If the SDK version
# doesn't match the system version, tests that use the system library
# may fail spuriously.
arch = self.get_lit_conf('arch')
if not arch:
arch = self.cxx.getTriple().split('-', 1)[0]
self.lit_config.note("inferred arch as: %r" % arch)
inferred_platform, name, version = self.target_info.get_platform()
if inferred_platform:
self.lit_config.note("inferred platform as: %r" % (name + version))
self.config.deployment = (arch, name, version)
# Set the target triple for use by lit.
self.config.target_triple = arch + '-apple-' + name + version
self.lit_config.note(
"computed 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'])