1#===----------------------------------------------------------------------===// 2# 3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4# See https://llvm.org/LICENSE.txt for license information. 5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6# 7#===----------------------------------------------------------------------===// 8 9import importlib 10import lit.util 11import os 12import platform 13import re 14import subprocess 15import sys 16 17from libcxx.util import executeCommand 18 19class DefaultTargetInfo(object): 20 def __init__(self, full_config): 21 self.full_config = full_config 22 self.executor = None 23 24 def platform(self): 25 return sys.platform.lower().strip() 26 27 def is_windows(self): 28 return self.platform() == 'win32' 29 30 def is_darwin(self): 31 return self.platform() == 'darwin' 32 33 def add_cxx_flags(self, flags): pass 34 def add_cxx_compile_flags(self, flags): pass 35 def add_cxx_link_flags(self, flags): pass 36 def allow_cxxabi_link(self): return True 37 38 def add_path(self, dest_env, new_path): 39 if not new_path: 40 return 41 if 'PATH' not in dest_env: 42 dest_env['PATH'] = new_path 43 else: 44 split_char = ';' if self.is_windows() else ':' 45 dest_env['PATH'] = '%s%s%s' % (new_path, split_char, 46 dest_env['PATH']) 47 48 49class DarwinLocalTI(DefaultTargetInfo): 50 def __init__(self, full_config): 51 super(DarwinLocalTI, self).__init__(full_config) 52 53 def is_host_macosx(self): 54 name = lit.util.to_string(subprocess.check_output(['sw_vers', '-productName'])).strip() 55 return name == "Mac OS X" 56 57 def get_macosx_version(self): 58 assert self.is_host_macosx() 59 version = lit.util.to_string(subprocess.check_output(['sw_vers', '-productVersion'])).strip() 60 version = re.sub(r'([0-9]+\.[0-9]+)(\..*)?', r'\1', version) 61 return version 62 63 def get_sdk_version(self, name): 64 assert self.is_host_macosx() 65 cmd = ['xcrun', '--sdk', name, '--show-sdk-path'] 66 try: 67 out = subprocess.check_output(cmd).strip() 68 except OSError: 69 pass 70 71 if not out: 72 self.full_config.lit_config.fatal( 73 "cannot infer sdk version with: %r" % cmd) 74 75 return re.sub(r'.*/[^0-9]+([0-9.]+)\.sdk', r'\1', out) 76 77 def add_cxx_flags(self, flags): 78 out, err, exit_code = executeCommand(['xcrun', '--show-sdk-path']) 79 if exit_code != 0: 80 self.full_config.lit_config.warning("Could not determine macOS SDK path! stderr was " + err) 81 if exit_code == 0 and out: 82 sdk_path = out.strip() 83 self.full_config.lit_config.note('using SDKROOT: %r' % sdk_path) 84 assert isinstance(sdk_path, str) 85 flags += ["-isysroot", sdk_path] 86 87 def add_cxx_link_flags(self, flags): 88 flags += ['-lSystem'] 89 90 def allow_cxxabi_link(self): 91 # Don't link libc++abi explicitly on OS X because the symbols 92 # should be available in libc++ directly. 93 return False 94 95 96class FreeBSDLocalTI(DefaultTargetInfo): 97 def __init__(self, full_config): 98 super(FreeBSDLocalTI, self).__init__(full_config) 99 100 def add_cxx_link_flags(self, flags): 101 flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt'] 102 103 104class NetBSDLocalTI(DefaultTargetInfo): 105 def __init__(self, full_config): 106 super(NetBSDLocalTI, self).__init__(full_config) 107 108 def add_cxx_link_flags(self, flags): 109 flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lc++abi', 110 '-lunwind'] 111 112 113class LinuxLocalTI(DefaultTargetInfo): 114 def __init__(self, full_config): 115 super(LinuxLocalTI, self).__init__(full_config) 116 117 def platform(self): 118 return 'linux' 119 120 def _distribution(self): 121 try: 122 # linux_distribution is not available since Python 3.8 123 # However, this function is only used to detect SLES 11, 124 # which is quite an old distribution that doesn't have 125 # Python 3.8. 126 return platform.linux_distribution() 127 except AttributeError: 128 return '', '', '' 129 130 def platform_name(self): 131 name, _, _ = self._distribution() 132 # Some distros have spaces, e.g. 'SUSE Linux Enterprise Server' 133 # lit features can't have spaces 134 name = name.lower().strip().replace(' ', '-') 135 return name # Permitted to be None 136 137 def platform_ver(self): 138 _, ver, _ = self._distribution() 139 ver = ver.lower().strip().replace(' ', '-') 140 return ver # Permitted to be None. 141 142 def add_cxx_compile_flags(self, flags): 143 flags += ['-D__STDC_FORMAT_MACROS', 144 '-D__STDC_LIMIT_MACROS', 145 '-D__STDC_CONSTANT_MACROS'] 146 147 def add_cxx_link_flags(self, flags): 148 enable_threads = ('libcpp-has-no-threads' not in 149 self.full_config.config.available_features) 150 llvm_unwinder = self.full_config.get_lit_bool('llvm_unwinder', False) 151 shared_libcxx = self.full_config.get_lit_bool('enable_shared', True) 152 flags += ['-lm'] 153 if not llvm_unwinder: 154 flags += ['-lgcc_s', '-lgcc'] 155 if enable_threads: 156 flags += ['-lpthread'] 157 if not shared_libcxx: 158 flags += ['-lrt'] 159 flags += ['-lc'] 160 if llvm_unwinder: 161 flags += ['-lunwind', '-ldl'] 162 else: 163 flags += ['-lgcc_s'] 164 builtins_lib = self.full_config.get_lit_conf('builtins_library') 165 if builtins_lib: 166 flags += [builtins_lib] 167 else: 168 flags += ['-lgcc'] 169 has_libatomic = self.full_config.get_lit_bool('has_libatomic', False) 170 if has_libatomic: 171 flags += ['-latomic'] 172 san = self.full_config.get_lit_conf('use_sanitizer', '').strip() 173 if san: 174 # The libraries and their order are taken from the 175 # linkSanitizerRuntimeDeps function in 176 # clang/lib/Driver/Tools.cpp 177 flags += ['-lpthread', '-lrt', '-lm', '-ldl'] 178 179class LinuxRemoteTI(LinuxLocalTI): 180 def __init__(self, full_config): 181 super(LinuxRemoteTI, self).__init__(full_config) 182 183class WindowsLocalTI(DefaultTargetInfo): 184 def __init__(self, full_config): 185 super(WindowsLocalTI, self).__init__(full_config) 186 187def make_target_info(full_config): 188 default = "libcxx.test.target_info.LocalTI" 189 info_str = full_config.get_lit_conf('target_info', default) 190 if info_str != default: 191 mod_path, _, info = info_str.rpartition('.') 192 mod = importlib.import_module(mod_path) 193 target_info = getattr(mod, info)(full_config) 194 full_config.lit_config.note("inferred target_info as: %r" % info_str) 195 return target_info 196 target_system = platform.system() 197 if target_system == 'Darwin': return DarwinLocalTI(full_config) 198 if target_system == 'FreeBSD': return FreeBSDLocalTI(full_config) 199 if target_system == 'NetBSD': return NetBSDLocalTI(full_config) 200 if target_system == 'Linux': return LinuxLocalTI(full_config) 201 if target_system == 'Windows': return WindowsLocalTI(full_config) 202 return DefaultTargetInfo(full_config) 203