xref: /aosp_15_r20/external/cronet/third_party/libc++/src/utils/libcxx/test/params.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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# ===----------------------------------------------------------------------===##
8import sys
9import re
10import shlex
11from pathlib import Path
12
13from libcxx.test.dsl import *
14from libcxx.test.features import _isClang, _isAppleClang, _isGCC, _isMSVC
15
16
17_warningFlags = [
18    "-Werror",
19    "-Wall",
20    "-Wctad-maybe-unsupported",
21    "-Wextra",
22    "-Wshadow",
23    "-Wundef",
24    "-Wunused-template",
25    "-Wno-unused-command-line-argument",
26    "-Wno-attributes",
27    "-Wno-pessimizing-move",
28    "-Wno-noexcept-type",
29    "-Wno-aligned-allocation-unavailable",
30    "-Wno-atomic-alignment",
31    "-Wno-reserved-module-identifier",
32    '-Wdeprecated-copy',
33    '-Wdeprecated-copy-dtor',
34    # GCC warns about places where we might want to add sized allocation/deallocation
35    # functions, but we know better what we're doing/testing in the test suite.
36    "-Wno-sized-deallocation",
37    # Turn off warnings about user-defined literals with reserved suffixes. Those are
38    # just noise since we are testing the Standard Library itself.
39    "-Wno-literal-suffix",  # GCC
40    "-Wno-user-defined-literals",  # Clang
41    # GCC warns about this when TEST_IS_CONSTANT_EVALUATED is used on a non-constexpr
42    # function. (This mostly happens in C++11 mode.)
43    # TODO(mordante) investigate a solution for this issue.
44    "-Wno-tautological-compare",
45    # -Wstringop-overread and -Wstringop-overflow seem to be a bit buggy currently
46    "-Wno-stringop-overread",
47    "-Wno-stringop-overflow",
48    # These warnings should be enabled in order to support the MSVC
49    # team using the test suite; They enable the warnings below and
50    # expect the test suite to be clean.
51    "-Wsign-compare",
52    "-Wunused-variable",
53    "-Wunused-parameter",
54    "-Wunreachable-code",
55    "-Wno-unused-local-typedef",
56
57    # Disable warnings for extensions used in C++03
58    "-Wno-local-type-template-args",
59    "-Wno-c++11-extensions",
60
61    # TODO(philnik) This fails with the PSTL.
62    "-Wno-unknown-pragmas",
63    # Don't fail compilation in case the compiler fails to perform the requested
64    # loop vectorization.
65    "-Wno-pass-failed",
66
67    # TODO: Find out why GCC warns in lots of places (is this a problem with always_inline?)
68    "-Wno-dangling-reference",
69    "-Wno-mismatched-new-delete",
70    "-Wno-redundant-move",
71
72    # This doesn't make sense in real code, but we have to test it because the standard requires us to not break
73    "-Wno-self-move",
74]
75
76_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26"]
77
78
79def getStdFlag(cfg, std):
80    if hasCompileFlag(cfg, "-std=" + std):
81        return "-std=" + std
82    # TODO(LLVM-19) Remove the fallbacks needed for Clang 16.
83    fallbacks = {
84        "c++23": "c++2b",
85    }
86    if std in fallbacks and hasCompileFlag(cfg, "-std=" + fallbacks[std]):
87        return "-std=" + fallbacks[std]
88    return None
89
90
91def getSpeedOptimizationFlag(cfg):
92    if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg):
93        return "-O3"
94    elif _isMSVC(cfg):
95        return "/O2"
96    else:
97        raise RuntimeError(
98            "Can't figure out what compiler is used in the configuration"
99        )
100
101
102def getSizeOptimizationFlag(cfg):
103    if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg):
104        return "-Os"
105    elif _isMSVC(cfg):
106        return "/O1"
107    else:
108        raise RuntimeError(
109            "Can't figure out what compiler is used in the configuration"
110        )
111
112
113def testClangTidy(cfg, version, executable):
114    try:
115        if version in commandOutput(cfg, [f"{executable} --version"]):
116            return executable
117    except ConfigurationRuntimeError:
118        return None
119
120
121def getSuitableClangTidy(cfg):
122    # If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests.
123    if (
124        runScriptExitCode(
125            cfg, ["stat %{test-tools-dir}/clang_tidy_checks/libcxx-tidy.plugin"]
126        )
127        != 0
128    ):
129        return None
130
131    version = "{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(
132        **compilerMacros(cfg)
133    )
134    exe = testClangTidy(
135        cfg, version, "clang-tidy-{__clang_major__}".format(**compilerMacros(cfg))
136    )
137
138    if not exe:
139        exe = testClangTidy(cfg, version, "clang-tidy")
140
141    return exe
142
143
144# fmt: off
145DEFAULT_PARAMETERS = [
146    Parameter(
147        name="target_triple",
148        type=str,
149        help="The target triple to compile the test suite for. This must be "
150        "compatible with the target that the tests will be run on.",
151        actions=lambda triple: filter(
152            None,
153            [
154                AddFeature("target={}".format(triple)),
155                AddFlagIfSupported("--target={}".format(triple)),
156                AddSubstitution("%{triple}", triple),
157            ],
158        ),
159    ),
160    Parameter(
161        name="std",
162        choices=_allStandards,
163        type=str,
164        help="The version of the standard to compile the test suite with.",
165        default=lambda cfg: next(
166            s for s in reversed(_allStandards) if getStdFlag(cfg, s)
167        ),
168        actions=lambda std: [
169            AddFeature(std),
170            AddSubstitution("%{cxx_std}", re.sub(r"\+", "x", std)),
171            AddCompileFlag(lambda cfg: getStdFlag(cfg, std)),
172        ],
173    ),
174    Parameter(
175        name="optimization",
176        choices=["none", "speed", "size"],
177        type=str,
178        help="The optimization level to use when compiling the test suite.",
179        default="none",
180        actions=lambda opt: filter(None, [
181            AddCompileFlag(lambda cfg: getSpeedOptimizationFlag(cfg)) if opt == "speed" else None,
182            AddCompileFlag(lambda cfg: getSizeOptimizationFlag(cfg)) if opt == "size" else None,
183            AddFeature(f'optimization={opt}'),
184        ]),
185    ),
186    Parameter(
187        name="enable_modules",
188        choices=["none", "clang", "clang-lsv"],
189        type=str,
190        help="Whether to build the test suite with modules enabled. "
191             "Select `clang` for Clang modules, and 'clang-lsv' for Clang modules with Local Submodule Visibility.",
192        default="none",
193        actions=lambda modules: filter(None, [
194            AddFeature("clang-modules-build")           if modules in ("clang", "clang-lsv") else None,
195
196            # Note: AppleClang disregards -fmodules entirely when compiling C++, so we also pass -fcxx-modules
197            #       to enable modules for C++.
198            AddCompileFlag("-fmodules -fcxx-modules")   if modules in ("clang", "clang-lsv") else None,
199
200            # Note: We use a custom modules cache path to make sure that we don't reuse
201            #       the default one, which can be shared across CI builds with different
202            #       configurations.
203            AddCompileFlag(lambda cfg: f"-fmodules-cache-path={cfg.test_exec_root}/ModuleCache") if modules in ("clang", "clang-lsv") else None,
204
205            AddCompileFlag("-Xclang -fmodules-local-submodule-visibility") if modules == "clang-lsv" else None,
206        ])
207    ),
208    Parameter(
209        name="enable_exceptions",
210        choices=[True, False],
211        type=bool,
212        default=True,
213        help="Whether to enable exceptions when compiling the test suite.",
214        actions=lambda exceptions: [] if exceptions else [
215            AddFeature("no-exceptions"),
216            AddCompileFlag("-fno-exceptions")
217        ],
218    ),
219    Parameter(
220        name="enable_rtti",
221        choices=[True, False],
222        type=bool,
223        default=True,
224        help="Whether to enable RTTI when compiling the test suite.",
225        actions=lambda rtti: [] if rtti else [
226            AddFeature("no-rtti"),
227            AddCompileFlag("-fno-rtti")
228        ],
229    ),
230    Parameter(
231        name="stdlib",
232        choices=["llvm-libc++", "apple-libc++", "libstdc++", "msvc"],
233        type=str,
234        default="llvm-libc++",
235        help="""The C++ Standard Library implementation being tested.
236
237                 Note that this parameter can also be used to encode different 'flavors' of the same
238                 standard library, such as libc++ as shipped by a different vendor, if it has different
239                 properties worth testing.
240
241                 The Standard libraries currently supported are:
242                 - llvm-libc++: The 'upstream' libc++ as shipped with LLVM.
243                 - apple-libc++: libc++ as shipped by Apple. This is basically like the LLVM one, but
244                                 there are a few differences like installation paths, the use of
245                                 universal dylibs and the existence of availability markup.
246                 - libstdc++: The GNU C++ library typically shipped with GCC.
247                 - msvc: The Microsoft implementation of the C++ Standard Library.
248                """,
249        actions=lambda stdlib: filter(
250            None,
251            [
252                AddFeature("stdlib={}".format(stdlib)),
253                # Also add an umbrella feature 'stdlib=libc++' for all flavors of libc++, to simplify
254                # the test suite.
255                AddFeature("stdlib=libc++") if re.match(r".+-libc\+\+", stdlib) else None,
256            ],
257        ),
258    ),
259    Parameter(
260        name="enable_warnings",
261        choices=[True, False],
262        type=bool,
263        default=True,
264        help="Whether to enable warnings when compiling the test suite.",
265        actions=lambda warnings: [] if not warnings else
266            [AddOptionalWarningFlag(w) for w in _warningFlags] +
267            [AddCompileFlag("-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER")],
268    ),
269    Parameter(
270        name="use_sanitizer",
271        choices=[
272            "",
273            "Address",
274            "HWAddress",
275            "Undefined",
276            "Memory",
277            "MemoryWithOrigins",
278            "Thread",
279            "DataFlow",
280            "Leaks",
281        ],
282        type=str,
283        default="",
284        help="An optional sanitizer to enable when building and running the test suite.",
285        actions=lambda sanitizer: filter(
286            None,
287            [
288                AddFlag("-g -fno-omit-frame-pointer") if sanitizer else None,
289
290                AddFlag("-fsanitize=undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all") if sanitizer == "Undefined" else None,
291                AddFeature("ubsan")                                                                          if sanitizer == "Undefined" else None,
292
293                AddFlag("-fsanitize=address") if sanitizer == "Address" else None,
294                AddFeature("asan")            if sanitizer == "Address" else None,
295
296                AddFlag("-fsanitize=hwaddress") if sanitizer == "HWAddress" else None,
297                AddFeature("hwasan")            if sanitizer == "HWAddress" else None,
298
299                AddFlag("-fsanitize=memory")               if sanitizer in ["Memory", "MemoryWithOrigins"] else None,
300                AddFeature("msan")                         if sanitizer in ["Memory", "MemoryWithOrigins"] else None,
301                AddFlag("-fsanitize-memory-track-origins") if sanitizer == "MemoryWithOrigins" else None,
302
303                AddFlag("-fsanitize=thread") if sanitizer == "Thread" else None,
304                AddFeature("tsan")           if sanitizer == "Thread" else None,
305
306                AddFlag("-fsanitize=dataflow") if sanitizer == "DataFlow" else None,
307                AddFlag("-fsanitize=leaks")    if sanitizer == "Leaks" else None,
308
309                AddFeature("sanitizer-new-delete") if sanitizer in ["Address", "HWAddress", "Memory", "MemoryWithOrigins", "Thread"] else None,
310                AddFeature("lsan") if sanitizer in ["Address", "HWAddress", "Leaks"] else None,
311            ]
312        )
313    ),
314    Parameter(
315        name="enable_experimental",
316        choices=[True, False],
317        type=bool,
318        default=True,
319        help="Whether to enable tests for experimental C++ Library features.",
320        actions=lambda experimental: [
321            # When linking in MSVC mode via the Clang driver, a -l<foo>
322            # maps to <foo>.lib, so we need to use -llibc++experimental here
323            # to make it link against the static libc++experimental.lib.
324            # We can't check for the feature 'msvc' in available_features
325            # as those features are added after processing parameters.
326            AddFeature("c++experimental"),
327            PrependLinkFlag(lambda cfg: "-llibc++experimental" if _isMSVC(cfg) else "-lc++experimental"),
328            AddCompileFlag("-D_LIBCPP_ENABLE_EXPERIMENTAL"),
329        ]
330        if experimental
331        else [
332            AddFeature("libcpp-has-no-incomplete-pstl"),
333            AddFeature("libcpp-has-no-experimental-stop_token"),
334            AddFeature("libcpp-has-no-incomplete-tzdb"),
335            AddFeature("libcpp-has-no-experimental-syncstream"),
336        ],
337    ),
338    Parameter(
339        name="long_tests",
340        choices=[True, False],
341        type=bool,
342        default=True,
343        help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.",
344        actions=lambda enabled: [] if not enabled else [AddFeature("long_tests")],
345    ),
346    Parameter(
347        name="large_tests",
348        choices=[True, False],
349        type=bool,
350        default=True,
351        help="Whether to enable tests that use a lot of memory. This can be useful when running on a device with limited amounts of memory.",
352        actions=lambda enabled: [] if not enabled else [AddFeature("large_tests")],
353    ),
354    Parameter(
355        name="hardening_mode",
356        choices=["none", "fast", "extensive", "debug"],
357        type=str,
358        default="none",
359        help="Whether to enable one of the hardening modes when compiling the test suite. This is only "
360        "meaningful when running the tests against libc++.",
361        actions=lambda hardening_mode: filter(
362            None,
363            [
364                AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE")      if hardening_mode == "none" else None,
365                AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST")      if hardening_mode == "fast" else None,
366                AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE") if hardening_mode == "extensive" else None,
367                AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG")     if hardening_mode == "debug" else None,
368                AddFeature("libcpp-hardening-mode={}".format(hardening_mode)),
369            ],
370        ),
371    ),
372    Parameter(
373        name="additional_features",
374        type=list,
375        default=[],
376        help="A comma-delimited list of additional features that will be enabled when running the tests. "
377        "This should be used sparingly since specifying ad-hoc features manually is error-prone and "
378        "brittle in the long run as changes are made to the test suite.",
379        actions=lambda features: [AddFeature(f) for f in features],
380    ),
381    Parameter(
382        name="enable_transitive_includes",
383        choices=[True, False],
384        type=bool,
385        default=True,
386        help="Whether to enable backwards-compatibility transitive includes when running the tests. This "
387        "is provided to ensure that the trimmed-down version of libc++ does not bit-rot in between "
388        "points at which we bulk-remove transitive includes.",
389        actions=lambda enabled: [] if enabled else [
390            AddFeature("transitive-includes-disabled"),
391            AddCompileFlag("-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES"),
392        ],
393    ),
394    Parameter(
395        name="executor",
396        type=str,
397        default=f"{shlex.quote(sys.executable)} {shlex.quote(str(Path(__file__).resolve().parent.parent.parent / 'run.py'))}",
398        help="Custom executor to use instead of the configured default.",
399        actions=lambda executor: [AddSubstitution("%{executor}", executor)],
400    ),
401    Parameter(
402        name='clang-tidy-executable',
403        type=str,
404        default=lambda cfg: getSuitableClangTidy(cfg),
405        help="Selects the clang-tidy executable to use.",
406        actions=lambda exe: [] if exe is None else [
407            AddFeature('has-clang-tidy'),
408            AddSubstitution('%{clang-tidy}', exe),
409        ]
410    ),
411]
412# fmt: on
413