Ejemplo n.º 1
0
 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:
         clangxx = lit.util.which('clang++',
                                  self.config.environment['PATH'])
         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'
Ejemplo n.º 2
0
    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf('cxx_under_test')

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            if clangxx:
                cxx = clangxx
                self.lit_config.note(
                    "inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal('must specify user parameter cxx_under_test '
                                  '(e.g., --param=cxx_under_test=clang++)')
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add('%s-%s' % (cxx_type, maj_v))
            self.config.available_features.add('%s-%s.%s' % (
                cxx_type, maj_v, min_v))
Ejemplo n.º 3
0
 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).startswith('clang-cl')
     # 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(self, cxx) if not self.cxx_is_clang_cl else \
                self._configure_clang_cl(cxx)
     self.cxx.compile_env = dict(os.environ)
Ejemplo n.º 4
0
    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf('cxx_under_test')

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            if clangxx:
                cxx = clangxx
                self.lit_config.note(
                    "inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal('must specify user parameter cxx_under_test '
                                  '(e.g., --param=cxx_under_test=clang++)')
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add('%s-%s' % (cxx_type, maj_v))
            self.config.available_features.add('%s-%s.%s' % (
                cxx_type, maj_v, min_v))
Ejemplo n.º 5
0
 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:
         clangxx = lit.util.which('clang++',
                                  self.config.environment['PATH'])
         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'
Ejemplo n.º 6
0
    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 = []
        link_flags = _prefixed_env_list('LIB', '-L')
        return CXXCompiler(self, clang_path, flags=flags,
                           compile_flags=compile_flags,
                           link_flags=link_flags)
Ejemplo n.º 7
0
 def _configure_clang_cl(self, clang_path):
     assert self.cxx_is_clang_cl
     # FIXME: don't hardcode the target
     flags = ['--target=i686-pc-windows']
     compile_flags = []
     link_flags = ['-fuse-ld=lld']
     if 'INCLUDE' in os.environ:
         compile_flags += ['-isystem %s' % p.strip()
                           for p in os.environ['INCLUDE'].split(';')
                           if p.strip()]
     if 'LIB' in os.environ:
         link_flags += ['-L%s' % p.strip()
                        for p in os.environ['LIB'].split(';') if p.strip()]
     return CXXCompiler(clang_path, flags=flags,
                        compile_flags=compile_flags,
                        link_flags=link_flags)
Ejemplo n.º 8
0
 def _configure_clang_cl(self, clang_path):
     assert self.cxx_is_clang_cl
     flags = []
     compile_flags = []
     link_flags = []
     if 'INCLUDE' in os.environ:
         compile_flags += [
             '-isystem %s' % p.strip()
             for p in os.environ['INCLUDE'].split(';') if p.strip()
         ]
     if 'LIB' in os.environ:
         for p in os.environ['LIB'].split(';'):
             p = p.strip()
             if not p:
                 continue
             link_flags += ['-L%s' % p]
             self.add_path(self.exec_env, p)
     return CXXCompiler(clang_path,
                        flags=flags,
                        compile_flags=compile_flags,
                        link_flags=link_flags)
Ejemplo n.º 9
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.libcxx_src_root = None
        self.libcxx_obj_root = None
        self.cxx_library_root = None
        self.abi_library_root = None
        self.env = {}
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None
        self.execute_external = False

    def get_lit_conf(self, name, default=None):
        val = self.lit_config.params.get(name, None)
        if val is None:
            val = getattr(self.config, name, None)
            if val is None:
                val = default
        return val

    def get_lit_bool(self, name, default=None):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if conf.lower() in ('1', 'true'):
            return True
        if conf.lower() in ('', '0', 'false'):
            return False
        self.lit_config.fatal(
            "parameter '{}' should be true or false".format(name))

    def configure(self):
        self.configure_executor()
        self.configure_target_info()
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_execute_external()
        self.configure_ccache()
        self.configure_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_color_diagnostics()
        self.configure_debug_mode()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note('Using compiler: %s' % self.cxx.path)
        self.lit_config.note('Using flags: %s' % self.cxx.flags)
        self.lit_config.note('Using compile flags: %s'
                             % self.cxx.compile_flags)
        self.lit_config.note('Using link flags: %s' % self.cxx.link_flags)
        # Print as list to prevent "set([...])" from being printed.
        self.lit_config.note('Using available_features: %s' %
                             list(self.config.available_features))
        self.lit_config.note('Using environment: %r' % self.env)

    def get_test_format(self):
        return LibcxxTestFormat(
            self.cxx,
            self.use_clang_verify,
            self.execute_external,
            self.executor,
            exec_env=self.env)

    def configure_executor(self):
        exec_str = self.get_lit_conf('executor', "None")
        te = eval(exec_str)
        if te:
            self.lit_config.note("Using executor: %r" % exec_str)
            if self.lit_config.useValgrind:
                # We have no way of knowing where in the chain the
                # ValgrindExecutor is supposed to go. It is likely
                # that the user wants it at the end, but we have no
                # way of getting at that easily.
                selt.lit_config.fatal("Cannot infer how to create a Valgrind "
                                      " executor.")
        else:
            te = LocalExecutor()
            if self.lit_config.useValgrind:
                te = ValgrindExecutor(self.lit_config.valgrindArgs, te)
        self.executor = te

    def configure_target_info(self):
        default = "libcxx.test.target_info.LocalTI"
        info_str = self.get_lit_conf('target_info', default)
        mod_path, _, info = info_str.rpartition('.')
        mod = importlib.import_module(mod_path)
        self.target_info = getattr(mod, info)()
        if info_str != default:
            self.lit_config.note("inferred target_info as: %r" % info_str)

    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf('cxx_under_test')

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            if clangxx:
                cxx = clangxx
                self.lit_config.note(
                    "inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal('must specify user parameter cxx_under_test '
                                  '(e.g., --param=cxx_under_test=clang++)')
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add('%s-%s.%s' % (
                cxx_type, maj_v, min_v))

    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf(
            'libcxx_src_root', os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root')

    def configure_cxx_library_root(self):
        self.cxx_library_root = self.get_lit_conf('cxx_library_root',
                                                  self.libcxx_obj_root)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib')
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note(
                "inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)

    def configure_use_clang_verify(self):
        '''If set, run clang with -verify on failing tests.'''
        self.use_clang_verify = self.get_lit_bool('use_clang_verify')
        if self.use_clang_verify is None:
            # NOTE: We do not test for the -verify flag directly because
            #   -verify will always exit with non-zero on an empty file.
            self.use_clang_verify = self.cxx.hasCompileFlag(
                ['-Xclang', '-verify-ignore-unexpected'])
            self.lit_config.note(
                "inferred use_clang_verify as: %r" % self.use_clang_verify)

    def configure_execute_external(self):
        # Choose between lit's internal shell pipeline runner and a real shell.
        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
        # default value. Otherwise we default to internal on Windows and
        # external elsewhere, as bash on Windows is usually very slow.
        use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL')
        if use_lit_shell_default is not None:
            use_lit_shell_default = use_lit_shell_default != '0'
        else:
            use_lit_shell_default = sys.platform == 'win32'
        # Check for the command line parameter using the default value if it is
        # not present.
        use_lit_shell = self.get_lit_bool('use_lit_shell',
                                          use_lit_shell_default)
        self.execute_external = not use_lit_shell

    def configure_ccache(self):
        use_ccache_default = os.environ.get('LIBCXX_USE_CCACHE') is not None
        use_ccache = self.get_lit_bool('use_ccache', use_ccache_default)
        if use_ccache:
            self.cxx.use_ccache = True
            self.lit_config.note('enabling ccache')

    def configure_features(self):
        additional_features = self.get_lit_conf('additional_features')
        if additional_features:
            for f in additional_features.split(','):
                self.config.available_features.add(f.strip())

        # Figure out which of the required locales we support
        locales = {
            'Darwin': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'FreeBSD': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'Linux': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO-8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO-8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'Windows': {
                'en_US.UTF-8': 'English_United States.1252',
                'cs_CZ.ISO8859-2': 'Czech_Czech Republic.1250',
                'fr_FR.UTF-8': 'French_France.1252',
                'fr_CA.ISO8859-1': 'French_Canada.1252',
                'ru_RU.UTF-8': 'Russian_Russia.1251',
                'zh_CN.UTF-8': 'Chinese_China.936',
            },
        }

        target_system = self.target_info.system()
        target_platform = self.target_info.platform()

        if target_system in locales:
            default_locale = locale.setlocale(locale.LC_ALL)
            for feature, loc in locales[target_system].items():
                try:
                    locale.setlocale(locale.LC_ALL, loc)
                    self.config.available_features.add(
                        'locale.{0}'.format(feature))
                except locale.Error:
                    self.lit_config.warning('The locale {0} is not supported by '
                                            'your platform. Some tests will be '
                                            'unsupported.'.format(loc))
            locale.setlocale(locale.LC_ALL, default_locale)
        else:
            # Warn that the user doesn't get any free XFAILs for locale issues
            self.lit_config.warning("No locales entry for target_system: %s" %
                                    target_system)

        # Write an "available feature" that combines the triple when
        # use_system_cxx_lib is enabled. This is so that we can easily write
        # XFAIL markers for tests that are known to fail with versions of
        # libc++ as were shipped with a particular triple.
        if self.use_system_cxx_lib:
            self.config.available_features.add(
                'with_system_cxx_lib=%s' % self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        self.config.available_features.add(target_platform)

        # Some linux distributions have different locale data than others.
        # Insert the distributions name and name-version into the available
        # features to allow tests to XFAIL on them.
        if target_platform == 'linux':
            name = self.target_info.platform_name()
            ver = self.target_info.platform_ver()
            if name:
                self.config.available_features.add(name)
            if name and ver:
                self.config.available_features.add('%s-%s' % (name, ver))

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool('long_tests')
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note(
                "inferred long_tests as: %r" % self.long_tests)

        if self.long_tests:
            self.config.available_features.add('long_tests')

        # Run a compile test for the -fsized-deallocation flag. This is needed
        # in test/std/language.support/support.dynamic/new.delete
        if self.cxx.hasCompileFlag('-fsized-deallocation'):
            self.config.available_features.add('fsized-deallocation')

    def configure_compile_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf('compile_flags', '')
        self.cxx.compile_flags += shlex.split(compile_flags_str)

    def configure_default_compile_flags(self):
        # Try and get the std version from the command line. Fall back to
        # default given in lit.site.cfg is not present. If default is not
        # present then force c++11.
        std = self.get_lit_conf('std')
        if not std:
            # Choose the newest possible language dialect if none is given.
            possible_stds = ['c++1z', 'c++14', 'c++11', 'c++03']
            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)
        # Configure include paths
        self.cxx.compile_flags += ['-nostdinc++']
        self.configure_compile_flags_header_includes()
        if self.target_info.platform() == 'linux':
            self.cxx.compile_flags += ['-D__STDC_FORMAT_MACROS',
                                       '-D__STDC_LIMIT_MACROS',
                                       '-D__STDC_CONSTANT_MACROS']
        # Configure feature flags.
        self.configure_compile_flags_exceptions()
        self.configure_compile_flags_rtti()
        self.configure_compile_flags_no_global_filesystem_namespace()
        self.configure_compile_flags_no_stdin()
        self.configure_compile_flags_no_stdout()
        enable_32bit = self.get_lit_bool('enable_32bit', False)
        if enable_32bit:
            self.cxx.flags += ['-m32']
        # Configure threading features.
        enable_threads = self.get_lit_bool('enable_threads', True)
        enable_monotonic_clock = self.get_lit_bool('enable_monotonic_clock',
                                                   True)
        if not enable_threads:
            self.configure_compile_flags_no_threads()
            if not enable_monotonic_clock:
                self.configure_compile_flags_no_monotonic_clock()
        elif not enable_monotonic_clock:
            self.lit_config.fatal('enable_monotonic_clock cannot be false when'
                                  ' enable_threads is true.')
        self.configure_compile_flags_no_thread_unsafe_c_functions()

        # Use verbose output for better errors
        self.cxx.flags += ['-v']
        sysroot = self.get_lit_conf('sysroot')
        if sysroot:
            self.cxx.flags += ['--sysroot', sysroot]
        gcc_toolchain = self.get_lit_conf('gcc_toolchain')
        if gcc_toolchain:
            self.cxx.flags += ['-gcc-toolchain', gcc_toolchain]
        if self.use_target:
            self.cxx.flags += ['-target', self.config.target_triple]

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        self.cxx.compile_flags += ['-I' + support_path]
        self.cxx.compile_flags += ['-include', os.path.join(support_path, 'nasty_macros.hpp')]
        libcxx_headers = self.get_lit_conf(
            'libcxx_headers', os.path.join(self.libcxx_src_root, 'include'))
        if not os.path.isdir(libcxx_headers):
            self.lit_config.fatal("libcxx_headers='%s' is not a directory."
                                  % libcxx_headers)
        self.cxx.compile_flags += ['-I' + libcxx_headers]

    def configure_compile_flags_exceptions(self):
        enable_exceptions = self.get_lit_bool('enable_exceptions', True)
        if not enable_exceptions:
            self.config.available_features.add('libcpp-no-exceptions')
            self.cxx.compile_flags += ['-fno-exceptions']

    def configure_compile_flags_rtti(self):
        enable_rtti = self.get_lit_bool('enable_rtti', True)
        if not enable_rtti:
            self.config.available_features.add('libcpp-no-rtti')
            self.cxx.compile_flags += ['-fno-rtti', '-D_LIBCPP_NO_RTTI']

    def configure_compile_flags_no_global_filesystem_namespace(self):
        enable_global_filesystem_namespace = self.get_lit_bool(
            'enable_global_filesystem_namespace', True)
        if not enable_global_filesystem_namespace:
            self.config.available_features.add(
                'libcpp-has-no-global-filesystem-namespace')
            self.cxx.compile_flags += [
                '-D_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE']

    def configure_compile_flags_no_stdin(self):
        enable_stdin = self.get_lit_bool('enable_stdin', True)
        if not enable_stdin:
            self.config.available_features.add('libcpp-has-no-stdin')
            self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDIN']

    def configure_compile_flags_no_stdout(self):
        enable_stdout = self.get_lit_bool('enable_stdout', True)
        if not enable_stdout:
            self.config.available_features.add('libcpp-has-no-stdout')
            self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDOUT']

    def configure_compile_flags_no_threads(self):
        self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_THREADS']
        self.config.available_features.add('libcpp-has-no-threads')

    def configure_compile_flags_no_thread_unsafe_c_functions(self):
        enable_thread_unsafe_c_functions = self.get_lit_bool(
            'enable_thread_unsafe_c_functions', True)
        if not enable_thread_unsafe_c_functions:
            self.cxx.compile_flags += [
                '-D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS']
            self.config.available_features.add(
                'libcpp-has-no-thread-unsafe-c-functions')

    def configure_compile_flags_no_monotonic_clock(self):
        self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_MONOTONIC_CLOCK']
        self.config.available_features.add('libcpp-has-no-monotonic-clock')

    def configure_link_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.cxx.link_flags += ['-nodefaultlibs']

            # Configure library path
            self.configure_link_flags_cxx_library_path()
            self.configure_link_flags_abi_library_path()

            # Configure libraries
            self.configure_link_flags_cxx_library()
            self.configure_link_flags_abi_library()
            self.configure_extra_library_flags()

        link_flags_str = self.get_lit_conf('link_flags', '')
        self.cxx.link_flags += shlex.split(link_flags_str)

    def configure_link_flags_cxx_library_path(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        # Configure libc++ library paths.
        if libcxx_library is not None:
            # Check that the given value for libcxx_library is valid.
            if not os.path.isfile(libcxx_library):
                self.lit_config.fatal(
                    "libcxx_library='%s' is not a valid file." %
                    libcxx_library)
            if self.use_system_cxx_lib:
                self.lit_config.fatal(
                    "Conflicting options: 'libcxx_library' cannot be used "
                    "with 'use_system_cxx_lib=true'")
            self.cxx.link_flags += ['-Wl,-rpath,' +
                                    os.path.dirname(libcxx_library)]
        elif not self.use_system_cxx_lib and self.cxx_library_root:
            self.cxx.link_flags += ['-L' + self.cxx_library_root,
                                    '-Wl,-rpath,' + self.cxx_library_root]

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        self.abi_library_root = self.get_lit_conf('abi_library_path')
        if self.abi_library_root:
            self.cxx.link_flags += ['-L' + self.abi_library_root,
                                    '-Wl,-rpath,' + self.abi_library_root]

    def configure_link_flags_cxx_library(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        if libcxx_library:
            self.cxx.link_flags += [libcxx_library]
        else:
            self.cxx.link_flags += ['-lc++']

    def configure_link_flags_abi_library(self):
        cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi')
        if cxx_abi == 'libstdc++':
            self.cxx.link_flags += ['-lstdc++']
        elif cxx_abi == 'libsupc++':
            self.cxx.link_flags += ['-lsupc++']
        elif cxx_abi == 'libcxxabi':
            # Don't link libc++abi explicitly on OS X because the symbols
            # should be available in libc++ directly.
            if self.target_info.platform() != 'darwin':
                self.cxx.link_flags += ['-lc++abi']
        elif cxx_abi == 'libcxxrt':
            self.cxx.link_flags += ['-lcxxrt']
        elif cxx_abi == 'none':
            pass
        else:
            self.lit_config.fatal(
                'C++ ABI setting %s unsupported for tests' % cxx_abi)

    def configure_extra_library_flags(self):
        enable_threads = self.get_lit_bool('enable_threads', True)
        llvm_unwinder = self.get_lit_bool('llvm_unwinder', False)
        target_platform = self.target_info.platform()
        if target_platform == 'darwin':
            self.cxx.link_flags += ['-lSystem']
        elif target_platform == 'linux':
            if not llvm_unwinder:
                self.cxx.link_flags += ['-lgcc_eh']
            self.cxx.link_flags += ['-lc', '-lm']
            if enable_threads:
                self.cxx.link_flags += ['-lpthread']
            if llvm_unwinder:
                self.cxx.link_flags += ['-lunwind', '-ldl']
            else:
                self.cxx.link_flags += ['-lgcc_s']
        elif target_platform.startswith('freebsd'):
            self.cxx.link_flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt']
        else:
            self.lit_config.fatal("unrecognized system: %r" % target_platform)

    def configure_color_diagnostics(self):
        use_color = self.get_lit_conf('color_diagnostics')
        if use_color is None:
            use_color = os.environ.get('LIBCXX_COLOR_DIAGNOSTICS')
        if use_color is None:
            return
        if use_color != '':
            self.lit_config.fatal('Invalid value for color_diagnostics "%s".'
                                  % use_color)
        color_flag = '-fdiagnostics-color=always'
        # Check if the compiler supports the color diagnostics flag. Issue a
        # warning if it does not since color diagnostics have been requested.
        if not self.cxx.hasCompileFlag(color_flag):
            self.lit_config.warning(
                'color diagnostics have been requested but are not supported '
                'by the compiler')
        else:
            self.cxx.flags += [color_flag]

    def configure_debug_mode(self):
        debug_level = self.get_lit_conf('debug_level', None)
        if not debug_level:
            return
        if debug_level not in ['0', '1']:
            self.lit_config.fatal('Invalid value for debug_level "%s".'
                                  % debug_level)
        self.cxx.compile_flags += ['-D_LIBCPP_DEBUG=%s' % debug_level]

    def configure_warnings(self):
        enable_warnings = self.get_lit_bool('enable_warnings', False)
        if enable_warnings:
            self.cxx.compile_flags += [
                '-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER',
                '-Wall', '-Werror'
            ]
            self.cxx.addWarningFlagIfSupported('-Wno-attributes')
            self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move')
            self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions')
            self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals')
            # TODO(EricWF) Remove the unused warnings once the test suite
            # compiles clean with them.
            self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')
            self.cxx.addWarningFlagIfSupported('-Wno-unused-variable')
            std = self.get_lit_conf('std', None)
            if std in ['c++98', 'c++03']:
                # The '#define static_assert' provided by libc++ in C++03 mode
                # causes an unused local typedef whenever it is used.
                self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')

    def configure_sanitizer(self):
        san = self.get_lit_conf('use_sanitizer', '').strip()
        if san:
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get('PATH', '')
            cxx_path = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = (
                    os.path.dirname(cxx_path) +
                    os.pathsep + symbolizer_search_paths)
            llvm_symbolizer = lit.util.which('llvm-symbolizer',
                                             symbolizer_search_paths)
            # Setup the sanitizer compile flags
            self.cxx.flags += ['-g', '-fno-omit-frame-pointer']
            if self.target_info.platform() == 'linux':
                # The libraries and their order are taken from the
                # linkSanitizerRuntimeDeps function in
                # clang/lib/Driver/Tools.cpp
                self.cxx.link_flags += ['-lpthread', '-lrt', '-lm', '-ldl']
            if san == 'Address':
                self.cxx.flags += ['-fsanitize=address']
                if llvm_symbolizer is not None:
                    self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('asan')
                self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Memory' or san == 'MemoryWithOrigins':
                self.cxx.flags += ['-fsanitize=memory']
                if san == 'MemoryWithOrigins':
                    self.cxx.compile_flags += [
                        '-fsanitize-memory-track-origins']
                if llvm_symbolizer is not None:
                    self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('msan')
                self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Undefined':
                self.cxx.flags += ['-fsanitize=undefined',
                                   '-fno-sanitize=vptr,function',
                                   '-fno-sanitize-recover']
                self.cxx.compile_flags += ['-O3']
                self.config.available_features.add('ubsan')
                if self.target_info.platform() == 'darwin':
                    self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Thread':
                self.cxx.flags += ['-fsanitize=thread']
                self.config.available_features.add('tsan')
                self.config.available_features.add('sanitizer-new-delete')
            else:
                self.lit_config.fatal('unsupported value for '
                                      'use_sanitizer: {0}'.format(san))
            san_lib = self.get_lit_conf('sanitizer_library')
            if san_lib:
                self.cxx.link_flags += [
                    san_lib, '-Wl,-rpath,%s' % os.path.dirname(san_lib)]

    def configure_coverage(self):
        self.generate_coverage = self.get_lit_bool('generate_coverage', False)
        if self.generate_coverage:
            self.cxx.flags += ['-g', '--coverage']
            self.cxx.compile_flags += ['-O0']

    def configure_substitutions(self):
        sub = self.config.substitutions
        # Configure compiler substitions
        sub.append(('%cxx', self.cxx.path))
        # Configure flags substitutions
        flags_str = ' '.join(self.cxx.flags)
        compile_flags_str = ' '.join(self.cxx.compile_flags)
        link_flags_str = ' '.join(self.cxx.link_flags)
        all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str)
        sub.append(('%flags', flags_str))
        sub.append(('%compile_flags', compile_flags_str))
        sub.append(('%link_flags', link_flags_str))
        sub.append(('%all_flags', all_flags))
        # Add compile and link shortcuts
        compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str
                       + compile_flags_str)
        link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str
                    + link_flags_str)
        assert type(link_str) is str
        build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
        sub.append(('%compile', compile_str))
        sub.append(('%link', link_str))
        sub.append(('%build', build_str))
        # Configure exec prefix substitutions.
        exec_env_str = 'env ' if len(self.env) != 0 else ''
        for k, v in self.env.items():
            exec_env_str += ' %s=%s' % (k, v)
        # Configure run env substitution.
        exec_str = ''
        if self.lit_config.useValgrind:
            exec_str = ' '.join(self.lit_config.valgrindArgs) + exec_env_str
        sub.append(('%exec', exec_str))
        # Configure run shortcut
        sub.append(('%run', exec_str + ' %t.exe'))
        # Configure not program substitions
        not_py = os.path.join(self.libcxx_src_root, 'utils', 'not', 'not.py')
        not_str = '%s %s' % (sys.executable, not_py)
        sub.append(('not', not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf('target_triple')
        self.use_target = bool(self.config.target_triple)
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.use_target:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)',
                                   r'\1-\2-\3\5', target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if (target_triple.endswith('redhat-linux') or
                target_triple.endswith('suse-linux')):
                target_triple += '-gnu'
            self.config.target_triple = target_triple
            self.lit_config.note(
                "inferred target_triple as: %r" % self.config.target_triple)

    def configure_env(self):
        if self.target_info.platform() == 'darwin':
            library_paths = []
            # Configure the library path for libc++
            libcxx_library = self.get_lit_conf('libcxx_library')
            if self.use_system_cxx_lib:
                pass
            elif libcxx_library:
                library_paths += [os.path.dirname(libcxx_library)]
            elif self.cxx_library_root:
                library_paths += [self.cxx_library_root]
            # Configure the abi library path
            if self.abi_library_root:
                library_paths += [self.abi_library_root]
            if library_paths:
                self.env['DYLD_LIBRARY_PATH'] = ':'.join(library_paths)
Ejemplo n.º 10
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.libcxx_src_root = None
        self.libcxx_obj_root = None
        self.cxx_library_root = None
        self.abi_library_root = None
        self.env = {}
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None
        self.execute_external = False

    def get_lit_conf(self, name, default=None):
        val = self.lit_config.params.get(name, None)
        if val is None:
            val = getattr(self.config, name, None)
            if val is None:
                val = default
        return val

    def get_lit_bool(self, name, default=None):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if conf.lower() in ("1", "true"):
            return True
        if conf.lower() in ("", "0", "false"):
            return False
        self.lit_config.fatal("parameter '{}' should be true or false".format(name))

    def configure(self):
        self.configure_executor()
        self.configure_target_info()
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_execute_external()
        self.configure_ccache()
        self.configure_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_color_diagnostics()
        self.configure_debug_mode()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note("Using compiler: %s" % self.cxx.path)
        self.lit_config.note("Using flags: %s" % self.cxx.flags)
        self.lit_config.note("Using compile flags: %s" % self.cxx.compile_flags)
        self.lit_config.note("Using link flags: %s" % self.cxx.link_flags)
        # Print as list to prevent "set([...])" from being printed.
        self.lit_config.note("Using available_features: %s" % list(self.config.available_features))
        self.lit_config.note("Using environment: %r" % self.env)

    def get_test_format(self):
        return LibcxxTestFormat(
            self.cxx, self.use_clang_verify, self.execute_external, self.executor, exec_env=self.env
        )

    def configure_executor(self):
        exec_str = self.get_lit_conf("executor", "None")
        te = eval(exec_str)
        if te:
            self.lit_config.note("Using executor: %r" % exec_str)
            if self.lit_config.useValgrind:
                # We have no way of knowing where in the chain the
                # ValgrindExecutor is supposed to go. It is likely
                # that the user wants it at the end, but we have no
                # way of getting at that easily.
                selt.lit_config.fatal("Cannot infer how to create a Valgrind " " executor.")
        else:
            te = LocalExecutor()
            if self.lit_config.useValgrind:
                te = ValgrindExecutor(self.lit_config.valgrindArgs, te)
        self.executor = te

    def configure_target_info(self):
        default = "libcxx.test.target_info.LocalTI"
        info_str = self.get_lit_conf("target_info", default)
        mod_path, _, info = info_str.rpartition(".")
        mod = importlib.import_module(mod_path)
        self.target_info = getattr(mod, info)()
        if info_str != default:
            self.lit_config.note("inferred target_info as: %r" % info_str)

    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf("cxx_under_test")

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which("clang++", self.config.environment["PATH"])
            if clangxx:
                cxx = clangxx
                self.lit_config.note("inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal(
                "must specify user parameter cxx_under_test " "(e.g., --param=cxx_under_test=clang++)"
            )
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add("%s-%s.%s" % (cxx_type, maj_v, min_v))

    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf("libcxx_src_root", os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.libcxx_obj_root = self.get_lit_conf("libcxx_obj_root")

    def configure_cxx_library_root(self):
        self.cxx_library_root = self.get_lit_conf("cxx_library_root", self.libcxx_obj_root)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool("use_system_cxx_lib")
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note("inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)

    def configure_use_clang_verify(self):
        """If set, run clang with -verify on failing tests."""
        self.use_clang_verify = self.get_lit_bool("use_clang_verify")
        if self.use_clang_verify is None:
            # NOTE: We do not test for the -verify flag directly because
            #   -verify will always exit with non-zero on an empty file.
            self.use_clang_verify = self.cxx.hasCompileFlag(["-Xclang", "-verify-ignore-unexpected"])
            self.lit_config.note("inferred use_clang_verify as: %r" % self.use_clang_verify)

    def configure_execute_external(self):
        # Choose between lit's internal shell pipeline runner and a real shell.
        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
        # default value. Otherwise we default to internal on Windows and
        # external elsewhere, as bash on Windows is usually very slow.
        use_lit_shell_default = os.environ.get("LIT_USE_INTERNAL_SHELL")
        if use_lit_shell_default is not None:
            use_lit_shell_default = use_lit_shell_default != "0"
        else:
            use_lit_shell_default = sys.platform == "win32"
        # Check for the command line parameter using the default value if it is
        # not present.
        use_lit_shell = self.get_lit_bool("use_lit_shell", use_lit_shell_default)
        self.execute_external = not use_lit_shell

    def configure_ccache(self):
        use_ccache_default = os.environ.get("LIBCXX_USE_CCACHE") is not None
        use_ccache = self.get_lit_bool("use_ccache", use_ccache_default)
        if use_ccache:
            self.cxx.use_ccache = True
            self.lit_config.note("enabling ccache")

    def configure_features(self):
        additional_features = self.get_lit_conf("additional_features")
        if additional_features:
            for f in additional_features.split(","):
                self.config.available_features.add(f.strip())

        # Figure out which of the required locales we support
        locales = {
            "Darwin": {
                "en_US.UTF-8": "en_US.UTF-8",
                "cs_CZ.ISO8859-2": "cs_CZ.ISO8859-2",
                "fr_FR.UTF-8": "fr_FR.UTF-8",
                "fr_CA.ISO8859-1": "fr_CA.ISO8859-1",
                "ru_RU.UTF-8": "ru_RU.UTF-8",
                "zh_CN.UTF-8": "zh_CN.UTF-8",
            },
            "FreeBSD": {
                "en_US.UTF-8": "en_US.UTF-8",
                "cs_CZ.ISO8859-2": "cs_CZ.ISO8859-2",
                "fr_FR.UTF-8": "fr_FR.UTF-8",
                "fr_CA.ISO8859-1": "fr_CA.ISO8859-1",
                "ru_RU.UTF-8": "ru_RU.UTF-8",
                "zh_CN.UTF-8": "zh_CN.UTF-8",
            },
            "Linux": {
                "en_US.UTF-8": "en_US.UTF-8",
                "cs_CZ.ISO8859-2": "cs_CZ.ISO-8859-2",
                "fr_FR.UTF-8": "fr_FR.UTF-8",
                "fr_CA.ISO8859-1": "fr_CA.ISO-8859-1",
                "ru_RU.UTF-8": "ru_RU.UTF-8",
                "zh_CN.UTF-8": "zh_CN.UTF-8",
            },
            "Windows": {
                "en_US.UTF-8": "English_United States.1252",
                "cs_CZ.ISO8859-2": "Czech_Czech Republic.1250",
                "fr_FR.UTF-8": "French_France.1252",
                "fr_CA.ISO8859-1": "French_Canada.1252",
                "ru_RU.UTF-8": "Russian_Russia.1251",
                "zh_CN.UTF-8": "Chinese_China.936",
            },
        }

        target_system = self.target_info.system()
        target_platform = self.target_info.platform()

        if target_system in locales:
            default_locale = locale.setlocale(locale.LC_ALL)
            for feature, loc in locales[target_system].items():
                try:
                    locale.setlocale(locale.LC_ALL, loc)
                    self.config.available_features.add("locale.{0}".format(feature))
                except locale.Error:
                    self.lit_config.warning(
                        "The locale {0} is not supported by "
                        "your platform. Some tests will be "
                        "unsupported.".format(loc)
                    )
            locale.setlocale(locale.LC_ALL, default_locale)
        else:
            # Warn that the user doesn't get any free XFAILs for locale issues
            self.lit_config.warning("No locales entry for target_system: %s" % target_system)

        # Write an "available feature" that combines the triple when
        # use_system_cxx_lib is enabled. This is so that we can easily write
        # XFAIL markers for tests that are known to fail with versions of
        # libc++ as were shipped with a particular triple.
        if self.use_system_cxx_lib:
            self.config.available_features.add("with_system_cxx_lib=%s" % self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        self.config.available_features.add(target_platform)

        # Some linux distributions have different locale data than others.
        # Insert the distributions name and name-version into the available
        # features to allow tests to XFAIL on them.
        if target_platform == "linux":
            name = self.target_info.platform_name()
            ver = self.target_info.platform_ver()
            if name:
                self.config.available_features.add(name)
            if name and ver:
                self.config.available_features.add("%s-%s" % (name, ver))

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool("long_tests")
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note("inferred long_tests as: %r" % self.long_tests)

        if self.long_tests:
            self.config.available_features.add("long_tests")

        # Run a compile test for the -fsized-deallocation flag. This is needed
        # in test/std/language.support/support.dynamic/new.delete
        if self.cxx.hasCompileFlag("-fsized-deallocation"):
            self.config.available_features.add("fsized-deallocation")

    def configure_compile_flags(self):
        no_default_flags = self.get_lit_bool("no_default_flags", False)
        if not no_default_flags:
            self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf("compile_flags", "")
        self.cxx.compile_flags += shlex.split(compile_flags_str)

    def configure_default_compile_flags(self):
        # Try and get the std version from the command line. Fall back to
        # default given in lit.site.cfg is not present. If default is not
        # present then force c++11.
        std = self.get_lit_conf("std", "c++11")
        self.cxx.compile_flags += ["-std={0}".format(std)]
        self.config.available_features.add(std)
        # Configure include paths
        self.cxx.compile_flags += ["-nostdinc++"]
        self.configure_compile_flags_header_includes()
        if self.target_info.platform() == "linux":
            self.cxx.compile_flags += ["-D__STDC_FORMAT_MACROS", "-D__STDC_LIMIT_MACROS", "-D__STDC_CONSTANT_MACROS"]
        # Configure feature flags.
        self.configure_compile_flags_exceptions()
        self.configure_compile_flags_rtti()
        self.configure_compile_flags_no_global_filesystem_namespace()
        self.configure_compile_flags_no_stdin()
        self.configure_compile_flags_no_stdout()
        enable_32bit = self.get_lit_bool("enable_32bit", False)
        if enable_32bit:
            self.cxx.flags += ["-m32"]
        # Configure threading features.
        enable_threads = self.get_lit_bool("enable_threads", True)
        enable_monotonic_clock = self.get_lit_bool("enable_monotonic_clock", True)
        if not enable_threads:
            self.configure_compile_flags_no_threads()
            if not enable_monotonic_clock:
                self.configure_compile_flags_no_monotonic_clock()
        elif not enable_monotonic_clock:
            self.lit_config.fatal("enable_monotonic_clock cannot be false when" " enable_threads is true.")
        self.configure_compile_flags_no_thread_unsafe_c_functions()

        # Use verbose output for better errors
        self.cxx.flags += ["-v"]
        sysroot = self.get_lit_conf("sysroot")
        if sysroot:
            self.cxx.flags += ["--sysroot", sysroot]
        gcc_toolchain = self.get_lit_conf("gcc_toolchain")
        if gcc_toolchain:
            self.cxx.flags += ["-gcc-toolchain", gcc_toolchain]
        if self.use_target:
            self.cxx.flags += ["-target", self.config.target_triple]

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, "test/support")
        self.cxx.compile_flags += ["-I" + support_path]
        self.cxx.compile_flags += ["-include", os.path.join(support_path, "nasty_macros.hpp")]
        libcxx_headers = self.get_lit_conf("libcxx_headers", os.path.join(self.libcxx_src_root, "include"))
        if not os.path.isdir(libcxx_headers):
            self.lit_config.fatal("libcxx_headers='%s' is not a directory." % libcxx_headers)
        self.cxx.compile_flags += ["-I" + libcxx_headers]

    def configure_compile_flags_exceptions(self):
        enable_exceptions = self.get_lit_bool("enable_exceptions", True)
        if not enable_exceptions:
            self.config.available_features.add("libcpp-no-exceptions")
            self.cxx.compile_flags += ["-fno-exceptions"]

    def configure_compile_flags_rtti(self):
        enable_rtti = self.get_lit_bool("enable_rtti", True)
        if not enable_rtti:
            self.config.available_features.add("libcpp-no-rtti")
            self.cxx.compile_flags += ["-fno-rtti", "-D_LIBCPP_NO_RTTI"]

    def configure_compile_flags_no_global_filesystem_namespace(self):
        enable_global_filesystem_namespace = self.get_lit_bool("enable_global_filesystem_namespace", True)
        if not enable_global_filesystem_namespace:
            self.config.available_features.add("libcpp-has-no-global-filesystem-namespace")
            self.cxx.compile_flags += ["-D_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE"]

    def configure_compile_flags_no_stdin(self):
        enable_stdin = self.get_lit_bool("enable_stdin", True)
        if not enable_stdin:
            self.config.available_features.add("libcpp-has-no-stdin")
            self.cxx.compile_flags += ["-D_LIBCPP_HAS_NO_STDIN"]

    def configure_compile_flags_no_stdout(self):
        enable_stdout = self.get_lit_bool("enable_stdout", True)
        if not enable_stdout:
            self.config.available_features.add("libcpp-has-no-stdout")
            self.cxx.compile_flags += ["-D_LIBCPP_HAS_NO_STDOUT"]

    def configure_compile_flags_no_threads(self):
        self.cxx.compile_flags += ["-D_LIBCPP_HAS_NO_THREADS"]
        self.config.available_features.add("libcpp-has-no-threads")

    def configure_compile_flags_no_thread_unsafe_c_functions(self):
        enable_thread_unsafe_c_functions = self.get_lit_bool("enable_thread_unsafe_c_functions", True)
        if not enable_thread_unsafe_c_functions:
            self.cxx.compile_flags += ["-D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS"]
            self.config.available_features.add("libcpp-has-no-thread-unsafe-c-functions")

    def configure_compile_flags_no_monotonic_clock(self):
        self.cxx.compile_flags += ["-D_LIBCPP_HAS_NO_MONOTONIC_CLOCK"]
        self.config.available_features.add("libcpp-has-no-monotonic-clock")

    def configure_link_flags(self):
        no_default_flags = self.get_lit_bool("no_default_flags", False)
        if not no_default_flags:
            self.cxx.link_flags += ["-nodefaultlibs"]

            # Configure library path
            self.configure_link_flags_cxx_library_path()
            self.configure_link_flags_abi_library_path()

            # Configure libraries
            self.configure_link_flags_cxx_library()
            self.configure_link_flags_abi_library()
            self.configure_extra_library_flags()

        link_flags_str = self.get_lit_conf("link_flags", "")
        self.cxx.link_flags += shlex.split(link_flags_str)

    def configure_link_flags_cxx_library_path(self):
        libcxx_library = self.get_lit_conf("libcxx_library")
        # Configure libc++ library paths.
        if libcxx_library is not None:
            # Check that the given value for libcxx_library is valid.
            if not os.path.isfile(libcxx_library):
                self.lit_config.fatal("libcxx_library='%s' is not a valid file." % libcxx_library)
            if self.use_system_cxx_lib:
                self.lit_config.fatal(
                    "Conflicting options: 'libcxx_library' cannot be used " "with 'use_system_cxx_lib=true'"
                )
            self.cxx.link_flags += ["-Wl,-rpath," + os.path.dirname(libcxx_library)]
        elif not self.use_system_cxx_lib and self.cxx_library_root:
            self.cxx.link_flags += ["-L" + self.cxx_library_root, "-Wl,-rpath," + self.cxx_library_root]

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        self.abi_library_root = self.get_lit_conf("abi_library_path")
        if self.abi_library_root:
            self.cxx.link_flags += ["-L" + self.abi_library_root, "-Wl,-rpath," + self.abi_library_root]

    def configure_link_flags_cxx_library(self):
        libcxx_library = self.get_lit_conf("libcxx_library")
        if libcxx_library:
            self.cxx.link_flags += [libcxx_library]
        else:
            self.cxx.link_flags += ["-lc++"]

    def configure_link_flags_abi_library(self):
        cxx_abi = self.get_lit_conf("cxx_abi", "libcxxabi")
        if cxx_abi == "libstdc++":
            self.cxx.link_flags += ["-lstdc++"]
        elif cxx_abi == "libsupc++":
            self.cxx.link_flags += ["-lsupc++"]
        elif cxx_abi == "libcxxabi":
            # Don't link libc++abi explicitly on OS X because the symbols
            # should be available in libc++ directly.
            if self.target_info.platform() != "darwin":
                self.cxx.link_flags += ["-lc++abi"]
        elif cxx_abi == "libcxxrt":
            self.cxx.link_flags += ["-lcxxrt"]
        elif cxx_abi == "none":
            pass
        else:
            self.lit_config.fatal("C++ ABI setting %s unsupported for tests" % cxx_abi)

    def configure_extra_library_flags(self):
        enable_threads = self.get_lit_bool("enable_threads", True)
        llvm_unwinder = self.get_lit_bool("llvm_unwinder", False)
        target_platform = self.target_info.platform()
        if target_platform == "darwin":
            self.cxx.link_flags += ["-lSystem"]
        elif target_platform == "linux":
            if not llvm_unwinder:
                self.cxx.link_flags += ["-lgcc_eh"]
            self.cxx.link_flags += ["-lc", "-lm"]
            if enable_threads:
                self.cxx.link_flags += ["-lpthread"]
            self.cxx.link_flags += ["-lrt"]
            if llvm_unwinder:
                self.cxx.link_flags += ["-lunwind", "-ldl"]
            else:
                self.cxx.link_flags += ["-lgcc_s"]
        elif target_platform.startswith("freebsd"):
            self.cxx.link_flags += ["-lc", "-lm", "-lpthread", "-lgcc_s", "-lcxxrt"]
        else:
            self.lit_config.fatal("unrecognized system: %r" % target_platform)

    def configure_color_diagnostics(self):
        use_color = self.get_lit_conf("color_diagnostics")
        if use_color is None:
            use_color = os.environ.get("LIBCXX_COLOR_DIAGNOSTICS")
        if use_color is None:
            return
        if use_color != "":
            self.lit_config.fatal('Invalid value for color_diagnostics "%s".' % use_color)
        color_flag = "-fdiagnostics-color=always"
        # Check if the compiler supports the color diagnostics flag. Issue a
        # warning if it does not since color diagnostics have been requested.
        if not self.cxx.hasCompileFlag(color_flag):
            self.lit_config.warning("color diagnostics have been requested but are not supported " "by the compiler")
        else:
            self.cxx.flags += [color_flag]

    def configure_debug_mode(self):
        debug_level = self.get_lit_conf("debug_level", None)
        if not debug_level:
            return
        if debug_level not in ["0", "1"]:
            self.lit_config.fatal('Invalid value for debug_level "%s".' % debug_level)
        self.cxx.compile_flags += ["-D_LIBCPP_DEBUG=%s" % debug_level]

    def configure_warnings(self):
        enable_warnings = self.get_lit_bool("enable_warnings", False)
        if enable_warnings:
            self.cxx.compile_flags += ["-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER", "-Wall", "-Werror"]
            self.cxx.addWarningFlagIfSupported("-Wno-attributes")
            self.cxx.addWarningFlagIfSupported("-Wno-pessimizing-move")
            self.cxx.addWarningFlagIfSupported("-Wno-c++11-extensions")
            self.cxx.addWarningFlagIfSupported("-Wno-user-defined-literals")
            # TODO(EricWF) Remove the unused warnings once the test suite
            # compiles clean with them.
            self.cxx.addWarningFlagIfSupported("-Wno-unused-local-typedef")
            self.cxx.addWarningFlagIfSupported("-Wno-unused-variable")
            std = self.get_lit_conf("std", None)
            if std in ["c++98", "c++03"]:
                # The '#define static_assert' provided by libc++ in C++03 mode
                # causes an unused local typedef whenever it is used.
                self.cxx.addWarningFlagIfSupported("-Wno-unused-local-typedef")

    def configure_sanitizer(self):
        san = self.get_lit_conf("use_sanitizer", "").strip()
        if san:
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get("PATH", "")
            cxx_path = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = os.path.dirname(cxx_path) + os.pathsep + symbolizer_search_paths
            llvm_symbolizer = lit.util.which("llvm-symbolizer", symbolizer_search_paths)
            # Setup the sanitizer compile flags
            self.cxx.flags += ["-g", "-fno-omit-frame-pointer"]
            if self.target_info.platform() == "linux":
                self.cxx.link_flags += ["-ldl"]
            if san == "Address":
                self.cxx.flags += ["-fsanitize=address"]
                if llvm_symbolizer is not None:
                    self.env["ASAN_SYMBOLIZER_PATH"] = llvm_symbolizer
                self.config.available_features.add("asan")
                self.config.available_features.add("sanitizer-new-delete")
            elif san == "Memory" or san == "MemoryWithOrigins":
                self.cxx.flags += ["-fsanitize=memory"]
                if san == "MemoryWithOrigins":
                    self.cxx.compile_flags += ["-fsanitize-memory-track-origins"]
                if llvm_symbolizer is not None:
                    self.env["MSAN_SYMBOLIZER_PATH"] = llvm_symbolizer
                self.config.available_features.add("msan")
                self.config.available_features.add("sanitizer-new-delete")
            elif san == "Undefined":
                self.cxx.flags += ["-fsanitize=undefined", "-fno-sanitize=vptr,function", "-fno-sanitize-recover"]
                self.cxx.compile_flags += ["-O3"]
                self.config.available_features.add("ubsan")
                if self.target_info.platform() == "darwin":
                    self.config.available_features.add("sanitizer-new-delete")
            elif san == "Thread":
                self.cxx.flags += ["-fsanitize=thread"]
                self.config.available_features.add("tsan")
                self.config.available_features.add("sanitizer-new-delete")
            else:
                self.lit_config.fatal("unsupported value for " "use_sanitizer: {0}".format(san))
            san_lib = self.get_lit_conf("sanitizer_library")
            if san_lib:
                self.cxx.link_flags += [san_lib, "-Wl,-rpath,%s" % os.path.dirname(san_lib)]

    def configure_coverage(self):
        self.generate_coverage = self.get_lit_bool("generate_coverage", False)
        if self.generate_coverage:
            self.cxx.flags += ["-g", "--coverage"]
            self.cxx.compile_flags += ["-O0"]

    def configure_substitutions(self):
        sub = self.config.substitutions
        # Configure compiler substitions
        sub.append(("%cxx", self.cxx.path))
        # Configure flags substitutions
        flags_str = " ".join(self.cxx.flags)
        compile_flags_str = " ".join(self.cxx.compile_flags)
        link_flags_str = " ".join(self.cxx.link_flags)
        all_flags = "%s %s %s" % (flags_str, compile_flags_str, link_flags_str)
        sub.append(("%flags", flags_str))
        sub.append(("%compile_flags", compile_flags_str))
        sub.append(("%link_flags", link_flags_str))
        sub.append(("%all_flags", all_flags))
        # Add compile and link shortcuts
        compile_str = self.cxx.path + " -o %t.o %s -c " + flags_str + compile_flags_str
        link_str = self.cxx.path + " -o %t.exe %t.o " + flags_str + link_flags_str
        assert type(link_str) is str
        build_str = self.cxx.path + " -o %t.exe %s " + all_flags
        sub.append(("%compile", compile_str))
        sub.append(("%link", link_str))
        sub.append(("%build", build_str))
        # Configure exec prefix substitutions.
        exec_env_str = "env " if len(self.env) != 0 else ""
        for k, v in self.env.items():
            exec_env_str += " %s=%s" % (k, v)
        # Configure run env substitution.
        exec_str = ""
        if self.lit_config.useValgrind:
            exec_str = " ".join(self.lit_config.valgrindArgs) + exec_env_str
        sub.append(("%exec", exec_str))
        # Configure run shortcut
        sub.append(("%run", exec_str + " %t.exe"))
        # Configure not program substitions
        not_py = os.path.join(self.libcxx_src_root, "utils", "not", "not.py")
        not_str = "%s %s" % (sys.executable, not_py)
        sub.append(("not", not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf("target_triple")
        self.use_target = bool(self.config.target_triple)
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.use_target:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r"([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)", r"\1-\2-\3\5", target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if target_triple.endswith("redhat-linux") or target_triple.endswith("suse-linux"):
                target_triple += "-gnu"
            self.config.target_triple = target_triple
            self.lit_config.note("inferred target_triple as: %r" % self.config.target_triple)

    def configure_env(self):
        if self.target_info.platform() == "darwin":
            library_paths = []
            # Configure the library path for libc++
            libcxx_library = self.get_lit_conf("libcxx_library")
            if self.use_system_cxx_lib:
                pass
            elif libcxx_library:
                library_paths += [os.path.dirname(libcxx_library)]
            elif self.cxx_library_root:
                library_paths += [self.cxx_library_root]
            # Configure the abi library path
            if self.abi_library_root:
                library_paths += [self.abi_library_root]
            if library_paths:
                self.env["DYLD_LIBRARY_PATH"] = ":".join(library_paths)
Ejemplo n.º 11
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.project_obj_root = None
        self.libcxx_src_root = None
        self.libcxx_obj_root = None
        self.cxx_library_root = None
        self.abi_library_root = None
        self.env = {}
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None
        self.execute_external = False

    def get_lit_conf(self, name, default=None):
        val = self.lit_config.params.get(name, None)
        if val is None:
            val = getattr(self.config, name, None)
            if val is None:
                val = default
        return val

    def get_lit_bool(self, name, default=None):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if conf.lower() in ('1', 'true'):
            return True
        if conf.lower() in ('', '0', 'false'):
            return False
        self.lit_config.fatal(
            "parameter '{}' should be true or false".format(name))

    def configure(self):
        self.configure_executor()
        self.configure_target_info()
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_execute_external()
        self.configure_ccache()
        self.configure_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_color_diagnostics()
        self.configure_debug_mode()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note('Using compiler: %s' % self.cxx.path)
        self.lit_config.note('Using flags: %s' % self.cxx.flags)
        self.lit_config.note('Using compile flags: %s' %
                             self.cxx.compile_flags)
        self.lit_config.note('Using link flags: %s' % self.cxx.link_flags)
        # Print as list to prevent "set([...])" from being printed.
        self.lit_config.note('Using available_features: %s' %
                             list(self.config.available_features))
        self.lit_config.note('Using environment: %r' % self.env)

    def get_test_format(self):
        return LibcxxTestFormat(self.cxx,
                                self.use_clang_verify,
                                self.execute_external,
                                self.executor,
                                exec_env=self.env)

    def configure_executor(self):
        exec_str = self.get_lit_conf('executor', "None")
        te = eval(exec_str)
        if te:
            self.lit_config.note("Using executor: %r" % exec_str)
            if self.lit_config.useValgrind:
                # We have no way of knowing where in the chain the
                # ValgrindExecutor is supposed to go. It is likely
                # that the user wants it at the end, but we have no
                # way of getting at that easily.
                selt.lit_config.fatal("Cannot infer how to create a Valgrind "
                                      " executor.")
        else:
            te = LocalExecutor()
            if self.lit_config.useValgrind:
                te = ValgrindExecutor(self.lit_config.valgrindArgs, te)
        self.executor = te

    def configure_target_info(self):
        default = "libcxx.test.target_info.LocalTI"
        info_str = self.get_lit_conf('target_info', default)
        mod_path, _, info = info_str.rpartition('.')
        mod = importlib.import_module(mod_path)
        self.target_info = getattr(mod, info)()
        if info_str != default:
            self.lit_config.note("inferred target_info as: %r" % info_str)

    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf('cxx_under_test')

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            if clangxx:
                cxx = clangxx
                self.lit_config.note("inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal('must specify user parameter cxx_under_test '
                                  '(e.g., --param=cxx_under_test=clang++)')
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add('%s-%s.%s' %
                                               (cxx_type, maj_v, min_v))

    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf(
            'libcxx_src_root', os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.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)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib')
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note("inferred use_system_cxx_lib as: %r" %
                                 self.use_system_cxx_lib)

    def configure_use_clang_verify(self):
        '''If set, run clang with -verify on failing tests.'''
        self.use_clang_verify = self.get_lit_bool('use_clang_verify')
        if self.use_clang_verify is None:
            # NOTE: We do not test for the -verify flag directly because
            #   -verify will always exit with non-zero on an empty file.
            self.use_clang_verify = self.cxx.hasCompileFlag(
                ['-Xclang', '-verify-ignore-unexpected'])
            self.lit_config.note("inferred use_clang_verify as: %r" %
                                 self.use_clang_verify)

    def configure_execute_external(self):
        # Choose between lit's internal shell pipeline runner and a real shell.
        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
        # default value. Otherwise we default to internal on Windows and
        # external elsewhere, as bash on Windows is usually very slow.
        use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL')
        if use_lit_shell_default is not None:
            use_lit_shell_default = use_lit_shell_default != '0'
        else:
            use_lit_shell_default = sys.platform == 'win32'
        # Check for the command line parameter using the default value if it is
        # not present.
        use_lit_shell = self.get_lit_bool('use_lit_shell',
                                          use_lit_shell_default)
        self.execute_external = not use_lit_shell

    def configure_ccache(self):
        use_ccache_default = os.environ.get('LIBCXX_USE_CCACHE') is not None
        use_ccache = self.get_lit_bool('use_ccache', use_ccache_default)
        if use_ccache:
            self.cxx.use_ccache = True
            self.lit_config.note('enabling ccache')

    def configure_features(self):
        additional_features = self.get_lit_conf('additional_features')
        if additional_features:
            for f in additional_features.split(','):
                self.config.available_features.add(f.strip())

        # Figure out which of the required locales we support
        locales = {
            'Darwin': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'FreeBSD': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'Linux': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO-8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO-8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'Windows': {
                'en_US.UTF-8': 'English_United States.1252',
                'cs_CZ.ISO8859-2': 'Czech_Czech Republic.1250',
                'fr_FR.UTF-8': 'French_France.1252',
                'fr_CA.ISO8859-1': 'French_Canada.1252',
                'ru_RU.UTF-8': 'Russian_Russia.1251',
                'zh_CN.UTF-8': 'Chinese_China.936',
            },
        }

        target_system = self.target_info.system()
        target_platform = self.target_info.platform()

        if target_system in locales:
            default_locale = locale.setlocale(locale.LC_ALL)
            for feature, loc in locales[target_system].items():
                try:
                    locale.setlocale(locale.LC_ALL, loc)
                    self.config.available_features.add(
                        'locale.{0}'.format(feature))
                except locale.Error:
                    self.lit_config.warning(
                        'The locale {0} is not supported by '
                        'your platform. Some tests will be '
                        'unsupported.'.format(loc))
            locale.setlocale(locale.LC_ALL, default_locale)
        else:
            # Warn that the user doesn't get any free XFAILs for locale issues
            self.lit_config.warning("No locales entry for target_system: %s" %
                                    target_system)

        # Write an "available feature" that combines the triple when
        # use_system_cxx_lib is enabled. This is so that we can easily write
        # XFAIL markers for tests that are known to fail with versions of
        # libc++ as were shipped with a particular triple.
        if self.use_system_cxx_lib:
            self.config.available_features.add('with_system_cxx_lib=%s' %
                                               self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        self.config.available_features.add(target_platform)

        # Some linux distributions have different locale data than others.
        # Insert the distributions name and name-version into the available
        # features to allow tests to XFAIL on them.
        if target_platform == 'linux':
            name = self.target_info.platform_name()
            ver = self.target_info.platform_ver()
            if name:
                self.config.available_features.add(name)
            if name and ver:
                self.config.available_features.add('%s-%s' % (name, ver))

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool('long_tests')
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note("inferred long_tests as: %r" %
                                 self.long_tests)

        if self.long_tests:
            self.config.available_features.add('long_tests')

        # Run a compile test for the -fsized-deallocation flag. This is needed
        # in test/std/language.support/support.dynamic/new.delete
        if self.cxx.hasCompileFlag('-fsized-deallocation'):
            self.config.available_features.add('fsized-deallocation')

    def configure_compile_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf('compile_flags', '')
        self.cxx.compile_flags += shlex.split(compile_flags_str)
        sysroot_flags = getSysrootFlagsOnDarwin(self.config, self.lit_config)
        self.cxx.compile_flags.extend(sysroot_flags)

    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']
            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)
        # Configure include paths
        self.cxx.compile_flags += ['-nostdinc++']
        self.configure_compile_flags_header_includes()
        if self.target_info.platform() == 'linux':
            self.cxx.compile_flags += [
                '-D__STDC_FORMAT_MACROS', '-D__STDC_LIMIT_MACROS',
                '-D__STDC_CONSTANT_MACROS'
            ]
        # Configure feature flags.
        self.configure_compile_flags_exceptions()
        self.configure_compile_flags_rtti()
        self.configure_compile_flags_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]
        if self.use_target:
            self.cxx.flags += ['-target', self.config.target_triple]

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        self.cxx.compile_flags += ['-I' + support_path]
        self.cxx.compile_flags += [
            '-include',
            os.path.join(support_path, 'nasty_macros.hpp')
        ]
        self.configure_config_site_header()
        libcxx_headers = self.get_lit_conf(
            'libcxx_headers', os.path.join(self.libcxx_src_root, 'include'))
        if not os.path.isdir(libcxx_headers):
            self.lit_config.fatal("libcxx_headers='%s' is not a directory." %
                                  libcxx_headers)
        self.cxx.compile_flags += ['-I' + libcxx_headers]

    def configure_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_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_link_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.cxx.link_flags += ['-nodefaultlibs']

            # Configure library path
            self.configure_link_flags_cxx_library_path()
            self.configure_link_flags_abi_library_path()

            # Configure libraries
            self.configure_link_flags_cxx_library()
            self.configure_link_flags_abi_library()
            self.configure_extra_library_flags()

        link_flags_str = self.get_lit_conf('link_flags', '')
        self.cxx.link_flags += shlex.split(link_flags_str)

    def configure_link_flags_cxx_library_path(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        # Configure libc++ library paths.
        if libcxx_library is not None:
            # Check that the given value for libcxx_library is valid.
            if not os.path.isfile(libcxx_library):
                self.lit_config.fatal(
                    "libcxx_library='%s' is not a valid file." %
                    libcxx_library)
            if self.use_system_cxx_lib:
                self.lit_config.fatal(
                    "Conflicting options: 'libcxx_library' cannot be used "
                    "with 'use_system_cxx_lib=true'")
            self.cxx.link_flags += [
                '-Wl,-rpath,' + os.path.dirname(libcxx_library)
            ]
        elif not self.use_system_cxx_lib and self.cxx_library_root:
            self.cxx.link_flags += [
                '-L' + self.cxx_library_root,
                '-Wl,-rpath,' + self.cxx_library_root
            ]

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        self.abi_library_root = self.get_lit_conf('abi_library_path')
        if self.abi_library_root:
            self.cxx.link_flags += [
                '-L' + self.abi_library_root,
                '-Wl,-rpath,' + self.abi_library_root
            ]

    def configure_link_flags_cxx_library(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        if libcxx_library:
            self.cxx.link_flags += [libcxx_library]
        else:
            self.cxx.link_flags += ['-lc++']

    def configure_link_flags_abi_library(self):
        cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi')
        if cxx_abi == 'libstdc++':
            self.cxx.link_flags += ['-lstdc++']
        elif cxx_abi == 'libsupc++':
            self.cxx.link_flags += ['-lsupc++']
        elif cxx_abi == 'libcxxabi':
            # Don't link libc++abi explicitly on OS X because the symbols
            # should be available in libc++ directly.
            if self.target_info.platform() != 'darwin':
                self.cxx.link_flags += ['-lc++abi']
        elif cxx_abi == 'libcxxrt':
            self.cxx.link_flags += ['-lcxxrt']
        elif cxx_abi == 'none':
            pass
        else:
            self.lit_config.fatal('C++ ABI setting %s unsupported for tests' %
                                  cxx_abi)

    def configure_extra_library_flags(self):
        enable_threads = ('libcpp-has-no-threads'
                          not in self.config.available_features)
        llvm_unwinder = self.get_lit_bool('llvm_unwinder', False)
        target_platform = self.target_info.platform()
        if target_platform == 'darwin':
            self.cxx.link_flags += ['-lSystem']
        elif target_platform == 'linux':
            self.cxx.link_flags += ['-lm']
            if not llvm_unwinder:
                self.cxx.link_flags += ['-lgcc_s', '-lgcc']
            if enable_threads:
                self.cxx.link_flags += ['-lpthread']
            self.cxx.link_flags += ['-lc']
            if llvm_unwinder:
                self.cxx.link_flags += ['-lunwind', '-ldl']
            else:
                self.cxx.link_flags += ['-lgcc_s', '-lgcc']
        elif target_platform.startswith('freebsd'):
            self.cxx.link_flags += [
                '-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt'
            ]
        else:
            self.lit_config.fatal("unrecognized system: %r" % target_platform)

    def configure_color_diagnostics(self):
        use_color = self.get_lit_conf('color_diagnostics')
        if use_color is None:
            use_color = os.environ.get('LIBCXX_COLOR_DIAGNOSTICS')
        if use_color is None:
            return
        if use_color != '':
            self.lit_config.fatal('Invalid value for color_diagnostics "%s".' %
                                  use_color)
        color_flag = '-fdiagnostics-color=always'
        # Check if the compiler supports the color diagnostics flag. Issue a
        # warning if it does not since color diagnostics have been requested.
        if not self.cxx.hasCompileFlag(color_flag):
            self.lit_config.warning(
                'color diagnostics have been requested but are not supported '
                'by the compiler')
        else:
            self.cxx.flags += [color_flag]

    def configure_debug_mode(self):
        debug_level = self.get_lit_conf('debug_level', None)
        if not debug_level:
            return
        if debug_level not in ['0', '1']:
            self.lit_config.fatal('Invalid value for debug_level "%s".' %
                                  debug_level)
        self.cxx.compile_flags += ['-D_LIBCPP_DEBUG=%s' % debug_level]

    def configure_warnings(self):
        enable_warnings = self.get_lit_bool('enable_warnings', False)
        if enable_warnings:
            self.cxx.compile_flags += [
                '-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER', '-Wall', '-Werror'
            ]
            self.cxx.addWarningFlagIfSupported('-Wno-attributes')
            self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move')
            self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions')
            self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals')
            # TODO(EricWF) Remove the unused warnings once the test suite
            # compiles clean with them.
            self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')
            self.cxx.addWarningFlagIfSupported('-Wno-unused-variable')
            std = self.get_lit_conf('std', None)
            if std in ['c++98', 'c++03']:
                # The '#define static_assert' provided by libc++ in C++03 mode
                # causes an unused local typedef whenever it is used.
                self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')

    def configure_sanitizer(self):
        san = self.get_lit_conf('use_sanitizer', '').strip()
        if san:
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get('PATH', '')
            cxx_path = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = (os.path.dirname(cxx_path) +
                                           os.pathsep +
                                           symbolizer_search_paths)
            llvm_symbolizer = lit.util.which('llvm-symbolizer',
                                             symbolizer_search_paths)
            # Setup the sanitizer compile flags
            self.cxx.flags += ['-g', '-fno-omit-frame-pointer']
            if self.target_info.platform() == 'linux':
                # The libraries and their order are taken from the
                # linkSanitizerRuntimeDeps function in
                # clang/lib/Driver/Tools.cpp
                self.cxx.link_flags += ['-lpthread', '-lrt', '-lm', '-ldl']
            if san == 'Address':
                self.cxx.flags += ['-fsanitize=address']
                if llvm_symbolizer is not None:
                    self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('asan')
                self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Memory' or san == 'MemoryWithOrigins':
                self.cxx.flags += ['-fsanitize=memory']
                if san == 'MemoryWithOrigins':
                    self.cxx.compile_flags += [
                        '-fsanitize-memory-track-origins'
                    ]
                if llvm_symbolizer is not None:
                    self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('msan')
                self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Undefined':
                self.cxx.flags += [
                    '-fsanitize=undefined', '-fno-sanitize=vptr,function',
                    '-fno-sanitize-recover'
                ]
                self.cxx.compile_flags += ['-O3']
                self.config.available_features.add('ubsan')
                if self.target_info.platform() == 'darwin':
                    self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Thread':
                self.cxx.flags += ['-fsanitize=thread']
                self.config.available_features.add('tsan')
                self.config.available_features.add('sanitizer-new-delete')
            else:
                self.lit_config.fatal('unsupported value for '
                                      'use_sanitizer: {0}'.format(san))
            san_lib = self.get_lit_conf('sanitizer_library')
            if san_lib:
                self.cxx.link_flags += [
                    san_lib,
                    '-Wl,-rpath,%s' % os.path.dirname(san_lib)
                ]

    def configure_coverage(self):
        self.generate_coverage = self.get_lit_bool('generate_coverage', False)
        if self.generate_coverage:
            self.cxx.flags += ['-g', '--coverage']
            self.cxx.compile_flags += ['-O0']

    def configure_substitutions(self):
        sub = self.config.substitutions
        # Configure compiler substitions
        sub.append(('%cxx', self.cxx.path))
        # Configure flags substitutions
        flags_str = ' '.join(self.cxx.flags)
        compile_flags_str = ' '.join(self.cxx.compile_flags)
        link_flags_str = ' '.join(self.cxx.link_flags)
        all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str)
        sub.append(('%flags', flags_str))
        sub.append(('%compile_flags', compile_flags_str))
        sub.append(('%link_flags', link_flags_str))
        sub.append(('%all_flags', all_flags))
        # Add compile and link shortcuts
        compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str +
                       compile_flags_str)
        link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str +
                    link_flags_str)
        assert type(link_str) is str
        build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
        sub.append(('%compile', compile_str))
        sub.append(('%link', link_str))
        sub.append(('%build', build_str))
        # Configure exec prefix substitutions.
        exec_env_str = 'env ' if len(self.env) != 0 else ''
        for k, v in self.env.items():
            exec_env_str += ' %s=%s' % (k, v)
        # Configure run env substitution.
        exec_str = ''
        if self.lit_config.useValgrind:
            exec_str = ' '.join(self.lit_config.valgrindArgs) + exec_env_str
        sub.append(('%exec', exec_str))
        # Configure run shortcut
        sub.append(('%run', exec_str + ' %t.exe'))
        # Configure not program substitions
        not_py = os.path.join(self.libcxx_src_root, 'utils', 'not', 'not.py')
        not_str = '%s %s' % (sys.executable, not_py)
        sub.append(('not', not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf('target_triple')
        self.use_target = bool(self.config.target_triple)
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.use_target:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)',
                                   r'\1-\2-\3\5', target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if (target_triple.endswith('redhat-linux')
                    or target_triple.endswith('suse-linux')):
                target_triple += '-gnu'
            self.config.target_triple = target_triple
            self.lit_config.note("inferred target_triple as: %r" %
                                 self.config.target_triple)

    def configure_env(self):
        if self.target_info.platform() == 'darwin':
            library_paths = []
            # Configure the library path for libc++
            libcxx_library = self.get_lit_conf('libcxx_library')
            if self.use_system_cxx_lib:
                pass
            elif libcxx_library:
                library_paths += [os.path.dirname(libcxx_library)]
            elif self.cxx_library_root:
                library_paths += [self.cxx_library_root]
            # Configure the abi library path
            if self.abi_library_root:
                library_paths += [self.abi_library_root]
            if library_paths:
                self.env['DYLD_LIBRARY_PATH'] = ':'.join(library_paths)
Ejemplo n.º 12
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.cxx_is_clang_cl = None
        self.cxx_stdlib_under_test = None
        self.project_obj_root = None
        self.libcxx_src_root = None
        self.libcxx_obj_root = None
        self.cxx_library_root = None
        self.cxx_runtime_root = None
        self.abi_library_root = None
        self.link_shared = self.get_lit_bool('enable_shared', default=True)
        self.debug_build = self.get_lit_bool('debug_build', default=False)
        self.exec_env = dict()
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None

    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.target_info.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_target_info()
        self.configure_executor()
        self.configure_use_system_cxx_lib()
        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_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_debug_mode()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_modules()
        self.configure_substitutions()
        self.configure_features()
        self.configure_new_features()

    def configure_new_features(self):
        supportedFeatures = [
            f for f in libcxx.test.features.features
            if f.isSupported(self.config)
        ]
        for feature in supportedFeatures:
            feature.enableIn(self.config)

    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(sorted(self.config.available_features)))
        show_env_vars = {}
        for k, v in self.exec_env.items():
            if k not in os.environ or os.environ[k] != v:
                show_env_vars[k] = v
        self.lit_config.note('Adding environment variables: %r' %
                             show_env_vars)
        sys.stderr.flush()  # Force flushing to avoid broken output on Windows

    def get_test_format(self):
        from libcxx.test.format import LibcxxTestFormat
        return LibcxxTestFormat(self.cxx,
                                self.use_clang_verify,
                                self.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:
                self.lit_config.fatal(
                    "The libc++ test suite can't run under Valgrind with a custom executor"
                )
        else:
            te = LocalExecutor()

        te.target_info = self.target_info
        self.target_info.executor = 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(self, cxx) if not self.cxx_is_clang_cl else \
                   self._configure_clang_cl(cxx)
        self.cxx.compile_env = dict(os.environ)

    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(self,
                           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_roots = [
                os.path.join(self.project_obj_root, 'libcxx'),
                os.path.join(self.project_obj_root, 'projects', 'libcxx'),
                os.path.join(self.project_obj_root, 'runtimes', 'libcxx'),
            ]
            for possible_root in possible_roots:
                if os.path.isdir(possible_root):
                    self.libcxx_obj_root = possible_root
                    break
            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
            ), "the specified use_system_cxx_lib parameter (%s) is not a valid directory" % self.use_system_cxx_lib
            self.use_system_cxx_lib = os.path.abspath(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++':
            # 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'

    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)

        # Write an "available feature" that combines the triple when
        # use_system_cxx_lib is enabled. This is so that we can easily write
        # XFAIL markers for tests that are known to fail with versions of
        # libc++ as were shipped with a particular triple.
        if self.use_system_cxx_lib:
            self.config.available_features.add('with_system_cxx_lib=%s' %
                                               self.config.target_triple)

            # Add available features for more generic versions of the target
            # triple attached to  with_system_cxx_lib.
            if self.use_deployment:
                (_, name, version) = self.config.deployment
                self.config.available_features.add('with_system_cxx_lib=%s' %
                                                   name)
                self.config.available_features.add('with_system_cxx_lib=%s%s' %
                                                   (name, version))

        # Configure the availability feature. Availability is only enabled
        # with libc++, because other standard libraries do not provide
        # availability markup.
        if self.use_deployment and self.cxx_stdlib_under_test == 'libc++':
            (_, name, version) = self.config.deployment
            self.config.available_features.add('availability=%s' % name)
            self.config.available_features.add('availability=%s%s' %
                                               (name, version))

        # Insert the platform name and version into the available features.
        self.target_info.add_platform_features(self.config.available_features)

        # 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')

        if not self.get_lit_bool('enable_filesystem', default=True):
            self.config.available_features.add('c++filesystem-disabled')

        if self.get_lit_bool('has_libatomic', False):
            self.config.available_features.add('libatomic')

        if self.target_info.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')

        libcxx_gdb = self.get_lit_conf('libcxx_gdb')
        if libcxx_gdb and 'NOTFOUND' not in libcxx_gdb:
            self.config.available_features.add('libcxx_gdb')
            self.cxx.libcxx_gdb = libcxx_gdb

    def configure_compile_flags(self):
        self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf('compile_flags', '')
        self.cxx.compile_flags += shlex.split(compile_flags_str)
        if self.target_info.is_windows():
            # FIXME: Can we remove this?
            self.cxx.compile_flags += ['-D_CRT_SECURE_NO_WARNINGS']
            # Required so that tests using min/max don't fail on Windows,
            # and so that those tests don't have to be changed to tolerate
            # this insanity.
            self.cxx.compile_flags += ['-DNOMINMAX']
        additional_flags = self.get_lit_conf('test_compiler_flags')
        if additional_flags:
            self.cxx.compile_flags += shlex.split(additional_flags)

    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++2a', 'c++17', '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')
                    possible_stds.remove('c++17')
                # 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)]
        std_feature = std.replace('gnu++', 'c++')
        std_feature = std.replace('1z', '17')
        self.config.available_features.add(std_feature)
        # 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()
        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.target_info.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]

        # Add includes for support headers used in the tests.
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        self.cxx.compile_flags += ['-I' + support_path]

        # Add includes for the PSTL headers
        pstl_src_root = self.get_lit_conf('pstl_src_root')
        pstl_obj_root = self.get_lit_conf('pstl_obj_root')
        if pstl_src_root is not None and pstl_obj_root is not None:
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_src_root, 'include')
            ]
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_obj_root, 'generated_headers')
            ]
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_src_root, 'test')
            ]
            self.config.available_features.add('parallel-algorithms')

        # FIXME(EricWF): variant_size.pass.cpp requires a slightly larger
        # template depth with older Clang versions.
        self.cxx.addCompileFlagIfSupported('-ftemplate-depth=270')

    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.target_info.is_windows():
            self.cxx.compile_flags += [
                '-include',
                os.path.join(support_path, 'nasty_macros.h')
            ]
        if self.cxx_stdlib_under_test == 'msvc':
            self.cxx.compile_flags += [
                '-include',
                os.path.join(support_path, 'msvc_stdlib_force_include.h')
            ]
            pass
        if self.target_info.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
        self.cxx.compile_flags += ['-include', config_site_header]

    def configure_compile_flags_exceptions(self):
        enable_exceptions = self.get_lit_bool('enable_exceptions', True)
        if not enable_exceptions:
            self.config.available_features.add('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('-fno-rtti')
            self.cxx.compile_flags += ['-fno-rtti', '-D_LIBCPP_NO_RTTI']

    def configure_link_flags(self):
        # 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.target_info.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++':
            self.config.available_features.add('c++experimental')
            self.cxx.link_flags += ['-lstdc++fs', '-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('invalid stdlib under test')

        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.target_info.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.target_info.is_windows():
                    self.cxx.link_flags += [
                        '-Wl,-rpath,' + self.cxx_runtime_root
                    ]
                elif self.target_info.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.target_info.is_windows():
                self.cxx.link_flags += [
                    '-Wl,-rpath,' + self.use_system_cxx_lib
                ]
            if self.target_info.is_windows() and self.link_shared:
                self.add_path(self.cxx.compile_env, self.use_system_cxx_lib)
        additional_flags = self.get_lit_conf('test_linker_flags')
        if additional_flags:
            self.cxx.link_flags += shlex.split(additional_flags)

    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.target_info.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 the C++ library requires explicitly linking to libc++abi, or
            # if we're testing libc++abi itself (the test configs are shared),
            # then link it.
            testing_libcxxabi = self.get_lit_conf('name', '') == 'libc++abi'
            if self.target_info.allow_cxxabi_link() or testing_libcxxabi:
                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_libcxxabi_flag = abs_path
                        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.target_info.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_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
        default_enable_warnings = self.cxx.type in ['clang', 'apple-clang']
        enable_warnings = self.get_lit_bool('enable_warnings',
                                            default_enable_warnings)
        self.cxx.useWarnings(enable_warnings)
        self.cxx.warning_flags += ['-Werror', '-Wall', '-Wextra']
        # On GCC, the libc++ headers cause errors due to throw() decorators
        # on operator new clashing with those from the test suite, so we
        # don't enable warnings in system headers on GCC.
        if self.cxx.type != 'gcc':
            self.cxx.warning_flags += ['-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER']
        self.cxx.addWarningFlagIfSupported('-Wshadow')
        self.cxx.addWarningFlagIfSupported('-Wno-unused-command-line-argument')
        self.cxx.addWarningFlagIfSupported('-Wno-attributes')
        self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move')
        self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions')
        self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals')
        self.cxx.addWarningFlagIfSupported('-Wno-noexcept-type')
        self.cxx.addWarningFlagIfSupported(
            '-Wno-aligned-allocation-unavailable')
        # These warnings should be enabled in order to support the MSVC
        # team using the test suite; They enable the warnings below and
        # expect the test suite to be clean.
        self.cxx.addWarningFlagIfSupported('-Wsign-compare')
        self.cxx.addWarningFlagIfSupported('-Wunused-variable')
        self.cxx.addWarningFlagIfSupported('-Wunused-parameter')
        self.cxx.addWarningFlagIfSupported('-Wunreachable-code')
        self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')

    def configure_sanitizer(self):
        san = self.get_lit_conf('use_sanitizer', '').strip()
        if san:
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get('PATH', '')
            cxx_path = 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=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')
            elif san == 'DataFlow':
                self.cxx.flags += ['-fsanitize=dataflow']
            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', '-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
        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):
        tool_env = ''
        if self.target_info.is_darwin():
            # Do not pass DYLD_LIBRARY_PATH to the compiler, linker, etc. as
            # these tools are not meant to exercise the just-built libraries.
            tool_env += 'env DYLD_LIBRARY_PATH=""'

        sub = self.config.substitutions
        # Configure compiler substitutions
        sub.append(('%{cxx}', '{} {}'.format(tool_env,
                                             pipes.quote(self.cxx.path))))
        sub.append(('%{libcxx_src_root}', self.libcxx_src_root))
        # Configure flags substitutions
        flags = self.cxx.flags + (self.cxx.modules_flags
                                  if self.cxx.use_modules else [])
        compile_flags = self.cxx.compile_flags + (
            self.cxx.warning_flags if self.cxx.use_warnings else [])
        sub.append(('%{flags}', ' '.join(map(pipes.quote, flags))))
        sub.append(
            ('%{compile_flags}', ' '.join(map(pipes.quote, compile_flags))))
        sub.append(
            ('%{link_flags}', ' '.join(map(pipes.quote, self.cxx.link_flags))))
        sub.append(
            ('%{link_libcxxabi}', pipes.quote(self.cxx.link_libcxxabi_flag)))

        # Configure exec prefix substitutions.
        # Configure run env substitution.
        codesign_ident = self.get_lit_conf('llvm_codesign_identity', '')
        env_vars = ' '.join('%s=%s' % (k, pipes.quote(v))
                            for (k, v) in self.exec_env.items())
        exec_args = [
            '--codesign_identity "{}"'.format(codesign_ident),
            '--dependencies %{file_dependencies}', '--env {}'.format(env_vars)
        ]
        if isinstance(self.executor, SSHExecutor):
            exec_args.append('--host {}'.format(self.executor.user_prefix +
                                                self.executor.host))
            executor = os.path.join(self.libcxx_src_root, 'utils', 'ssh.py')
        else:
            exec_args.append('--execdir %t.execdir')
            executor = os.path.join(self.libcxx_src_root, 'utils', 'run.py')
        sub.append(
            ('%{exec}', '{} {} {} -- '.format(pipes.quote(sys.executable),
                                              pipes.quote(executor),
                                              ' '.join(exec_args))))
        if self.get_lit_conf('libcxx_gdb'):
            sub.append(('%{libcxx_gdb}', self.get_lit_conf('libcxx_gdb')))

    def can_use_deployment(self):
        # Check if the host is on an Apple platform using clang.
        if not self.target_info.is_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)

        # If we're testing a system libc++ as opposed to the upstream LLVM one,
        # take the version of the system libc++ into account to compute which
        # features are enabled/disabled. Otherwise, disable availability markup,
        # which is not relevant for non-shipped flavors of libc++.
        if self.use_system_cxx_lib:
            # Dylib support for shared_mutex was added in macosx10.12.
            if name == 'macosx' and version in ('10.%s' % v
                                                for v in range(9, 12)):
                self.config.available_features.add('dylib-has-no-shared_mutex')
                self.lit_config.note(
                    "shared_mutex is not supported by the deployment target")
            # Throwing bad_optional_access, bad_variant_access and bad_any_cast is
            # supported starting in macosx10.14.
            if name == 'macosx' and version in ('10.%s' % v
                                                for v in range(9, 14)):
                self.config.available_features.add(
                    'dylib-has-no-bad_optional_access')
                self.lit_config.note(
                    "throwing bad_optional_access is not supported by the deployment target"
                )

                self.config.available_features.add(
                    'dylib-has-no-bad_variant_access')
                self.lit_config.note(
                    "throwing bad_variant_access is not supported by the deployment target"
                )

                self.config.available_features.add('dylib-has-no-bad_any_cast')
                self.lit_config.note(
                    "throwing bad_any_cast is not supported by the deployment target"
                )
            # Filesystem is support on Apple platforms starting with macosx10.15.
            if name == 'macosx' and version in ('10.%s' % v
                                                for v in range(9, 15)):
                self.config.available_features.add('c++filesystem-disabled')
                self.lit_config.note(
                    "the deployment target does not support <filesystem>")
        else:
            self.cxx.compile_flags += ['-D_LIBCPP_DISABLE_AVAILABILITY']

    def configure_env(self):
        self.target_info.configure_env(self.exec_env)
        self.config.environment = dict(os.environ)

    def add_path(self, dest_env, new_path):
        self.target_info.add_path(dest_env, new_path)
Ejemplo n.º 13
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.libcxx_src_root = None
        self.obj_root = None
        self.cxx_library_root = None
        self.env = {}
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None
        self.execute_external = False

        if platform.system() not in ('Darwin', 'FreeBSD', 'Linux'):
            self.lit_config.fatal("unrecognized system")

    def get_lit_conf(self, name, default=None):
        val = self.lit_config.params.get(name, None)
        if val is None:
            val = getattr(self.config, name, None)
            if val is None:
                val = default
        return val

    def get_lit_bool(self, name, default=None):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if conf.lower() in ('1', 'true'):
            return True
        if conf.lower() in ('', '0', 'false'):
            return False
        self.lit_config.fatal(
            "parameter '{}' should be true or false".format(name))

    def configure(self):
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_execute_external()
        self.configure_ccache()
        self.configure_env()
        self.configure_compile_flags()
        self.configure_link_flags()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note('Using compiler: %s' % self.cxx.path)
        self.lit_config.note('Using flags: %s' % self.cxx.flags)
        self.lit_config.note('Using compile flags: %s' %
                             self.cxx.compile_flags)
        self.lit_config.note('Using link flags: %s' % self.cxx.link_flags)
        # Print as list to prevent "set([...])" from being printed.
        self.lit_config.note('Using available_features: %s' %
                             list(self.config.available_features))
        self.lit_config.note('Using environment: %r' % self.env)

    def get_test_format(self):
        return LibcxxTestFormat(self.cxx,
                                self.use_clang_verify,
                                self.execute_external,
                                exec_env=self.env)

    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf('cxx_under_test')

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            if clangxx:
                cxx = clangxx
                self.lit_config.note("inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal('must specify user parameter cxx_under_test '
                                  '(e.g., --param=cxx_under_test=clang++)')
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add('%s-%s.%s' %
                                               (cxx_type, maj_v, min_v))

    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf(
            'libcxx_src_root', os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.obj_root = self.get_lit_conf('libcxx_obj_root',
                                          self.libcxx_src_root)

    def configure_cxx_library_root(self):
        self.cxx_library_root = self.get_lit_conf('cxx_library_root',
                                                  self.obj_root)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib')
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note("inferred use_system_cxx_lib as: %r" %
                                 self.use_system_cxx_lib)

    def configure_use_clang_verify(self):
        '''If set, run clang with -verify on failing tests.'''
        self.use_clang_verify = self.get_lit_bool('use_clang_verify')
        if self.use_clang_verify is None:
            # TODO: Default this to True when using clang.
            self.use_clang_verify = False
            self.lit_config.note("inferred use_clang_verify as: %r" %
                                 self.use_clang_verify)

    def configure_execute_external(self):
        # Choose between lit's internal shell pipeline runner and a real shell.
        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
        # default value. Otherwise we default to internal on Windows and
        # external elsewhere, as bash on Windows is usually very slow.
        use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL')
        if use_lit_shell_default is not None:
            use_lit_shell_default = use_lit_shell_default != '0'
        else:
            use_lit_shell_default = sys.platform == 'win32'
        # Check for the command line parameter using the default value if it is
        # not present.
        use_lit_shell = self.get_lit_bool('use_lit_shell',
                                          use_lit_shell_default)
        self.execute_external = not use_lit_shell

    def configure_ccache(self):
        use_ccache = self.get_lit_bool('use_ccache', False)
        if use_ccache:
            self.cxx.use_ccache = True
            self.lit_config.note('enabling ccache')

    def configure_features(self):
        additional_features = self.get_lit_conf('additional_features')
        if additional_features:
            for f in additional_features.split(','):
                self.config.available_features.add(f.strip())

        # Figure out which of the required locales we support
        locales = {
            'Darwin': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'cs_CZ.ISO8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'FreeBSD': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'Linux': {
                'en_US.UTF-8': 'en_US.UTF-8',
                'cs_CZ.ISO8859-2': 'cs_CZ.ISO-8859-2',
                'fr_FR.UTF-8': 'fr_FR.UTF-8',
                'fr_CA.ISO8859-1': 'fr_CA.ISO-8859-1',
                'ru_RU.UTF-8': 'ru_RU.UTF-8',
                'zh_CN.UTF-8': 'zh_CN.UTF-8',
            },
            'Windows': {
                'en_US.UTF-8': 'English_United States.1252',
                'cs_CZ.ISO8859-2': 'Czech_Czech Republic.1250',
                'fr_FR.UTF-8': 'French_France.1252',
                'fr_CA.ISO8859-1': 'French_Canada.1252',
                'ru_RU.UTF-8': 'Russian_Russia.1251',
                'zh_CN.UTF-8': 'Chinese_China.936',
            },
        }

        default_locale = locale.setlocale(locale.LC_ALL)
        for feature, loc in locales[platform.system()].items():
            try:
                locale.setlocale(locale.LC_ALL, loc)
                self.config.available_features.add(
                    'locale.{0}'.format(feature))
            except locale.Error:
                self.lit_config.warning('The locale {0} is not supported by '
                                        'your platform. Some tests will be '
                                        'unsupported.'.format(loc))
        locale.setlocale(locale.LC_ALL, default_locale)

        # Write an "available feature" that combines the triple when
        # use_system_cxx_lib is enabled. This is so that we can easily write
        # XFAIL markers for tests that are known to fail with versions of
        # libc++ as were shipped with a particular triple.
        if self.use_system_cxx_lib:
            self.config.available_features.add('with_system_cxx_lib=%s' %
                                               self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        # Strip the '2' from linux2.
        if sys.platform.startswith('linux'):
            platform_name = 'linux'
        else:
            platform_name = sys.platform
        self.config.available_features.add(platform_name.lower())

        # Some linux distributions have different locale data than others.
        # Insert the distributions name and name-version into the available
        # features to allow tests to XFAIL on them.
        if sys.platform.startswith('linux'):
            name, ver, _ = platform.linux_distribution()
            name = name.lower().strip()
            ver = ver.lower().strip()
            if name:
                self.config.available_features.add(name)
            if name and ver:
                self.config.available_features.add('%s-%s' % (name, ver))

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool('long_tests')
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note("inferred long_tests as: %r" %
                                 self.long_tests)

        if self.long_tests:
            self.config.available_features.add('long_tests')

    def configure_compile_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf('compile_flags', '')
        self.cxx.compile_flags += shlex.split(compile_flags_str)

    def configure_default_compile_flags(self):
        # Try and get the std version from the command line. Fall back to
        # default given in lit.site.cfg is not present. If default is not
        # present then force c++11.
        std = self.get_lit_conf('std', 'c++11')
        self.cxx.compile_flags += ['-std={0}'.format(std)]
        self.config.available_features.add(std)
        # Configure include paths
        self.cxx.compile_flags += ['-nostdinc++']
        self.configure_compile_flags_header_includes()
        if sys.platform.startswith('linux'):
            self.cxx.compile_flags += [
                '-D__STDC_FORMAT_MACROS', '-D__STDC_LIMIT_MACROS',
                '-D__STDC_CONSTANT_MACROS'
            ]
        # Configure feature flags.
        self.configure_compile_flags_exceptions()
        self.configure_compile_flags_rtti()
        enable_32bit = self.get_lit_bool('enable_32bit', False)
        if enable_32bit:
            self.cxx.flags += ['-m32']
        # Configure threading features.
        enable_threads = self.get_lit_bool('enable_threads', True)
        enable_monotonic_clock = self.get_lit_bool('enable_monotonic_clock',
                                                   True)
        if not enable_threads:
            self.configure_compile_flags_no_threads()
            if not enable_monotonic_clock:
                self.configure_compile_flags_no_monotonic_clock()
        elif not enable_monotonic_clock:
            self.lit_config.fatal('enable_monotonic_clock cannot be false when'
                                  ' enable_threads is true.')
        # Use verbose output for better errors
        self.cxx.flags += ['-v']
        sysroot = self.get_lit_conf('sysroot')
        if sysroot:
            self.cxx.flags += ['--sysroot', sysroot]
        gcc_toolchain = self.get_lit_conf('gcc_toolchain')
        if gcc_toolchain:
            self.cxx.flags += ['-gcc-toolchain', gcc_toolchain]
        if self.use_target:
            self.cxx.flags += ['-target', self.config.target_triple]

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        self.cxx.compile_flags += ['-I' + support_path]
        self.cxx.compile_flags += [
            '-include',
            os.path.join(support_path, 'nasty_macros.hpp')
        ]
        libcxx_headers = self.get_lit_conf(
            'libcxx_headers', os.path.join(self.libcxx_src_root, 'include'))
        if not os.path.isdir(libcxx_headers):
            self.lit_config.fatal("libcxx_headers='%s' is not a directory." %
                                  libcxx_headers)
        self.cxx.compile_flags += ['-I' + libcxx_headers]

    def configure_compile_flags_exceptions(self):
        enable_exceptions = self.get_lit_bool('enable_exceptions', True)
        if not enable_exceptions:
            self.config.available_features.add('libcpp-no-exceptions')
            self.cxx.compile_flags += ['-fno-exceptions']

    def configure_compile_flags_rtti(self):
        enable_rtti = self.get_lit_bool('enable_rtti', True)
        if not enable_rtti:
            self.config.available_features.add('libcpp-no-rtti')
            self.cxx.compile_flags += ['-fno-rtti', '-D_LIBCPP_NO_RTTI']

    def configure_compile_flags_no_threads(self):
        self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_THREADS']
        self.config.available_features.add('libcpp-has-no-threads')

    def configure_compile_flags_no_monotonic_clock(self):
        self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_MONOTONIC_CLOCK']
        self.config.available_features.add('libcpp-has-no-monotonic-clock')

    def configure_link_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.cxx.link_flags += ['-nodefaultlibs']

            # Configure library path
            self.configure_link_flags_cxx_library_path()
            self.configure_link_flags_abi_library_path()

            # Configure libraries
            self.configure_link_flags_cxx_library()
            self.configure_link_flags_abi_library()
            self.configure_extra_library_flags()

        link_flags_str = self.get_lit_conf('link_flags', '')
        self.cxx.link_flags += shlex.split(link_flags_str)

    def configure_link_flags_cxx_library_path(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        # Configure libc++ library paths.
        if libcxx_library is not None:
            # Check that the given value for libcxx_library is valid.
            if not os.path.isfile(libcxx_library):
                self.lit_config.fatal(
                    "libcxx_library='%s' is not a valid file." %
                    libcxx_library)
            if self.use_system_cxx_lib:
                self.lit_config.fatal(
                    "Conflicting options: 'libcxx_library' cannot be used "
                    "with 'use_system_cxx_lib=true'")
            self.cxx.link_flags += [
                '-Wl,-rpath,' + os.path.dirname(libcxx_library)
            ]
        elif not self.use_system_cxx_lib:
            self.cxx.link_flags += [
                '-L' + self.cxx_library_root,
                '-Wl,-rpath,' + self.cxx_library_root
            ]

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        abi_library_path = self.get_lit_conf('abi_library_path', '')
        if abi_library_path:
            self.cxx.link_flags += [
                '-L' + abi_library_path, '-Wl,-rpath,' + abi_library_path
            ]

    def configure_link_flags_cxx_library(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        if libcxx_library:
            self.cxx.link_flags += [libcxx_library]
        else:
            self.cxx.link_flags += ['-lc++']

    def configure_link_flags_abi_library(self):
        cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi')
        if cxx_abi == 'libstdc++':
            self.cxx.link_flags += ['-lstdc++']
        elif cxx_abi == 'libsupc++':
            self.cxx.link_flags += ['-lsupc++']
        elif cxx_abi == 'libcxxabi':
            self.cxx.link_flags += ['-lc++abi']
        elif cxx_abi == 'libcxxrt':
            self.cxx.link_flags += ['-lcxxrt']
        elif cxx_abi == 'none':
            pass
        else:
            self.lit_config.fatal('C++ ABI setting %s unsupported for tests' %
                                  cxx_abi)

    def configure_extra_library_flags(self):
        enable_threads = self.get_lit_bool('enable_threads', True)
        llvm_unwinder = self.get_lit_bool('llvm_unwinder', False)
        if sys.platform == 'darwin':
            self.cxx.link_flags += ['-lSystem']
        elif sys.platform.startswith('linux'):
            if not llvm_unwinder:
                self.cxx.link_flags += ['-lgcc_eh']
            self.cxx.link_flags += ['-lc', '-lm']
            if enable_threads:
                self.cxx.link_flags += ['-lpthread']
            self.cxx.link_flags += ['-lrt']
            if llvm_unwinder:
                self.cxx.link_flags += ['-lunwind', '-ldl']
            else:
                self.cxx.link_flags += ['-lgcc_s']
        elif sys.platform.startswith('freebsd'):
            self.cxx.link_flags += ['-lc', '-lm', '-lpthread', '-lgcc_s']
        else:
            self.lit_config.fatal("unrecognized system: %r" % sys.platform)

    def configure_warnings(self):
        enable_warnings = self.get_lit_bool('enable_warnings', False)
        if enable_warnings:
            self.cxx.compile_flags += ['-Wsystem-headers', '-Wall', '-Werror']
            if ('clang' in self.config.available_features
                    or 'apple-clang' in self.config.available_features):
                self.cxx.compile_flags += ['-Wno-user-defined-literals']

    def configure_sanitizer(self):
        san = self.get_lit_conf('use_sanitizer', '').strip()
        if san:
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get('PATH', '')
            cxx_path = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = (os.path.dirname(cxx_path) +
                                           os.pathsep +
                                           symbolizer_search_paths)
            llvm_symbolizer = lit.util.which('llvm-symbolizer',
                                             symbolizer_search_paths)
            # Setup the sanitizer compile flags
            self.cxx.flags += ['-g', '-fno-omit-frame-pointer']
            if sys.platform.startswith('linux'):
                self.cxx.link_flags += ['-ldl']
            if san == 'Address':
                self.cxx.flags += ['-fsanitize=address']
                if llvm_symbolizer is not None:
                    self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('asan')
            elif san == 'Memory' or san == 'MemoryWithOrigins':
                self.cxx.flags += ['-fsanitize=memory']
                if san == 'MemoryWithOrigins':
                    self.cxx.compile_flags += [
                        '-fsanitize-memory-track-origins'
                    ]
                if llvm_symbolizer is not None:
                    self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('msan')
            elif san == 'Undefined':
                self.cxx.flags += [
                    '-fsanitize=undefined', '-fno-sanitize=vptr,function',
                    '-fno-sanitize-recover'
                ]
                self.cxx.compile_flags += ['-O3']
                self.config.available_features.add('ubsan')
            elif san == 'Thread':
                self.cxx.flags += ['-fsanitize=thread']
                self.config.available_features.add('tsan')
            else:
                self.lit_config.fatal('unsupported value for '
                                      'use_sanitizer: {0}'.format(san))

    def configure_substitutions(self):
        sub = self.config.substitutions
        # Configure compiler substitions
        sub.append(('%cxx', self.cxx.path))
        # Configure flags substitutions
        flags_str = ' '.join(self.cxx.flags)
        compile_flags_str = ' '.join(self.cxx.compile_flags)
        link_flags_str = ' '.join(self.cxx.link_flags)
        all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str)
        sub.append(('%flags', flags_str))
        sub.append(('%compile_flags', compile_flags_str))
        sub.append(('%link_flags', link_flags_str))
        sub.append(('%all_flags', all_flags))
        # Add compile and link shortcuts
        compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str +
                       compile_flags_str)
        link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str +
                    link_flags_str)
        assert type(link_str) is str
        build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
        sub.append(('%compile', compile_str))
        sub.append(('%link', link_str))
        sub.append(('%build', build_str))
        # Configure exec prefix substitutions.
        exec_env_str = 'env ' if len(self.env) != 0 else ''
        for k, v in self.env.items():
            exec_env_str += ' %s=%s' % (k, v)
        # Configure run env substitution.
        exec_str = ''
        if self.lit_config.useValgrind:
            exec_str = ' '.join(self.lit_config.valgrindArgs) + exec_env_str
        sub.append(('%exec', exec_str))
        # Configure run shortcut
        sub.append(('%run', exec_str + ' %t.exe'))
        # Configure not program substitions
        not_py = os.path.join(self.libcxx_src_root, 'utils', 'not', 'not.py')
        not_str = '%s %s' % (sys.executable, not_py)
        sub.append(('not', not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf('target_triple')
        self.use_target = bool(self.config.target_triple)
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.use_target:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)',
                                   r'\1-\2-\3\5', target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if target_triple.endswith('redhat-linux') or \
               target_triple.endswith('suse-linux'):
                target_triple += '-gnu'
            self.config.target_triple = target_triple
            self.lit_config.note("inferred target_triple as: %r" %
                                 self.config.target_triple)

    def configure_env(self):
        if sys.platform == 'darwin' and not self.use_system_cxx_lib:
            libcxx_library = self.get_lit_conf('libcxx_library')
            if libcxx_library:
                cxx_library_root = os.path.dirname(libcxx_library)
            else:
                cxx_library_root = self.cxx_library_root
            self.env['DYLD_LIBRARY_PATH'] = cxx_library_root
Ejemplo n.º 14
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.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.env = {}
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None
        self.execute_external = False

    def get_lit_conf(self, name, default=None):
        val = self.lit_config.params.get(name, None)
        if val is None:
            val = getattr(self.config, name, None)
            if val is None:
                val = default
        return val

    def get_lit_bool(self, name, default=None):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if isinstance(conf, bool):
            return conf
        if not isinstance(conf, str):
            raise TypeError('expected bool or string')
        if conf.lower() in ('1', 'true'):
            return True
        if conf.lower() in ('', '0', 'false'):
            return False
        self.lit_config.fatal(
            "parameter '{}' should be true or false".format(name))

    def configure(self):
        self.configure_executor()
        self.configure_target_info()
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_stdlib_under_test()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_use_thread_safety()
        self.configure_execute_external()
        self.configure_ccache()
        self.configure_compile_flags()
        self.configure_filesystem_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_color_diagnostics()
        self.configure_debug_mode()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_modules()
        self.configure_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note('Using compiler: %s' % self.cxx.path)
        self.lit_config.note('Using flags: %s' % self.cxx.flags)
        if self.cxx.use_modules:
            self.lit_config.note('Using modules flags: %s' %
                                 self.cxx.modules_flags)
        self.lit_config.note('Using compile flags: %s'
                             % self.cxx.compile_flags)
        if len(self.cxx.warning_flags):
            self.lit_config.note('Using warnings: %s' % self.cxx.warning_flags)
        self.lit_config.note('Using link flags: %s' % self.cxx.link_flags)
        # Print as list to prevent "set([...])" from being printed.
        self.lit_config.note('Using available_features: %s' %
                             list(self.config.available_features))
        self.lit_config.note('Using environment: %r' % self.env)

    def get_test_format(self):
        return LibcxxTestFormat(
            self.cxx,
            self.use_clang_verify,
            self.execute_external,
            self.executor,
            exec_env=self.env)

    def configure_executor(self):
        exec_str = self.get_lit_conf('executor', "None")
        te = eval(exec_str)
        if te:
            self.lit_config.note("Using executor: %r" % exec_str)
            if self.lit_config.useValgrind:
                # We have no way of knowing where in the chain the
                # ValgrindExecutor is supposed to go. It is likely
                # that the user wants it at the end, but we have no
                # way of getting at that easily.
                selt.lit_config.fatal("Cannot infer how to create a Valgrind "
                                      " executor.")
        else:
            te = LocalExecutor()
            if self.lit_config.useValgrind:
                te = ValgrindExecutor(self.lit_config.valgrindArgs, te)
        self.executor = te

    def configure_target_info(self):
        self.target_info = make_target_info(self)

    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf('cxx_under_test')

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            if clangxx:
                cxx = clangxx
                self.lit_config.note(
                    "inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal('must specify user parameter cxx_under_test '
                                  '(e.g., --param=cxx_under_test=clang++)')
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add('%s-%s' % (cxx_type, maj_v))
            self.config.available_features.add('%s-%s.%s' % (
                cxx_type, maj_v, min_v))

    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf(
            'libcxx_src_root', os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.project_obj_root = self.get_lit_conf('project_obj_root')
        self.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root')
        if not self.libcxx_obj_root and self.project_obj_root is not None:
            possible_root = os.path.join(self.project_obj_root, 'projects', 'libcxx')
            if os.path.isdir(possible_root):
                self.libcxx_obj_root = possible_root
            else:
                self.libcxx_obj_root = self.project_obj_root

    def configure_cxx_library_root(self):
        self.cxx_library_root = self.get_lit_conf('cxx_library_root',
                                                  self.libcxx_obj_root)
        self.cxx_runtime_root = self.get_lit_conf('cxx_runtime_root',
                                                   self.cxx_library_root)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib')
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note(
                "inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)

    def configure_cxx_stdlib_under_test(self):
        self.cxx_stdlib_under_test = self.get_lit_conf(
            'cxx_stdlib_under_test', 'libc++')
        if self.cxx_stdlib_under_test not in \
                ['libc++', 'libstdc++', 'cxx_default']:
            self.lit_config.fatal(
                'unsupported value for "cxx_stdlib_under_test": %s'
                % self.cxx_stdlib_under_test)
        self.config.available_features.add(self.cxx_stdlib_under_test)
        if self.cxx_stdlib_under_test == 'libstdc++':
            self.config.available_features.add('libstdc++')
            # Manually enable the experimental and filesystem tests for libstdc++
            # if the options aren't present.
            # FIXME this is a hack.
            if self.get_lit_conf('enable_experimental') is None:
                self.config.enable_experimental = 'true'
            if self.get_lit_conf('enable_filesystem') is None:
                self.config.enable_filesystem = 'true'

    def configure_use_clang_verify(self):
        '''If set, run clang with -verify on failing tests.'''
        self.use_clang_verify = self.get_lit_bool('use_clang_verify')
        if self.use_clang_verify is None:
            # NOTE: We do not test for the -verify flag directly because
            #   -verify will always exit with non-zero on an empty file.
            self.use_clang_verify = self.cxx.isVerifySupported()
            if self.use_clang_verify:
                self.config.available_features.add('verify-support')
            self.lit_config.note(
                "inferred use_clang_verify as: %r" % self.use_clang_verify)

    def configure_use_thread_safety(self):
        '''If set, run clang with -verify on failing tests.'''
        has_thread_safety = self.cxx.hasCompileFlag('-Werror=thread-safety')
        if has_thread_safety:
            self.cxx.compile_flags += ['-Werror=thread-safety']
            self.config.available_features.add('thread-safety')
            self.lit_config.note("enabling thread-safety annotations")

    def configure_execute_external(self):
        # Choose between lit's internal shell pipeline runner and a real shell.
        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
        # default value. Otherwise we ask the target_info.
        use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL')
        if use_lit_shell_default is not None:
            use_lit_shell_default = use_lit_shell_default != '0'
        else:
            use_lit_shell_default = self.target_info.use_lit_shell_default()
        # Check for the command line parameter using the default value if it is
        # not present.
        use_lit_shell = self.get_lit_bool('use_lit_shell',
                                          use_lit_shell_default)
        self.execute_external = not use_lit_shell

    def configure_ccache(self):
        use_ccache_default = os.environ.get('LIBCXX_USE_CCACHE') is not None
        use_ccache = self.get_lit_bool('use_ccache', use_ccache_default)
        if use_ccache:
            self.cxx.use_ccache = True
            self.lit_config.note('enabling ccache')

    def configure_features(self):
        additional_features = self.get_lit_conf('additional_features')
        if additional_features:
            for f in additional_features.split(','):
                self.config.available_features.add(f.strip())
        self.target_info.add_locale_features(self.config.available_features)

        target_platform = self.target_info.platform()

        # Write an "available feature" that combines the triple when
        # use_system_cxx_lib is enabled. This is so that we can easily write
        # XFAIL markers for tests that are known to fail with versions of
        # libc++ as were shipped with a particular triple.
        if self.use_system_cxx_lib:
            self.config.available_features.add('with_system_cxx_lib')
            self.config.available_features.add(
                'with_system_cxx_lib=%s' % self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        self.config.available_features.add(target_platform)

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool('long_tests')
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note(
                "inferred long_tests as: %r" % self.long_tests)

        if self.long_tests:
            self.config.available_features.add('long_tests')

        # Run a compile test for the -fsized-deallocation flag. This is needed
        # in test/std/language.support/support.dynamic/new.delete
        if self.cxx.hasCompileFlag('-fsized-deallocation'):
            self.config.available_features.add('fsized-deallocation')

        if self.cxx.hasCompileFlag('-faligned-allocation'):
            self.config.available_features.add('-faligned-allocation')
        else:
            # FIXME remove this once more than just clang-4.0 support
            # C++17 aligned allocation.
            self.config.available_features.add('no-aligned-allocation')

        if self.get_lit_bool('has_libatomic', False):
            self.config.available_features.add('libatomic')

        if '__cpp_if_constexpr' not in self.cxx.dumpMacros():
            self.config.available_features.add('libcpp-no-if-constexpr')

    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)

    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']
            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]
        if self.use_target:
            if not self.cxx.addFlagIfSupported(
                    ['-target', self.config.target_triple]):
                self.lit_config.warning('use_target is true but -target is '\
                        'not supported by the compiler')

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        if self.cxx_stdlib_under_test != 'libstdc++':
            self.cxx.compile_flags += [
                '-include', os.path.join(support_path, 'nasty_macros.hpp')]
        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]
        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_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.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']
                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 == '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.cxx_runtime_root:
                self.cxx.link_flags += ['-Wl,-rpath,' + self.cxx_runtime_root]

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        self.abi_library_root = self.get_lit_conf('abi_library_path')
        if self.abi_library_root:
            self.cxx.link_flags += ['-L' + self.abi_library_root,
                                    '-Wl,-rpath,' + 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']
        libcxx_shared = self.get_lit_bool('enable_shared', default=True)
        if libcxx_shared:
            self.cxx.link_flags += ['-lc++']
        else:
            cxx_library_root = self.get_lit_conf('cxx_library_root')
            if cxx_library_root:
                abs_path = os.path.join(cxx_library_root, 'libc++.a')
                self.cxx.link_flags += [abs_path]
            else:
                self.cxx.link_flags += ['-lc++']
        # This needs to come after -lc++ as we want its unresolved thread-api symbols
        # to be picked up from this one.
        if self.get_lit_bool('libcxx_external_thread_api', default=False):
            self.cxx.link_flags += ['-lc++external_threads']

    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:
                        abs_path = os.path.join(cxxabi_library_root, 'libc++abi.a')
                        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 == 'none':
            pass
        else:
            self.lit_config.fatal(
                'C++ ABI setting %s unsupported for tests' % cxx_abi)

    def configure_extra_library_flags(self):
        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)
        if enable_warnings:
            self.cxx.useWarnings(True)
            self.cxx.warning_flags += [
                '-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER',
                '-Wall', '-Wextra', '-Werror'
            ]
            self.cxx.addWarningFlagIfSupported('-Wshadow')
            self.cxx.addWarningFlagIfSupported('-Wno-unused-command-line-argument')
            self.cxx.addWarningFlagIfSupported('-Wno-attributes')
            self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move')
            self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions')
            self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals')
            # These warnings should be enabled in order to support the MSVC
            # team using the test suite; They enable the warnings below and
            # expect the test suite to be clean.
            self.cxx.addWarningFlagIfSupported('-Wsign-compare')
            self.cxx.addWarningFlagIfSupported('-Wunused-variable')
            self.cxx.addWarningFlagIfSupported('-Wunused-parameter')
            self.cxx.addWarningFlagIfSupported('-Wunreachable-code')
            # FIXME: Enable the two warnings below.
            self.cxx.addWarningFlagIfSupported('-Wno-conversion')
            self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')
            std = self.get_lit_conf('std', None)
            if std in ['c++98', 'c++03']:
                # The '#define static_assert' provided by libc++ in C++03 mode
                # causes an unused local typedef whenever it is used.
                self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')

    def configure_sanitizer(self):
        san = self.get_lit_conf('use_sanitizer', '').strip()
        if san:
            self.target_info.add_sanitizer_features(san, self.config.available_features)
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get('PATH', '')
            cxx_path = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = (
                    os.path.dirname(cxx_path) +
                    os.pathsep + symbolizer_search_paths)
            llvm_symbolizer = lit.util.which('llvm-symbolizer',
                                             symbolizer_search_paths)

            def add_ubsan():
                self.cxx.flags += ['-fsanitize=undefined',
                                   '-fno-sanitize=vptr,function,float-divide-by-zero',
                                   '-fno-sanitize-recover=all']
                self.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.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                # FIXME: Turn ODR violation back on after PR28391 is resolved
                # https://llvm.org/bugs/show_bug.cgi?id=28391
                self.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.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_default = supports_modules and \
            os.environ.get('LIBCXX_USE_MODULES') is not None
        enable_modules = self.get_lit_bool('enable_modules',
                                           enable_modules_default)
        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
        # Configure compiler substitutions
        sub.append(('%cxx', self.cxx.path))
        # Configure flags substitutions
        flags_str = ' '.join(self.cxx.flags)
        compile_flags_str = ' '.join(self.cxx.compile_flags)
        link_flags_str = ' '.join(self.cxx.link_flags)
        all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str)
        sub.append(('%flags', flags_str))
        sub.append(('%compile_flags', compile_flags_str))
        sub.append(('%link_flags', link_flags_str))
        sub.append(('%all_flags', all_flags))
        if self.cxx.isVerifySupported():
            verify_str = ' ' + ' '.join(self.cxx.verify_flags) + ' '
            sub.append(('%verify', verify_str))
        # Add compile and link shortcuts
        compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str
                       + ' ' + compile_flags_str)
        link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str + ' '
                    + link_flags_str)
        assert type(link_str) is str
        build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
        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 = 'env ' if len(self.env) != 0 else ''
        for k, v in self.env.items():
            exec_env_str += ' %s=%s' % (k, v)
        # Configure run env substitution.
        exec_str = 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', 'not.py')
        not_str = '%s %s ' % (sys.executable, not_py)
        sub.append(('not ', not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf('target_triple')
        self.use_target = self.get_lit_bool('use_target', False)
        if self.use_target and self.config.target_triple:
            self.lit_config.warning('use_target is true but no triple is specified')
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.config.target_triple:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)',
                                   r'\1-\2-\3\5', target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if (target_triple.endswith('redhat-linux') or
                target_triple.endswith('suse-linux')):
                target_triple += '-gnu'
            self.config.target_triple = target_triple
            self.lit_config.note(
                "inferred target_triple as: %r" % self.config.target_triple)

    def configure_env(self):
        self.target_info.configure_env(self.env)
Ejemplo n.º 15
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.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.env = {}
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None
        self.execute_external = False

    def get_lit_conf(self, name, default=None):
        val = self.lit_config.params.get(name, None)
        if val is None:
            val = getattr(self.config, name, None)
            if val is None:
                val = default
        return val

    def get_lit_bool(self, name, default=None):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if conf.lower() in ("1", "true"):
            return True
        if conf.lower() in ("", "0", "false"):
            return False
        self.lit_config.fatal("parameter '{}' should be true or false".format(name))

    def configure(self):
        self.configure_executor()
        self.configure_target_info()
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_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_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note("Using compiler: %s" % self.cxx.path)
        self.lit_config.note("Using flags: %s" % self.cxx.flags)
        self.lit_config.note("Using compile flags: %s" % self.cxx.compile_flags)
        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.env)

    def get_test_format(self):
        return LibcxxTestFormat(
            self.cxx, self.use_clang_verify, self.execute_external, self.executor, exec_env=self.env
        )

    def configure_executor(self):
        exec_str = self.get_lit_conf("executor", "None")
        te = eval(exec_str)
        if te:
            self.lit_config.note("Using executor: %r" % exec_str)
            if self.lit_config.useValgrind:
                # We have no way of knowing where in the chain the
                # ValgrindExecutor is supposed to go. It is likely
                # that the user wants it at the end, but we have no
                # way of getting at that easily.
                selt.lit_config.fatal("Cannot infer how to create a Valgrind " " executor.")
        else:
            te = LocalExecutor()
            if self.lit_config.useValgrind:
                te = ValgrindExecutor(self.lit_config.valgrindArgs, te)
        self.executor = te

    def configure_target_info(self):
        self.target_info = make_target_info(self)

    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf("cxx_under_test")

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which("clang++", self.config.environment["PATH"])
            if clangxx:
                cxx = clangxx
                self.lit_config.note("inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal(
                "must specify user parameter cxx_under_test " "(e.g., --param=cxx_under_test=clang++)"
            )
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add("%s-%s.%s" % (cxx_type, maj_v, min_v))

    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf("libcxx_src_root", os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.project_obj_root = self.get_lit_conf("project_obj_root")
        self.libcxx_obj_root = self.get_lit_conf("libcxx_obj_root")
        if not self.libcxx_obj_root and self.project_obj_root is not None:
            possible_root = os.path.join(self.project_obj_root, "projects", "libcxx")
            if os.path.isdir(possible_root):
                self.libcxx_obj_root = possible_root
            else:
                self.libcxx_obj_root = self.project_obj_root

    def configure_cxx_library_root(self):
        self.cxx_library_root = self.get_lit_conf("cxx_library_root", self.libcxx_obj_root)
        self.cxx_runtime_root = self.get_lit_conf("cxx_runtime_root", self.cxx_library_root)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool("use_system_cxx_lib")
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note("inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)

    def configure_use_clang_verify(self):
        """If set, run clang with -verify on failing tests."""
        self.use_clang_verify = self.get_lit_bool("use_clang_verify")
        if self.use_clang_verify is None:
            # NOTE: We do not test for the -verify flag directly because
            #   -verify will always exit with non-zero on an empty file.
            self.use_clang_verify = self.cxx.hasCompileFlag(["-Xclang", "-verify-ignore-unexpected"])
            self.lit_config.note("inferred use_clang_verify as: %r" % self.use_clang_verify)

    def configure_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=%s" % self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        self.config.available_features.add(target_platform)

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool("long_tests")
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note("inferred long_tests as: %r" % self.long_tests)

        if self.long_tests:
            self.config.available_features.add("long_tests")

        # Run a compile test for the -fsized-deallocation flag. This is needed
        # in test/std/language.support/support.dynamic/new.delete
        if self.cxx.hasCompileFlag("-fsized-deallocation"):
            self.config.available_features.add("fsized-deallocation")

        if self.get_lit_bool("has_libatomic", False):
            self.config.available_features.add("libatomic")

    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)

    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"]
            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)
        # Configure include paths
        self.cxx.compile_flags += ["-nostdinc++"]
        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]
        if self.use_target:
            self.cxx.flags += ["-target", self.config.target_triple]

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, "test/support")
        self.cxx.compile_flags += ["-include", os.path.join(support_path, "nasty_macros.hpp")]
        self.configure_config_site_header()
        libcxx_headers = self.get_lit_conf("libcxx_headers", os.path.join(self.libcxx_src_root, "include"))
        if not os.path.isdir(libcxx_headers):
            self.lit_config.fatal("libcxx_headers='%s' is not a directory." % libcxx_headers)
        self.cxx.compile_flags += ["-I" + libcxx_headers]

    def configure_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_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.libcxx_obj_root, "test", "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.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:
            self.cxx.link_flags += ["-nodefaultlibs"]

            # Configure library path
            self.configure_link_flags_cxx_library_path()
            self.configure_link_flags_abi_library_path()

            # Configure libraries
            self.configure_link_flags_cxx_library()
            self.configure_link_flags_abi_library()
            self.configure_extra_library_flags()

        link_flags_str = self.get_lit_conf("link_flags", "")
        self.cxx.link_flags += shlex.split(link_flags_str)

    def configure_link_flags_cxx_library_path(self):
        if not self.use_system_cxx_lib:
            if self.cxx_library_root:
                self.cxx.link_flags += ["-L" + self.cxx_library_root]
            if self.cxx_runtime_root:
                self.cxx.link_flags += ["-Wl,-rpath," + self.cxx_runtime_root]

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        self.abi_library_root = self.get_lit_conf("abi_library_path")
        if self.abi_library_root:
            self.cxx.link_flags += ["-L" + self.abi_library_root, "-Wl,-rpath," + 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"]
        libcxx_shared = self.get_lit_bool("enable_shared", default=True)
        if libcxx_shared:
            self.cxx.link_flags += ["-lc++"]
        else:
            cxx_library_root = self.get_lit_conf("cxx_library_root")
            if cxx_library_root:
                abs_path = os.path.join(cxx_library_root, "libc++.a")
                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:
                        abs_path = os.path.join(cxxabi_library_root, "libc++abi.a")
                        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 == "none":
            pass
        else:
            self.lit_config.fatal("C++ ABI setting %s unsupported for tests" % cxx_abi)

    def configure_extra_library_flags(self):
        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):
        enable_warnings = self.get_lit_bool("enable_warnings", False)
        if enable_warnings:
            self.cxx.warning_flags += ["-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER", "-Wall", "-Wextra", "-Werror"]
            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")
            # TODO(EricWF) Remove the unused warnings once the test suite
            # compiles clean with them.
            self.cxx.addWarningFlagIfSupported("-Wno-unused-local-typedef")
            self.cxx.addWarningFlagIfSupported("-Wno-unused-variable")
            self.cxx.addWarningFlagIfSupported("-Wno-unused-parameter")
            self.cxx.addWarningFlagIfSupported("-Wno-sign-compare")
            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 = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = os.path.dirname(cxx_path) + os.pathsep + symbolizer_search_paths
            llvm_symbolizer = lit.util.which("llvm-symbolizer", symbolizer_search_paths)
            # Setup the sanitizer compile flags
            self.cxx.flags += ["-g", "-fno-omit-frame-pointer"]
            if san == "Address":
                self.cxx.flags += ["-fsanitize=address"]
                if llvm_symbolizer is not None:
                    self.env["ASAN_SYMBOLIZER_PATH"] = llvm_symbolizer
                # FIXME: Turn ODR violation back on after PR28391 is resolved
                # https://llvm.org/bugs/show_bug.cgi?id=28391
                self.env["ASAN_OPTIONS"] = "detect_odr_violation=0"
                self.config.available_features.add("asan")
                self.config.available_features.add("sanitizer-new-delete")
            elif san == "Memory" or san == "MemoryWithOrigins":
                self.cxx.flags += ["-fsanitize=memory"]
                if san == "MemoryWithOrigins":
                    self.cxx.compile_flags += ["-fsanitize-memory-track-origins"]
                if llvm_symbolizer is not None:
                    self.env["MSAN_SYMBOLIZER_PATH"] = llvm_symbolizer
                self.config.available_features.add("msan")
                self.config.available_features.add("sanitizer-new-delete")
            elif san == "Undefined":
                self.cxx.flags += [
                    "-fsanitize=undefined",
                    "-fno-sanitize=vptr,function,float-divide-by-zero",
                    "-fno-sanitize-recover=all",
                ]
                self.cxx.compile_flags += ["-O2"]
                self.env["UBSAN_OPTIONS"] = "print_stacktrace=1"
                self.config.available_features.add("ubsan")
            elif san == "Thread":
                self.cxx.flags += ["-fsanitize=thread"]
                self.config.available_features.add("tsan")
                self.config.available_features.add("sanitizer-new-delete")
            else:
                self.lit_config.fatal("unsupported value for " "use_sanitizer: {0}".format(san))
            san_lib = self.get_lit_conf("sanitizer_library")
            if san_lib:
                self.cxx.link_flags += [san_lib, "-Wl,-rpath,%s" % os.path.dirname(san_lib)]

    def configure_coverage(self):
        self.generate_coverage = self.get_lit_bool("generate_coverage", False)
        if self.generate_coverage:
            self.cxx.flags += ["-g", "--coverage"]
            self.cxx.compile_flags += ["-O0"]

    def configure_substitutions(self):
        sub = self.config.substitutions
        # Configure compiler substitutions
        sub.append(("%cxx", self.cxx.path))
        # Configure flags substitutions
        flags_str = " ".join(self.cxx.flags)
        compile_flags_str = " ".join(self.cxx.compile_flags)
        link_flags_str = " ".join(self.cxx.link_flags)
        all_flags = "%s %s %s" % (flags_str, compile_flags_str, link_flags_str)
        sub.append(("%flags", flags_str))
        sub.append(("%compile_flags", compile_flags_str))
        sub.append(("%link_flags", link_flags_str))
        sub.append(("%all_flags", all_flags))
        # Add compile and link shortcuts
        compile_str = self.cxx.path + " -o %t.o %s -c " + flags_str + compile_flags_str
        link_str = self.cxx.path + " -o %t.exe %t.o " + flags_str + link_flags_str
        assert type(link_str) is str
        build_str = self.cxx.path + " -o %t.exe %s " + all_flags
        sub.append(("%compile", compile_str))
        sub.append(("%link", link_str))
        sub.append(("%build", build_str))
        # Configure exec prefix substitutions.
        exec_env_str = "env " if len(self.env) != 0 else ""
        for k, v in self.env.items():
            exec_env_str += " %s=%s" % (k, v)
        # Configure run env substitution.
        exec_str = 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 substitions
        not_py = os.path.join(self.libcxx_src_root, "utils", "not", "not.py")
        not_str = "%s %s" % (sys.executable, not_py)
        sub.append(("not", not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf("target_triple")
        self.use_target = bool(self.config.target_triple)
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.use_target:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r"([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)", r"\1-\2-\3\5", target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if target_triple.endswith("redhat-linux") or target_triple.endswith("suse-linux"):
                target_triple += "-gnu"
            self.config.target_triple = target_triple
            self.lit_config.note("inferred target_triple as: %r" % self.config.target_triple)

    def configure_env(self):
        self.target_info.configure_env(self.env)
Ejemplo n.º 16
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.cxx_is_clang_cl = None
        self.cxx_stdlib_under_test = None
        self.project_obj_root = None
        self.libcxx_src_root = None
        self.libcxx_obj_root = None
        self.cxx_library_root = None
        self.cxx_runtime_root = None
        self.abi_library_root = None
        self.link_shared = self.get_lit_bool('enable_shared', default=True)
        self.debug_build = self.get_lit_bool('debug_build', default=False)
        self.exec_env = dict()
        self.use_clang_verify = 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.target_info.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.target_info = make_target_info(self)
        self.executor = self.get_lit_conf('executor')
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.cxx_stdlib_under_test = self.get_lit_conf('cxx_stdlib_under_test',
                                                       'libc++')
        self.cxx_library_root = self.get_lit_conf('cxx_library_root',
                                                  self.libcxx_obj_root)
        self.abi_library_root = self.get_lit_conf('abi_library_path', None)
        self.cxx_runtime_root = self.get_lit_conf('cxx_runtime_root',
                                                  self.cxx_library_root)
        self.configure_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_debug_mode()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_modules()
        self.configure_substitutions()
        self.configure_features()

        libcxx.test.newconfig.configure(libcxx.test.params.DEFAULT_PARAMETERS,
                                        libcxx.test.features.DEFAULT_FEATURES,
                                        self.config, self.lit_config)

        self.lit_config.note("All available features: {}".format(
            self.config.available_features))

    def print_config_info(self):
        if self.cxx.use_modules:
            self.lit_config.note('Using modules flags: %s' %
                                 self.cxx.modules_flags)
        if len(self.cxx.warning_flags):
            self.lit_config.note('Using warnings: %s' % self.cxx.warning_flags)
        show_env_vars = {}
        for k, v in self.exec_env.items():
            if k not in os.environ or os.environ[k] != v:
                show_env_vars[k] = v
        self.lit_config.note('Adding environment variables: %r' %
                             show_env_vars)
        self.lit_config.note("Linking against the C++ Library at {}".format(
            self.cxx_library_root))
        self.lit_config.note("Running against the C++ Library at {}".format(
            self.cxx_runtime_root))
        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.executor,
                                exec_env=self.exec_env)

    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(self, cxx) if not self.cxx_is_clang_cl else \
                   self._configure_clang_cl(cxx)
        self.cxx.compile_env = dict(os.environ)

    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(self,
                           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_roots = [
                os.path.join(self.project_obj_root, 'libcxx'),
                os.path.join(self.project_obj_root, 'projects', 'libcxx'),
                os.path.join(self.project_obj_root, 'runtimes', 'libcxx'),
            ]
            for possible_root in possible_roots:
                if os.path.isdir(possible_root):
                    self.libcxx_obj_root = possible_root
                    break
            else:
                self.libcxx_obj_root = self.project_obj_root

    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())

        if self.target_info.is_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')

        target_triple = getattr(self.config, 'target_triple', None)
        if target_triple:
            if re.match(r'^x86_64.*-apple', target_triple):
                self.config.available_features.add('x86_64-apple')
            if re.match(r'^x86_64.*-linux', target_triple):
                self.config.available_features.add('x86_64-linux')
            if re.match(r'^i.86.*', target_triple):
                self.config.available_features.add('target-x86')
            elif re.match(r'^x86_64.*', target_triple):
                self.config.available_features.add('target-x86_64')
            elif re.match(r'^aarch64.*', target_triple):
                self.config.available_features.add('target-aarch64')
            elif re.match(r'^arm.*', target_triple):
                self.config.available_features.add('target-arm')

    def configure_compile_flags(self):
        self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf('compile_flags', '')
        self.cxx.compile_flags += shlex.split(compile_flags_str)
        if self.target_info.is_windows():
            self.cxx.compile_flags += ['-D_CRT_SECURE_NO_WARNINGS']
            # Don't warn about using common but nonstandard unprefixed functions
            # like chdir, fileno.
            self.cxx.compile_flags += ['-D_CRT_NONSTDC_NO_WARNINGS']
            # Required so that tests using min/max don't fail on Windows,
            # and so that those tests don't have to be changed to tolerate
            # this insanity.
            self.cxx.compile_flags += ['-DNOMINMAX']
        additional_flags = self.get_lit_conf('test_compiler_flags')
        if additional_flags:
            self.cxx.compile_flags += shlex.split(additional_flags)

    def configure_default_compile_flags(self):
        # Configure include paths
        self.configure_compile_flags_header_includes()
        self.target_info.add_cxx_compile_flags(self.cxx.compile_flags)
        self.target_info.add_cxx_flags(self.cxx.flags)
        # Configure feature flags.
        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.target_info.is_windows() and self.debug_build:
            self.cxx.compile_flags += ['-D_DEBUG']
        if not self.cxx.addFlagIfSupported(
            ['--target=' + self.config.target_triple]):
            self.lit_config.warning(
                'Not adding any target triple -- the compiler does '
                'not support --target=<triple>')

        # Add includes for support headers used in the tests.
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        self.cxx.compile_flags += ['-I' + support_path]

        # On GCC, the libc++ headers cause errors due to throw() decorators
        # on operator new clashing with those from the test suite, so we
        # don't enable warnings in system headers on GCC.
        if self.cxx.type != 'gcc':
            self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER']

        # Add includes for the PSTL headers
        pstl_src_root = self.get_lit_conf('pstl_src_root')
        pstl_obj_root = self.get_lit_conf('pstl_obj_root')
        if pstl_src_root is not None and pstl_obj_root is not None:
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_src_root, 'include')
            ]
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_obj_root, 'generated_headers')
            ]
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_src_root, 'test')
            ]
            self.config.available_features.add('parallel-algorithms')

    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.target_info.is_windows():
            self.cxx.compile_flags += [
                '-include',
                os.path.join(support_path, 'nasty_macros.h')
            ]
        if self.cxx_stdlib_under_test == 'msvc':
            self.cxx.compile_flags += [
                '-include',
                os.path.join(support_path, 'msvc_stdlib_force_include.h')
            ]
            pass
        if self.target_info.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
        self.cxx.compile_flags += ['-include', config_site_header]

    def configure_link_flags(self):
        # 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.target_info.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++':
            self.cxx.link_flags += ['-lstdc++fs', '-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('invalid stdlib under test')

        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 self.cxx_library_root:
            self.cxx.link_flags += ['-L' + self.cxx_library_root]
            if self.target_info.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.target_info.is_windows():
                self.cxx.link_flags += ['-Wl,-rpath,' + self.cxx_runtime_root]
            elif self.target_info.is_windows() and self.link_shared:
                self.add_path(self.exec_env, self.cxx_runtime_root)
        additional_flags = self.get_lit_conf('test_linker_flags')
        if additional_flags:
            self.cxx.link_flags += shlex.split(additional_flags)

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        if self.abi_library_root:
            self.cxx.link_flags += ['-L' + self.abi_library_root]
            if not self.target_info.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):
        if self.link_shared:
            self.cxx.link_flags += ['-lc++']
        else:
            if self.cxx_library_root:
                libname = self.make_static_lib_name('c++')
                abs_path = os.path.join(self.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 the C++ library requires explicitly linking to libc++abi, or
            # if we're testing libc++abi itself (the test configs are shared),
            # then link it.
            testing_libcxxabi = self.get_lit_conf('name', '') == 'libc++abi'
            if self.target_info.allow_cxxabi_link() or testing_libcxxabi:
                libcxxabi_shared = self.get_lit_bool('libcxxabi_shared',
                                                     default=True)
                if libcxxabi_shared:
                    self.cxx.link_flags += ['-lc++abi']
                else:
                    if self.abi_library_root:
                        libname = self.make_static_lib_name('c++abi')
                        abs_path = os.path.join(self.abi_library_root, libname)
                        self.cxx.link_libcxxabi_flag = abs_path
                        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.target_info.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_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_sanitizer(self):
        san = self.get_lit_conf('use_sanitizer', '').strip()
        if san:
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get('PATH', '')
            cxx_path = 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=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')
            elif san == 'DataFlow':
                self.cxx.flags += ['-fsanitize=dataflow']
            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', '-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
        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
        sub.append(('%{cxx}', pipes.quote(self.cxx.path)))
        flags = self.cxx.flags + (self.cxx.modules_flags
                                  if self.cxx.use_modules else [])
        compile_flags = self.cxx.compile_flags + (
            self.cxx.warning_flags if self.cxx.use_warnings else [])
        sub.append(('%{flags}', ' '.join(map(pipes.quote, flags))))
        sub.append(
            ('%{compile_flags}', ' '.join(map(pipes.quote, compile_flags))))
        sub.append(
            ('%{link_flags}', ' '.join(map(pipes.quote, self.cxx.link_flags))))
        sub.append(
            ('%{link_libcxxabi}', pipes.quote(self.cxx.link_libcxxabi_flag)))
        codesign_ident = self.get_lit_conf('llvm_codesign_identity', '')
        env_vars = ' '.join('%s=%s' % (k, pipes.quote(v))
                            for (k, v) in self.exec_env.items())
        exec_args = [
            '--execdir %T', '--codesign_identity "{}"'.format(codesign_ident),
            '--env {}'.format(env_vars)
        ]
        sub.append(('%{exec}', '{} {} -- '.format(self.executor,
                                                  ' '.join(exec_args))))

    def configure_triple(self):
        # Get or infer the target triple.
        target_triple = self.get_lit_conf('target_triple')

        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not target_triple:
            self.lit_config.note(
                'Trying to infer the target_triple because none was specified')

            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'

        # Save the triple
        self.lit_config.note(
            "Setting target_triple to {}".format(target_triple))
        self.config.target_triple = target_triple

    def configure_env(self):
        self.config.environment = dict(os.environ)

    def add_path(self, dest_env, new_path):
        self.target_info.add_path(dest_env, new_path)
Ejemplo n.º 17
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.project_obj_root = None
        self.libcxx_src_root = None
        self.libcxx_obj_root = None
        self.cxx_library_root = None
        self.abi_library_root = None
        self.env = {}
        self.use_target = False
        self.use_system_cxx_lib = False
        self.use_clang_verify = False
        self.long_tests = None
        self.execute_external = False

    def get_lit_conf(self, name, default=None):
        val = self.lit_config.params.get(name, None)
        if val is None:
            val = getattr(self.config, name, None)
            if val is None:
                val = default
        return val

    def get_lit_bool(self, name, default=None):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if conf.lower() in ('1', 'true'):
            return True
        if conf.lower() in ('', '0', 'false'):
            return False
        self.lit_config.fatal(
            "parameter '{}' should be true or false".format(name))

    def configure(self):
        self.configure_executor()
        self.configure_target_info()
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_execute_external()
        self.configure_ccache()
        self.configure_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_color_diagnostics()
        self.configure_debug_mode()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note('Using compiler: %s' % self.cxx.path)
        self.lit_config.note('Using flags: %s' % self.cxx.flags)
        self.lit_config.note('Using compile flags: %s'
                             % self.cxx.compile_flags)
        self.lit_config.note('Using link flags: %s' % self.cxx.link_flags)
        # Print as list to prevent "set([...])" from being printed.
        self.lit_config.note('Using available_features: %s' %
                             list(self.config.available_features))
        self.lit_config.note('Using environment: %r' % self.env)

    def get_test_format(self):
        return LibcxxTestFormat(
            self.cxx,
            self.use_clang_verify,
            self.execute_external,
            self.executor,
            exec_env=self.env)

    def configure_executor(self):
        exec_str = self.get_lit_conf('executor', "None")
        te = eval(exec_str)
        if te:
            self.lit_config.note("Using executor: %r" % exec_str)
            if self.lit_config.useValgrind:
                # We have no way of knowing where in the chain the
                # ValgrindExecutor is supposed to go. It is likely
                # that the user wants it at the end, but we have no
                # way of getting at that easily.
                selt.lit_config.fatal("Cannot infer how to create a Valgrind "
                                      " executor.")
        else:
            te = LocalExecutor()
            if self.lit_config.useValgrind:
                te = ValgrindExecutor(self.lit_config.valgrindArgs, te)
        self.executor = te

    def configure_target_info(self):
        self.target_info = make_target_info(self)

    def configure_cxx(self):
        # Gather various compiler parameters.
        cxx = self.get_lit_conf('cxx_under_test')

        # If no specific cxx_under_test was given, attempt to infer it as
        # clang++.
        if cxx is None:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            if clangxx:
                cxx = clangxx
                self.lit_config.note(
                    "inferred cxx_under_test as: %r" % cxx)
        if not cxx:
            self.lit_config.fatal('must specify user parameter cxx_under_test '
                                  '(e.g., --param=cxx_under_test=clang++)')
        self.cxx = CXXCompiler(cxx)
        cxx_type = self.cxx.type
        if cxx_type is not None:
            assert self.cxx.version is not None
            maj_v, min_v, _ = self.cxx.version
            self.config.available_features.add(cxx_type)
            self.config.available_features.add('%s-%s.%s' % (
                cxx_type, maj_v, min_v))

    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf(
            'libcxx_src_root', os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.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)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib')
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note(
                "inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)

    def configure_use_clang_verify(self):
        '''If set, run clang with -verify on failing tests.'''
        self.use_clang_verify = self.get_lit_bool('use_clang_verify')
        if self.use_clang_verify is None:
            # NOTE: We do not test for the -verify flag directly because
            #   -verify will always exit with non-zero on an empty file.
            self.use_clang_verify = self.cxx.hasCompileFlag(
                ['-Xclang', '-verify-ignore-unexpected'])
            self.lit_config.note(
                "inferred use_clang_verify as: %r" % self.use_clang_verify)

    def configure_execute_external(self):
        # Choose between lit's internal shell pipeline runner and a real shell.
        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
        # default value. Otherwise we 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=%s' % self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        self.config.available_features.add(target_platform)

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool('long_tests')
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note(
                "inferred long_tests as: %r" % self.long_tests)

        if self.long_tests:
            self.config.available_features.add('long_tests')

        # Run a compile test for the -fsized-deallocation flag. This is needed
        # in test/std/language.support/support.dynamic/new.delete
        if self.cxx.hasCompileFlag('-fsized-deallocation'):
            self.config.available_features.add('fsized-deallocation')

    def configure_compile_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf('compile_flags', '')
        self.cxx.compile_flags += shlex.split(compile_flags_str)

    def configure_default_compile_flags(self):
        # Try and get the std version from the command line. Fall back to
        # default given in lit.site.cfg is not present. If default is not
        # present then force c++11.
        std = self.get_lit_conf('std')
        if not std:
            # Choose the newest possible language dialect if none is given.
            possible_stds = ['c++1z', 'c++14', 'c++11', 'c++03']
            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)
        # Configure include paths
        self.cxx.compile_flags += ['-nostdinc++']
        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]
        if self.use_target:
            self.cxx.flags += ['-target', self.config.target_triple]

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        self.cxx.compile_flags += ['-I' + support_path]
        self.cxx.compile_flags += ['-include', os.path.join(support_path, 'nasty_macros.hpp')]
        self.configure_config_site_header()
        libcxx_headers = self.get_lit_conf(
            'libcxx_headers', os.path.join(self.libcxx_src_root, 'include'))
        if not os.path.isdir(libcxx_headers):
            self.lit_config.fatal("libcxx_headers='%s' is not a directory."
                                  % libcxx_headers)
        self.cxx.compile_flags += ['-I' + libcxx_headers]

    def configure_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_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_link_flags(self):
        no_default_flags = self.get_lit_bool('no_default_flags', False)
        if not no_default_flags:
            self.cxx.link_flags += ['-nodefaultlibs']

            # Configure library path
            self.configure_link_flags_cxx_library_path()
            self.configure_link_flags_abi_library_path()

            # Configure libraries
            self.configure_link_flags_cxx_library()
            self.configure_link_flags_abi_library()
            self.configure_extra_library_flags()

        link_flags_str = self.get_lit_conf('link_flags', '')
        self.cxx.link_flags += shlex.split(link_flags_str)

    def configure_link_flags_cxx_library_path(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        # Configure libc++ library paths.
        if libcxx_library is not None:
            # Check that the given value for libcxx_library is valid.
            if not os.path.isfile(libcxx_library):
                self.lit_config.fatal(
                    "libcxx_library='%s' is not a valid file." %
                    libcxx_library)
            if self.use_system_cxx_lib:
                self.lit_config.fatal(
                    "Conflicting options: 'libcxx_library' cannot be used "
                    "with 'use_system_cxx_lib=true'")
            self.cxx.link_flags += ['-Wl,-rpath,' +
                                    os.path.dirname(libcxx_library)]
        elif not self.use_system_cxx_lib and self.cxx_library_root:
            self.cxx.link_flags += ['-L' + self.cxx_library_root,
                                    '-Wl,-rpath,' + self.cxx_library_root]

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        self.abi_library_root = self.get_lit_conf('abi_library_path')
        if self.abi_library_root:
            self.cxx.link_flags += ['-L' + self.abi_library_root,
                                    '-Wl,-rpath,' + self.abi_library_root]

    def configure_link_flags_cxx_library(self):
        libcxx_library = self.get_lit_conf('libcxx_library')
        if libcxx_library:
            self.cxx.link_flags += [libcxx_library]
        else:
            self.cxx.link_flags += ['-lc++']

    def configure_link_flags_abi_library(self):
        cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi')
        if cxx_abi == 'libstdc++':
            self.cxx.link_flags += ['-lstdc++']
        elif cxx_abi == 'libsupc++':
            self.cxx.link_flags += ['-lsupc++']
        elif cxx_abi == 'libcxxabi':
            if self.target_info.allow_cxxabi_link():
                self.cxx.link_flags += ['-lc++abi']
        elif cxx_abi == 'libcxxrt':
            self.cxx.link_flags += ['-lcxxrt']
        elif cxx_abi == 'none':
            pass
        else:
            self.lit_config.fatal(
                'C++ ABI setting %s unsupported for tests' % cxx_abi)

    def configure_extra_library_flags(self):
        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):
        enable_warnings = self.get_lit_bool('enable_warnings', False)
        if enable_warnings:
            self.cxx.compile_flags += [
                '-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER',
                '-Wall', '-Werror'
            ]
            self.cxx.addWarningFlagIfSupported('-Wno-attributes')
            self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move')
            self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions')
            self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals')
            # TODO(EricWF) Remove the unused warnings once the test suite
            # compiles clean with them.
            self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')
            self.cxx.addWarningFlagIfSupported('-Wno-unused-variable')
            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 = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = (
                    os.path.dirname(cxx_path) +
                    os.pathsep + symbolizer_search_paths)
            llvm_symbolizer = lit.util.which('llvm-symbolizer',
                                             symbolizer_search_paths)
            # Setup the sanitizer compile flags
            self.cxx.flags += ['-g', '-fno-omit-frame-pointer']
            if san == 'Address':
                self.cxx.flags += ['-fsanitize=address']
                if llvm_symbolizer is not None:
                    self.env['ASAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('asan')
                self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Memory' or san == 'MemoryWithOrigins':
                self.cxx.flags += ['-fsanitize=memory']
                if san == 'MemoryWithOrigins':
                    self.cxx.compile_flags += [
                        '-fsanitize-memory-track-origins']
                if llvm_symbolizer is not None:
                    self.env['MSAN_SYMBOLIZER_PATH'] = llvm_symbolizer
                self.config.available_features.add('msan')
                self.config.available_features.add('sanitizer-new-delete')
            elif san == 'Undefined':
                self.cxx.flags += ['-fsanitize=undefined',
                                   '-fno-sanitize=vptr,function',
                                   '-fno-sanitize-recover']
                self.cxx.compile_flags += ['-O3']
                self.config.available_features.add('ubsan')
            elif san == 'Thread':
                self.cxx.flags += ['-fsanitize=thread']
                self.config.available_features.add('tsan')
                self.config.available_features.add('sanitizer-new-delete')
            else:
                self.lit_config.fatal('unsupported value for '
                                      'use_sanitizer: {0}'.format(san))
            san_lib = self.get_lit_conf('sanitizer_library')
            if san_lib:
                self.cxx.link_flags += [
                    san_lib, '-Wl,-rpath,%s' % os.path.dirname(san_lib)]

    def configure_coverage(self):
        self.generate_coverage = self.get_lit_bool('generate_coverage', False)
        if self.generate_coverage:
            self.cxx.flags += ['-g', '--coverage']
            self.cxx.compile_flags += ['-O0']

    def configure_substitutions(self):
        sub = self.config.substitutions
        # Configure compiler substitions
        sub.append(('%cxx', self.cxx.path))
        # Configure flags substitutions
        flags_str = ' '.join(self.cxx.flags)
        compile_flags_str = ' '.join(self.cxx.compile_flags)
        link_flags_str = ' '.join(self.cxx.link_flags)
        all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str)
        sub.append(('%flags', flags_str))
        sub.append(('%compile_flags', compile_flags_str))
        sub.append(('%link_flags', link_flags_str))
        sub.append(('%all_flags', all_flags))
        # Add compile and link shortcuts
        compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str
                       + compile_flags_str)
        link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str
                    + link_flags_str)
        assert type(link_str) is str
        build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
        sub.append(('%compile', compile_str))
        sub.append(('%link', link_str))
        sub.append(('%build', build_str))
        # Configure exec prefix substitutions.
        exec_env_str = 'env ' if len(self.env) != 0 else ''
        for k, v in self.env.items():
            exec_env_str += ' %s=%s' % (k, v)
        # Configure run env substitution.
        exec_str = ''
        if self.lit_config.useValgrind:
            exec_str = ' '.join(self.lit_config.valgrindArgs) + exec_env_str
        sub.append(('%exec', exec_str))
        # Configure run shortcut
        sub.append(('%run', exec_str + ' %t.exe'))
        # Configure not program substitions
        not_py = os.path.join(self.libcxx_src_root, 'utils', 'not', 'not.py')
        not_str = '%s %s' % (sys.executable, not_py)
        sub.append(('not', not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf('target_triple')
        self.use_target = bool(self.config.target_triple)
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.use_target:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)',
                                   r'\1-\2-\3\5', target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if (target_triple.endswith('redhat-linux') or
                target_triple.endswith('suse-linux')):
                target_triple += '-gnu'
            self.config.target_triple = target_triple
            self.lit_config.note(
                "inferred target_triple as: %r" % self.config.target_triple)

    def configure_env(self):
        self.target_info.configure_env(self.env)
Ejemplo n.º 18
0
class Configuration(object):
    # pylint: disable=redefined-outer-name
    def __init__(self, lit_config, config):
        self.lit_config = lit_config
        self.config = config
        self.cxx = None
        self.cxx_is_clang_cl = None
        self.cxx_stdlib_under_test = None
        self.project_obj_root = None
        self.libcxx_src_root = None
        self.libcxx_obj_root = None
        self.cxx_library_root = None
        self.cxx_runtime_root = None
        self.abi_library_root = None
        self.link_shared = self.get_lit_bool('enable_shared', default=True)
        self.debug_build = self.get_lit_bool('debug_build', default=False)
        self.exec_env = dict()
        self.use_clang_verify = 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.target_info.is_windows() and not self.target_info.is_mingw():
            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.target_info = make_target_info(self)
        self.executor = self.get_lit_conf('executor')
        self.configure_cxx()
        self.configure_src_root()
        self.configure_obj_root()
        self.cxx_stdlib_under_test = self.get_lit_conf('cxx_stdlib_under_test',
                                                       'libc++')
        self.cxx_library_root = self.get_lit_conf('cxx_library_root',
                                                  self.libcxx_obj_root)
        self.abi_library_root = self.get_lit_conf(
            'abi_library_root') or self.cxx_library_root
        self.cxx_runtime_root = self.get_lit_conf('cxx_runtime_root',
                                                  self.cxx_library_root)
        self.abi_runtime_root = self.get_lit_conf('abi_runtime_root',
                                                  self.abi_library_root)
        self.configure_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_coverage()
        self.configure_modules()
        self.configure_substitutions()
        self.configure_features()

        libcxx.test.newconfig.configure(libcxx.test.params.DEFAULT_PARAMETERS,
                                        libcxx.test.features.DEFAULT_FEATURES,
                                        self.config, self.lit_config)

        self.lit_config.note("All available features: {}".format(
            self.config.available_features))

    def print_config_info(self):
        if self.cxx.use_modules:
            self.lit_config.note('Using modules flags: %s' %
                                 self.cxx.modules_flags)
        if len(self.cxx.warning_flags):
            self.lit_config.note('Using warnings: %s' % self.cxx.warning_flags)
        show_env_vars = {}
        for k, v in self.exec_env.items():
            if k not in os.environ or os.environ[k] != v:
                show_env_vars[k] = v
        self.lit_config.note('Adding environment variables: %r' %
                             show_env_vars)
        self.lit_config.note("Linking against the C++ Library at {}".format(
            self.cxx_library_root))
        self.lit_config.note("Running against the C++ Library at {}".format(
            self.cxx_runtime_root))
        self.lit_config.note("Linking against the ABI Library at {}".format(
            self.abi_library_root))
        self.lit_config.note("Running against the ABI Library at {}".format(
            self.abi_runtime_root))
        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.executor,
                                exec_env=self.exec_env)

    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).startswith('clang-cl')
        # 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(self, cxx) if not self.cxx_is_clang_cl else \
                   self._configure_clang_cl(cxx)
        self.cxx.compile_env = dict(os.environ)

    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 = []
        link_flags = _prefixed_env_list('LIB', '-L')
        return CXXCompiler(self,
                           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_roots = [
                os.path.join(self.project_obj_root, 'libcxx'),
                os.path.join(self.project_obj_root, 'projects', 'libcxx'),
                os.path.join(self.project_obj_root, 'runtimes', 'libcxx'),
            ]
            for possible_root in possible_roots:
                if os.path.isdir(possible_root):
                    self.libcxx_obj_root = possible_root
                    break
            else:
                self.libcxx_obj_root = self.project_obj_root

    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())

        if self.target_info.is_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')

    def configure_compile_flags(self):
        self.configure_default_compile_flags()
        # Configure extra flags
        compile_flags_str = self.get_lit_conf('compile_flags', '')
        self.cxx.compile_flags += shlex.split(compile_flags_str)
        if self.target_info.is_windows():
            self.cxx.compile_flags += ['-D_CRT_SECURE_NO_WARNINGS']
            # Don't warn about using common but nonstandard unprefixed functions
            # like chdir, fileno.
            self.cxx.compile_flags += ['-D_CRT_NONSTDC_NO_WARNINGS']
            # Build the tests in the same configuration as libcxx itself,
            # to avoid mismatches if linked statically.
            self.cxx.compile_flags += ['-D_CRT_STDIO_ISO_WIDE_SPECIFIERS']
            # Required so that tests using min/max don't fail on Windows,
            # and so that those tests don't have to be changed to tolerate
            # this insanity.
            self.cxx.compile_flags += ['-DNOMINMAX']
        additional_flags = self.get_lit_conf('test_compiler_flags')
        if additional_flags:
            self.cxx.compile_flags += shlex.split(additional_flags)

    def configure_default_compile_flags(self):
        # Configure include paths
        self.configure_compile_flags_header_includes()
        self.target_info.add_cxx_compile_flags(self.cxx.compile_flags)
        self.target_info.add_cxx_flags(self.cxx.flags)
        # Configure feature flags.
        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.target_info.is_windows() and self.debug_build:
            self.cxx.compile_flags += ['-D_DEBUG']

        # Add includes for support headers used in the tests.
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        self.cxx.compile_flags += ['-I' + support_path]

        # On GCC, the libc++ headers cause errors due to throw() decorators
        # on operator new clashing with those from the test suite, so we
        # don't enable warnings in system headers on GCC.
        if self.cxx.type != 'gcc':
            self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER']

        # Add includes for the PSTL headers
        pstl_src_root = self.get_lit_conf('pstl_src_root')
        pstl_obj_root = self.get_lit_conf('pstl_obj_root')
        if pstl_src_root is not None and pstl_obj_root is not None:
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_src_root, 'include')
            ]
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_obj_root, 'generated_headers')
            ]
            self.cxx.compile_flags += [
                '-I' + os.path.join(pstl_src_root, 'test')
            ]
            self.config.available_features.add('parallel-algorithms')

    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.target_info.is_windows() and \
           not self.target_info.is_zos():
            self.cxx.compile_flags += [
                '-include',
                os.path.join(support_path, 'nasty_macros.h')
            ]
        if self.cxx_stdlib_under_test == 'msvc':
            self.cxx.compile_flags += [
                '-include',
                os.path.join(support_path, 'msvc_stdlib_force_include.h')
            ]
            pass
        if self.target_info.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 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 not os.path.isdir(cxx_headers):
            self.lit_config.fatal(
                "cxx_headers='{}' is not a directory.".format(cxx_headers))
        (path, version) = os.path.split(cxx_headers)
        (path, cxx) = os.path.split(path)
        triple = self.get_lit_conf('target_triple', None)
        if triple is not None:
            cxx_target_headers = os.path.join(path, triple, cxx, version)
            if os.path.isdir(cxx_target_headers):
                self.cxx.compile_flags += ['-I' + cxx_target_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_link_flags(self):
        # 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++':
            if self.target_info.is_mingw():
                self.cxx.link_flags += ['-nostdlib++']
            else:
                self.cxx.link_flags += ['-nodefaultlibs']
            # FIXME: Handle MSVCRT as part of the ABI library handling.
            if self.target_info.is_windows(
            ) and not self.target_info.is_mingw():
                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++':
            self.cxx.link_flags += ['-lstdc++fs', '-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('invalid stdlib under test')

        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 self.cxx_library_root:
            self.cxx.link_flags += ['-L' + self.cxx_library_root]
            if self.target_info.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.target_info.is_windows():
                self.cxx.link_flags += ['-Wl,-rpath,' + self.cxx_runtime_root]
            elif self.target_info.is_windows() and self.link_shared:
                self.add_path(self.exec_env, self.cxx_runtime_root)
        additional_flags = self.get_lit_conf('test_linker_flags')
        if additional_flags:
            self.cxx.link_flags += shlex.split(additional_flags)

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        if self.abi_library_root:
            self.cxx.link_flags += ['-L' + self.abi_library_root]
        if self.abi_runtime_root:
            if not self.target_info.is_windows():
                self.cxx.link_flags += ['-Wl,-rpath,' + self.abi_runtime_root]
            else:
                self.add_path(self.exec_env, self.abi_runtime_root)

    def configure_link_flags_cxx_library(self):
        if self.link_shared:
            self.cxx.link_flags += ['-lc++']
        else:
            if self.cxx_library_root:
                libname = self.make_static_lib_name('c++')
                abs_path = os.path.join(self.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 the C++ library requires explicitly linking to libc++abi, or
            # if we're testing libc++abi itself (the test configs are shared),
            # then link it.
            testing_libcxxabi = self.get_lit_conf('name', '') == 'libc++abi'
            if self.target_info.allow_cxxabi_link() or testing_libcxxabi:
                libcxxabi_shared = self.get_lit_bool('libcxxabi_shared',
                                                     default=True)
                if libcxxabi_shared:
                    self.cxx.link_flags += ['-lc++abi']
                else:
                    if self.abi_library_root:
                        libname = self.make_static_lib_name('c++abi')
                        abs_path = os.path.join(self.abi_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 ''
            # This matches the set of libraries linked in the toplevel
            # libcxx CMakeLists.txt if building targeting msvc.
            self.cxx.link_flags += [
                '-l%s%s' % (lib, debug_suffix)
                for lib in ['vcruntime', 'ucrt', 'msvcrt', 'msvcprt']
            ]
            # The compiler normally links in oldnames.lib too, but we've
            # specified -nostdlib above, so we need to specify it manually.
            self.cxx.link_flags += ['-loldnames']
        elif cxx_abi == 'none' or cxx_abi == 'default':
            if self.target_info.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_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', '-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
        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
        sub.append(('%{cxx}', pipes.quote(self.cxx.path)))
        flags = self.cxx.flags + (self.cxx.modules_flags
                                  if self.cxx.use_modules else [])
        compile_flags = self.cxx.compile_flags + (
            self.cxx.warning_flags if self.cxx.use_warnings else [])
        sub.append(('%{flags}', ' '.join(map(pipes.quote, flags))))
        sub.append(
            ('%{compile_flags}', ' '.join(map(pipes.quote, compile_flags))))
        sub.append(
            ('%{link_flags}', ' '.join(map(pipes.quote, self.cxx.link_flags))))

        codesign_ident = self.get_lit_conf('llvm_codesign_identity', '')
        env_vars = ' '.join('%s=%s' % (k, pipes.quote(v))
                            for (k, v) in self.exec_env.items())
        exec_args = [
            '--execdir %T', '--codesign_identity "{}"'.format(codesign_ident),
            '--env {}'.format(env_vars)
        ]
        sub.append(('%{exec}', '{} {} -- '.format(self.executor,
                                                  ' '.join(exec_args))))

    def configure_env(self):
        self.config.environment = dict(os.environ)

    def add_path(self, dest_env, new_path):
        self.target_info.add_path(dest_env, new_path)
Ejemplo n.º 19
0
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.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):
        conf = self.get_lit_conf(name)
        if conf is None:
            return default
        if isinstance(conf, bool):
            return conf
        if not isinstance(conf, str):
            raise TypeError('expected bool or string')
        if conf.lower() in ('1', 'true'):
            return True
        if conf.lower() in ('', '0', 'false'):
            return False
        self.lit_config.fatal(
            "parameter '{}' should be true or false".format(name))

    def make_static_lib_name(self, name):
        """Return the full filename for the specified library name"""
        if self.is_windows:
            return name + '.lib'
        else:
            return 'lib' + name + '.a'

    def configure(self):
        self.configure_executor()
        self.configure_target_info()
        self.configure_cxx()
        self.configure_triple()
        self.configure_src_root()
        self.configure_obj_root()
        self.configure_cxx_stdlib_under_test()
        self.configure_cxx_library_root()
        self.configure_use_system_cxx_lib()
        self.configure_use_clang_verify()
        self.configure_use_thread_safety()
        self.configure_execute_external()
        self.configure_ccache()
        self.configure_compile_flags()
        self.configure_filesystem_compile_flags()
        self.configure_link_flags()
        self.configure_env()
        self.configure_color_diagnostics()
        self.configure_debug_mode()
        self.configure_warnings()
        self.configure_sanitizer()
        self.configure_coverage()
        self.configure_modules()
        self.configure_substitutions()
        self.configure_features()

    def print_config_info(self):
        # Print the final compile and link flags.
        self.lit_config.note('Using compiler: %s' % self.cxx.path)
        self.lit_config.note('Using flags: %s' % self.cxx.flags)
        if self.cxx.use_modules:
            self.lit_config.note('Using modules flags: %s' %
                                 self.cxx.modules_flags)
        self.lit_config.note('Using compile flags: %s'
                             % self.cxx.compile_flags)
        if len(self.cxx.warning_flags):
            self.lit_config.note('Using warnings: %s' % self.cxx.warning_flags)
        self.lit_config.note('Using link flags: %s' % self.cxx.link_flags)
        # Print as list to prevent "set([...])" from being printed.
        self.lit_config.note('Using available_features: %s' %
                             list(self.config.available_features))
        self.lit_config.note('Using environment: %r' % self.exec_env)

    def get_test_format(self):
        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:
            clangxx = lit.util.which('clang++',
                                     self.config.environment['PATH'])
            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):
        assert self.cxx_is_clang_cl
        # FIXME: don't hardcode the target
        flags = ['--target=i686-pc-windows']
        compile_flags = []
        link_flags = ['-fuse-ld=lld']
        if 'INCLUDE' in os.environ:
            compile_flags += ['-isystem %s' % p.strip()
                              for p in os.environ['INCLUDE'].split(';')
                              if p.strip()]
        if 'LIB' in os.environ:
            link_flags += ['-L%s' % p.strip()
                           for p in os.environ['LIB'].split(';') if p.strip()]
        return CXXCompiler(clang_path, flags=flags,
                           compile_flags=compile_flags,
                           link_flags=link_flags)


    def configure_src_root(self):
        self.libcxx_src_root = self.get_lit_conf(
            'libcxx_src_root', os.path.dirname(self.config.test_source_root))

    def configure_obj_root(self):
        self.project_obj_root = self.get_lit_conf('project_obj_root')
        self.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root')
        if not self.libcxx_obj_root and self.project_obj_root is not None:
            possible_root = os.path.join(self.project_obj_root, 'projects', 'libcxx')
            if os.path.isdir(possible_root):
                self.libcxx_obj_root = possible_root
            else:
                self.libcxx_obj_root = self.project_obj_root

    def configure_cxx_library_root(self):
        self.cxx_library_root = self.get_lit_conf('cxx_library_root',
                                                  self.libcxx_obj_root)
        self.cxx_runtime_root = self.get_lit_conf('cxx_runtime_root',
                                                   self.cxx_library_root)

    def configure_use_system_cxx_lib(self):
        # This test suite supports testing against either the system library or
        # the locally built one; the former mode is useful for testing ABI
        # compatibility between the current headers and a shipping dynamic
        # library.
        self.use_system_cxx_lib = self.get_lit_bool('use_system_cxx_lib')
        if self.use_system_cxx_lib is None:
            # Default to testing against the locally built libc++ library.
            self.use_system_cxx_lib = False
            self.lit_config.note(
                "inferred use_system_cxx_lib as: %r" % self.use_system_cxx_lib)

    def configure_cxx_stdlib_under_test(self):
        self.cxx_stdlib_under_test = self.get_lit_conf(
            'cxx_stdlib_under_test', 'libc++')
        if self.cxx_stdlib_under_test not in \
                ['libc++', 'libstdc++', 'cxx_default']:
            self.lit_config.fatal(
                'unsupported value for "cxx_stdlib_under_test": %s'
                % self.cxx_stdlib_under_test)
        self.config.available_features.add(self.cxx_stdlib_under_test)
        if self.cxx_stdlib_under_test == 'libstdc++':
            self.config.available_features.add('libstdc++')
            # Manually enable the experimental and filesystem tests for libstdc++
            # if the options aren't present.
            # FIXME this is a hack.
            if self.get_lit_conf('enable_experimental') is None:
                self.config.enable_experimental = 'true'
            if self.get_lit_conf('enable_filesystem') is None:
                self.config.enable_filesystem = 'true'

    def configure_use_clang_verify(self):
        '''If set, run clang with -verify on failing tests.'''
        self.use_clang_verify = self.get_lit_bool('use_clang_verify')
        if self.use_clang_verify is None:
            # NOTE: We do not test for the -verify flag directly because
            #   -verify will always exit with non-zero on an empty file.
            self.use_clang_verify = self.cxx.isVerifySupported()
            if self.use_clang_verify:
                self.config.available_features.add('verify-support')
            self.lit_config.note(
                "inferred use_clang_verify as: %r" % self.use_clang_verify)

    def configure_use_thread_safety(self):
        '''If set, run clang with -verify on failing tests.'''
        has_thread_safety = self.cxx.hasCompileFlag('-Werror=thread-safety')
        if has_thread_safety:
            self.cxx.compile_flags += ['-Werror=thread-safety']
            self.config.available_features.add('thread-safety')
            self.lit_config.note("enabling thread-safety annotations")

    def configure_execute_external(self):
        # Choose between lit's internal shell pipeline runner and a real shell.
        # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the
        # default value. Otherwise we ask the target_info.
        use_lit_shell_default = os.environ.get('LIT_USE_INTERNAL_SHELL')
        if use_lit_shell_default is not None:
            use_lit_shell_default = use_lit_shell_default != '0'
        else:
            use_lit_shell_default = self.target_info.use_lit_shell_default()
        # Check for the command line parameter using the default value if it is
        # not present.
        use_lit_shell = self.get_lit_bool('use_lit_shell',
                                          use_lit_shell_default)
        self.execute_external = not use_lit_shell

    def configure_ccache(self):
        use_ccache_default = os.environ.get('LIBCXX_USE_CCACHE') is not None
        use_ccache = self.get_lit_bool('use_ccache', use_ccache_default)
        if use_ccache:
            self.cxx.use_ccache = True
            self.lit_config.note('enabling ccache')

    def configure_features(self):
        additional_features = self.get_lit_conf('additional_features')
        if additional_features:
            for f in additional_features.split(','):
                self.config.available_features.add(f.strip())
        self.target_info.add_locale_features(self.config.available_features)

        target_platform = self.target_info.platform()

        # Write an "available feature" that combines the triple when
        # use_system_cxx_lib is enabled. This is so that we can easily write
        # XFAIL markers for tests that are known to fail with versions of
        # libc++ as were shipped with a particular triple.
        if self.use_system_cxx_lib:
            self.config.available_features.add('with_system_cxx_lib')
            self.config.available_features.add(
                'with_system_cxx_lib=%s' % self.config.target_triple)

        # Insert the platform name into the available features as a lower case.
        self.config.available_features.add(target_platform)

        # Simulator testing can take a really long time for some of these tests
        # so add a feature check so we can REQUIRES: long_tests in them
        self.long_tests = self.get_lit_bool('long_tests')
        if self.long_tests is None:
            # Default to running long tests.
            self.long_tests = True
            self.lit_config.note(
                "inferred long_tests as: %r" % self.long_tests)

        if self.long_tests:
            self.config.available_features.add('long_tests')

        # Run a compile test for the -fsized-deallocation flag. This is needed
        # in test/std/language.support/support.dynamic/new.delete
        if self.cxx.hasCompileFlag('-fsized-deallocation'):
            self.config.available_features.add('fsized-deallocation')

        if self.cxx.hasCompileFlag('-faligned-allocation'):
            self.config.available_features.add('-faligned-allocation')
        else:
            # FIXME remove this once more than just clang-4.0 support
            # C++17 aligned allocation.
            self.config.available_features.add('no-aligned-allocation')

        if self.get_lit_bool('has_libatomic', False):
            self.config.available_features.add('libatomic')

        macros = self.cxx.dumpMacros()
        if '__cpp_if_constexpr' not in macros:
            self.config.available_features.add('libcpp-no-if-constexpr')

        if '__cpp_structured_bindings' not in macros:
            self.config.available_features.add('libcpp-no-structured-bindings')

    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]
        if self.use_target:
            if not self.cxx.addFlagIfSupported(
                    ['-target', self.config.target_triple]):
                self.lit_config.warning('use_target is true but -target is '\
                        'not supported by the compiler')

    def configure_compile_flags_header_includes(self):
        support_path = os.path.join(self.libcxx_src_root, 'test/support')
        if self.cxx_stdlib_under_test != 'libstdc++' and \
           not self.is_windows:
            self.cxx.compile_flags += [
                '-include', os.path.join(support_path, 'nasty_macros.hpp')]
        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 == 'cxx_default':
                self.cxx.link_flags += ['-pthread']
            else:
                self.lit_config.fatal(
                    'unsupported value for "use_stdlib_type": %s'
                    %  use_stdlib_type)

        link_flags_str = self.get_lit_conf('link_flags', '')
        self.cxx.link_flags += shlex.split(link_flags_str)

    def configure_link_flags_cxx_library_path(self):
        if not self.use_system_cxx_lib:
            if self.cxx_library_root:
                self.cxx.link_flags += ['-L' + self.cxx_library_root]
                if self.is_windows and self.link_shared:
                    self.add_path(self.cxx.compile_env, self.cxx_library_root)
            if self.cxx_runtime_root:
                if not self.is_windows:
                    self.cxx.link_flags += ['-Wl,-rpath,' +
                                            self.cxx_runtime_root]
                elif self.is_windows and self.link_shared:
                    self.add_path(self.exec_env, self.cxx_runtime_root)

    def configure_link_flags_abi_library_path(self):
        # Configure ABI library paths.
        self.abi_library_root = self.get_lit_conf('abi_library_path')
        if self.abi_library_root:
            self.cxx.link_flags += ['-L' + self.abi_library_root]
            if not self.is_windows:
                self.cxx.link_flags += ['-Wl,-rpath,' + self.abi_library_root]
            else:
                self.add_path(self.exec_env, self.abi_library_root)

    def configure_link_flags_cxx_library(self):
        libcxx_experimental = self.get_lit_bool('enable_experimental', default=False)
        if libcxx_experimental:
            self.config.available_features.add('c++experimental')
            self.cxx.link_flags += ['-lc++experimental']
        if self.link_shared:
            self.cxx.link_flags += ['-lc++']
        else:
            cxx_library_root = self.get_lit_conf('cxx_library_root')
            if cxx_library_root:
                libname = self.make_static_lib_name('c++')
                abs_path = os.path.join(cxx_library_root, libname)
                assert os.path.exists(abs_path) and \
                       "static libc++ library does not exist"
                self.cxx.link_flags += [abs_path]
            else:
                self.cxx.link_flags += ['-lc++']

    def configure_link_flags_abi_library(self):
        cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi')
        if cxx_abi == 'libstdc++':
            self.cxx.link_flags += ['-lstdc++']
        elif cxx_abi == 'libsupc++':
            self.cxx.link_flags += ['-lsupc++']
        elif cxx_abi == 'libcxxabi':
            if self.target_info.allow_cxxabi_link():
                libcxxabi_shared = self.get_lit_bool('libcxxabi_shared', default=True)
                if libcxxabi_shared:
                    self.cxx.link_flags += ['-lc++abi']
                else:
                    cxxabi_library_root = self.get_lit_conf('abi_library_path')
                    if cxxabi_library_root:
                        libname = self.make_static_lib_name('c++abi')
                        abs_path = os.path.join(cxxabi_library_root, libname)
                        self.cxx.link_flags += [abs_path]
                    else:
                        self.cxx.link_flags += ['-lc++abi']
        elif cxx_abi == 'libcxxrt':
            self.cxx.link_flags += ['-lcxxrt']
        elif cxx_abi == 'none' or cxx_abi == 'default':
            if self.is_windows:
                self.cxx.link_flags += ['-lmsvcrtd']
        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)
        if enable_warnings:
            self.cxx.useWarnings(True)
            self.cxx.warning_flags += [
                '-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER',
                '-Wall', '-Wextra', '-Werror'
            ]
            self.cxx.addWarningFlagIfSupported('-Wshadow')
            self.cxx.addWarningFlagIfSupported('-Wno-unused-command-line-argument')
            self.cxx.addWarningFlagIfSupported('-Wno-attributes')
            self.cxx.addWarningFlagIfSupported('-Wno-pessimizing-move')
            self.cxx.addWarningFlagIfSupported('-Wno-c++11-extensions')
            self.cxx.addWarningFlagIfSupported('-Wno-user-defined-literals')
            # These warnings should be enabled in order to support the MSVC
            # team using the test suite; They enable the warnings below and
            # expect the test suite to be clean.
            self.cxx.addWarningFlagIfSupported('-Wsign-compare')
            self.cxx.addWarningFlagIfSupported('-Wunused-variable')
            self.cxx.addWarningFlagIfSupported('-Wunused-parameter')
            self.cxx.addWarningFlagIfSupported('-Wunreachable-code')
            # FIXME: Enable the two warnings below.
            self.cxx.addWarningFlagIfSupported('-Wno-conversion')
            self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')
            std = self.get_lit_conf('std', None)
            if std in ['c++98', 'c++03']:
                # The '#define static_assert' provided by libc++ in C++03 mode
                # causes an unused local typedef whenever it is used.
                self.cxx.addWarningFlagIfSupported('-Wno-unused-local-typedef')

    def configure_sanitizer(self):
        san = self.get_lit_conf('use_sanitizer', '').strip()
        if san:
            self.target_info.add_sanitizer_features(san, self.config.available_features)
            # Search for llvm-symbolizer along the compiler path first
            # and then along the PATH env variable.
            symbolizer_search_paths = os.environ.get('PATH', '')
            cxx_path = lit.util.which(self.cxx.path)
            if cxx_path is not None:
                symbolizer_search_paths = (
                    os.path.dirname(cxx_path) +
                    os.pathsep + symbolizer_search_paths)
            llvm_symbolizer = lit.util.which('llvm-symbolizer',
                                             symbolizer_search_paths)

            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://llvm.org/bugs/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_default = supports_modules and \
            os.environ.get('LIBCXX_USE_MODULES') is not None
        enable_modules = self.get_lit_bool('enable_modules',
                                           enable_modules_default)
        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
        # Configure compiler substitutions
        sub.append(('%cxx', self.cxx.path))
        # Configure flags substitutions
        flags_str = ' '.join(self.cxx.flags)
        compile_flags_str = ' '.join(self.cxx.compile_flags)
        link_flags_str = ' '.join(self.cxx.link_flags)
        all_flags = '%s %s %s' % (flags_str, compile_flags_str, link_flags_str)
        sub.append(('%flags', flags_str))
        sub.append(('%compile_flags', compile_flags_str))
        sub.append(('%link_flags', link_flags_str))
        sub.append(('%all_flags', all_flags))
        if self.cxx.isVerifySupported():
            verify_str = ' ' + ' '.join(self.cxx.verify_flags) + ' '
            sub.append(('%verify', verify_str))
        # Add compile and link shortcuts
        compile_str = (self.cxx.path + ' -o %t.o %s -c ' + flags_str
                       + ' ' + compile_flags_str)
        link_str = (self.cxx.path + ' -o %t.exe %t.o ' + flags_str + ' '
                    + link_flags_str)
        assert type(link_str) is str
        build_str = self.cxx.path + ' -o %t.exe %s ' + all_flags
        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 = 'env ' if len(self.exec_env) != 0 else ''
        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', 'not.py')
        not_str = '%s %s ' % (sys.executable, not_py)
        sub.append(('not ', not_str))

    def configure_triple(self):
        # Get or infer the target triple.
        self.config.target_triple = self.get_lit_conf('target_triple')
        self.use_target = self.get_lit_bool('use_target', False)
        if self.use_target and self.config.target_triple:
            self.lit_config.warning('use_target is true but no triple is specified')
        # If no target triple was given, try to infer it from the compiler
        # under test.
        if not self.config.target_triple:
            target_triple = self.cxx.getTriple()
            # Drop sub-major version components from the triple, because the
            # current XFAIL handling expects exact matches for feature checks.
            # Example: x86_64-apple-darwin14.0.0 -> x86_64-apple-darwin14
            # The 5th group handles triples greater than 3 parts
            # (ex x86_64-pc-linux-gnu).
            target_triple = re.sub(r'([^-]+)-([^-]+)-([^.]+)([^-]*)(.*)',
                                   r'\1-\2-\3\5', target_triple)
            # linux-gnu is needed in the triple to properly identify linuxes
            # that use GLIBC. Handle redhat and opensuse triples as special
            # cases and append the missing `-gnu` portion.
            if (target_triple.endswith('redhat-linux') or
                target_triple.endswith('suse-linux')):
                target_triple += '-gnu'
            self.config.target_triple = target_triple
            self.lit_config.note(
                "inferred target_triple as: %r" % self.config.target_triple)

    def configure_env(self):
        self.target_info.configure_env(self.exec_env)

    def add_path(self, dest_env, new_path):
        if 'PATH' not in dest_env:
            dest_env['PATH'] = new_path
        else:
            split_char = ';' if self.is_windows else ':'
            dest_env['PATH'] = '%s%s%s' % (new_path, split_char,
                                           dest_env['PATH'])