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 is_windows(self):
25        return False
26
27    def is_zos(self):
28        return False
29
30    def is_mingw(self):
31        return False
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 add_cxx_flags(self, flags):
54        out, err, exit_code = executeCommand(['xcrun', '--show-sdk-path'])
55        if exit_code != 0:
56            self.full_config.lit_config.warning("Could not determine macOS SDK path! stderr was " + err)
57        if exit_code == 0 and out:
58            sdk_path = out.strip()
59            self.full_config.lit_config.note('using SDKROOT: %r' % sdk_path)
60            assert isinstance(sdk_path, str)
61            flags += ["-isysroot", sdk_path]
62
63    def add_cxx_link_flags(self, flags):
64        flags += ['-lSystem']
65
66    def allow_cxxabi_link(self):
67        # Don't link libc++abi explicitly on OS X because the symbols
68        # should be available in libc++ directly.
69        return False
70
71
72class FreeBSDLocalTI(DefaultTargetInfo):
73    def __init__(self, full_config):
74        super(FreeBSDLocalTI, self).__init__(full_config)
75
76    def add_cxx_link_flags(self, flags):
77        flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lcxxrt']
78
79
80class NetBSDLocalTI(DefaultTargetInfo):
81    def __init__(self, full_config):
82        super(NetBSDLocalTI, self).__init__(full_config)
83
84    def add_cxx_link_flags(self, flags):
85        flags += ['-lc', '-lm', '-lpthread', '-lgcc_s', '-lc++abi',
86                  '-lunwind']
87
88
89class LinuxLocalTI(DefaultTargetInfo):
90    def __init__(self, full_config):
91        super(LinuxLocalTI, self).__init__(full_config)
92
93    def add_cxx_compile_flags(self, flags):
94        flags += ['-D__STDC_FORMAT_MACROS',
95                  '-D__STDC_LIMIT_MACROS',
96                  '-D__STDC_CONSTANT_MACROS']
97
98    def add_cxx_link_flags(self, flags):
99        enable_threads = ('libcpp-has-no-threads' not in
100                          self.full_config.config.available_features)
101        llvm_unwinder = self.full_config.get_lit_bool('llvm_unwinder', False)
102        shared_libcxx = self.full_config.get_lit_bool('enable_shared', True)
103        flags += ['-lm']
104        if not llvm_unwinder:
105            flags += ['-lgcc_s', '-lgcc']
106        if enable_threads:
107            flags += ['-lpthread']
108            if not shared_libcxx:
109                flags += ['-lrt']
110        flags += ['-lc']
111        if llvm_unwinder:
112            flags += ['-lunwind', '-ldl']
113        else:
114            flags += ['-lgcc_s']
115        builtins_lib = self.full_config.get_lit_conf('builtins_library')
116        if builtins_lib:
117            flags += [builtins_lib]
118        else:
119            flags += ['-lgcc']
120        has_libatomic = self.full_config.get_lit_bool('has_libatomic', False)
121        if has_libatomic:
122            flags += ['-latomic']
123        san = self.full_config.get_lit_conf('use_sanitizer', '').strip()
124        if san:
125            # The libraries and their order are taken from the
126            # linkSanitizerRuntimeDeps function in
127            # clang/lib/Driver/Tools.cpp
128            flags += ['-lpthread', '-lrt', '-lm', '-ldl']
129
130class LinuxRemoteTI(LinuxLocalTI):
131    def __init__(self, full_config):
132        super(LinuxRemoteTI, self).__init__(full_config)
133
134class WindowsLocalTI(DefaultTargetInfo):
135    def __init__(self, full_config):
136        super(WindowsLocalTI, self).__init__(full_config)
137
138    def is_windows(self):
139        return True
140
141class ZOSLocalTI(DefaultTargetInfo):
142    def __init__(self, full_config):
143        super(ZOSLocalTI, self).__init__(full_config)
144
145    def is_zos(self):
146        return True
147
148class MingwLocalTI(WindowsLocalTI):
149    def __init__(self, full_config):
150        super(MingwLocalTI, self).__init__(full_config)
151
152    def is_mingw(self):
153        return True
154
155def make_target_info(full_config):
156    default = "libcxx.test.target_info.LocalTI"
157    info_str = full_config.get_lit_conf('target_info', default)
158    if info_str != default:
159        mod_path, _, info = info_str.rpartition('.')
160        mod = importlib.import_module(mod_path)
161        target_info = getattr(mod, info)(full_config)
162        full_config.lit_config.note("inferred target_info as: %r" % info_str)
163        return target_info
164    target_system = platform.system()
165    if target_system == 'Darwin':  return DarwinLocalTI(full_config)
166    if target_system == 'FreeBSD': return FreeBSDLocalTI(full_config)
167    if target_system == 'NetBSD':  return NetBSDLocalTI(full_config)
168    if target_system == 'Linux':   return LinuxLocalTI(full_config)
169    if target_system == 'Windows': return WindowsLocalTI(full_config)
170    if target_system == 'OS/390':  return ZOSLocalTI(full_config)
171    return DefaultTargetInfo(full_config)
172