diff options
Diffstat (limited to 'utils/libcxx/test/config.py')
| -rw-r--r-- | utils/libcxx/test/config.py | 1069 | 
1 files changed, 1069 insertions, 0 deletions
| diff --git a/utils/libcxx/test/config.py b/utils/libcxx/test/config.py new file mode 100644 index 000000000000..c941f65b2c57 --- /dev/null +++ b/utils/libcxx/test/config.py @@ -0,0 +1,1069 @@ +#===----------------------------------------------------------------------===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is dual licensed under the MIT and the University of Illinois Open +# Source Licenses. See LICENSE.TXT for details. +# +#===----------------------------------------------------------------------===## + +import locale +import os +import platform +import pkgutil +import pipes +import re +import shlex +import shutil +import sys + +from libcxx.compiler import CXXCompiler +from libcxx.test.target_info import make_target_info +from libcxx.test.executor import * +from libcxx.test.tracing import * +import libcxx.util + +def loadSiteConfig(lit_config, config, param_name, env_name): +    # We haven't loaded the site specific configuration (the user is +    # probably trying to run on a test file directly, and either the site +    # configuration hasn't been created by the build system, or we are in an +    # out-of-tree build situation). +    site_cfg = lit_config.params.get(param_name, +                                     os.environ.get(env_name)) +    if not site_cfg: +        lit_config.warning('No site specific configuration file found!' +                           ' Running the tests in the default configuration.') +    elif not os.path.isfile(site_cfg): +        lit_config.fatal( +            "Specified site configuration file does not exist: '%s'" % +            site_cfg) +    else: +        lit_config.note('using site specific configuration at %s' % site_cfg) +        ld_fn = lit_config.load_config + +        # Null out the load_config function so that lit.site.cfg doesn't +        # recursively load a config even if it tries. +        # TODO: This is one hell of a hack. Fix it. +        def prevent_reload_fn(*args, **kwargs): +            pass +        lit_config.load_config = prevent_reload_fn +        ld_fn(config, site_cfg) +        lit_config.load_config = ld_fn + +class Configuration(object): +    # pylint: disable=redefined-outer-name +    def __init__(self, lit_config, config): +        self.lit_config = lit_config +        self.config = config +        self.is_windows = platform.system() == 'Windows' +        self.cxx = None +        self.cxx_is_clang_cl = None +        self.cxx_stdlib_under_test = None +        self.project_obj_root = None +        self.libcxx_src_root = None +        self.libcxx_obj_root = None +        self.cxx_library_root = None +        self.cxx_runtime_root = None +        self.abi_library_root = None +        self.link_shared = self.get_lit_bool('enable_shared', default=True) +        self.debug_build = self.get_lit_bool('debug_build',   default=False) +        self.exec_env = {} +        self.use_target = False +        self.use_system_cxx_lib = False +        self.use_clang_verify = False +        self.long_tests = None +        self.execute_external = False + +    def get_lit_conf(self, name, default=None): +        val = self.lit_config.params.get(name, None) +        if val is None: +            val = getattr(self.config, name, None) +            if val is None: +                val = default +        return val + +    def get_lit_bool(self, name, default=None, env_var=None): +        def check_value(value, var_name): +            if value is None: +                return default +            if isinstance(value, bool): +                return value +            if not isinstance(value, str): +                raise TypeError('expected bool or string') +            if value.lower() in ('1', 'true'): +                return True +            if value.lower() in ('', '0', 'false'): +                return False +            self.lit_config.fatal( +                "parameter '{}' should be true or false".format(var_name)) + +        conf_val = self.get_lit_conf(name) +        if env_var is not None and env_var in os.environ and \ +                os.environ[env_var] is not None: +            val = os.environ[env_var] +            if conf_val is not None: +                self.lit_config.warning( +                    'Environment variable %s=%s is overriding explicit ' +                    '--param=%s=%s' % (env_var, val, name, conf_val)) +            return check_value(val, env_var) +        return check_value(conf_val, name) + +    def make_static_lib_name(self, name): +        """Return the full filename for the specified library name""" +        if self.is_windows: +            return name + '.lib' +        else: +            return 'lib' + name + '.a' + +    def configure(self): +        self.configure_executor() +        self.configure_use_system_cxx_lib() +        self.configure_target_info() +        self.configure_cxx() +        self.configure_triple() +        self.configure_deployment() +        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 _list_env_var('LIB'): +            self.add_path(self.exec_env, path) +        return CXXCompiler(clang_path, flags=flags, +                           compile_flags=compile_flags, +                           link_flags=link_flags) + + +    def configure_src_root(self): +        self.libcxx_src_root = self.get_lit_conf( +            'libcxx_src_root', os.path.dirname(self.config.test_source_root)) + +    def configure_obj_root(self): +        self.project_obj_root = self.get_lit_conf('project_obj_root') +        self.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root') +        if not self.libcxx_obj_root and self.project_obj_root is not None: +            possible_root = os.path.join(self.project_obj_root, 'projects', 'libcxx') +            if os.path.isdir(possible_root): +                self.libcxx_obj_root = possible_root +            else: +                self.libcxx_obj_root = self.project_obj_root + +    def configure_cxx_library_root(self): +        self.cxx_library_root = self.get_lit_conf('cxx_library_root', +                                                  self.libcxx_obj_root) +        self.cxx_runtime_root = self.get_lit_conf('cxx_runtime_root', +                                                   self.cxx_library_root) + +    def configure_use_system_cxx_lib(self): +        # This test suite supports testing against either the system library or +        # the locally built one; the former mode is useful for testing ABI +        # compatibility between the current headers and a shipping dynamic +        # library. +        # 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_cxx_stdlib_under_test(self): +        self.cxx_stdlib_under_test = self.get_lit_conf( +            'cxx_stdlib_under_test', 'libc++') +        if self.cxx_stdlib_under_test not in \ +                ['libc++', 'libstdc++', 'msvc', 'cxx_default']: +            self.lit_config.fatal( +                'unsupported value for "cxx_stdlib_under_test": %s' +                % self.cxx_stdlib_under_test) +        self.config.available_features.add(self.cxx_stdlib_under_test) +        if self.cxx_stdlib_under_test == 'libstdc++': +            self.config.available_features.add('libstdc++') +            # Manually enable the experimental and filesystem tests for libstdc++ +            # if the options aren't present. +            # FIXME this is a hack. +            if self.get_lit_conf('enable_experimental') is None: +                self.config.enable_experimental = 'true' +            if self.get_lit_conf('enable_filesystem') is None: +                self.config.enable_filesystem = 'true' + +    def configure_use_clang_verify(self): +        '''If set, run clang with -verify on failing tests.''' +        self.use_clang_verify = self.get_lit_bool('use_clang_verify') +        if self.use_clang_verify is None: +            # NOTE: We do not test for the -verify flag directly because +            #   -verify will always exit with non-zero on an empty file. +            self.use_clang_verify = self.cxx.isVerifySupported() +            if self.use_clang_verify: +                self.config.available_features.add('verify-support') +            self.lit_config.note( +                "inferred use_clang_verify as: %r" % self.use_clang_verify) + +    def configure_use_thread_safety(self): +        '''If set, run clang with -verify on failing tests.''' +        has_thread_safety = self.cxx.hasCompileFlag('-Werror=thread-safety') +        if has_thread_safety: +            self.cxx.compile_flags += ['-Werror=thread-safety'] +            self.config.available_features.add('thread-safety') +            self.lit_config.note("enabling thread-safety annotations") + +    def configure_execute_external(self): +        # Choose between lit's internal shell pipeline runner and a real shell. +        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the +        # default value. Otherwise we ask the target_info. +        use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL') +        if use_lit_shell_default is not None: +            use_lit_shell_default = use_lit_shell_default != '0' +        else: +            use_lit_shell_default = self.target_info.use_lit_shell_default() +        # Check for the command line parameter using the default value if it is +        # not present. +        use_lit_shell = self.get_lit_bool('use_lit_shell', +                                          use_lit_shell_default) +        self.execute_external = not use_lit_shell + +    def configure_ccache(self): +        use_ccache_default = os.environ.get('LIBCXX_USE_CCACHE') is not None +        use_ccache = self.get_lit_bool('use_ccache', use_ccache_default) +        if use_ccache: +            self.cxx.use_ccache = True +            self.lit_config.note('enabling ccache') + +    def configure_features(self): +        additional_features = self.get_lit_conf('additional_features') +        if additional_features: +            for f in additional_features.split(','): +                self.config.available_features.add(f.strip()) +        self.target_info.add_locale_features(self.config.available_features) + +        target_platform = self.target_info.platform() + +        # Write an "available feature" that combines the triple when +        # use_system_cxx_lib is enabled. This is so that we can easily write +        # XFAIL markers for tests that are known to fail with versions of +        # libc++ as were shipped with a particular triple. +        if self.use_system_cxx_lib: +            self.config.available_features.add('with_system_cxx_lib') +            self.config.available_features.add( +                'with_system_cxx_lib=%s' % self.config.target_triple) + +        # Insert the platform name into the available features as a lower case. +        self.config.available_features.add(target_platform) + +        # If we're using deployment, add sub-components of the triple using +        # "darwin" instead of the platform name. +        if self.use_deployment: +            arch, _, _ = self.config.deployment +            self.config.available_features.add('apple-darwin') +            self.config.available_features.add(arch + '-apple-darwin') + +        # 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') + +        # 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] + +    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']) | 
