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
46  # Note: We use a custom modules cache path to make sure that we don't reuse
47  #       the default one, which can be shared across builds. This is important
48  #       because we define macros in headers files, and a change in these macros
49  #       doesn't seem to invalidate modules cache entries, which means we could
50  #       build against now-invalid cached headers from a previous build.
51  Feature(name='modules-support',
52          when=lambda cfg: hasCompileFlag(cfg, '-fmodules'),
53          actions=lambda cfg: [AddCompileFlag('-fmodules-cache-path=%t/ModuleCache')]),
54
55  Feature(name='non-lockfree-atomics',
56          when=lambda cfg: sourceBuilds(cfg, """
57            #include <atomic>
58            struct Large { int storage[100]; };
59            std::atomic<Large> x;
60            int main(int, char**) { (void)x.load(); return 0; }
61          """)),
62  # TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree()
63  # on all supported platforms.
64  Feature(name='is-lockfree-runtime-function',
65          when=lambda cfg: sourceBuilds(cfg, """
66            #include <atomic>
67            struct Large { int storage[100]; };
68            std::atomic<Large> x;
69            int main(int, char**) { return x.is_lock_free(); }
70          """)),
71
72  Feature(name='apple-clang',                                                                                                      when=_isAppleClang),
73  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}'.format(**compilerMacros(cfg)),                                          when=_isAppleClang),
74  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)),                        when=_isAppleClang),
75  Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isAppleClang),
76
77  Feature(name='clang',                                                                                                            when=_isClang),
78  Feature(name=lambda cfg: 'clang-{__clang_major__}'.format(**compilerMacros(cfg)),                                                when=_isClang),
79  Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)),                              when=_isClang),
80  Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)),       when=_isClang),
81
82  Feature(name='gcc',                                                                                                              when=_isGCC),
83  Feature(name=lambda cfg: 'gcc-{__GNUC__}'.format(**compilerMacros(cfg)),                                                         when=_isGCC),
84  Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}'.format(**compilerMacros(cfg)),                                        when=_isGCC),
85  Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}'.format(**compilerMacros(cfg)),                  when=_isGCC),
86
87  Feature(name='msvc',                                                                                                             when=_isMSVC),
88  Feature(name=lambda cfg: 'msvc-{}'.format(*_msvcVersion(cfg)),                                                                   when=_isMSVC),
89  Feature(name=lambda cfg: 'msvc-{}.{}'.format(*_msvcVersion(cfg)),                                                                when=_isMSVC),
90]
91
92# Deduce and add the test features that that are implied by the #defines in
93# the <__config_site> header.
94#
95# For each macro of the form `_LIBCPP_XXX_YYY_ZZZ` defined below that
96# is defined after including <__config_site>, add a Lit feature called
97# `libcpp-xxx-yyy-zzz`. When a macro is defined to a specific value
98# (e.g. `_LIBCPP_ABI_VERSION=2`), the feature is `libcpp-xxx-yyy-zzz=<value>`.
99macros = {
100  '_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE': 'libcpp-has-no-global-filesystem-namespace',
101  '_LIBCPP_HAS_NO_MONOTONIC_CLOCK': 'libcpp-has-no-monotonic-clock',
102  '_LIBCPP_HAS_NO_STDIN': 'libcpp-has-no-stdin',
103  '_LIBCPP_HAS_NO_STDOUT': 'libcpp-has-no-stdout',
104  '_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS': 'libcpp-has-no-thread-unsafe-c-functions',
105  '_LIBCPP_HAS_NO_THREADS': 'libcpp-has-no-threads',
106  '_LIBCPP_HAS_THREAD_API_EXTERNAL': 'libcpp-has-thread-api-external',
107  '_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread',
108  '_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime',
109  '_LIBCPP_ABI_VERSION': 'libcpp-abi-version',
110  '_LIBCPP_ABI_UNSTABLE': 'libcpp-abi-unstable',
111  '_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY': 'libcpp-has-no-filesystem-library',
112  '_LIBCPP_HAS_NO_RANDOM_DEVICE': 'libcpp-has-no-random-device',
113  '_LIBCPP_HAS_NO_LOCALIZATION': 'libcpp-has-no-localization',
114}
115for macro, feature in macros.items():
116  DEFAULT_FEATURES += [
117    Feature(name=lambda cfg, m=macro, f=feature: f + (
118              '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
119            ),
120            when=lambda cfg, m=macro: m in compilerMacros(cfg),
121
122            # FIXME: This is a hack that should be fixed using module maps.
123            # If modules are enabled then we have to lift all of the definitions
124            # in <__config_site> onto the command line.
125            actions=lambda cfg, m=macro: [
126              AddCompileFlag('-Wno-macro-redefined -D{}'.format(m) + (
127                '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
128              ))
129            ]
130    )
131  ]
132
133
134# Mapping from canonical locale names (used in the tests) to possible locale
135# names on various systems. Each locale is considered supported if any of the
136# alternative names is supported.
137locales = {
138  'en_US.UTF-8':     ['en_US.UTF-8', 'en_US.utf8', 'English_United States.1252'],
139  'fr_FR.UTF-8':     ['fr_FR.UTF-8', 'fr_FR.utf8', 'French_France.1252'],
140  'ru_RU.UTF-8':     ['ru_RU.UTF-8', 'ru_RU.utf8', 'Russian_Russia.1251'],
141  'zh_CN.UTF-8':     ['zh_CN.UTF-8', 'zh_CN.utf8', 'Chinese_China.936'],
142  'fr_CA.ISO8859-1': ['fr_CA.ISO8859-1', 'French_Canada.1252'],
143  'cs_CZ.ISO8859-2': ['cs_CZ.ISO8859-2', 'Czech_Czech Republic.1250']
144}
145for locale, alts in locales.items():
146  # Note: Using alts directly in the lambda body here will bind it to the value at the
147  # end of the loop. Assigning it to a default argument works around this issue.
148  DEFAULT_FEATURES.append(Feature(name='locale.{}'.format(locale),
149                                  when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts)))
150
151
152# Add features representing the platform name: darwin, linux, windows, etc...
153DEFAULT_FEATURES += [
154  Feature(name='darwin', when=lambda cfg: '__APPLE__' in compilerMacros(cfg)),
155  Feature(name='windows', when=lambda cfg: '_WIN32' in compilerMacros(cfg)),
156  Feature(name='windows-dll', when=lambda cfg: '_WIN32' in compilerMacros(cfg) and not '_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS' in compilerMacros(cfg)),
157  Feature(name='linux', when=lambda cfg: '__linux__' in compilerMacros(cfg)),
158  Feature(name='netbsd', when=lambda cfg: '__NetBSD__' in compilerMacros(cfg)),
159  Feature(name='freebsd', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg))
160]
161
162
163# Detect whether GDB is on the system, and if so add a substitution to access it.
164DEFAULT_FEATURES += [
165  Feature(name='host-has-gdb',
166    when=lambda cfg: shutil.which('gdb') is not None,
167    actions=[AddSubstitution('%{gdb}', lambda cfg: shutil.which('gdb'))]
168  )
169]
170