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
9from libcxx.test.dsl import *
10import re
11import shutil
12import sys
13
14_isClang      = lambda cfg: '__clang__' in compilerMacros(cfg) and '__apple_build_version__' not in compilerMacros(cfg)
15_isAppleClang = lambda cfg: '__apple_build_version__' in compilerMacros(cfg)
16_isGCC        = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg)
17_isMSVC       = lambda cfg: '_MSC_VER' in compilerMacros(cfg)
18_msvcVersion  = lambda cfg: (int(compilerMacros(cfg)['_MSC_VER']) // 100, int(compilerMacros(cfg)['_MSC_VER']) % 100)
19
20DEFAULT_FEATURES = [
21  Feature(name='fcoroutines-ts',
22          when=lambda cfg: hasCompileFlag(cfg, '-fcoroutines-ts') and
23                           featureTestMacros(cfg, flags='-fcoroutines-ts').get('__cpp_coroutines', 0) >= 201703,
24          actions=[AddCompileFlag('-fcoroutines-ts')]),
25
26  Feature(name='thread-safety',
27          when=lambda cfg: hasCompileFlag(cfg, '-Werror=thread-safety'),
28          actions=[AddCompileFlag('-Werror=thread-safety')]),
29
30  Feature(name='diagnose-if-support',
31          when=lambda cfg: hasCompileFlag(cfg, '-Wuser-defined-warnings'),
32          actions=[AddCompileFlag('-Wuser-defined-warnings')]),
33
34  Feature(name='has-fblocks',                   when=lambda cfg: hasCompileFlag(cfg, '-fblocks')),
35  Feature(name='-fsized-deallocation',          when=lambda cfg: hasCompileFlag(cfg, '-fsized-deallocation')),
36  Feature(name='-faligned-allocation',          when=lambda cfg: hasCompileFlag(cfg, '-faligned-allocation')),
37  Feature(name='fdelayed-template-parsing',     when=lambda cfg: hasCompileFlag(cfg, '-fdelayed-template-parsing')),
38  Feature(name='libcpp-no-if-constexpr',        when=lambda cfg: '__cpp_if_constexpr' not in featureTestMacros(cfg)),
39  Feature(name='libcpp-no-structured-bindings', when=lambda cfg: '__cpp_structured_bindings' not in featureTestMacros(cfg)),
40  Feature(name='libcpp-no-deduction-guides',    when=lambda cfg: featureTestMacros(cfg).get('__cpp_deduction_guides', 0) < 201611),
41  Feature(name='libcpp-no-concepts',            when=lambda cfg: featureTestMacros(cfg).get('__cpp_concepts', 0) < 201907),
42  Feature(name='has-fobjc-arc',                 when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc') and
43                                                                 sys.platform.lower().strip() == 'darwin'), # TODO: this doesn't handle cross-compiling to Apple platforms.
44  Feature(name='objective-c++',                 when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc')),
45  Feature(name='no-noexcept-function-type',     when=lambda cfg: featureTestMacros(cfg).get('__cpp_noexcept_function_type', 0) < 201510),
46
47  Feature(name='non-lockfree-atomics',
48          when=lambda cfg: sourceBuilds(cfg, """
49            #include <atomic>
50            struct Large { int storage[100]; };
51            std::atomic<Large> x;
52            int main(int, char**) { (void)x.load(); return 0; }
53          """)),
54  # TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree()
55  # on all supported platforms.
56  Feature(name='is-lockfree-runtime-function',
57          when=lambda cfg: sourceBuilds(cfg, """
58            #include <atomic>
59            struct Large { int storage[100]; };
60            std::atomic<Large> x;
61            int main(int, char**) { return x.is_lock_free(); }
62          """)),
63
64  Feature(name='apple-clang',                                                                                                      when=_isAppleClang),
65  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}'.format(**compilerMacros(cfg)),                                          when=_isAppleClang),
66  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)),                        when=_isAppleClang),
67  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isAppleClang),
68
69  Feature(name='clang',                                                                                                            when=_isClang,
70          actions=[AddCompileFlag('-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER')]),
71  Feature(name=lambda cfg: 'clang-{__clang_major__}'.format(**compilerMacros(cfg)),                                                when=_isClang),
72  Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)),                              when=_isClang),
73  Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)),       when=_isClang),
74
75  Feature(name='gcc',                                                                                                              when=_isGCC),
76  Feature(name=lambda cfg: 'gcc-{__GNUC__}'.format(**compilerMacros(cfg)),                                                         when=_isGCC),
77  Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}'.format(**compilerMacros(cfg)),                                        when=_isGCC),
78  Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}'.format(**compilerMacros(cfg)),                  when=_isGCC),
79
80  Feature(name='msvc',                                                                                                             when=_isMSVC),
81  Feature(name=lambda cfg: 'msvc-{}'.format(*_msvcVersion(cfg)),                                                                   when=_isMSVC),
82  Feature(name=lambda cfg: 'msvc-{}.{}'.format(*_msvcVersion(cfg)),                                                                when=_isMSVC),
83]
84
85# Deduce and add the test features that that are implied by the #defines in
86# the <__config_site> header.
87#
88# For each macro of the form `_LIBCPP_XXX_YYY_ZZZ` defined below that
89# is defined after including <__config_site>, add a Lit feature called
90# `libcpp-xxx-yyy-zzz`. When a macro is defined to a specific value
91# (e.g. `_LIBCPP_ABI_VERSION=2`), the feature is `libcpp-xxx-yyy-zzz=<value>`.
92macros = {
93  '_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE': 'libcpp-has-no-global-filesystem-namespace',
94  '_LIBCPP_HAS_NO_MONOTONIC_CLOCK': 'libcpp-has-no-monotonic-clock',
95  '_LIBCPP_HAS_NO_STDIN': 'libcpp-has-no-stdin',
96  '_LIBCPP_HAS_NO_STDOUT': 'libcpp-has-no-stdout',
97  '_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS': 'libcpp-has-no-thread-unsafe-c-functions',
98  '_LIBCPP_HAS_NO_THREADS': 'libcpp-has-no-threads',
99  '_LIBCPP_HAS_THREAD_API_EXTERNAL': 'libcpp-has-thread-api-external',
100  '_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread',
101  '_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime',
102  '_LIBCPP_ABI_VERSION': 'libcpp-abi-version',
103  '_LIBCPP_ABI_UNSTABLE': 'libcpp-abi-unstable',
104  '_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY': 'libcpp-has-no-filesystem-library',
105  '_LIBCPP_HAS_NO_RANDOM_DEVICE': 'libcpp-has-no-random-device',
106  '_LIBCPP_HAS_NO_LOCALIZATION': 'libcpp-has-no-localization',
107  '_LIBCPP_HAS_NO_INCOMPLETE_FORMAT': 'libcpp-has-no-incomplete-format',
108  '_LIBCPP_HAS_NO_INCOMPLETE_RANGES': 'libcpp-has-no-incomplete-ranges',
109}
110for macro, feature in macros.items():
111  DEFAULT_FEATURES += [
112    Feature(name=lambda cfg, m=macro, f=feature: f + (
113              '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
114            ),
115            when=lambda cfg, m=macro: m in compilerMacros(cfg),
116
117            # FIXME: This is a hack that should be fixed using module maps.
118            # If modules are enabled then we have to lift all of the definitions
119            # in <__config_site> onto the command line.
120            actions=lambda cfg, m=macro: [
121              AddCompileFlag('-Wno-macro-redefined -D{}'.format(m) + (
122                '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
123              ))
124            ]
125    )
126  ]
127
128
129# Mapping from canonical locale names (used in the tests) to possible locale
130# names on various systems. Each locale is considered supported if any of the
131# alternative names is supported.
132locales = {
133  'en_US.UTF-8':     ['en_US.UTF-8', 'en_US.utf8', 'English_United States.1252'],
134  'fr_FR.UTF-8':     ['fr_FR.UTF-8', 'fr_FR.utf8', 'French_France.1252'],
135  'ru_RU.UTF-8':     ['ru_RU.UTF-8', 'ru_RU.utf8', 'Russian_Russia.1251'],
136  'zh_CN.UTF-8':     ['zh_CN.UTF-8', 'zh_CN.utf8', 'Chinese_China.936'],
137  'fr_CA.ISO8859-1': ['fr_CA.ISO8859-1', 'French_Canada.1252'],
138  'cs_CZ.ISO8859-2': ['cs_CZ.ISO8859-2', 'Czech_Czech Republic.1250']
139}
140for locale, alts in locales.items():
141  # Note: Using alts directly in the lambda body here will bind it to the value at the
142  # end of the loop. Assigning it to a default argument works around this issue.
143  DEFAULT_FEATURES.append(Feature(name='locale.{}'.format(locale),
144                                  when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts)))
145
146
147# Add features representing the platform name: darwin, linux, windows, etc...
148DEFAULT_FEATURES += [
149  Feature(name='darwin', when=lambda cfg: '__APPLE__' in compilerMacros(cfg)),
150  Feature(name='windows', when=lambda cfg: '_WIN32' in compilerMacros(cfg)),
151  Feature(name='windows-dll', when=lambda cfg: '_WIN32' in compilerMacros(cfg) and not '_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS' in compilerMacros(cfg)),
152  Feature(name='linux', when=lambda cfg: '__linux__' in compilerMacros(cfg)),
153  Feature(name='netbsd', when=lambda cfg: '__NetBSD__' in compilerMacros(cfg)),
154  Feature(name='freebsd', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg))
155]
156
157
158# Detect whether GDB is on the system, and if so add a substitution to access it.
159DEFAULT_FEATURES += [
160  Feature(name='host-has-gdb',
161    when=lambda cfg: shutil.which('gdb') is not None,
162    actions=[AddSubstitution('%{gdb}', lambda cfg: shutil.which('gdb'))]
163  )
164]
165