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] 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.addCompileFlagIfSupported('-Wno-attributes') if self.cxx.type == 'clang' or self.cxx.type == 'apple-clang': self.cxx.addCompileFlagIfSupported('-Wno-pessimizing-move') self.cxx.addCompileFlagIfSupported('-Wno-c++11-extensions') self.cxx.addCompileFlagIfSupported('-Wno-user-defined-literals') 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.addCompileFlagIfSupported('-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)
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)
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.addCompileFlagIfSupported('-Wno-attributes') if self.cxx.type == 'clang' or self.cxx.type == 'apple-clang': self.cxx.addCompileFlagIfSupported('-Wno-pessimizing-move') self.cxx.addCompileFlagIfSupported('-Wno-c++11-extensions') self.cxx.addCompileFlagIfSupported( '-Wno-user-defined-literals') 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.addCompileFlagIfSupported('-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)