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 pathlib, functools 10 11libcxx_root = pathlib.Path(__file__).resolve().parent.parent.parent 12libcxx_include = libcxx_root / "include" 13assert libcxx_root.exists() 14 15def _is_header_file(file): 16 """Returns whether the given file is a header file, i.e. not a directory or the modulemap file.""" 17 return not file.is_dir() and not file.name in [ 18 "module.modulemap", 19 "CMakeLists.txt", 20 "libcxx.imp", 21 "__config_site.in", 22 ] 23 24@functools.total_ordering 25class Header: 26 _name: str 27 """Relative path from the root of libcxx/include""" 28 29 def __init__(self, name: str): 30 """Create a Header. 31 32 name: The path of the header relative to libc++'s include directory. 33 For example '__algorithm/find.h' or 'coroutine'. 34 """ 35 self._name = name 36 37 def is_public(self) -> bool: 38 """Returns whether the header is a public libc++ API header.""" 39 return "__" not in self._name and not self._name.startswith("ext/") 40 41 def is_internal(self) -> bool: 42 """Returns whether the header is an internal implementation detail of the library.""" 43 return not self.is_public() 44 45 def is_C_compatibility(self) -> bool: 46 """ 47 Returns whether the header is a C compatibility header (headers ending in .h like stdlib.h). 48 49 Note that headers like <cstdlib> are not considered C compatibility headers. 50 """ 51 return self.is_public() and self._name.endswith(".h") 52 53 def is_cstd(self) -> bool: 54 """Returns whether the header is a C 'std' header, like <cstddef>, <cerrno>, etc.""" 55 return self._name in [ 56 "cassert", 57 "ccomplex", 58 "cctype", 59 "cerrno", 60 "cfenv", 61 "cfloat", 62 "cinttypes", 63 "ciso646", 64 "climits", 65 "clocale", 66 "cmath", 67 "csetjmp", 68 "csignal", 69 "cstdalign", 70 "cstdarg", 71 "cstdbool", 72 "cstddef", 73 "cstdint", 74 "cstdio", 75 "cstdlib", 76 "cstring", 77 "ctgmath", 78 "ctime", 79 "cuchar", 80 "cwchar", 81 "cwctype", 82 ] 83 84 def is_experimental(self) -> bool: 85 """Returns whether the header is a public experimental header.""" 86 return self.is_public() and self._name.startswith("experimental/") 87 88 def has_cxx20_module(self) -> bool: 89 """ 90 Returns whether the header is in the std and std.compat C++20 modules. 91 92 These headers are all C++23-and-later headers, excluding C compatibility headers and 93 experimental headers. 94 """ 95 # These headers have been removed in C++20 so are never part of a module. 96 removed_in_20 = ["ccomplex", "ciso646", "cstdalign", "cstdbool", "ctgmath"] 97 return self.is_public() and not self.is_experimental() and not self.is_C_compatibility() and not self._name in removed_in_20 98 99 def is_cxx03_frozen_header(self) -> bool: 100 """Returns whether the header is a frozen C++03 support header.""" 101 return self._name.startswith("__cxx03/") 102 103 def is_in_modulemap(self) -> bool: 104 """Returns whether a header should be listed in the modulemap.""" 105 # TODO: Should `__config_site` be in the modulemap? 106 if self._name == "__config_site": 107 return False 108 109 if self._name == "__assertion_handler": 110 return False 111 112 # exclude libc++abi files 113 if self._name in ["cxxabi.h", "__cxxabi_config.h"]: 114 return False 115 116 # exclude headers in __support/ - these aren't supposed to work everywhere, 117 # so they shouldn't be included in general 118 if self._name.startswith("__support/"): 119 return False 120 121 # exclude ext/ headers - these are non-standard extensions and are barely 122 # maintained. People should migrate away from these and we don't need to 123 # burden ourself with maintaining them in any way. 124 if self._name.startswith("ext/"): 125 return False 126 127 # TODO: Frozen C++03 headers should probably be in the modulemap as well 128 if self.is_cxx03_frozen_header(): 129 return False 130 131 return True 132 133 def __str__(self) -> str: 134 return self._name 135 136 def __repr__(self) -> str: 137 return repr(self._name) 138 139 def __eq__(self, other) -> bool: 140 if isinstance(other, str): 141 return self._name == other 142 return self._name == other._name 143 144 def __lt__(self, other) -> bool: 145 if isinstance(other, str): 146 return self._name < other 147 return self._name < other._name 148 149 def __hash__(self) -> int: 150 return hash(self._name) 151 152 153# Commonly-used sets of headers 154all_headers = [Header(p.relative_to(libcxx_include).as_posix()) for p in libcxx_include.rglob("[_a-z]*") if _is_header_file(p)] 155all_headers += [Header("__config_site"), Header("__assertion_handler")] # Headers generated during the build process 156public_headers = [h for h in all_headers if h.is_public()] 157module_headers = [h for h in all_headers if h.has_cxx20_module()] 158module_c_headers = [h for h in all_headers if h.has_cxx20_module() and h.is_cstd()] 159 160# These headers are not yet implemented in libc++ 161# 162# These headers are required by the latest (draft) Standard but have not been 163# implemented yet. They are used in the generated module input. The C++23 standard 164# modules will fail to build if a header is added but this list is not updated. 165headers_not_available = list(map(Header, [ 166 "debugging", 167 "flat_set", 168 "generator", 169 "hazard_pointer", 170 "inplace_vector", 171 "linalg", 172 "rcu", 173 "spanstream", 174 "stacktrace", 175 "stdfloat", 176 "text_encoding", 177])) 178 179header_restrictions = { 180 # headers with #error directives 181 "atomic": "_LIBCPP_HAS_ATOMIC_HEADER", 182 "stdatomic.h": "_LIBCPP_HAS_ATOMIC_HEADER", 183 184 # headers with #error directives 185 "ios": "_LIBCPP_HAS_LOCALIZATION", 186 # transitive includers of the above headers 187 "clocale": "_LIBCPP_HAS_LOCALIZATION", 188 "codecvt": "_LIBCPP_HAS_LOCALIZATION", 189 "fstream": "_LIBCPP_HAS_LOCALIZATION", 190 "iomanip": "_LIBCPP_HAS_LOCALIZATION", 191 "iostream": "_LIBCPP_HAS_LOCALIZATION", 192 "istream": "_LIBCPP_HAS_LOCALIZATION", 193 "locale": "_LIBCPP_HAS_LOCALIZATION", 194 "ostream": "_LIBCPP_HAS_LOCALIZATION", 195 "regex": "_LIBCPP_HAS_LOCALIZATION", 196 "sstream": "_LIBCPP_HAS_LOCALIZATION", 197 "streambuf": "_LIBCPP_HAS_LOCALIZATION", 198 "strstream": "_LIBCPP_HAS_LOCALIZATION", 199 "syncstream": "_LIBCPP_HAS_LOCALIZATION", 200} 201 202lit_header_restrictions = { 203 "barrier": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17", 204 "clocale": "// UNSUPPORTED: no-localization", 205 "codecvt": "// UNSUPPORTED: no-localization", 206 "coroutine": "// UNSUPPORTED: c++03, c++11, c++14, c++17", 207 "cwchar": "// UNSUPPORTED: no-wide-characters", 208 "cwctype": "// UNSUPPORTED: no-wide-characters", 209 "experimental/iterator": "// UNSUPPORTED: c++03", 210 "experimental/propagate_const": "// UNSUPPORTED: c++03", 211 "experimental/simd": "// UNSUPPORTED: c++03", 212 "experimental/type_traits": "// UNSUPPORTED: c++03", 213 "experimental/utility": "// UNSUPPORTED: c++03", 214 "filesystem": "// UNSUPPORTED: no-filesystem, c++03, c++11, c++14", 215 "fstream": "// UNSUPPORTED: no-localization, no-filesystem", 216 "future": "// UNSUPPORTED: no-threads, c++03", 217 "iomanip": "// UNSUPPORTED: no-localization", 218 "ios": "// UNSUPPORTED: no-localization", 219 "iostream": "// UNSUPPORTED: no-localization", 220 "istream": "// UNSUPPORTED: no-localization", 221 "latch": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17", 222 "locale": "// UNSUPPORTED: no-localization", 223 "mutex": "// UNSUPPORTED: no-threads, c++03", 224 "ostream": "// UNSUPPORTED: no-localization", 225 "print": "// UNSUPPORTED: no-filesystem, c++03, c++11, c++14, c++17, c++20, availability-fp_to_chars-missing", # TODO PRINT investigate 226 "regex": "// UNSUPPORTED: no-localization", 227 "semaphore": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17", 228 "shared_mutex": "// UNSUPPORTED: no-threads, c++03, c++11", 229 "sstream": "// UNSUPPORTED: no-localization", 230 "stdatomic.h": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17, c++20", 231 "stop_token": "// UNSUPPORTED: no-threads, c++03, c++11, c++14, c++17", 232 "streambuf": "// UNSUPPORTED: no-localization", 233 "strstream": "// UNSUPPORTED: no-localization", 234 "syncstream": "// UNSUPPORTED: no-localization", 235 "thread": "// UNSUPPORTED: no-threads, c++03", 236 "wchar.h": "// UNSUPPORTED: no-wide-characters", 237 "wctype.h": "// UNSUPPORTED: no-wide-characters", 238} 239 240# Undeprecate headers that are deprecated in C++17 and removed in C++20. 241lit_header_undeprecations = { 242 "ccomplex": "// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS", 243 "ciso646": "// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS", 244 "cstdalign": "// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS", 245 "cstdbool": "// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS", 246 "ctgmath": "// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS", 247} 248 249# This table was produced manually, by grepping the TeX source of the Standard's 250# library clauses for the string "#include". Each header's synopsis contains 251# explicit "#include" directives for its mandatory inclusions. 252# For example, [algorithm.syn] contains "#include <initializer_list>". 253mandatory_inclusions = { 254 "algorithm": ["initializer_list"], 255 "array": ["compare", "initializer_list"], 256 "bitset": ["iosfwd", "string"], 257 "chrono": ["compare"], 258 "cinttypes": ["cstdint"], 259 "complex.h": ["complex"], 260 "coroutine": ["compare"], 261 "deque": ["compare", "initializer_list"], 262 "filesystem": ["compare"], 263 "flat_map": ["compare", "initializer_list"], 264 "forward_list": ["compare", "initializer_list"], 265 "ios": ["iosfwd"], 266 "iostream": ["ios", "istream", "ostream", "streambuf"], 267 "iterator": ["compare", "concepts"], 268 "list": ["compare", "initializer_list"], 269 "map": ["compare", "initializer_list"], 270 "memory": ["compare"], 271 "optional": ["compare"], 272 "queue": ["compare", "initializer_list"], 273 "random": ["initializer_list"], 274 "ranges": ["compare", "initializer_list", "iterator"], 275 "regex": ["compare", "initializer_list"], 276 "set": ["compare", "initializer_list"], 277 "stack": ["compare", "initializer_list"], 278 "string_view": ["compare"], 279 "string": ["compare", "initializer_list"], 280 "syncstream": ["ostream"], 281 "system_error": ["compare"], 282 "tgmath.h": ["cmath", "complex"], 283 "thread": ["compare"], 284 "tuple": ["compare"], 285 "typeindex": ["compare"], 286 "unordered_map": ["compare", "initializer_list"], 287 "unordered_set": ["compare", "initializer_list"], 288 "utility": ["compare", "initializer_list"], 289 "valarray": ["initializer_list"], 290 "variant": ["compare"], 291 "vector": ["compare", "initializer_list"], 292} 293