• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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