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 shlex 16import sys 17 18from libcxx.util import executeCommand 19 20class DefaultTargetInfo(object): 21 def __init__(self, full_config): 22 self.full_config = full_config 23 self.executor = None 24 25 def platform(self): 26 return sys.platform.lower().strip() 27 28 def is_windows(self): 29 return self.platform() == 'win32' 30 31 def is_darwin(self): 32 return self.platform() == 'darwin' 33 34 def add_cxx_flags(self, flags): pass 35 def add_cxx_compile_flags(self, flags): pass 36 def add_cxx_link_flags(self, flags): pass 37 def allow_cxxabi_link(self): return True 38 def default_cxx_abi_library(self): raise NotImplementedError(self.__class__.__name__) 39 40 def add_path(self, dest_env, new_path): 41 if not new_path: 42 return 43 if 'PATH' not in dest_env: 44 dest_env['PATH'] = new_path 45 else: 46 split_char = ';' if self.is_windows() else ':' 47 dest_env['PATH'] = '%s%s%s' % (new_path, split_char, 48 dest_env['PATH']) 49 50 51class DarwinLocalTI(DefaultTargetInfo): 52 def __init__(self, full_config): 53 super(DarwinLocalTI, self).__init__(full_config) 54 55 def is_host_macosx(self): 56 name = lit.util.to_string(subprocess.check_output(['sw_vers', '-productName'])).strip() 57 return name == "Mac OS X" 58 59 def get_macosx_version(self): 60 assert self.is_host_macosx() 61 version = lit.util.to_string(subprocess.check_output(['sw_vers', '-productVersion'])).strip() 62 version = re.sub(r'([0-9]+\.[0-9]+)(\..*)?', r'\1', version) 63 return version 64 65 def get_sdk_version(self, name): 66 assert self.is_host_macosx() 67 cmd = ['xcrun', '--sdk', name, '--show-sdk-path'] 68 try: 69 out = subprocess.check_output(cmd).strip() 70 except OSError: 71 pass 72 73 if not out: 74 self.full_config.lit_config.fatal( 75 "cannot infer sdk version with: %r" % cmd) 76 77 return re.sub(r'.*/[^0-9]+([0-9.]+)\.sdk', r'\1', out) 78 79 def add_cxx_flags(self, flags): 80 out, err, exit_code = executeCommand(['xcrun', '--show-sdk-path']) 81 if exit_code != 0: 82 self.full_config.lit_config.warning("Could not determine macOS SDK path! stderr was " + err) 83 if exit_code == 0 and out: 84 sdk_path = out.strip() 85 self.full_config.lit_config.note('using SDKROOT: %r' % sdk_path) 86 assert isinstance(sdk_path, str) 87 flags += ["-isysroot", sdk_path] 88 89 def add_cxx_link_flags(self, flags): 90 flags += ['-lSystem'] 91 92 def allow_cxxabi_link(self): 93 # Don't link libc++abi explicitly on OS X because the symbols 94 # should be available in libc++ directly. 95 return False 96 97 def default_cxx_abi_library(self): 98 return "libcxxabi" 99 100 101class FreeBSDLocalTI(DefaultTargetInfo): 102 def __init__(self, full_config): 103 super(FreeBSDLocalTI, self).__init__(full_config) 104 105 def add_cxx_link_flags(self, flags): 106 flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt'] 107 108 def default_cxx_abi_library(self): 109 return "libcxxrt" 110 111 112class CheriBSDRemoteTI(DefaultTargetInfo): 113 def __init__(self, full_config): 114 super(CheriBSDRemoteTI, self).__init__(full_config) 115 # TODO: support dynamically linked 116 self.static = True 117 118 def platform(self): 119 return 'freebsd' 120 121 def add_cxx_link_flags(self, flags): 122 explicit_flags = shlex.split(self.full_config.get_lit_conf('test_linker_flags')) 123 if self.full_config.link_shared is False: 124 # We also need to pull in compiler-rt and libunwind (gcc_eh) when building static tests 125 flags += ['-lcompiler_rt', '-lgcc_eh', '-static'] 126 # FIXME: work around bug in libthr (or lld?) that doesn't pull in all symbols (if a weak symbol already exists) 127 #flags += ['-Wl,--whole-archive', '-lthr', '-Wl,--no-whole-archive'] 128 # else: 129 flags += ['-lpthread'] 130 131 flags += ['-lc', '-lm', '-fuse-ld=lld', 132 '-B' + self.full_config.get_lit_conf('sysroot') + '/../bin'] 133 if self.full_config.lit_config.run_with_debugger: 134 flags += ['-Wl,--gdb-index'] 135 if self.full_config.get_lit_conf('target_triple').startswith("cheri-"): 136 assert '-mabi=purecap' in explicit_flags, explicit_flags 137 138 def add_cxx_compile_flags(self, flags): 139 explicit_flags = shlex.split(self.full_config.get_lit_conf('test_compiler_flags')) 140 if self.full_config.link_shared is False: 141 # we currently only support static linking so we need to add _LIBCPP_BUILD_STATIC 142 flags += ["-D_LIBCPP_BUILD_STATIC"] 143 144 # def configure_env(self, env): pass 145 def allow_cxxabi_link(self): 146 return False # should either be included or using libcxxrt 147 # def add_sanitizer_features(self, sanitizer_type, features): pass 148 # def use_lit_shell_default(self): return False 149 150 def default_cxx_abi_library(self): 151 return "libcxxrt" 152 153class NetBSDLocalTI(DefaultTargetInfo): 154 def __init__(self, full_config): 155 super(NetBSDLocalTI, self).__init__(full_config) 156 157 def add_cxx_link_flags(self, flags): 158 flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lc++abi', 159 '-lunwind'] 160 161 162class LinuxLocalTI(DefaultTargetInfo): 163 def __init__(self, full_config): 164 super(LinuxLocalTI, self).__init__(full_config) 165 166 def platform(self): 167 return 'linux' 168 169 def _distribution(self): 170 try: 171 # linux_distribution is not available since Python 3.8 172 # However, this function is only used to detect SLES 11, 173 # which is quite an old distribution that doesn't have 174 # Python 3.8. 175 return platform.linux_distribution() 176 except AttributeError: 177 return '', '', '' 178 179 def platform_name(self): 180 name, _, _ = self._distribution() 181 # Some distros have spaces, e.g. 'SUSE Linux Enterprise Server' 182 # lit features can't have spaces 183 name = name.lower().strip().replace(' ', '-') 184 return name # Permitted to be None 185 186 def platform_ver(self): 187 _, ver, _ = self._distribution() 188 ver = ver.lower().strip().replace(' ', '-') 189 return ver # Permitted to be None. 190 191 def add_cxx_compile_flags(self, flags): 192 flags += ['-D__STDC_FORMAT_MACROS', 193 '-D__STDC_LIMIT_MACROS', 194 '-D__STDC_CONSTANT_MACROS'] 195 196 def add_cxx_link_flags(self, flags): 197 enable_threads = ('libcpp-has-no-threads' not in 198 self.full_config.config.available_features) 199 llvm_unwinder = self.full_config.get_lit_bool('llvm_unwinder', False) 200 shared_libcxx = self.full_config.get_lit_bool('enable_shared', True) 201 flags += ['-lm'] 202 if not llvm_unwinder: 203 flags += ['-lgcc_s', '-lgcc'] 204 if enable_threads: 205 flags += ['-lpthread'] 206 if not shared_libcxx: 207 flags += ['-lrt'] 208 flags += ['-lc'] 209 if llvm_unwinder: 210 flags += ['-lunwind', '-ldl'] 211 else: 212 flags += ['-lgcc_s'] 213 builtins_lib = self.full_config.get_lit_conf('builtins_library') 214 if builtins_lib: 215 flags += [builtins_lib] 216 else: 217 flags += ['-lgcc'] 218 has_libatomic = self.full_config.get_lit_bool('has_libatomic', False) 219 if has_libatomic: 220 flags += ['-latomic'] 221 san = self.full_config.get_lit_conf('use_sanitizer', '').strip() 222 if san: 223 # The libraries and their order are taken from the 224 # linkSanitizerRuntimeDeps function in 225 # clang/lib/Driver/Tools.cpp 226 flags += ['-lpthread', '-lrt', '-lm', '-ldl'] 227 228 def default_cxx_abi_library(self): 229 return "libsupc++" 230 231class LinuxRemoteTI(LinuxLocalTI): 232 def __init__(self, full_config): 233 super(LinuxRemoteTI, self).__init__(full_config) 234 235class WindowsLocalTI(DefaultTargetInfo): 236 def __init__(self, full_config): 237 super(WindowsLocalTI, self).__init__(full_config) 238 239class BaremetalNewlibTI(DefaultTargetInfo): 240 def __init__(self, full_config): 241 super(BaremetalNewlibTI, self).__init__(full_config) 242 243 def platform(self): 244 return 'baremetal-' + self.full_config.config.target_triple 245 246 def add_locale_features(self, features): 247 add_common_locales(features, self.full_config.lit_config, unchecked_add=True) 248 249 def add_cxx_compile_flags(self, flags): 250 # I'm not sure the _LIBCPP_BUILD_STATIC should be passed when building 251 # against libcpp but it seems to be needed 252 flags += ['-D_GNU_SOURCE', '-D_LIBCPP_BUILD_STATIC'] 253 # For now always build with debug info: 254 flags.append('-g') 255 pass 256 257 def add_cxx_link_flags(self, flags): 258 llvm_unwinder = self.full_config.get_lit_bool('llvm_unwinder', False) 259 use_exceptions = self.full_config.get_lit_bool('enable_exceptions', False) 260 # shared_libcxx = self.full_config.get_lit_bool('enable_shared', False) 261 flags += ['-static', '-lm', '-lc'] 262 enable_threads = ('libcpp-has-no-threads' not in self.full_config.config.available_features) 263 if enable_threads: 264 pass 265 # flags += ['-lpthread'] 266 # if not shared_libcxx: 267 # flags += ['-lrt'] 268 if use_exceptions: 269 flags += ['-lunwind', '-ldl'] if llvm_unwinder else ['-lgcc_s'] 270 use_libatomic = self.full_config.get_lit_bool('use_libatomic', False) 271 if use_libatomic: 272 flags += ['-latomic'] 273 274 275def make_target_info(full_config): 276 default = "libcxx.test.target_info.LocalTI" 277 info_str = full_config.get_lit_conf('target_info', default) 278 if info_str != default: 279 mod_path, _, info = info_str.rpartition('.') 280 mod = importlib.import_module(mod_path) 281 target_info = getattr(mod, info)(full_config) 282 full_config.lit_config.note("inferred target_info as: %r" % info_str) 283 return target_info 284 target_system = platform.system() 285 if target_system == 'Darwin': return DarwinLocalTI(full_config) 286 if target_system == 'FreeBSD': return FreeBSDLocalTI(full_config) 287 if target_system == 'NetBSD': return NetBSDLocalTI(full_config) 288 if target_system == 'Linux': return LinuxLocalTI(full_config) 289 if target_system == 'Windows': return WindowsLocalTI(full_config) 290 return DefaultTargetInfo(full_config) 291