From 9669df28d4fd3c52d09f451186bd217cdc3322c0 Mon Sep 17 00:00:00 2001 From: Ben Craig Date: Mon, 8 May 2017 13:15:22 +0000 Subject: [PATCH] Fix Windows tests when __config_site is present. Previously, the force includes would complain about a missing _DEBUG symbol. Now we dump macros before adding the force includes to the command line. llvm-svn: 302421 --- libcxx/utils/libcxx/test/config.py | 2226 ++++++++++++++-------------- 1 file changed, 1113 insertions(+), 1113 deletions(-) diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py index 7f1ae851b9ce..a998e21039c9 100644 --- a/libcxx/utils/libcxx/test/config.py +++ b/libcxx/utils/libcxx/test/config.py @@ -1,1113 +1,1113 @@ -#===----------------------------------------------------------------------===## -# -# 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: - 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_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 _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.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)) - - 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') - 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') - 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) - 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') - # 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 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']) +#===----------------------------------------------------------------------===## +# +# 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: + 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_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 _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.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)) + + 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') + 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 + # 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) + 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') + # 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 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'])