[libcxx-commits] [libcxx] [libc++] Split features.py into multiple files (PR #167353)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 10 09:59:13 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Louis Dionne (ldionne)
<details>
<summary>Changes</summary>
The features.py file that performs detection of Lit features had grown to be massive, so this patch splits it into smaller chunks which makes it easier to keep things organized.
---
Patch is 78.08 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/167353.diff
10 Files Affected:
- (removed) libcxx/utils/libcxx/test/features.py (-920)
- (added) libcxx/utils/libcxx/test/features/__init__.py (+21)
- (added) libcxx/utils/libcxx/test/features/availability.py (+199)
- (added) libcxx/utils/libcxx/test/features/compiler.py (+82)
- (added) libcxx/utils/libcxx/test/features/gdb.py (+50)
- (added) libcxx/utils/libcxx/test/features/libcxx_macros.py (+76)
- (added) libcxx/utils/libcxx/test/features/localization.py (+142)
- (added) libcxx/utils/libcxx/test/features/misc.py (+299)
- (added) libcxx/utils/libcxx/test/features/platform.py (+132)
- (modified) libcxx/utils/libcxx/test/params.py (+1-1)
``````````diff
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
deleted file mode 100644
index 5da1d9afee911..0000000000000
--- a/libcxx/utils/libcxx/test/features.py
+++ /dev/null
@@ -1,920 +0,0 @@
-# ===----------------------------------------------------------------------===##
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-# ===----------------------------------------------------------------------===##
-
-from libcxx.test.dsl import *
-from lit.BooleanExpression import BooleanExpression
-import re
-import shutil
-import subprocess
-import sys
-
-_isAnyClang = lambda cfg: "__clang__" in compilerMacros(cfg)
-_isAppleClang = lambda cfg: "__apple_build_version__" in compilerMacros(cfg)
-_isAnyGCC = lambda cfg: "__GNUC__" in compilerMacros(cfg)
-_isClang = lambda cfg: _isAnyClang(cfg) and not _isAppleClang(cfg)
-_isGCC = lambda cfg: _isAnyGCC(cfg) and not _isAnyClang(cfg)
-_isAnyClangOrGCC = lambda cfg: _isAnyClang(cfg) or _isAnyGCC(cfg)
-_isClExe = lambda cfg: not _isAnyClangOrGCC(cfg)
-_isMSVC = lambda cfg: "_MSC_VER" in compilerMacros(cfg)
-_msvcVersion = lambda cfg: (int(compilerMacros(cfg)["_MSC_VER"]) // 100, int(compilerMacros(cfg)["_MSC_VER"]) % 100)
-
-def _getAndroidDeviceApi(cfg):
- return int(
- programOutput(
- cfg,
- r"""
- #include <android/api-level.h>
- #include <stdio.h>
- int main(int, char**) {
- printf("%d\n", android_get_device_api_level());
- return 0;
- }
- """,
- )
- )
-
-
-def _mingwSupportsModules(cfg):
- # Only mingw headers are known to work with libc++ built as a module,
- # at the moment.
- if not "__MINGW32__" in compilerMacros(cfg):
- return False
- # For mingw headers, check for a version known to support being built
- # as a module.
- return sourceBuilds(
- cfg,
- """
- #include <_mingw_mac.h>
- #if __MINGW64_VERSION_MAJOR < 12
- #error Headers known to be incompatible
- #elif __MINGW64_VERSION_MAJOR == 12
- // The headers were fixed to work with libc++ modules during
- // __MINGW64_VERSION_MAJOR == 12. The headers became compatible
- // with libc++ built as a module in
- // 1652e9241b5d8a5a779c6582b1c3c4f4a7cc66e5 (Apr 2024), but the
- // following commit 8c13b28ace68f2c0094d45121d59a4b951b533ed
- // removed the now unused __mingw_static_ovr define. Use this
- // as indicator for whether we've got new enough headers.
- #ifdef __mingw_static_ovr
- #error Headers too old
- #endif
- #else
- // __MINGW64_VERSION_MAJOR > 12 should be ok.
- #endif
- int main(int, char**) { return 0; }
- """,
- )
-
-
-# Lit features are evaluated in order. Some checks may require the compiler detection to have
-# run first in order to work properly.
-DEFAULT_FEATURES = [
- # gcc-style-warnings detects compilers that understand -Wno-meow flags, unlike MSVC's compiler driver cl.exe.
- Feature(name="gcc-style-warnings", when=_isAnyClangOrGCC),
- Feature(name="cl-style-warnings", when=_isClExe),
- Feature(name="apple-clang", when=_isAppleClang),
- Feature(
- name=lambda cfg: "apple-clang-{__clang_major__}".format(**compilerMacros(cfg)),
- when=_isAppleClang,
- ),
- Feature(
- name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}".format(**compilerMacros(cfg)),
- when=_isAppleClang,
- ),
- Feature(
- name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(**compilerMacros(cfg)),
- when=_isAppleClang,
- ),
- Feature(name="clang", when=_isClang),
- Feature(
- name=lambda cfg: "clang-{__clang_major__}".format(**compilerMacros(cfg)),
- when=_isClang,
- ),
- Feature(
- name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}".format(**compilerMacros(cfg)),
- when=_isClang,
- ),
- Feature(
- name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(**compilerMacros(cfg)),
- when=_isClang,
- ),
- # Note: Due to a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104760), we must disable deprecation warnings
- # on GCC or spurious diagnostics are issued.
- #
- # TODO:
- # - Enable -Wplacement-new with GCC.
- # - Enable -Wclass-memaccess with GCC.
- Feature(
- name="gcc",
- when=_isGCC,
- actions=[
- AddCompileFlag("-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS"),
- AddCompileFlag("-Wno-placement-new"),
- AddCompileFlag("-Wno-class-memaccess"),
- AddFeature("GCC-ALWAYS_INLINE-FIXME"),
- ],
- ),
- Feature(
- name=lambda cfg: "gcc-{__GNUC__}".format(**compilerMacros(cfg)), when=_isGCC
- ),
- Feature(
- name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}".format(**compilerMacros(cfg)),
- when=_isGCC,
- ),
- Feature(
- name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}".format(**compilerMacros(cfg)),
- when=_isGCC,
- ),
- Feature(name="msvc", when=_isMSVC),
- Feature(name=lambda cfg: "msvc-{}".format(*_msvcVersion(cfg)), when=_isMSVC),
- Feature(name=lambda cfg: "msvc-{}.{}".format(*_msvcVersion(cfg)), when=_isMSVC),
-
- Feature(
- name="diagnose-if-support",
- when=lambda cfg: hasCompileFlag(cfg, "-Wuser-defined-warnings"),
- actions=[AddCompileFlag("-Wuser-defined-warnings")],
- ),
- Feature(
- name="character-conversion-warnings",
- when=lambda cfg: hasCompileFlag(cfg, "-Wcharacter-conversion"),
- ),
- # Tests to validate whether the compiler has a way to set the maximum number
- # of steps during constant evaluation. Since the flag differs per compiler
- # store the "valid" flag as a feature. This allows passing the proper compile
- # flag to the compiler:
- # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12345678
- # // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12345678
- Feature(
- name="has-fconstexpr-steps",
- when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-steps=1"),
- ),
- Feature(
- name="has-fconstexpr-ops-limit",
- when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-ops-limit=1"),
- ),
- Feature(name="has-fblocks", when=lambda cfg: hasCompileFlag(cfg, "-fblocks")),
- Feature(
- name="fdelayed-template-parsing",
- when=lambda cfg: hasCompileFlag(cfg, "-fdelayed-template-parsing"),
- ),
- Feature(
- name="has-fobjc-arc",
- when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc")
- and sys.platform.lower().strip() == "darwin",
- ), # TODO: this doesn't handle cross-compiling to Apple platforms.
- Feature(
- name="objective-c++",
- when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc"),
- ),
- Feature(
- name="verify-support",
- when=lambda cfg: hasCompileFlag(cfg, "-Xclang -verify-ignore-unexpected"),
- ),
- Feature(
- name="add-latomic-workaround", # https://llvm.org/PR73361
- when=lambda cfg: sourceBuilds(
- cfg, "int main(int, char**) { return 0; }", ["-latomic"]
- ),
- actions=[AddLinkFlag("-latomic")],
- ),
- Feature(
- name="has-64-bit-atomics",
- when=lambda cfg: sourceBuilds(
- cfg,
- """
- #include <atomic>
- struct Large { char storage[64/8]; };
- std::atomic<Large> x;
- int main(int, char**) { (void)x.load(); (void)x.is_lock_free(); return 0; }
- """,
- ),
- ),
- Feature(
- name="has-1024-bit-atomics",
- when=lambda cfg: sourceBuilds(
- cfg,
- """
- #include <atomic>
- struct Large { char storage[1024/8]; };
- std::atomic<Large> x;
- int main(int, char**) { (void)x.load(); (void)x.is_lock_free(); return 0; }
- """,
- ),
- ),
- # Tests that require 64-bit architecture
- Feature(
- name="32-bit-pointer",
- when=lambda cfg: sourceBuilds(
- cfg,
- """
- int main(int, char**) {
- static_assert(sizeof(void *) == 4);
- }
- """,
- ),
- ),
- # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.20348.0):
- # https://developercommunity.visualstudio.com/t/utf-8-locales-break-ctype-functions-for-wchar-type/1653678
- Feature(
- name="win32-broken-utf8-wchar-ctype",
- when=lambda cfg: not "_LIBCPP_HAS_LOCALIZATION" in compilerMacros(cfg)
- or compilerMacros(cfg)["_LIBCPP_HAS_LOCALIZATION"] == "1"
- and "_WIN32" in compilerMacros(cfg)
- and not programSucceeds(
- cfg,
- """
- #include <locale.h>
- #include <wctype.h>
- int main(int, char**) {
- setlocale(LC_ALL, "en_US.UTF-8");
- return towlower(L'\\xDA') != L'\\xFA';
- }
- """,
- ),
- ),
- # Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.19041.0).
- # https://developercommunity.visualstudio.com/t/printf-formatting-with-g-outputs-too/1660837
- Feature(
- name="win32-broken-printf-g-precision",
- when=lambda cfg: "_WIN32" in compilerMacros(cfg)
- and not programSucceeds(
- cfg,
- """
- #include <stdio.h>
- #include <string.h>
- int main(int, char**) {
- char buf[100];
- snprintf(buf, sizeof(buf), "%#.*g", 0, 0.0);
- return strcmp(buf, "0.");
- }
- """,
- ),
- ),
- # Check for a Windows UCRT bug (not fixed upstream yet).
- # With UCRT, printf("%a", 0.0) produces "0x0.0000000000000p+0",
- # while other C runtimes produce just "0x0p+0".
- # https://developercommunity.visualstudio.com/t/Printf-formatting-of-float-as-hex-prints/1660844
- Feature(
- name="win32-broken-printf-a-precision",
- when=lambda cfg: "_WIN32" in compilerMacros(cfg)
- and not programSucceeds(
- cfg,
- """
- #include <stdio.h>
- #include <string.h>
- int main(int, char**) {
- char buf[100];
- snprintf(buf, sizeof(buf), "%a", 0.0);
- return strcmp(buf, "0x0p+0");
- }
- """,
- ),
- ),
- # Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had
- # mon_decimal_point == ".", which our tests don't handle.
- Feature(
- name="glibc-old-ru_RU-decimal-point",
- when=lambda cfg: not "_LIBCPP_HAS_LOCALIZATION" in compilerMacros(cfg)
- or compilerMacros(cfg)["_LIBCPP_HAS_LOCALIZATION"] == "1"
- and not programSucceeds(
- cfg,
- """
- #include <locale.h>
- #include <string.h>
- int main(int, char**) {
- setlocale(LC_ALL, "ru_RU.UTF-8");
- return strcmp(localeconv()->mon_decimal_point, ",");
- }
- """,
- ),
- ),
- Feature(
- name="has-unix-headers",
- when=lambda cfg: sourceBuilds(
- cfg,
- """
- #include <unistd.h>
- #include <sys/wait.h>
- int main(int, char**) {
- int fd[2];
- return pipe(fd);
- }
- """,
- ),
- ),
- # Whether Bash can run on the executor.
- # This is not always the case, for example when running on embedded systems.
- #
- # For the corner case of bash existing, but it being missing in the path
- # set in %{exec} as "--env PATH=one-single-dir", the executor does find
- # and executes bash, but bash then can't find any other common shell
- # utilities. Test executing "bash -c 'bash --version'" to see if bash
- # manages to find binaries to execute.
- Feature(
- name="executor-has-no-bash",
- when=lambda cfg: runScriptExitCode(cfg, ["%{exec} bash -c 'bash --version'"]) != 0,
- ),
- # Whether module support for the platform is available.
- Feature(
- name="has-no-cxx-module-support",
- # The libc of these platforms have functions with internal linkage.
- # This is not allowed per C11 7.1.2 Standard headers/6
- # Any declaration of a library function shall have external linkage.
- when=lambda cfg: "__ANDROID__" in compilerMacros(cfg)
- or "__FreeBSD__" in compilerMacros(cfg)
- or ("_WIN32" in compilerMacros(cfg) and not _mingwSupportsModules(cfg))
- or platform.system().lower().startswith("aix")
- # Avoid building on platforms that don't support modules properly.
- or not hasCompileFlag(cfg, "-Wno-reserved-module-identifier")
- # older versions don't support extern "C++", newer versions don't support main in named module.
- or not (
- sourceBuilds(
- cfg,
- """
- export module test;
- extern "C++" int main(int, char**) { return 0; }
- """,
- )
- or sourceBuilds(
- cfg,
- """
- export module test;
- int main(int, char**) { return 0; }
- """,
- )
- ),
- ),
- # The time zone validation tests compare the output of zdump against the
- # output generated by <chrono>'s time zone support.
- Feature(
- name="has-no-zdump",
- when=lambda cfg: runScriptExitCode(cfg, ["zdump --version"]) != 0,
- ),
-]
-
-# Deduce and add the test features that that are implied by the #defines in
-# the <__config> header.
-#
-# For each macro of the form `_LIBCPP_XXX_YYY_ZZZ` defined below that
-# is defined after including <__config>, add a Lit feature called
-# `libcpp-xxx-yyy-zzz`. When a macro is defined to a specific value
-# (e.g. `_LIBCPP_ABI_VERSION=2`), the feature is `libcpp-xxx-yyy-zzz=<value>`.
-#
-# Note that features that are more strongly tied to libc++ are named libcpp-foo,
-# while features that are more general in nature are not prefixed with 'libcpp-'.
-macros = {
- "_LIBCPP_NO_VCRUNTIME": "libcpp-no-vcruntime",
- "_LIBCPP_ABI_VERSION": "libcpp-abi-version",
- "_LIBCPP_ABI_BOUNDED_ITERATORS": "libcpp-has-abi-bounded-iterators",
- "_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING": "libcpp-has-abi-bounded-iterators-in-string",
- "_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR": "libcpp-has-abi-bounded-iterators-in-vector",
- "_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY": "libcpp-has-abi-bounded-iterators-in-std-array",
- "_LIBCPP_ABI_BOUNDED_UNIQUE_PTR": "libcpp-has-abi-bounded-unique_ptr",
- "_LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE": "libcpp-has-abi-fix-unordered-container-size-type",
- "_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR": "libcpp-deprecated-abi-disable-pair-trivial-copy-ctor",
- "_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING": "libcpp-abi-no-compressed-pair-padding",
- "_LIBCPP_PSTL_BACKEND_LIBDISPATCH": "libcpp-pstl-backend-libdispatch",
-}
-for macro, feature in macros.items():
- DEFAULT_FEATURES.append(
- Feature(
- name=lambda cfg, m=macro, f=feature: f + ("={}".format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ""),
- when=lambda cfg, m=macro: m in compilerMacros(cfg),
- )
- )
-
-true_false_macros = {
- "_LIBCPP_HAS_THREAD_API_EXTERNAL": "libcpp-has-thread-api-external",
- "_LIBCPP_HAS_THREAD_API_PTHREAD": "libcpp-has-thread-api-pthread",
-}
-for macro, feature in true_false_macros.items():
- DEFAULT_FEATURES.append(
- Feature(
- name=feature,
- when=lambda cfg, m=macro: m in compilerMacros(cfg)
- and compilerMacros(cfg)[m] == "1",
- )
- )
-
-inverted_macros = {
- "_LIBCPP_HAS_TIME_ZONE_DATABASE": "no-tzdb",
- "_LIBCPP_HAS_FILESYSTEM": "no-filesystem",
- "_LIBCPP_HAS_LOCALIZATION": "no-localization",
- "_LIBCPP_HAS_THREADS": "no-threads",
- "_LIBCPP_HAS_MONOTONIC_CLOCK": "no-monotonic-clock",
- "_LIBCPP_HAS_WIDE_CHARACTERS": "no-wide-characters",
- "_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS": "libcpp-has-no-availability-markup",
- "_LIBCPP_HAS_RANDOM_DEVICE": "no-random-device",
- "_LIBCPP_HAS_UNICODE": "libcpp-has-no-unicode",
- "_LIBCPP_HAS_TERMINAL": "no-terminal",
-}
-for macro, feature in inverted_macros.items():
- DEFAULT_FEATURES.append(
- Feature(
- name=feature,
- when=lambda cfg, m=macro: m in compilerMacros(cfg)
- and compilerMacros(cfg)[m] == "0",
- )
- )
-
-# Mapping from canonical locale names (used in the tests) to possible locale
-# names on various systems. Each locale is considered supported if any of the
-# alternative names is supported.
-locales = {
- "en_US.UTF-8": ["en_US.UTF-8", "en_US.utf8", "English_United States.1252"],
- "fr_FR.UTF-8": ["fr_FR.UTF-8", "fr_FR.utf8", "French_France.1252"],
- "ja_JP.UTF-8": ["ja_JP.UTF-8", "ja_JP.utf8", "Japanese_Japan.923"],
- "ru_RU.UTF-8": ["ru_RU.UTF-8", "ru_RU.utf8", "Russian_Russia.1251"],
- "zh_CN.UTF-8": ["zh_CN.UTF-8", "zh_CN.utf8", "Chinese_China.936"],
- "fr_CA.ISO8859-1": ["fr_CA.ISO8859-1", "French_Canada.1252"],
- "cs_CZ.ISO8859-2": ["cs_CZ.ISO8859-2", "Czech_Czech Republic.1250"],
-}
-provide_locale_conversions = {
- "fr_FR.UTF-8": ["decimal_point", "mon_thousands_sep", "thousands_sep"],
- "ru_RU.UTF-8": ["mon_thousands_sep"],
-}
-for locale, alts in locales.items():
- # Note: Using alts directly in the lambda body here will bind it to the value at the
- # end of the loop. Assigning it to a default argument works around this issue.
- DEFAULT_FEATURES.append(
- Feature(
- name="locale.{}".format(locale),
- when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts),
- actions=lambda cfg, locale=locale, alts=alts: _getLocaleFlagsAction(
- cfg, locale, alts, provide_locale_conversions[locale]
- )
- if locale in provide_locale_conversions
- and ("_LIBCPP_HAS_WIDE_CHARACTERS" not in compilerMacros(cfg) or
- compilerMacros(cfg)["_LIBCPP_HAS_WIDE_CHARACTERS"] == "1")
- else [],
- ),
- )
-
-
-# Provide environment locale conversions through substitutions to avoid platform specific
-# maintenance.
-def _getLocaleFlagsAction(cfg, locale, alts, members):
- alts_list = ",".join([f'"{l}"' for l in alts])
- get_member_list = ",".join([f"lc->{m}" for m in members])
-
- localeconv_info = programOutput(
- cfg,
- r"""
- #if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS)
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #include <stdio.h>
- #include <locale.h>
- #include <stdlib.h>
- #include <wchar.h>
-
- // Print each requested locale conversion member on separate lines.
- int main(int, char**) {
- const char* locales[] = { %s };
- for (int loc_i = 0; loc_i < %d; ++loc_i) {
- if (!setlocale(LC_ALL, locales[loc_i])) {
- continue; // Choose first locale name that is recognized.
- }
-
- lconv* lc = localeconv();
- const char* members[] = { %s };
- for (size_t m_i = 0; m_i < %d; ++m_i) {
- if (!members[m_i]) {
- printf("\n"); // member value is an empty string
- continue;
- }
-
- size_t len = mbstowcs(nullptr, members[m_i], 0);
- if (len == static_cast<size_t>(-1)) {
- fprintf(stderr, "mbstowcs failed unexpectedly\n");
- return 1;
- }
- // Include room for null terminator. Use malloc as these features
- // are also used by lit configs that don't use -lc++ (libunwind tests).
- wchar_t* dst = (wchar_t*)malloc((len + 1) * sizeof(wchar_t...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/167353
More information about the libcxx-commits
mailing list