# ===----------------------------------------------------------------------===// # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # # ===----------------------------------------------------------------------===// import importlib import locale import os import platform import re import subprocess import sys from libcudacxx.util import executeCommand class DefaultTargetInfo(object): def __init__(self, full_config): self.full_config = full_config def platform(self): return sys.platform.lower().strip() def add_locale_features(self, features): self.full_config.lit_config.warning( "No locales entry for target_system: %s" % self.platform() ) def add_cxx_compile_flags(self, flags): pass def add_cxx_link_flags(self, flags): pass def configure_env(self, env): pass def allow_cxxabi_link(self): return True def add_sanitizer_features(self, sanitizer_type, features): pass def use_lit_shell_default(self): return False def test_locale(loc): assert loc is not None default_locale = locale.setlocale(locale.LC_ALL) try: locale.setlocale(locale.LC_ALL, loc) return True except locale.Error: return False finally: locale.setlocale(locale.LC_ALL, default_locale) def add_common_locales(features, lit_config, is_windows=False): # A list of locales needed by the test-suite. # The list uses the canonical name for the locale used in the test-suite # TODO: On Linux ISO8859 *may* needs to hyphenated. locales = [ ("en_US.UTF-8", "English_United States.1252"), ("fr_FR.UTF-8", "French_France.1252"), ("ru_RU.UTF-8", "Russian_Russia.1251"), ("zh_CN.UTF-8", "Chinese_China.936"), ("fr_CA.ISO8859-1", "French_Canada.1252"), ("cs_CZ.ISO8859-2", "Czech_Czech Republic.1250"), ] for loc_id, windows_loc_name in locales: loc_name = windows_loc_name if is_windows else loc_id if test_locale(loc_name): features.add("locale.{0}".format(loc_id)) else: lit_config.warning( "The locale {0} is not supported by " "your platform. Some tests will be " "unsupported.".format(loc_name) ) class DarwinLocalTI(DefaultTargetInfo): def __init__(self, full_config): super(DarwinLocalTI, self).__init__(full_config) def is_host_macosx(self): name = subprocess.check_output(["sw_vers", "-productName"]).strip() return name == "Mac OS X" def get_macosx_version(self): assert self.is_host_macosx() version = subprocess.check_output(["sw_vers", "-productVersion"]).strip() version = re.sub(r"([0-9]+\.[0-9]+)(\..*)?", r"\1", version) return version def get_sdk_version(self, name): assert self.is_host_macosx() cmd = ["xcrun", "--sdk", name, "--show-sdk-path"] try: out = subprocess.check_output(cmd).strip() except OSError: pass if not out: self.full_config.lit_config.fatal("cannot infer sdk version with: %r" % cmd) return re.sub(r".*/[^0-9]+([0-9.]+)\.sdk", r"\1", out) def get_platform(self): platform = self.full_config.get_lit_conf("platform") if platform: platform = re.sub(r"([^0-9]+)([0-9\.]*)", r"\1-\2", platform) name, version = tuple(platform.split("-", 1)) else: name = "macosx" version = None if version: return (False, name, version) # Infer the version, either from the SDK or the system itself. For # macosx, ignore the SDK version; what matters is what's at # /usr/lib/libc++.dylib. if name == "macosx": version = self.get_macosx_version() else: version = self.get_sdk_version(name) return (True, name, version) def add_locale_features(self, features): add_common_locales(features, self.full_config.lit_config) def add_cxx_compile_flags(self, flags): if self.full_config.use_deployment: _, name, _ = self.full_config.config.deployment cmd = ["xcrun", "--sdk", name, "--show-sdk-path"] else: cmd = ["xcrun", "--show-sdk-path"] out, err, exit_code = executeCommand(cmd) if exit_code != 0: self.full_config.lit_config.warning( "Could not determine macOS SDK path! stderr was " + err ) if exit_code == 0 and out: sdk_path = out.strip() self.full_config.lit_config.note("using SDKROOT: %r" % sdk_path) assert isinstance(sdk_path, str) flags += ["-isysroot", sdk_path] def add_cxx_link_flags(self, flags): flags += ["-lSystem"] def configure_env(self, env): library_paths = [] # Configure the library path for libc++ if self.full_config.cxx_runtime_root: library_paths += [self.full_config.cxx_runtime_root] elif self.full_config.use_system_cxx_lib: if os.path.isdir(str(self.full_config.use_system_cxx_lib)): library_paths += [self.full_config.use_system_cxx_lib] # Configure the abi library path if self.full_config.abi_library_root: library_paths += [self.full_config.abi_library_root] if library_paths: env["DYLD_LIBRARY_PATH"] = ":".join(library_paths) def allow_cxxabi_link(self): # Don't link libc++abi explicitly on OS X because the symbols # should be available in libc++ directly. return False class FreeBSDLocalTI(DefaultTargetInfo): def __init__(self, full_config): super(FreeBSDLocalTI, self).__init__(full_config) def add_locale_features(self, features): add_common_locales(features, self.full_config.lit_config) def add_cxx_link_flags(self, flags): flags += ["-lc", "-lm", "-lpthread", "-lgcc_s", "-lcxxrt"] class NetBSDLocalTI(DefaultTargetInfo): def __init__(self, full_config): super(NetBSDLocalTI, self).__init__(full_config) def add_locale_features(self, features): add_common_locales(features, self.full_config.lit_config) def add_cxx_link_flags(self, flags): flags += ["-lc", "-lm", "-lpthread", "-lgcc_s", "-lc++abi", "-lunwind"] class LinuxLocalTI(DefaultTargetInfo): def __init__(self, full_config): super(LinuxLocalTI, self).__init__(full_config) def platform(self): return "linux" def add_locale_features(self, features): add_common_locales(features, self.full_config.lit_config) def add_cxx_compile_flags(self, flags): flags += [ "-D__STDC_FORMAT_MACROS", "-D__STDC_LIMIT_MACROS", "-D__STDC_CONSTANT_MACROS", ] def add_cxx_link_flags(self, flags): enable_threads = ( "libcpp-has-no-threads" not in self.full_config.config.available_features ) llvm_unwinder = self.full_config.get_lit_bool("llvm_unwinder", False) shared_libcxx = self.full_config.get_lit_bool("enable_shared", True) flags += ["-lm"] if not llvm_unwinder: flags += ["-lgcc_s", "-lgcc"] if enable_threads: flags += ["-lpthread"] if not shared_libcxx: flags += ["-lrt"] flags += ["-lc"] if llvm_unwinder: flags += ["-lunwind", "-ldl"] else: flags += ["-lgcc_s"] builtins_lib = self.full_config.get_lit_conf("builtins_library") if builtins_lib: flags += [builtins_lib] else: flags += ["-lgcc"] use_libatomic = self.full_config.get_lit_bool("use_libatomic", False) if use_libatomic: flags += ["-latomic"] san = self.full_config.get_lit_conf("use_sanitizer", "").strip() if san: # The libraries and their order are taken from the # linkSanitizerRuntimeDeps function in # clang/lib/Driver/Tools.cpp flags += ["-lpthread", "-lrt", "-lm", "-ldl"] class WindowsLocalTI(DefaultTargetInfo): def __init__(self, full_config): super(WindowsLocalTI, self).__init__(full_config) def add_locale_features(self, features): add_common_locales(features, self.full_config.lit_config, is_windows=True) def use_lit_shell_default(self): # Default to the internal shell on Windows, as bash on Windows is # usually very slow. return True def make_target_info(full_config): default = "libcudacxx.test.target_info.LocalTI" info_str = full_config.get_lit_conf("target_info", default) if info_str != default: mod_path, _, info = info_str.rpartition(".") mod = importlib.import_module(mod_path) target_info = getattr(mod, info)(full_config) full_config.lit_config.note("inferred target_info as: %r" % info_str) return target_info target_system = platform.system() if target_system == "Darwin": return DarwinLocalTI(full_config) if target_system == "FreeBSD": return FreeBSDLocalTI(full_config) if target_system == "NetBSD": return NetBSDLocalTI(full_config) if target_system == "Linux": return LinuxLocalTI(full_config) if target_system == "Windows": return WindowsLocalTI(full_config) return DefaultTargetInfo(full_config)